Merge "sound: usb: Handle iova map/unmap properly for SMMU stage 1"
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index d11af52..ac9489f 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -54,6 +54,7 @@
 | ARM            | Cortex-A57      | #852523         | N/A                         |
 | ARM            | Cortex-A57      | #834220         | ARM64_ERRATUM_834220        |
 | ARM            | Cortex-A72      | #853709         | N/A                         |
+| ARM            | Cortex-A55      | #1024718        | ARM64_ERRATUM_1024718       |
 | ARM            | MMU-500         | #841119,#826419 | N/A                         |
 |                |                 |                 |                             |
 | Cavium         | ThunderX ITS    | #22375, #24313  | CAVIUM_ERRATUM_22375        |
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 9a9a6d0..3a96610 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -190,6 +190,20 @@
 	* reg-names: funnel-base-real: actual register space for the
 	  duplicate funnel.
 
+* Optional properties for CSRs:
+
+	* qcom,usb-bam-support: boolean, indicates CSR has the ability to operate on
+	  usb bam, include enable,disable and flush.
+
+	* qcom,hwctrl-set-support: boolean, indicates CSR has the ability to operate on
+	  to "HWCTRL" register.
+
+	* qcom,set-byte-cntr-support:boolean, indicates CSR has the ability to operate on
+	  to "BYTECNT" register.
+
+	* qcom,timestamp-support:boolean, indicates CSR support sys interface to read
+	  timestamp value.
+
 Example:
 
 1. Sinks
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
index 4cc49a59..83a1601 100644
--- a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
+++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt
@@ -12,10 +12,14 @@
 Required properties:
 - compatible:           Must be one of following,
 			"qcom,gcc-8953"
+			"qcom,gcc-sdm632"
 			"qcom,cc-debug-8953"
+			"qcom,cc-debug-sdm632"
 			"qcom,gcc-mdss-8953"
+			"qcom,gcc-mdss-sdm632"
                         "qcom,gcc-gfx-8953"
                         "qcom,gcc-gfx-sdm450"
+                        "qcom,gcc-gfx-sdm632"
 
 - reg:                  Pairs of physical base addresses and region sizes of
                         memory mapped registers.
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index 9bc8168..1b8b7cf 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -175,6 +175,9 @@
 - VR device:
   compatible = "qcom,qvr"
 
+- SVR device:
+  compatible = "qcom,svr"
+
 - HDK device:
   compatible = "qcom,hdk"
 
@@ -295,6 +298,7 @@
 compatible = "qcom,sda845-mtp"
 compatible = "qcom,sda845-qrd"
 compatible = "qcom,sda845-hdk"
+compatible = "qcom,sda845-svr"
 compatible = "qcom,sdm670-rumi"
 compatible = "qcom,sdm670-cdp"
 compatible = "qcom,sdm670-mtp"
@@ -328,6 +332,9 @@
 compatible = "qcom,sdm450-cdp"
 compatible = "qcom,sdm450-qrd"
 compatible = "qcom,sdm632-rumi"
+compatible = "qcom,sdm632-cdp"
+compatible = "qcom,sdm632-mtp"
+compatible = "qcom,sdm632-qrd"
 compatible = "qcom,mdm9640-cdp"
 compatible = "qcom,mdm9640-mtp"
 compatible = "qcom,mdm9640-rumi"
diff --git a/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
new file mode 100644
index 0000000..0149ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/cnss/cnss-sdio-wlan.txt
@@ -0,0 +1,57 @@
+* Qualcomm Technologies, Inc. Connectivity SubSystem Platform Driver
+
+This platform driver adds support for the CNSS subsystem used for SDIO
+based Wi-Fi devices. It also adds support to manage two 1.8V voltage
+regulators and WLAN power enable 3.3V regulators. The main purpose of this
+device tree entry below is to invoke the CNSS SDIO platform driver
+and provide handle to the WLAN power enable 3.3V pmic GPIO and two 1.8V
+PMIC voltage regulator resources.
+
+Required properties:
+  - compatible: "qcom,cnss_sdio"
+  - reg: memory resource to save firmware dump, optional.
+  - reg-names: memory resource name.
+  - subsys-name: cnss sdio subsytem device name, required.
+  - vdd-wlan-supply: phandle to the WLAN vdd regulator device tree node.
+  - vdd-wlan-dsrc-supply: phandle to the WLAN dsrc vdd regulator device tree node.
+  - vdd-wlan-io-supply: phandle to the WLAN IO regulator device tree node.
+  - vdd-wlan-xtal-supply: phandle to the WLAM XTAL regulator device tree node.
+
+Optional properties:
+  - pinctrl-names: Names corresponding to the numbered pinctrl states
+  - pinctrl-<n>: Pinctrl states as described in
+                bindings/pinctrl/pinctrl-bindings.txt
+  - qcom,is-antenna-shared: Enabled for Platforms with both sdio and pcie QCA
+                           Chipsets are attached.
+  - qcom,cnss-enable-bus-bandwidth: Boolean - Define this property when target
+					support to vote for bus bandwidth.
+  - qcom,msm-bus,name: client name for msm bus register.
+  - qcom,msm-bus,num-cases: number of cases for bus scaling.
+  - qcom,msm-bus,num-paths: number of paths for bus scale vector.
+  - qcom,msm-bus,vectors-KBps: bus scale vector table.
+  - qcom,skip-wlan-en-toggle: Boolean property to be enabled for platforms where
+                           wlan_en toggling is not supported.
+Example:
+	qcom,cnss-sdio {
+		compatible = "qcom,cnss_sdio";
+		reg = <0x87a00000, 0x200000>;
+		reg-names = "ramdump";
+		subsys-name = "AR6320";
+		vdd-wlan-supply = <&rome_vreg>;
+		vdd-wlan-dsrc-supply = <&sdcard_ext_vreg>;
+		vdd-wlan-io-supply = <&mdm9607_l11>;
+		vdd-wlan-xtal-supply = <&mdm9607_l2>;
+		qcom,is-antenna-shared;
+		pinctrl-names = "active", "sleep";
+		pinctrl-0 = <&cnss_sdio_active>;
+		pinctrl-1 = <&cnss_sdio_sleep>;
+		qcom,cnss-enable-bus-bandwidth;
+		qcom,msm-bus,name = "msm-cnss";
+		qcom,msm-bus,num-cases = <4>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<79 512 0 0>,			/* No vote */
+				<79 512 6250 200000>,		/* 50 Mbps */
+				<79 512 25000 200000>,		/* 200 Mbps */
+				<79 512 2048000 4096000>;	/* MAX */
+	};
diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt
index ad9d190..e70109d 100644
--- a/Documentation/devicetree/bindings/cnss/icnss.txt
+++ b/Documentation/devicetree/bindings/cnss/icnss.txt
@@ -30,6 +30,7 @@
   - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
   - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory
   - qcom,gpio-force-fatal-error: SMP2P bit triggered by WLAN FW to force error fatal.
+  - qcom,gpio-early-crash-ind: SMP2P bit triggered by WLAN FW to indicate FW is in assert.
 
 Example:
 
@@ -61,4 +62,5 @@
 	vdd-0.8-cx-mx-supply = <&pm8998_l5>;
 	qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
 	qcom,gpio-forced-fatal-error = <&smp2pgpio_wlan_1_in 0 0>;
+	qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>;
     };
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index a89b834..0f40cbce 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -66,6 +66,10 @@
 - qcom,dsi-display:       Specifies dsi display is present
 - qcom,hdmi-display:      Specifies hdmi is present
 - qcom,dp-display:        Specified dp is present
+- ports:                  This video port is used when external bridge is present. The connection is modelled
+                          using the OF graph bindings specified in Documentation/devicetree/bindings/graph.txt.
+                          Video port 0 is for the bridge output. The remote endpoint phandle should be
+                          mipi_dsi_device device node.
 - qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the
 					a particular "type" of DSI module. The module "types"
 					can be "core", "ctrl", and "phy". Within the same type,
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 493a1aa..7bcb2dc 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi-panel
+Qualcomm Technologies, Inc. mdss-dsi-panel
 
 mdss-dsi-panel is a dsi panel device which supports panels that
 are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
index 2f74f7f..8b593a9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
@@ -1,4 +1,4 @@
-Qualcomm mdss-dsi
+Qualcomm Technologies, Inc. mdss-dsi
 
 mdss-dsi is the master DSI device which supports multiple DSI host controllers that
 are compatible with MIPI display serial interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index c474b88..3d649e5 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS EDP
+Qualcomm Technologies, Inc. MDSS EDP
 
 MDSS EDP is a edp driver which supports panels that are compatible with
 VESA EDP display interface specification.
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index e33d358..3661221 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -1,4 +1,4 @@
-Qualcomm MDSS MDP
+Qualcomm Technologies, Inc. MDSS MDP
 
 MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to
 drive user interface to different panel interfaces. MDP driver is the core of
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index d746a52..6b9238c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -1,8 +1,7 @@
-Qualcomm MDSS pll for DSI/EDP/HDMI
+Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI
 
-mdss-pll is a pll controller device which supports pll devices that
-are compatiable with MIPI display serial interface specification,
-HDMI and edp.
+mdss-pll is a pll controller device which supports pll devices that are
+compatiable with MIPI display serial interface specification, HDMI and edp.
 
 Required properties:
 - compatible:		Compatible name used in the driver. Should be one of:
diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
index 7f95ed4..285a14f 100644
--- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
+++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt
@@ -1,4 +1,4 @@
-* Qualcomm HDMI Tx
+* Qualcomm Technologies, Inc. HDMI Tx
 
 Required properties:
 - cell-index: hdmi tx controller index
diff --git a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
index b399145..c679fe6 100644
--- a/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno-iommu.txt
@@ -42,6 +42,7 @@
   currently supported names are:
   - gfx3d_user : Used for the 'normal' GPU address space.
   - gfx3d_secure : Used for the content protection address space.
+  - gfx3d_secure_alt : Used for the content protection address space for alternative SID.
   Each sub node has the following required properties:
 
 	- compatible : "qcom,smmu-kgsl-cb"
@@ -83,4 +84,9 @@
 			compatible = "qcom,smmu-kgsl-cb";
 			iommus = <&kgsl_smmu 2>;
 		};
+
+		gfx3d_secure_alt: gfx3d_secure_alt {
+			compatible = "qcom,smmu-kgsl-cb";
+			iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
+		};
 	};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 55cd383..375e929 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -130,6 +130,13 @@
 				mask   - mask for the relevant bits in the efuse register.
 				shift  - number of bits to right shift to get the disable_gpu
 				fuse bit value.
+
+- qcom,soc-hw-rev-efuse:	SOC hardware revision fuse information in the format
+				<offset bit_position mask>
+				offset - offset of the efuse register from the base.
+				bit_position - hardware revision starting bit in the efuse register.
+				mask - mask for the relevant bits in the efuse register.
+
 - qcom,highest-bank-bit:
 				Specify the bit of the highest DDR bank. This
 				is programmed into protected registers and also
@@ -200,6 +207,9 @@
 - qcom,gpu-quirk-limit-uche-gbif-rw:
 				Limit number of read and write transactions from UCHE block to
 				GBIF to avoid possible deadlock between GBIF, SMMU and MEMNOC.
+- qcom,gpu-quirk-mmu-secure-cb-alt:
+				Select alternate secure context bank to generate SID1 for
+				secure playback.
 
 KGSL Memory Pools:
 - qcom,gpu-mempools:		Container for sets of GPU mempools.Multiple sets
@@ -230,7 +240,7 @@
 		Defines a SOC hardware revision.
 
 Properties:
-- reg:
+-  qcom,soc-hw-revision:
 		Identifier for the hardware revision - must match the value read
 		from the hardware.
 - qcom,chipid:
diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
index b0c5b57..d9d3470 100644
--- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
+++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt
@@ -51,6 +51,8 @@
   device (see pinctrl binding [0]).
 
 [0]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+- #thermal-sensor-cells : To register ADC sensors with of_thermal. Should be 1.
+  See ./thermal.txt for a description.
 
 Client required property:
 - qcom,<consumer name>-vadc : The phandle to the corresponding vadc device.
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
index 7dece8e..c33daab 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
@@ -11,6 +11,8 @@
  - reg			               : i2c slave address of the device.
  - interrupt-parent	           : parent of interrupt.
  - synaptics,irq-gpio	       : irq gpio.
+ - synaptics,reset-gpio	       : reset gpio.
+ - synaptics,power-gpio	       : power switch gpio.
  - synaptics,irq-flags         : irq flags.
 
 Optional property:
@@ -18,13 +20,23 @@
  - vcc_i2c-supply			   : analog voltage power supply needed to power device.
  - synaptics,pwr-reg-name	   : power reg name of digital voltage.
  - synaptics,bus-reg-name	   : bus reg name of analog voltage.
- - synaptics,irq-on-state      : status of irq gpio.
+ - synaptics,irq-on-state	 : irq gpio active state.
+ - synaptics,reset-on-state      : reset gpio active state.
+ - synaptics,power-on-state      : power switch active state.
+ - synaptics,ub-i2c-addr	 : microbootloader mode I2C slave address.
  - synaptics,cap-button-codes  : virtual key code mappings to be used.
  - synaptics,vir-button-codes  : virtual key code and the response region on panel.
  - synaptics,x-flip		       : modify orientation of the x axis.
  - synaptics,y-flip		       : modify orientation of the y axis.
  - synaptics,reset-delay-ms	   : reset delay for controller (ms), default 100.
+ - synaptics,reset-active-ms	   : reset active duration for controller (ms), default 100.
+ - synaptics,power-delay-ms	   : power delay for controller (ms), default 100.
  - synaptics,max-y-for-2d	   : maximal y value of the panel.
+ - synaptics,swap-axes		   : specify whether to swap axes.
+ - synaptics,resume-in-workqueue	: specify whether to defer the resume to workqueue.
+ - clock-names			: Clock names used for secure touch. They are: "iface_clk", "core_clk"
+ - clocks			: Defined if 'clock-names' DT property is defined. These clocks
+				  are associated with the underlying I2C bus.
 
 Example:
 	i2c@78b7000 {
@@ -34,8 +46,8 @@
 			reg = <0x4b>;
 			interrupt-parent = <&tlmm>;
 			interrupts = <65 0x2008>;
-			vdd_ana-supply = <&pmtitanium_l17>;
-			vcc_i2c-supply = <&pmtitanium_l6>;
+			vdd_ana-supply = <&pm8953_l17>;
+			vcc_i2c-supply = <&pm8953_l6>;
 			synaptics,pwr-reg-name = "vdd_ana";
 			synaptics,bus-reg-name = "vcc_i2c";
 			synaptics,irq-gpio = <&tlmm 65 0x2008>;
@@ -46,5 +58,9 @@
 			synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */
 			synaptics,cap-button-codes = <139 172 158>;
 			synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>;
+			/* Underlying clocks used by secure touch */
+			clock-names = "iface_clk", "core_clk";
+			clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+				<&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
 		};
 	};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
index 07667a4..8d6fad0 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
@@ -31,6 +31,7 @@
 	* "qcom,pdc-sdm845": For sdm845 pin data
 	* "qcom,pdc-sdm845-v2": For sdm845 v2 pin data
 	* "qcom,pdc-sdm670": For sdm670 pin data
+	* "qcom,pdc-sdxpoorwills": For sdxpoorwills pin data
 
 - reg:
 	Usage: required
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
index b7ce662..1a76d5d 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
@@ -118,6 +118,18 @@
 
 Following properties are specific only to LRA vibrators.
 
+- qcom,lra-auto-mode
+  Usage:      optional
+  Value type: <empty>
+  Definition: If specified, a set of pre-configured settings will be applied
+		based on the pattern duration. For example, for a duration of
+		< 20 ms (short duration), one set of settings will be applied
+		and for a duration of >= 20 ms (long duration), another set of
+		settings will be applied. The parameters configured in the
+		driver when this property is specified is based on the LRA
+		tested internally. Those parameters should be fine-tuned or
+		adjusted based on the LRA used on different hardware platforms.
+
 - qcom,lra-auto-res-mode
   Usage:      optional
   Value type: <string>
@@ -200,9 +212,13 @@
 - qcom,wave-samples
   Usage:      optional
   Value type: <prop-encoded-array>
-  Definition: Wave samples in an array of 8 elements. Each element takes the
+  Definition: Wave samples in an array of 32 elements. Each element takes the
 		following representation, bit 0: unused, bits[5:1] : amplitude,
 		bit 6: overdrive, bit 7: sign. Default sample value is 0x3E.
+		Since the hardware supports configuring upto 8 samples, a set
+		of 8 samples will be configured initially and the next set will
+		be configured upon the play interrupt until all the samples are
+		configured and played.
 
 Following properties are applicable only when "qcom,play-mode" is set to
 "pwm".
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt b/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt
new file mode 100644
index 0000000..5b5323e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc-vmem.txt
@@ -0,0 +1,42 @@
+* Qualcomm Technologies Inc MSM VIDC VMEM
+
+Required properties:
+- compatible : "qcom,msm-vmem"
+- interrupts : Contains the interrupt that maps to the VMEM module
+- reg : A set of 2 start address and size pairs that describe the hardware
+register address space and mappable memory address space.
+- reg-names : Strings that describe the pairs in "reg".  The register address
+space should be called "reg-base" and the memory space should be called "mem-base".
+- clocks : A set of clocks that correspond to the AHB and MAXI clocks that the
+hardware uses.
+- clock-names : A string that describes the "clocks" property.  The AHB clock
+should be named "ahb" and the MAXI clock should be named "maxi".
+- qcom,bank-size : The size of each memory bank, in bytes.
+- vdd-supply: phandle to a regulator that is considered to be the footswitch for vmem.
+- qcom,msm-bus,(name|num-cases,num-paths,vectors-KBps) - Bus to be voted for prior to
+  issuing any IO transactions to vmem.  Refer to Documentation/devicetree/bindings/arm/\
+  msm/msm_bus_adhoc.txt for further details.
+
+Example:
+
+qcom,vmem@880000 {
+	compatible = "qcom,msm-vmem";
+	interrupts = <0 429 0>;
+	reg = <0x880000 0x800>,
+	    <0x6800000 0x100000>;
+	reg-names = "reg-base", "mem-base";
+
+	vdd-supply = <&gdsc_mmagic_video>;
+	clocks = <&clock_mmss clk_vmem_ahb_clk>,
+	       <&clock_mmss clk_vmem_maxi_clk>;
+	clock-names = "ahb", "maxi";
+
+	qcom,bank-size = <131072>;
+
+	qcom,msm-bus,name = "vmem";
+	qcom,msm-bus,num-cases = <2>;
+	qcom,msm-bus,num-paths = <1>;
+	qcom,msm-bus,vectors-KBps =
+	        <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_VMEM_CFG   0   0>,
+	        <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_VMEM_CFG 500 800>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 001f74f3..6c61ada 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -121,6 +121,10 @@
 
 	- qcom,wakeup-on-idle: if configured, the mmcqd thread will call
 	  set_wake_up_idle(), thereby voting for it to be called on idle CPUs.
+	- nvmem-cells: specifies the handle to represent the SoC revision.
+	  usually it is defined by qfprom device node.
+	- nvmem-cell-names: specifies the given nvmem cell name as defined in
+	  qfprom node.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8937-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8937-pinctrl.txt
new file mode 100644
index 0000000..f697704
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8937-pinctrl.txt
@@ -0,0 +1,204 @@
+Qualcomm Technologies, Inc. MSM8937 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MSM8937 platform.
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be "qcom,msm8937-pinctrl"
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+	Usage: required
+	Value type: <none>
+	Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: must be 2. Specifying the pin number and flags, as defined
+		    in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+	Usage: required
+	Value type: <string-array>
+	Definition: List of gpio pins affected by the properties specified in
+		    this subnode.
+		    Valid pins are:
+		    gpio0-gpio133,
+		    sdc1_clk,
+		    sdc1_cmd,
+		    sdc1_data,
+		    sdc1_rclk,
+		    sdc2_clk,
+		    sdc2_cmd,
+		    sdc2_data,
+		    qdsd_clk,
+		    qdsd_cmd,
+		    qdsd_data0,
+		    qdsd_data1,
+		    qdsd_data2,
+		    qdsd_data3,
+
+- function:
+	Usage: required
+	Value type: <string>
+	Definition: Specify the alternative function to be configured for the
+		    specified pins. Functions are only valid for gpio pins.
+		    Valid values are:
+        qdss_tracedata_b, blsp_uart1, gpio, blsp_spi1, adsp_ext, blsp_i2c1, prng_rosc,
+        qdss_cti_trig_out_b0, blsp_spi2, blsp_uart2, blsp_uart3, pbs0, pbs1,
+        pwr_modem_enabled_b, blsp_i2c3, gcc_gp2_clk_b, ldo_update,
+        atest_combodac_to_gpio_native, ldo_en, blsp_i2c2, gcc_gp1_clk_b, pbs2,
+        atest_gpsadc_dtest0_native, blsp_spi3, gcc_gp3_clk_b, blsp_spi4, blsp_uart4,
+        sec_mi2s, pwr_nav_enabled_b, codec_mad, pwr_crypto_enabled_b, blsp_i2c4,
+        blsp_spi5, blsp_uart5, qdss_traceclk_a, atest_bbrx1, m_voc,
+        qdss_cti_trig_in_a0, qdss_cti_trig_in_b0, blsp_i2c6, qdss_traceclk_b,
+        atest_wlan0, atest_wlan1, atest_bbrx0, blsp_i2c5, qdss_tracectl_a,
+        atest_gpsadc_dtest1_native, qdss_tracedata_a, blsp_spi6, blsp_uart6,
+        qdss_tracectl_b, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, cam_mclk,
+        cci_i2c, pwr_modem_enabled_a, cci_timer0, cci_timer1, cam1_standby,
+        pwr_nav_enabled_a, cam1_rst, pwr_crypto_enabled_a, forced_usb,
+        qdss_cti_trig_out_b1, cam2_rst, webcam_standby, cci_async, webcam_rst,
+        ov_ldo, sd_write, accel_int, gcc_gp1_clk_a, alsp_int, gcc_gp2_clk_a,
+        mag_int, gcc_gp3_clk_a, blsp6_spi, fp_int, qdss_cti_trig_in_b1, uim_batt,
+        cam2_standby, uim1_data, uim1_clk, uim1_reset, uim1_present, uim2_data,
+        uim2_clk, uim2_reset, uim2_present, sensor_rst, mipi_dsi0, smb_int,
+        cam0_ldo, us_euro, atest_char3, dbg_out, bimc_dte0, ts_resout, ts_sample,
+        sec_mi2s_mclk_b, pri_mi2s, sdcard_det, atest_char1, ebi_cdc, audio_reset,
+        atest_char0, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, lpass_slimbus,
+        lpass_slimbus0, lpass_slimbus1, codec_int1, codec_int2, wcss_bt,
+        atest_char2, ebi_ch0, wcss_wlan2, wcss_wlan1, wcss_wlan0, wcss_wlan,
+        wcss_fm, ext_lpass, cri_trng, cri_trng1, cri_trng0, blsp_spi7, blsp_uart7,
+        pri_mi2s_ws, blsp_i2c7, gcc_tlmm, dmic0_clk, dmic0_data, key_volp,
+        qdss_cti_trig_in_a1, us_emitter, wsa_irq, wsa_io, wsa_reset, blsp_spi8,
+        blsp_uart8, blsp_i2c8, gcc_plltest, nav_pps_in_a, pa_indicator, modem_tsync,
+        nav_tsync, nav_pps_in_b, nav_pps, gsm0_tx, atest_char, atest_tsens,
+        bimc_dte1, ssbi_wtr1, fp_gpio, coex_uart, key_snapshot, key_focus, nfc_pwr,
+        blsp8_spi, qdss_cti_trig_out_a0, qdss_cti_trig_out_a1
+
+- bias-disable:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins should be configued as pull up.
+
+- output-high:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    high.
+		    Not valid for sdc pins.
+
+- output-low:
+	Usage: optional
+	Value type: <none>
+	Definition: The specified pins are configured in output mode, driven
+		    low.
+		    Not valid for sdc pins.
+
+- drive-strength:
+	Usage: optional
+	Value type: <u32>
+	Definition: Selects the drive strength for the specified pins, in mA.
+		    Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+	tlmm: pinctrl@1000000 {
+		compatible = "qcom,msm8937-pinctrl";
+		reg = <0x1000000 0x300000>;
+		interrupts = <0 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		pmx-uartconsole {
+			uart_console_active: uart_console_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			uart_console_sleep: uart_console_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+		};
+	};
diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt
index d272b7f..73cd1db 100644
--- a/Documentation/devicetree/bindings/platform/msm/ipa.txt
+++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt
@@ -135,6 +135,8 @@
 - qcom,additional-mapping: specifies any addtional mapping needed for this
 				context bank. The format is <iova pa size>
 
+- qcom,ipa-q6-smem-size: specifies the Q6 SMEM partition size
+
 IPA SMP2P sub nodes
 
 -compatible: "qcom,smp2pgpio-map-ipa-1-out" - represents the out gpio from
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index f50fd88..75996a5 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -104,6 +104,13 @@
 		    this property is not specified, then the default value used
 		    will be 75mA.
 
+- qcom,fg-cutoff-current
+	Usage:      optional
+	Value type: <u32>
+	Definition: Minimum Battery current (in mA) used for cutoff SOC
+		    estimate. If this property is not specified, then a default
+		    value of 500 mA will be applied.
+
 - qcom,fg-delta-soc-thr
 	Usage:      optional
 	Value type: <u32>
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
new file mode 100644
index 0000000..65c3cb8
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
@@ -0,0 +1,304 @@
+Qualcomm Technologies, Inc. SMB5 Charger Specific Bindings
+
+SMB5 Charger is an efficient programmable battery charger capable of charging a
+high-capacity lithium-ion battery over micro-USB or USB Type-C ultrafast with
+Quick Charge 2.0, Quick Charge 3.0, and USB Power Delivery support. Wireless
+charging features full A4WP Rezence 1.2, WPC 1.2, and PMA support.
+
+=======================
+Required Node Structure
+=======================
+
+SMB5 Charger must be described in two levels of devices nodes.
+
+===============================
+First Level Node - SMB5 Charger
+===============================
+
+Charger specific properties:
+- compatible
+  Usage:      required
+  Value type: <string>
+  Definition: "qcom,qpnp-smb5".
+
+- qcom,pmic-revid
+  Usage:      required
+  Value type: phandle
+  Definition: Should specify the phandle of PMI's revid module. This is used to
+		identify the PMI subtype.
+
+- qcom,batteryless-platform
+  Usage:      optional
+  Value type: <empty>
+  Definition: Boolean flag which indicates that the platform does not have a
+		battery, and therefore charging should be disabled. In
+		addition battery properties will be faked such that the device
+		assumes normal operation.
+
+- qcom,fcc-max-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the maximum fast charge current in micro-amps.
+		If the value is not present, 1Amp is used as default.
+
+- qcom,fv-max-uv
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the maximum float voltage in micro-volts.
+		If the value is not present, 4.35V is used as default.
+
+- qcom,usb-icl-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the USB input current limit in micro-amps.
+		 If the value is not present, 1.5Amps is used as default.
+
+- qcom,usb-ocl-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the OTG output current limit in micro-amps.
+		If the value is not present, 1.5Amps is used as default.
+
+- qcom,dc-icl-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the DC input current limit in micro-amps.
+
+- qcom,boost-threshold-ua
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the boost current threshold in micro-amps.
+		If the value is not present, 100mA is used as default.
+
+- qcom,thermal-mitigation
+  Usage:      optional
+  Value type: Array of <u32>
+  Definition: Array of fast charge current limit values for
+		different system thermal mitigation levels.
+		This should be a flat array that denotes the
+		maximum charge current in mA for each thermal
+		level.
+
+- qcom,float-option
+  Usage:      optional
+  Value type: <u32>
+  Definition: Configures how the charger behaves when a float charger is
+	      detected by APSD.
+	        1 - Treat as a DCP.
+	        2 - Treat as a SDP.
+	        3 - Disable charging.
+	        4 - Suspend USB input.
+
+- qcom,hvdcp-disable
+  Usage:      optional
+  Value type: <empty>
+  Definition: Specifies if hvdcp charging is to be enabled or not.
+		If this property is not specified hvdcp will be enabled.
+		If this property is specified, hvdcp 2.0 detection will still
+		happen but the adapter won't be asked to switch to a higher
+		voltage point.
+
+- qcom,chg-inhibit-threshold-mv
+  Usage:      optional
+  Value type: <u32>
+  Definition: Charge inhibit threshold in milli-volts. Charging will be
+		inhibited when the battery voltage is within this threshold
+		from Vfloat at charger insertion. If this is not specified
+		then charge inhibit will be disabled by default.
+		Allowed values are: 50, 100, 200, 300.
+
+- qcom,auto-recharge-soc
+  Usage:      optional
+  Value type: <empty>
+  Definition: Specifies if automatic recharge needs to be based off battery
+		SOC. If this property is not specified, then auto recharge will
+		be based off battery voltage.
+
+- qcom,suspend-input-on-debug-batt
+  Usage:      optional
+  Value type: <empty>
+  Definition: Boolean flag which when present enables input suspend for
+		debug battery.
+
+- qcom,min-freq-khz
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the minimum charger buck/boost switching frequency
+		in KHz. It overrides the min frequency defined for the charger.
+
+- qcom,max-freq-khz
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the maximum charger buck/boost switching frequency in
+		 KHz. It overrides the max frequency defined for the charger.
+
+- qcom,otg-deglitch-time-ms
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the deglitch interval for OTG detection.
+		If the value is not present, 50 msec is used as default.
+
+- qcom,step-charging-enable
+  Usage:      optional
+  Value type: bool
+  Definition: Boolean flag which when present enables step-charging.
+
+- qcom,wd-bark-time-secs
+  Usage:      optional
+  Value type: <u32>
+  Definition: WD bark-timeout in seconds. The possible values are
+		16, 32, 64, 128. If not defined it defaults to 64.
+
+- qcom,sw-jeita-enable
+  Usage:      optional
+  Value type: bool
+  Definition: Boolean flag which when present enables sw compensation for
+		jeita.
+
+- qcom,battery-data
+  Usage:      optional
+  Value type: <phandle>
+  Definition: Specifies the phandle of the node which contains the battery
+		profiles supported on the device. This is only specified
+		when step charging and sw-jeita configurations are desired
+		to be get from these properties defined in battery profile:
+		qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges.
+
+=============================================
+Second Level Nodes - SMB5 Charger Peripherals
+=============================================
+
+Peripheral specific properties:
+- reg
+  Usage:      required
+  Value type: <prop-encoded-array>
+  Definition: Address and size of the peripheral's register block.
+
+- interrupts
+  Usage:      required
+  Value type: <prop-encoded-array>
+  Definition: Peripheral interrupt specifier.
+
+- interrupt-names
+  Usage:      required
+  Value type: <stringlist>
+  Definition: Interrupt names.  This list must match up 1-to-1 with the
+	      interrupts specified in the 'interrupts' property.
+
+=======
+Example
+=======
+
+pmi8998_charger: qcom,qpnp-smb5 {
+	compatible = "qcom,qpnp-smb5";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	dpdm-supply = <&qusb_phy0>;
+
+	qcom,chgr@1000 {
+		reg = <0x1000 0x100>;
+		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>;
+
+		interrupt-names =	"chg-error",
+					"chg-state-change",
+					"step-chg-state-change",
+					"step-chg-soc-update-fail",
+					"step-chg-soc-update-request";
+	};
+
+	qcom,otg@1100 {
+		reg = <0x1100 0x100>;
+		interrupts =	<0x2 0x11 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x11 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x11 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x11 0x3 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"otg-fail",
+					"otg-overcurrent",
+					"otg-oc-dis-sw-sts",
+					"testmode-change-detect";
+	};
+
+	qcom,bat-if@1200 {
+		reg = <0x1200 0x100>;
+		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>;
+
+		interrupt-names =	"bat-temp",
+					"bat-ocp",
+					"bat-ov",
+					"bat-low",
+					"bat-therm-or-id-missing",
+					"bat-terminal-missing";
+	};
+
+	qcom,usb-chgpth@1300 {
+		reg = <0x1300 0x100>;
+		interrupts =	<0x2 0x13 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x3 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x4 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x5 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x6 IRQ_TYPE_NONE>,
+				<0x2 0x13 0x7 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"usbin-collapse",
+					"usbin-lt-3p6v",
+					"usbin-uv",
+					"usbin-ov",
+					"usbin-plugin",
+					"usbin-src-change",
+					"usbin-icl-change",
+					"type-c-change";
+	};
+
+	qcom,dc-chgpth@1400 {
+		reg = <0x1400 0x100>;
+		interrupts =	<0x2 0x14 0x0 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x1 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x2 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x3 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x4 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x5 IRQ_TYPE_NONE>,
+				<0x2 0x14 0x6 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"dcin-collapse",
+					"dcin-lt-3p6v",
+					"dcin-uv",
+					"dcin-ov",
+					"dcin-plugin",
+					"div2-en-dg",
+					"dcin-icl-change";
+	};
+
+	qcom,chgr-misc@1600 {
+		reg = <0x1600 0x100>;
+		interrupts =	<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>,
+				<0x2 0x16 0x6 IRQ_TYPE_NONE>,
+				<0x2 0x16 0x7 IRQ_TYPE_NONE>;
+
+		interrupt-names =	"wdog-snarl",
+					"wdog-bark",
+					"aicl-fail",
+					"aicl-done",
+					"high-duty-cycle",
+					"input-current-limiting",
+					"temperature-change",
+					"switcher-power-ok";
+	};
+};
diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
index be8c2f0..de40a7c 100644
--- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
+++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
@@ -47,36 +47,39 @@
 Legacy SMMU v1/v2:
 
 Required properties:
-- compatible : Must be "qcom,msm-fastprc-legacy-compute-cb"
+- compatible : Must be "qcom,msm-fastrpc-legacy-compute"
 
 Required subnode:
 - qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context
                                 banks
 
 Required subnode properties:
-- qcom,adsp-shared-phandle: phandle that describe the context bank handle
-- qcom,adsp-shared-sids : A list of SID associated with the context bank
-- qcom,virtual-addr-pool : Virtual address range that the context bank
-                           will be using
+- compatible : Must be "qcom,msm-fastrpc-legacy-compute-cb"
+- label	     : Label describing the channel this context bank belongs to
+- iommus     : A list of phandle and IOMMU specifier pairs that describe the
+			IOMMU master interfaces of the device
+- sids       : A list of SID associated with the context bank
 
 Example:
-        qcom,adsprpc_domains {
-                compatible = "qcom,msm-fastrpc-legacy-compute-cb";
-                qcom,msm_fastrpc_compute_cb {
-                       qcom,adsp-shared-phandle = <&adsp_shared>;
-                       qcom,adsp-shared-sids = <0x8 0x9>;
-                       qcom,virtual-addr-pool = <0x80000000 0x7FFFFFFF>;
-                };
-        };
-
+	qcom,msm_fastrpc {
+		compatible = "qcom,msm-fastrpc-legacy-compute";
+		qcom,msm_fastrpc_compute_cb {
+			compatible = "qcom,msm-fastrpc-legacy-compute-cb";
+			label = "adsprpc-smd";
+			iommus = <&apps_iommu 0x2408 0x7>;
+			sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>;
+		};
+	};
 Remote Heap:
 
 Required properties:
 - compatible : Must be "qcom,msm-adsprpc-mem-region"
 - memory-region : CMA region which is owned by this device
+- restrict-access : Blocking vote for hyp_assign_phys function call
 
 Example:
        qcom,adsprpc-mem {
                compatible = "qcom,msm-adsprpc-mem-region";
                memory-region = <&adsp_mem>;
+               restrict-access;
        };
diff --git a/Documentation/devicetree/bindings/regulator/cpr-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr-regulator.txt
index 1c4dfbf..0f5e27a 100644
--- a/Documentation/devicetree/bindings/regulator/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr-regulator.txt
@@ -709,19 +709,6 @@
 				The number of quadruples should be equal to the number of values specified in
 				the qcom,cpr-aging-sensor-id property. This property is required if
 				the qcom,cpr-aging-sensor-id property has been specified.
-- qcom,cpr-thermal-sensor-id:	TSENS hardware sensor-id of the sensor which
-				needs to be monitored.
-- qcom,cpr-disable-temp-threshold:	The TSENS temperature threshold in degrees Celsius at which CPR
-				closed-loop is disabled. CPR closed-loop will stay disabled as long as the
-				temperature is below this threshold. This property is required
-				only if 'qcom,cpr-thermal-sensor-id' is present.
-- qcom,cpr-enable-temp-threshold:	The TSENS temperature threshold in degrees Celsius at which CPR
-				closed-loop is enabled. CPR closed-loop will stay enabled above this
-				temperature threshold. This property is required only if
-				'qcom,cpr-thermal-sensor-id' is present.
-- qcom,disable-closed-loop-in-pc:	Bool property to disable closed-loop CPR during
-				power-collapse. This can be enabled only for single core
-				designs. The property 'qcom,cpr-cpus' is required to enable this logic.
 Example:
 	apc_vreg_corner: regulator@f9018000 {
 		status = "okay";
@@ -971,8 +958,4 @@
 		qcom,cpr-fuse-aging-init-quot-diff =
 				<101 0 8 0>,
 				<101 8 8 0>;
-
-		qcom,cpr-thermal-sensor-id = <9>;
-		qcom,cpr-disable-temp-threshold = <5>;
-		qcom,cpr-enable-temp-threshold = <10>;
 	};
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index 28ab2dd..97b71a7 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -61,6 +61,8 @@
 - qcom,adc-tm-recalib-check: Add this property to check if recalibration required due to inaccuracy.
 - hkadc_ldo-supply : Add this property if VADC needs to perform a Software Vote for the HKADC.
 - hkadc_ok-supply : Add this property if the VADC needs to perform a Software vote for the HKADC VREG_OK.
+- #thermal-sensor-cells : To register ADC sensors with of_thermal. Should be 1.
+  See ./thermal.txt for a description.
 
 Client required property:
 - qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device.
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 67ffaed..6ff6e9b 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -19,6 +19,7 @@
 	       should be "qcom,sdm630-tsens" for 630 TSENS driver.
 	       should be "qcom,sdm845-tsens" for SDM845 TSENS driver.
 	       should be "qcom,tsens24xx" for 2.4 TSENS controller.
+	       should be "qcom,msm8937-tsens" for 8937 TSENS driver.
 	       The compatible property is used to identify the respective controller to use
 	       for the corresponding SoC.
 - reg : offset and length of the TSENS registers with associated property in reg-names
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 8654a3e..e13a6a3 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -1,110 +1,315 @@
 MSM SoC HSUSB controllers
 
-EHCI
+OTG:
 
-Required properties:
-- compatible:	Should contain "qcom,ehci-host"
-- regs:			offset and length of the register set in the memory map
-- usb-phy:		phandle for the PHY device
+Required properties :
+- compatible : should be "qcom,hsusb-otg"
+- regs : Array of offset and length of the register sets in the memory map
+- reg-names : indicates various iomem resources passed by name. The possible
+	strings in this field are:
+	    "core": USB controller register space. (Required)
+	    "tcsr": TCSR register for routing USB Controller signals to
+		    either picoPHY0 or picoPHY1. (Optional)
+	    "phy_csr": PHY Wrapper CSR register space. Provides register level
+		       interface through AHB2PHY for performing PHY related
+		       operations like retention and HV interrupts management.
+- interrupts: IRQ line
+- interrupt-names: OTG interrupt name(s) referenced in interrupts above
+            HSUSB OTG expects "core_irq" which is IRQ line from CORE and
+            "async_irq" from HSPHY for asynchronous wakeup events in LPM.
+            optional ones are described in next section.
+- qcom,hsusb-otg-phy-type: PHY type can be one of
+	    1 - Chipidea PHY (obsolete)
+	    2 - Synopsis Pico PHY
+	    3 - Synopsis Femto PHY
+	    4 - QUSB ULPI PHY
+- qcom,hsusb-otg-mode: Operational mode. Can be one of
+            1 - Peripheral only mode
+	    2 - Host only mode
+	    3 - OTG mode
+	    Based on the mode, OTG driver registers platform devices for
+	    gadget and host.
+- qcom,hsusb-otg-otg-control: OTG control (VBUS and ID notifications)
+  can be one of
+            1 - PHY control
+	    2 - PMIC control
+	    3 - User control (via debugfs)
+- <supply-name>-supply: handle to the regulator device tree node
+         Required "supply-name" is "HSUSB_VDDCX" (when voting for VDDCX) or
+         "hsusb_vdd_dig" (when voting for VDDCX Corner voltage),
+         "HSUSB_1p8-supply" and "HSUSB_3p3-supply".
+- qcom,vdd-voltage-level: This property must be a list of three integer
+	values (none, min, max) where each value represents either a voltage
+	in microvolts or a value corresponding to voltage corner. If usb core
+	supports svs, min value will have absolute SVS or SVS corner otherwise
+	min value will have absolute nominal or nominal corner.
+- clocks: a list of phandles to the USB clocks. Usage is as per
+	Documentation/devicetree/bindings/clock/clock-bindings.txt
+- clock-names: Names of the clocks in 1-1 correspondence with the "clocks"
+	property.
 
-Example EHCI controller device node:
+	Required clocks:
+	"core_clk": USB core clock that is required for data transfers.
+	"iface_clk": USB core clock that is required for register access.
 
-	ehci: ehci@f9a55000 {
-		compatible = "qcom,ehci-host";
-		reg = <0xf9a55000 0x400>;
-		usb-phy = <&usb_otg>;
+	Optional clocks:
+	"sleep_clk": PHY sleep clock. Required for interrupts.
+	"phy_reset_clk": PHY blocks asynchronous reset clock. Required
+		for the USB block reset. It is a reset only clock.
+	"phy_por_clk": Reset only clock for asserting/de-asserting
+		PHY POR signal. Required for overriding PHY parameters.
+	"phy_csr_clk": Required for accessing PHY CSR registers through
+		AHB2PHY interface.
+	"phy_ref_clk": Required when PHY have referance clock,
+	"xo": XO clock. The source clock that is used as a reference clock
+		to the PHY.
+	"bimc_clk", "snoc_clk", "pcnoc_clk": bus voting clocks. Used to
+		keep buses at a nominal frequency during USB peripheral
+		mode for achieving max throughput.
+- qcom,max-nominal-sysclk-rate: Indicates maximum nominal frequency for which
+	system clock should be voted whenever streaming mode is enabled.
+- resets: reset specifier pair consists of phandle for the reset provider
+	and reset lines used by this controller.
+- reset-names: reset signal name strings sorted in the same order as the resets
+	property.
+
+Optional properties :
+- interrupt-names : Optional interrupt resource entries are:
+    "pmic_id_irq" : Interrupt from PMIC for external ID pin notification.
+    "phy_irq" : Interrupt from PHY. Used for ID detection.
+- qcom,hsusb-otg-disable-reset: If present then core is RESET only during
+	    init, otherwise core is RESET for every cable disconnect as well
+- qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC
+	    performance issue is applied which requires changing the mem-type
+	    attribute via VMIDMT.
+- qcom,hsusb-otg-default-mode: The default USB mode after boot-up.
+  Applicable only when OTG is controlled by user. Can be one of
+            0 - None. Low power mode
+            1 - Peripheral
+	    2 - Host
+- qcom,hsusb-otg-phy-init-seq: PHY configuration sequence. val, reg pairs
+  terminate with -1
+- qcom,hsusb-otg-power-budget: VBUS power budget in mA
+  0 will be treated as 500mA
+- qcom,hsusb-otg-pclk-src-name: The source of pclk
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm-bus.txt" for
+  below optional properties:
+    - qcom,msm-bus,name
+    - qcom,msm-bus,num_cases - There are three valid cases for this: NONE, MAX
+		and MIN bandwidth votes. Minimum two cases must be defined for
+		both NONE and MAX votes. If MIN vote is different from NONE VOTE
+		then specify third case for MIN VOTE. If explicit NOC clock rates
+		are not specified then MAX value should be large enough to get
+		desired BUS frequencies. In case explicit NOC clock rates are
+		specified, peripheral mode bus bandwidth vote should be defined
+		to vote for arbitrated bandwidth so that 60MHz frequency is met.
+
+    - qcom,msm-bus,num_paths
+    - qcom,msm-bus,vectors
+- qcom,hsusb-otg-lpm-on-dev-suspend: If present then USB enter to
+	    low power mode upon receiving bus suspend.
+- qcom,hsusb-otg-clk-always-on-workaround: If present then USB core clocks
+	    remain active upon receiving bus suspend and USB cable is connected.
+	    Used for allowing USB to respond for remote wakup.
+- qcom,hsusb-otg-delay-lpm: If present then USB core will wait one second
+	after disconnect before entering low power mode.
+- <supply-name>-supply: handle to the regulator device tree node.
+         Optional "supply-name" is "vbus_otg" to supply vbus in host mode.
+- qcom,dp-manual-pullup: If present, vbus is not routed to USB controller/phy
+	and controller driver therefore enables pull-up explicitly before
+	starting controller using usbcmd run/stop bit.
+- qcom,usb2-enable-hsphy2: If present then USB2 controller is connected to 2nd
+	HSPHY.
+- qcom,hsusb-log2-itc: value of 2^(log2_itc-1) will be used as the
+	interrupt threshold (ITC), when log2_itc is between 1 to 7.
+- qcom,hsusb-l1-supported: If present, the device supports l1 (Link power
+	management).
+- qcom,no-selective-suspend: If present selective suspend is disabled on hub ports.
+- qcom,hsusb-otg-mpm-dpsehv-int: If present, indicates mpm interrupt to be
+	configured for detection of dp line transition during VDD minimization.
+- qcom,hsusb-otg-mpm-dmsehv-int: If present, indicates mpm interrupt to be
+	configured for detection of dm line transition during VDD minimization.
+- pinctrl-names : This should be defined if a target uses gpio and pinctrl framework.
+  See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+  It should specify the names of the configs that pinctrl can install in driver
+	Following are the pinctrl config that can be installed
+	"hsusb_active" : Active configuration of pins, this should specify active
+	config of vddmin gpio (if used) defined in their pin groups.
+	"hsusb_sleep" : Disabled configuration of pins, this should specify sleep
+	config of vddmin gpio (if used) defined in their pin groups.
+- qcom,hsusb-otg-vddmin-gpio = If present, indicates a gpio that will be used
+	to supply voltage to the D+ line during VDD minimization and peripheral
+	bus suspend. If not exists, then VDD minimization will not be allowed
+	during peripheral bus suspend.
+- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
+	mode with device controller for better throughput. With this mode, USB Core
+	runs using PNOC clock and synchronous to it. Hence it is must to have proper
+	"qcom,msm-bus,vectors" to have high bus frequency. User shouldn't try to
+	enable this feature without proper bus voting. When this feature is enabled,
+	it is required to do HW reset during cable disconnect for host mode functionality
+	working and hence need to disable qcom,hsusb-otg-disable-reset. With this feature
+	enabled, USB HW has to vote for maximum PNOC frequency as USB HW cannot tolerate
+	changes in PNOC frequency which results in USB functionality failure.
+- qcom,disable-retention-with-vdd-min: If present don't allow phy retention but allow
+	vdd min.
+- qcom,usbin-vadc: Corresponding vadc device's phandle to read usbin voltage using VADC.
+	This will be used to get value of usb power supply's VOLTAGE_NOW property.
+- qcom,usbid-gpio: This corresponds to gpio which is used for USB ID detection.
+- qcom,hub-reset-gpio: This corresponds to gpio which is used for HUB reset.
+- qcom,sw-sel-gpio: This corresponds to gpio which is used for switch select routing
+	of D+/D- between the USB HUB and type B USB jack for peripheral mode.
+- qcom,bus-clk-rate: If present, indicates nominal bus frequency to be voted for
+	bimc/snoc/pcnoc clock with usb cable connected. If AHB2AHB bypass is enabled,
+	pcnoc value should be defined to very large number so that PNOC runs at max
+	frequency. If 'qcom,default-mode-svs' is also set then two set of frequencies
+	must be specified for SVS and NOM modes which user can change using sysfs node.
+- qcom,phy-dvdd-always-on: If present PHY DVDD is supplied by a always-on
+	regulator unlike vddcx/vddmx. PHY can keep D+ pull-up and D+/D-
+	pull-down resistors during peripheral and host bus suspend without
+	any re-work.
+- qcom,emulation: Indicates that we are running on emulation platform.
+- qcom,boost-sysclk-with-streaming: If present, enable controller specific
+	streaming feature. Also this flag can bump up usb system clock to max in streaming
+	mode. This flag enables streaming mode for all compositions and is different from
+	streaming-func property defined in android device node. Please refer Doumentation/
+	devicetree/bindings/usb/android-dev.txt for details about "streaming-func" property.
+- qcom,axi-prefetch-enable: If present, AXI64 interface will be used for transferring data
+       to/from DDR by controller.
+- qcom,enable-sdp-typec-current-limit: Indicates whether type-c current for SDP CHARGER to
+	be limited.
+- qcom,enable-phy-id-pullup: If present, PHY can keep D+ pull-up resistor on USB ID line
+	during cable disconnect.
+- qcom,max-svs-sysclk-rate: Indicates system clock frequency voted by driver in
+	non-perf mode. In perf mode driver uses qcom,max-nominal-sysclk-rate.
+- qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs,
+	which is used as a vote by driver to get max performance in perf mode.
+- qcom,default-mode-svs: Indicates USB system clock should run at SVS frequency.
+	User can bump it up using 'perf_mode' sysfs attribute for gadget.
+- qcom,vbus-low-as-hostmode: If present, specifies USB_VBUS to switch to host mode
+	if USB_VBUS is low or device mode if USB_VBUS is high.
+- qcom,usbeth-reset-gpio: If present then an external usb-to-eth is connected to
+	the USB host controller and its RESET_N signal is connected to this
+	usbeth-reset-gpio GPIO. It should be driven LOW to RESET the usb-to-eth.
+- extcon: phandles to external connector devices. First phandle should point to
+	external connector, which provide "USB" cable events, the second should
+	point to external connector device, which provide "USB-HOST" cable events.
+	A single phandle may be specified if a single connector device provides
+	both "USB" and "USB-HOST" events.
+
+Example HSUSB OTG controller device node :
+	usb@f9690000 {
+		compatible = "qcom,hsusb-otg";
+		reg = <0xf9690000 0x400>;
+		reg-names = "core";
+		interrupts = <134>;
+		interrupt-names = "core_irq";
+
+		qcom,hsusb-otg-phy-type = <2>;
+		qcom,hsusb-otg-mode = <1>;
+		qcom,hsusb-otg-otg-control = <1>;
+		qcom,hsusb-otg-disable-reset;
+		qcom,hsusb-otg-pnoc-errata-fix;
+		qcom,hsusb-otg-default-mode = <2>;
+		qcom,hsusb-otg-phy-init-seq = <0x01 0x90 0xffffffff>;
+		qcom,hsusb-otg-power-budget = <500>;
+		qcom,hsusb-otg-pclk-src-name = "dfab_usb_clk";
+		qcom,hsusb-otg-lpm-on-dev-suspend;
+		qcom,hsusb-otg-clk-always-on-workaround;
+		hsusb_vdd_dig-supply = <&pm8226_s1_corner>;
+                HSUSB_1p8-supply = <&pm8226_l10>;
+                HSUSB_3p3-supply = <&pm8226_l20>;
+		qcom,vdd-voltage-level = <1 5 7>;
+		qcom,dp-manual-pullup;
+		qcom,hsusb-otg-mpm-dpsehv-int = <49>;
+		qcom,hsusb-otg-mpm-dmsehv-int = <58>;
+		qcom,max-nominal-sysclk-rate = <133330000>;
+		qcom,max-svs-sysclk-rate = <100000000>;
+		qcom,pm-qos-latency = <59>;
+
+		qcom,msm-bus,name = "usb2";
+		qcom,msm-bus,num_cases = <2>;
+		qcom,msm-bus,num_paths = <1>;
+		qcom,msm-bus,vectors =
+				<87 512 0 0>,
+				<87 512 60000000 960000000>;
+		pinctrl-names = "hsusb_active","hsusb_sleep";
+		pinctrl-0 = <&vddmin_act>;
+		pinctrl-0 = <&vddmin_sus>;
+		qcom,hsusb-otg-vddmin-gpio = <&pm8019_mpps 6 0>;
+		qcom,disable-retention-with-vdd-min;
+		qcom,usbin-vadc = <&pm8226_vadc>;
+		qcom,usbid-gpio = <&msm_gpio 110 0>;
 	};
 
-USB PHY with optional OTG:
+MSM HSUSB EHCI controller
 
-Required properties:
-- compatible:   Should contain:
-  "qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY
-  "qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY
+Required properties :
+- compatible : should be "qcom,ehci-host"
+- reg : offset and length of the register set in the memory map
+- interrupts: IRQ lines used by this controller
+- interrupt-names : Required interrupt resource entries are:
+            HSUSB EHCI expects "core_irq" and optionally "async_irq".
+- <supply-name>-supply: handle to the regulator device tree node
+  Required "supply-name" is either "hsusb_vdd_dig" or "HSUSB_VDDCX"
+  "HSUSB_1p8-supply" "HSUSB_3p3-supply".
+- qcom,usb2-power-budget: maximum vbus power (in mA) that can be provided.
+- qcom,vdd-voltage-level: This property must be a list of five integer
+  values (no, 0.5vsuspend, 0.75suspend, min, max) where each value respresents
+  either a voltage in microvolts or a value corresponding to voltage corner.
+  First value represents value to vote when USB is not at all active, second
+  value represents value to vote when target is not connected to dock during low
+  power mode, third value represents vlaue to vote when target is connected to dock
+  and no peripheral connected over dock during low power mode, fourth value represents
+  minimum value to vote when USB is operational, fifth item represents maximum value
+  to vote for USB is operational.
 
-- regs:         Offset and length of the register set in the memory map
-- interrupts:   interrupt-specifier for the OTG interrupt.
+Optional properties :
+- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
+- pinctrl-names : This should be defined if a target uses pinctrl framework.
+  See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+  It should specify the names of the configs that pinctrl can install in driver
+  Following are the pinctrl configs that can be installed
+	"ehci_active" : Active configuration of pins, this should specify active
+	config defined in pin groups of used gpio's from resume and
+	ext-hub-reset.
+	"ehci_sleep" : Disabled configuration of pins, this should specify sleep
+	config defined in pin groups of used gpio's from resume and
+	ext-hub-reset.
+- qcom,resume-gpio: if present then peripheral connected to usb controller
+  cannot wakeup from XO shutdown using in-band usb bus resume. Use resume
+  gpio to wakeup peripheral.
+- qcom,ext-hub-reset-gpio: If present then an external HUB is connected to
+  the USB host controller and its RESET_N signal is connected to this
+  ext-hub-reset-gpio GPIO. It should be driven LOW to RESET the HUB.
+- qcom,usb2-enable-uicc: If present, usb2 port will be used for uicc card connection.
+- usb-phy: phandle for the PHY device, if described as a separate device tree node
+- qcom,pm-qos-latency: This property represents the maximum tolerable CPU latency in
+  microsecs, which is used as a vote to keep the CPUs in a high enough power state when
+  USB bus is in use (not suspended).
+- Refer to "Documentation/devicetree/bindings/arm/msm/msm-bus.txt" for
+  below optional properties:
+    - qcom,msm-bus,name
+    - qcom,msm-bus,num_cases - Two cases (NONE and MAX) for voting are supported.
+    - qcom,msm-bus,num_paths
+    - qcom,msm-bus,vectors
 
-- clocks:       A list of phandle + clock-specifier pairs for the
-                clocks listed in clock-names
-- clock-names:  Should contain the following:
-  "phy"         USB PHY reference clock
-  "core"        Protocol engine clock
-  "iface"       Interface bus clock
-  "alt_core"    Protocol engine clock for targets with asynchronous
-                reset methodology. (optional)
-
-- vdccx-supply: phandle to the regulator for the vdd supply for
-                digital circuit operation.
-- v1p8-supply:  phandle to the regulator for the 1.8V supply
-- v3p3-supply:  phandle to the regulator for the 3.3V supply
-
-- resets:       A list of phandle + reset-specifier pairs for the
-                resets listed in reset-names
-- reset-names:  Should contain the following:
-  "phy"         USB PHY controller reset
-  "link"        USB LINK controller reset
-
-- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of
-                1 - PHY control
-                2 - PMIC control
-
-Optional properties:
-- dr_mode:      One of "host", "peripheral" or "otg". Defaults to "otg"
-
-- switch-gpio:  A phandle + gpio-specifier pair. Some boards are using Dual
-                SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex
-                D+/D- USB lines between connectors.
-
-- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device
-                Mode Eye Diagram test. Start address at which these values will be
-                written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
-                "do not overwrite default value at this address".
-                For example: qcom,phy-init-sequence = < -1 0x63 >;
-                Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1.
-
-- qcom,phy-num: Select number of pyco-phy to use, can be one of
-                0 - PHY one, default
-                1 - Second PHY
-                Some platforms may have configuration to allow USB
-                controller work with any of the two HSPHYs present.
-
-- qcom,vdd-levels: This property must be a list of three integer values
-                (no, min, max) where each value represents either a voltage
-                in microvolts or a value corresponding to voltage corner.
-
-- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
-                and controller driver therefore enables pull-up explicitly
-                before starting controller using usbcmd run/stop bit.
-
-- extcon:       phandles to external connector devices. First phandle
-                should point to external connector, which provide "USB"
-                cable events, the second should point to external connector
-                device, which provide "USB-HOST" cable events. If one of
-                the external connector devices is not required empty <0>
-                phandle should be specified.
-
-Example HSUSB OTG controller device node:
-
-    usb@f9a55000 {
-        compatible = "qcom,usb-otg-snps";
-        reg = <0xf9a55000 0x400>;
-        interrupts = <0 134 0>;
-        dr_mode = "peripheral";
-
-        clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>,
-                <&gcc GCC_USB_HS_AHB_CLK>;
-
-        clock-names = "phy", "core", "iface";
-
-        vddcx-supply = <&pm8841_s2_corner>;
-        v1p8-supply = <&pm8941_l6>;
-        v3p3-supply = <&pm8941_l24>;
-
-        resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>;
-        reset-names = "phy", "link";
-
-        qcom,otg-control = <1>;
-        qcom,phy-init-sequence = < -1 0x63 >;
-        qcom,vdd-levels = <1 5 7>;
+Example MSM HSUSB EHCI controller device node :
+	ehci: qcom,ehci-host@f9a55000 {
+		compatible = "qcom,ehci-host";
+		reg = <0xf9a55000 0x400>;
+		interrupts = <0 134 0>, <0 140 0>;
+		interrupt-names = "core_irq", "async_irq";
+		/* If pinctrl is used and ext-hub-reset and resume gpio's are present*/
+		pinctrl-names = "ehci_active","ehci_sleep";
+		pinctrl-0 = <&ehci_reset_act &resume_act>;
+		pinctrl-1 = <&ehci_reset_sus &resume_sus>;
+		qcom,resume-gpio = <&msm_gpio 80 0>;
+		qcom,ext-hub-reset-gpio = <&msm_gpio 0 0>;
+		hsusb_vdd_dig-supply = <&pm8841_s2_corner>;
+		HSUSB_1p8-supply = <&pm8941_l6>;
+		HSUSB_3p3-supply = <&pm8941_l24>;
+		qcom,usb2-enable-hsphy2;
+		qcom,usb2-power-budget = <500>;
+		qcom,vdd-voltage-level = <1 2 3 5 7>;
+		qcom,usb2-enable-uicc;
 	};
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index f8c8a69..e94299f 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -101,6 +101,8 @@
  - qcom,core-voltage-level: This property must be a list of three integer
    values (no, min, max) where each value represents either a voltage in
    microvolts or a value corresponding to voltage corner.
+ - "pcs_clamp_enable_reg" : Clamps the phy data inputs and enables USB3
+   autonomous mode.
 
 Example:
 	ssphy0: ssphy@f9b38000 {
@@ -184,6 +186,10 @@
    state when attached in host mode and "suspend" state when detached.
  - qcom,tune2-efuse-correction: The value to be adjusted from fused value for
    improved rise/fall times.
+ - nvmem-cells: specifies the handle to represent the SoC revision.
+   usually it is defined by qfprom device node.
+ - nvmem-cell-names: specifies the given nvmem cell name as defined in
+   qfprom node.
 
 Example:
 	qusb_phy: qusb@f9b39000 {
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 95ccbe6..206c9b0 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -30,6 +30,7 @@
 - dirty_writeback_centisecs
 - drop_caches
 - extfrag_threshold
+- extra_free_kbytes
 - hugepages_treat_as_movable
 - hugetlb_shm_group
 - laptop_mode
@@ -240,6 +241,21 @@
 
 ==============================================================
 
+extra_free_kbytes
+
+This parameter tells the VM to keep extra free memory between the threshold
+where background reclaim (kswapd) kicks in, and the threshold where direct
+reclaim (by allocating processes) kicks in.
+
+This is useful for workloads that require low latency memory allocations
+and have a bounded burstiness in memory allocations, for example a
+realtime application that receives and transmits network traffic
+(causing in-kernel memory allocations) with a maximum total message burst
+size of 200MB may need 200MB of extra free memory to avoid direct reclaim
+related latencies.
+
+==============================================================
+
 hugepages_treat_as_movable
 
 This parameter controls whether we can allocate hugepages from ZONE_MOVABLE
diff --git a/Documentation/x86/pti.txt b/Documentation/x86/pti.txt
index d11eff6..5cd5843 100644
--- a/Documentation/x86/pti.txt
+++ b/Documentation/x86/pti.txt
@@ -78,7 +78,7 @@
      non-PTI SYSCALL entry code, so requires mapping fewer
      things into the userspace page tables.  The downside is
      that stacks must be switched at entry time.
-  d. Global pages are disabled for all kernel structures not
+  c. Global pages are disabled for all kernel structures not
      mapped into both kernel and userspace page tables.  This
      feature of the MMU allows different processes to share TLB
      entries mapping the kernel.  Losing the feature means more
diff --git a/Makefile b/Makefile
index cf9657e..b075470 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 77
+SUBLEVEL = 80
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d8d8b82..41245ce 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -12,6 +12,7 @@
 	select ARCH_USE_BUILTIN_BSWAP
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select ARCH_WANT_IPC_PARSE_VERSION
+	select ARM_PSCI_FW if PM
 	select BUILDTIME_EXTABLE_SORT if MMU
 	select CLONE_BACKWARDS
 	select CPU_PM if (SUSPEND || CPU_IDLE)
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
index 7c9e0fa..65e0db1 100644
--- a/arch/arm/boot/dts/bcm-nsp.dtsi
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -85,7 +85,7 @@
 		timer@20200 {
 			compatible = "arm,cortex-a9-global-timer";
 			reg = <0x20200 0x100>;
-			interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <GIC_PPI 11 IRQ_TYPE_EDGE_RISING>;
 			clocks = <&periph_clk>;
 		};
 
@@ -93,7 +93,7 @@
 			compatible = "arm,cortex-a9-twd-timer";
 			reg = <0x20600 0x20>;
 			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
-						  IRQ_TYPE_LEVEL_HIGH)>;
+						  IRQ_TYPE_EDGE_RISING)>;
 			clocks = <&periph_clk>;
 		};
 
diff --git a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
index cf2f524..27cc913 100644
--- a/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
+++ b/arch/arm/boot/dts/kirkwood-openblocks_a7.dts
@@ -53,7 +53,8 @@
 		};
 
 		pinctrl: pin-controller@10000 {
-			pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header>;
+			pinctrl-0 = <&pmx_dip_switches &pmx_gpio_header
+				     &pmx_gpio_header_gpo>;
 			pinctrl-names = "default";
 
 			pmx_uart0: pmx-uart0 {
@@ -85,11 +86,16 @@
 			 * ground.
 			 */
 			pmx_gpio_header: pmx-gpio-header {
-				marvell,pins = "mpp17", "mpp7", "mpp29", "mpp28",
+				marvell,pins = "mpp17", "mpp29", "mpp28",
 					       "mpp35", "mpp34", "mpp40";
 				marvell,function = "gpio";
 			};
 
+			pmx_gpio_header_gpo: pxm-gpio-header-gpo {
+				marvell,pins = "mpp7";
+				marvell,function = "gpo";
+			};
+
 			pmx_gpio_init: pmx-init {
 				marvell,pins = "mpp38";
 				marvell,function = "gpio";
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index c51581d..8f6af4c 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -1,7 +1,9 @@
 
 dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb \
 	sdxpoorwills-cdp.dtb \
-	sdxpoorwills-mtp.dtb
+	sdxpoorwills-mtp.dtb \
+	sdxpoorwills-pcie-ep-cdp.dtb \
+	sdxpoorwills-pcie-ep-mtp.dtb
 
 targets += dtbs
 targets += $(addprefix ../, $(dtb-y))
diff --git a/arch/arm/boot/dts/qcom/pmxpoorwills.dtsi b/arch/arm/boot/dts/qcom/pmxpoorwills.dtsi
index 2106759..8f7edab 100644
--- a/arch/arm/boot/dts/qcom/pmxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/pmxpoorwills.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -97,6 +97,7 @@
 			qcom,adc-vdd-reference = <1875>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&ambient_therm_default>;
+			#thermal-sensor-cells = <1>;
 
 			chan@6 {
 				label = "die_temp";
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 261829f..38137a2 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,10 +12,7 @@
 
 /dts-v1/;
 
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
-#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+#include "sdxpoorwills-cdp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP";
@@ -23,132 +20,3 @@
 		"qcom,sdxpoorwills", "qcom,cdp";
 	qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>;
 };
-
-&serial_uart {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart3_console_active>;
-	status = "ok";
-};
-
-&qnand_1 {
-	status = "ok";
-};
-
-&sdhc_1 {
-	vdd-supply = <&vreg_sd_mmc>;
-
-	vdd-io-supply = <&pmxpoorwills_l7>;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <200 10000>;
-
-	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
-	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
-							200000000>;
-	qcom,devfreq,freq-table = <50000000 200000000>;
-
-	cd-gpios = <&tlmm 93 0x1>;
-
-	status = "ok";
-};
-
-&pmxpoorwills_vadc {
-	chan@83 {
-		label = "vph_pwr";
-		reg = <0x83>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <1>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@4c {
-		label = "xo_therm";
-		reg = <0x4c>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4d {
-		label = "pa_therm1";
-		reg = <0x4d>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4e {
-		label = "pa_therm2";
-		reg = <0x4e>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4f {
-		label = "mdm_case_therm";
-		reg = <0x4f>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@52 {
-		label = "ambient_therm";
-		reg = <0x52>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-};
-
-&i2c_3 {
-	status = "okay";
-	#include "smb138x.dtsi"
-};
-
-&smb138x {
-	pinctrl-names = "default";
-	pinctrl-0 = <&smb_int_default>;
-	interrupt-parent = <&tlmm>;
-	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
-	smb1381_charger: qcom,smb1381-charger@1000 {
-		compatible = "qcom,smb138x-charger";
-		qcom,use-extcon;
-	};
-};
-
-&smb138x_vbus {
-	status = "okay";
-};
-
-&usb {
-	status = "okay";
-	extcon = <&smb1381_charger>;
-};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
new file mode 100644
index 0000000..b5944d1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi
@@ -0,0 +1,144 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-cdp-audio-overlay.dtsi"
+
+&serial_uart {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_console_active>;
+	status = "ok";
+};
+
+&qnand_1 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	vdd-supply = <&vreg_sd_mmc>;
+
+	vdd-io-supply = <&pmxpoorwills_l7>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 10000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+							200000000>;
+	qcom,devfreq,freq-table = <50000000 200000000>;
+
+	cd-gpios = <&tlmm 93 0x1>;
+
+	status = "ok";
+};
+
+&pmxpoorwills_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4d {
+		label = "pa_therm1";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4e {
+		label = "pa_therm2";
+		reg = <0x4e>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4f {
+		label = "mdm_case_therm";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@52 {
+		label = "ambient_therm";
+		reg = <0x52>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+};
+
+&i2c_3 {
+	status = "okay";
+	#include "smb138x.dtsi"
+};
+
+&smb138x {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+	smb1381_charger: qcom,smb1381-charger@1000 {
+		compatible = "qcom,smb138x-charger";
+		qcom,use-extcon;
+	};
+};
+
+&smb138x_vbus {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi
new file mode 100644
index 0000000..eb5c210
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-coresight.dtsi
@@ -0,0 +1,1090 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	csr: csr@6001000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6001000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-name = "coresight-csr";
+		qcom,usb-bam-support;
+		qcom,hwctrl-set-support;
+		qcom,set-byte-cntr-support;
+
+		qcom,blk-size = <1>;
+	};
+
+	swao_csr: csr@6b0e000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6b0e000 0x1000>;
+		reg-names = "csr-base";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		coresight-name = "coresight-swao-csr";
+		qcom,timestamp-support;
+
+		qcom,blk-size = <1>;
+	};
+
+	tmc_etr: tmc@6048000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6048000 0x1000>,
+		      <0x6064000 0x15000>;
+		reg-names = "tmc-base", "bam-base";
+
+		arm,buffer-size = <0x400000>;
+		arm,sg-enable;
+
+		coresight-name = "coresight-tmc-etr";
+		coresight-ctis = <&cti0 &cti8>;
+		coresight-csr = <&csr>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		interrupts = <GIC_SPI 251 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "byte-cntr-irq";
+
+		port {
+			tmc_etr_in_replicator: endpoint {
+				slave-mode;
+				remote-endpoint = <&replicator_out_tmc_etr>;
+			};
+		};
+	};
+
+	replicator_qdss: replicator@6046000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b909>;
+
+		reg = <0x6046000 0x1000>;
+		reg-names = "replicator-base";
+
+		coresight-name = "coresight-replicator";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				replicator_out_tmc_etr: endpoint {
+					remote-endpoint=
+						<&tmc_etr_in_replicator>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				replicator_in_tmc_etf: endpoint {
+					slave-mode;
+					remote-endpoint=
+						<&tmc_etf_out_replicator>;
+				};
+			};
+		};
+	};
+
+	tmc_etf: tmc@6047000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b961>;
+
+		reg = <0x6047000 0x1000>;
+		reg-names = "tmc-base";
+
+		coresight-name = "coresight-tmc-etf";
+		coresight-ctis = <&cti0 &cti8>;
+		coresight-csr = <&csr>;
+		arm,default-sink;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				tmc_etf_out_replicator: endpoint {
+					remote-endpoint =
+						<&replicator_in_tmc_etf>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tmc_etf_in_funnel_merg: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_merg_out_tmc_etf>;
+				};
+			};
+		};
+	};
+
+	funnel_merg: funnel@6045000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6045000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-merg";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_merg_out_tmc_etf: endpoint {
+					remote-endpoint =
+						<&tmc_etf_in_funnel_merg>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_merg_in_funnel_in0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in0_out_funnel_merg>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				funnel_merg_in_funnel_in1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_in1_out_funnel_merg>;
+				};
+			};
+		};
+	};
+
+	funnel_in0: funnel@6041000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6041000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-in0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_in0_out_funnel_merg: endpoint {
+					remote-endpoint =
+						<&funnel_merg_in_funnel_in0>;
+				};
+			};
+
+			port@1 {
+				reg = <6>;
+				funnel_in0_in_funnel_qatb: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_qatb_out_funnel_in0>;
+				};
+			};
+
+			port@2 {
+				reg = <7>;
+				funnel_in0_in_stm: endpoint {
+					slave-mode;
+					remote-endpoint = <&stm_out_funnel_in0>;
+				};
+			};
+		};
+	};
+
+	stm: stm@6002000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b962>;
+
+		reg = <0x6002000 0x1000>,
+		      <0x16280000 0x180000>;
+		reg-names = "stm-base", "stm-stimulus-base";
+
+		coresight-name = "coresight-stm";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port {
+			stm_out_funnel_in0: endpoint {
+				remote-endpoint = <&funnel_in0_in_stm>;
+			};
+		};
+
+	};
+
+	funnel_qatb: funnel@6005000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6005000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-qatb";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_qatb_out_funnel_in0: endpoint {
+					remote-endpoint =
+						<&funnel_in0_in_funnel_qatb>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_qatb_in_tpda: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpda_out_funnel_qatb>;
+				};
+			};
+		};
+	};
+
+	tpda: tpda@6004000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x6004000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda";
+
+		qcom,tpda-atid = <65>;
+		qcom,bc-elem-size = <10 32>,
+				    <13 32>;
+		qcom,tc-elem-size = <13 32>;
+		qcom,dsb-elem-size = <0 32>,
+				     <2 32>,
+				     <3 32>,
+				     <5 32>,
+				     <6 32>,
+				     <10 32>,
+				     <11 32>,
+				     <13 32>;
+		qcom,cmb-elem-size = <3 64>,
+				     <7 64>,
+				     <9 64>,
+				     <13 64>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				tpda_out_funnel_qatb: endpoint {
+					remote-endpoint =
+						<&funnel_qatb_in_tpda>;
+				};
+
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_in_funnel_ddr_0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_ddr_0_out_tpda>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				tpda_in_tpdm_vsense: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_vsense_out_tpda>;
+				};
+			};
+
+			port@3 {
+				reg = <2>;
+				tpda_in_tpdm_dcc: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_dcc_out_tpda>;
+				};
+			};
+
+			port@4 {
+				reg = <5>;
+				tpda_in_tpdm_center: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_center_out_tpda>;
+				};
+			};
+		};
+	};
+
+	funnel_ddr_0: funnel@69e2000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x69e2000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-ddr-0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_ddr_0_out_tpda: endpoint {
+					remote-endpoint =
+					    <&tpda_in_funnel_ddr_0>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_ddr_0_in_tpdm_ddr: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&tpdm_ddr_out_funnel_ddr_0>;
+				};
+			};
+		};
+	};
+
+	tpdm_dcc: tpdm@6870280 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6870280 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-dcc";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port{
+			tpdm_dcc_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_dcc>;
+			};
+		};
+	};
+
+	tpdm_vsense: tpdm@6840000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6840000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-vsense";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port{
+			tpdm_vsense_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_vsense>;
+			};
+		};
+	};
+
+	tpdm_center: tpdm@6c28000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6c28000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-center";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port{
+			tpdm_center_out_tpda: endpoint {
+				remote-endpoint = <&tpda_in_tpdm_center>;
+			};
+		};
+	};
+
+	tpdm_ddr: tpdm@69e0000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x69e0000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-ddr";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		qcom,msr-fix-req;
+
+		port {
+			tpdm_ddr_out_funnel_ddr_0: endpoint {
+				remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>;
+			};
+		};
+	};
+
+	funnel_in1: funnel@6042000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6042000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-in1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_in1_out_funnel_merg: endpoint {
+					remote-endpoint =
+						<&funnel_merg_in_funnel_in1>;
+				};
+			};
+
+			port@1 {
+				reg = <2>;
+				funnel_in1_in_funnel_swao: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_swao_out_funnel_in1>;
+				};
+			};
+
+			port@2 {
+				reg = <3>;
+				funnel_in1_in_modem_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&modem_etm0_out_funnel_in1>;
+				};
+			};
+
+			port@3 {
+				reg = <7>;
+				funnel_in1_in_tpda_modem: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpda_modem_out_funnel_in1>;
+				};
+			};
+		};
+	};
+
+	modem_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+
+		coresight-name = "coresight-modem-etm0";
+		qcom,inst-id = <2>;
+
+		port {
+			modem_etm0_out_funnel_in1: endpoint {
+				remote-endpoint =
+					<&funnel_in1_in_modem_etm0>;
+			};
+		};
+	};
+
+	funnel_swao:funnel@6b08000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6b08000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-swao";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_swao_out_funnel_in1: endpoint {
+					remote-endpoint =
+						<&funnel_in1_in_funnel_swao>;
+				};
+			};
+
+			port@1 {
+				reg = <7>;
+				funnel_swao_in_tpda_swao: endpoint {
+					slave-mode;
+					remote-endpoint=
+						<&tpda_swao_out_funnel_swao>;
+				};
+			};
+		};
+	};
+
+	tpda_modem: tpda@6832000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x6832000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda-modem";
+
+		qcom,tpda-atid = <67>;
+		qcom,dsb-elem-size = <0 32>;
+		qcom,cmb-elem-size = <0 64>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			port@0 {
+				reg = <0>;
+				tpda_modem_out_funnel_in1: endpoint {
+					remote-endpoint =
+						<&funnel_in1_in_tpda_modem>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_modem_in_tpdm_modem: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_modem_out_tpda_modem>;
+				};
+			};
+		};
+	};
+
+	tpdm_modem: tpdm@6830000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6830000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-modem";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port {
+			tpdm_modem_out_tpda_modem: endpoint {
+				remote-endpoint = <&tpda_modem_in_tpdm_modem>;
+			};
+		};
+	};
+
+	tpda_swao: tpda@6b01000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x6b01000 0x1000>;
+		reg-names = "tpda-base";
+
+		coresight-name = "coresight-tpda-swao";
+
+		qcom,tpda-atid = <71>;
+		qcom,dsb-elem-size = <1 32>;
+		qcom,cmb-elem-size = <0 64>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				tpda_swao_out_funnel_swao: endpoint {
+					remote-endpoint =
+						<&funnel_swao_in_tpda_swao>;
+				};
+
+			};
+
+			port@1 {
+				reg = <0>;
+				tpda_swao_in_tpdm_swao0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_swao0_out_tpda_swao>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				tpda_swao_in_tpdm_swao1: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&tpdm_swao1_out_tpda_swao>;
+				};
+
+			};
+		};
+	};
+
+	tpdm_swao0: tpdm@6b02000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+
+		reg = <0x6b02000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-swao-0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port {
+			tpdm_swao0_out_tpda_swao: endpoint {
+				remote-endpoint = <&tpda_swao_in_tpdm_swao0>;
+			};
+		};
+	};
+
+	tpdm_swao1: tpdm@6b03000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
+		reg = <0x6b03000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name="coresight-tpdm-swao-1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		qcom,msr-fix-req;
+
+		port {
+			tpdm_swao1_out_tpda_swao: endpoint {
+				remote-endpoint = <&tpda_swao_in_tpdm_swao1>;
+			};
+		};
+	};
+
+	ipcb_tgu: tgu@6b0c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b999>;
+		reg = <0x6b0c000 0x1000>;
+		reg-names = "tgu-base";
+		tgu-steps = <3>;
+		tgu-conditions = <4>;
+		tgu-regs = <4>;
+		tgu-timer-counters = <8>;
+
+		coresight-name = "coresight-tgu-ipcb";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0: cti@6010000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6010000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti1: cti@6011000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6011000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti2: cti@6012000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6012000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti2";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti3: cti@6013000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6013000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti3";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti4: cti@6014000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6014000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti4";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti5: cti@6015000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6015000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti5";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti6: cti@6016000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6016000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti6";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti7: cti@6017000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6017000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti7";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti8: cti@6018000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6018000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti8";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti9: cti@6019000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6019000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti9";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti10: cti@601a000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601a000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti10";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti11: cti@601b000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601b000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti11";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti12: cti@601c000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601c000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti12";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti13: cti@601d000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601d000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti13";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti14: cti@601e000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601e000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti14";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti15: cti@601f000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x601f000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti15";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti_cpu0: cti@7003000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x7003000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-cpu0";
+		cpu = <&CPU0>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+	};
+
+	cti_modem_cpu0:cti@6837000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6837000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-modem-cpu0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_modem_cpu1:cti@683b000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x683b000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-modem-cpu1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0_swao:cti@6b04000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b04000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti1_swao:cti@6b05000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b05000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti2_swao:cti@6b06000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b06000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti2";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti3_swao:cti@6b07000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b07000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-swao_cti3";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0_ddr0: cti@69e1000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e1000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_0_cti";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti0_ddr1: cti@69e4000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e4000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_1_cti0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti1_ddr1: cti@69e5000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e5000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_1_cti1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti2_ddr1: cti@69e6000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x69e6000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr_dl_1_cti2";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	hwevent: hwevent@0x014066f0 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0x14066f0 0x4>,
+		      <0x14166f0 0x4>,
+		      <0x1406038 0x4>,
+		      <0x1416038 0x4>;
+		reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl",
+			    "ddr-ch23-ctrl";
+
+		coresight-name = "coresight-hwevent";
+		coresight-csr = <&csr>;
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-audio-overlay.dtsi
similarity index 61%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm/boot/dts/qcom/sdxpoorwills-mtp-audio-overlay.dtsi
index 194bfeb..5b3e0b5 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-audio-overlay.dtsi
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,14 +10,13 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
+#include "sdxpoorwills-audio-overlay.dtsi"
 
-#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>;
-
+&soc {
+	sound-tavil {
+		qcom,wsa-max-devs = <1>;
+		qcom,wsa-devs = <&wsa881x_0214>;
+		qcom,wsa-aux-dev-prefix = "SpkrRight";
+	};
 };
+
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index 575febe..a0bcdc9 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,9 +12,7 @@
 
 /dts-v1/;
 
-
-#include "sdxpoorwills.dtsi"
-#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-mtp.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP";
@@ -22,132 +20,3 @@
 		"qcom,sdxpoorwills", "qcom,mtp";
 	qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>;
 };
-
-&serial_uart {
-	pinctrl-names = "default";
-	pinctrl-0 = <&uart3_console_active>;
-	status = "ok";
-};
-
-&qnand_1 {
-	status = "ok";
-};
-
-&sdhc_1 {
-	vdd-supply = <&vreg_sd_mmc>;
-
-	vdd-io-supply = <&pmxpoorwills_l7>;
-	qcom,vdd-io-voltage-level = <1800000 2950000>;
-	qcom,vdd-io-current-level = <200 10000>;
-
-	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
-	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
-
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
-							200000000>;
-	qcom,devfreq,freq-table = <50000000 200000000>;
-
-	cd-gpios = <&tlmm 93 0x1>;
-
-	status = "ok";
-};
-
-&pmxpoorwills_vadc {
-	chan@83 {
-		label = "vph_pwr";
-		reg = <0x83>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <1>;
-		qcom,calibration-type = "absolute";
-		qcom,scale-function = <0>;
-		qcom,hw-settle-time = <0>;
-		qcom,fast-avg-setup = <0>;
-	};
-
-	chan@4c {
-		label = "xo_therm";
-		reg = <0x4c>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <4>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4d {
-		label = "pa_therm1";
-		reg = <0x4d>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4e {
-		label = "pa_therm2";
-		reg = <0x4e>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@4f {
-		label = "mdm_case_therm";
-		reg = <0x4f>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-
-	chan@52 {
-		label = "ambient_therm";
-		reg = <0x52>;
-		qcom,decimation = <2>;
-		qcom,pre-div-channel-scaling = <0>;
-		qcom,calibration-type = "ratiometric";
-		qcom,scale-function = <2>;
-		qcom,hw-settle-time = <2>;
-		qcom,fast-avg-setup = <0>;
-		qcom,vadc-thermal-node;
-	};
-};
-
-&i2c_3 {
-	status = "okay";
-	#include "smb138x.dtsi"
-};
-
-&smb138x {
-	pinctrl-names = "default";
-	pinctrl-0 = <&smb_int_default>;
-	interrupt-parent = <&tlmm>;
-	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
-
-	smb1381_charger: qcom,smb1381-charger@1000 {
-		compatible = "qcom,smb138x-charger";
-		qcom,use-extcon;
-	};
-};
-
-&smb138x_vbus {
-	status = "okay";
-};
-
-&usb {
-	status = "okay";
-	extcon = <&smb1381_charger>;
-};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
new file mode 100644
index 0000000..63cc3a4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi
@@ -0,0 +1,144 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+#include "sdxpoorwills-mtp-audio-overlay.dtsi"
+
+&serial_uart {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_console_active>;
+	status = "ok";
+};
+
+&qnand_1 {
+	status = "ok";
+};
+
+&sdhc_1 {
+	vdd-supply = <&vreg_sd_mmc>;
+
+	vdd-io-supply = <&pmxpoorwills_l7>;
+	qcom,vdd-io-voltage-level = <1800000 2950000>;
+	qcom,vdd-io-current-level = <200 10000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_cd_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_cd_off>;
+
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+							200000000>;
+	qcom,devfreq,freq-table = <50000000 200000000>;
+
+	cd-gpios = <&tlmm 93 0x1>;
+
+	status = "ok";
+};
+
+&pmxpoorwills_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4d {
+		label = "pa_therm1";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4e {
+		label = "pa_therm2";
+		reg = <0x4e>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@4f {
+		label = "mdm_case_therm";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+
+	chan@52 {
+		label = "ambient_therm";
+		reg = <0x52>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+		qcom,vadc-thermal-node;
+	};
+};
+
+&i2c_3 {
+	status = "okay";
+	#include "smb138x.dtsi"
+};
+
+&smb138x {
+	pinctrl-names = "default";
+	pinctrl-0 = <&smb_int_default>;
+	interrupt-parent = <&tlmm>;
+	interrupts = <42 IRQ_TYPE_LEVEL_LOW>;
+
+	smb1381_charger: qcom,smb1381-charger@1000 {
+		compatible = "qcom,smb138x-charger";
+		qcom,use-extcon;
+	};
+};
+
+&smb138x_vbus {
+	status = "okay";
+};
+
+&usb {
+	status = "okay";
+	extcon = <&smb1381_charger>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
index 194bfeb..8339f9a 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,12 +12,11 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdxpoorwills-cdp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP CDP";
+	compatible = "qcom,sdxpoorwills-cdp",
+		"qcom,sdxpoorwills", "qcom,cdp";
+	qcom,board-id = <1 0x1>, <1 0x101>;
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
index 194bfeb..2240133 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,12 +12,11 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdxpoorwills-mtp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDXPOORWILLS PCIE-EP MTP";
+	compatible = "qcom,sdxpoorwills-mtp",
+		"qcom,sdxpoorwills", "qcom,mtp";
+	qcom,board-id = <8 0x1>, <8 0x101>;
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index 1e212b7..6c172c1 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -13,11 +13,13 @@
 &soc {
 	tlmm: pinctrl@3900000 {
 		compatible = "qcom,sdxpoorwills-pinctrl";
-		reg = <0x3900000 0x300000>;
+		reg = <0x3900000 0x300000>,
+			<0xB204900 0x280>;
 		interrupts = <0 212 0>;
 		gpio-controller;
 		#gpio-cells = <2>;
 		interrupt-controller;
+		interrupt-parent = <&pdc>;
 		#interrupt-cells = <2>;
 
 		uart2_console_active: uart2_console_active {
@@ -982,6 +984,44 @@
 			};
 		};
 
+		pcie_ep {
+			pcie_ep_clkreq_default: pcie_ep_clkreq_default {
+				mux {
+					pins = "gpio56";
+					function = "pcie_clkreq";
+				};
+				config {
+					pins = "gpio56";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			pcie_ep_perst_default: pcie_ep_perst_default {
+				mux {
+					pins = "gpio57";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio57";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			pcie_ep_wake_default: pcie_ep_wake_default {
+				mux {
+					pins = "gpio53";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio53";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
 		wcd9xxx_intr {
 			wcd_intr_default: wcd_intr_default{
 				mux {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
new file mode 100644
index 0000000..eab887c
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
@@ -0,0 +1,95 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&soc {
+
+	qcom,lpm-levels {
+		compatible = "qcom,lpm-levels";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,pm-cluster@0{
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+			label = "system";
+			qcom,psci-mode-shift = <0>;
+			qcom,psci-mode-mask = <0xf>;
+
+			qcom,pm-cluster-level@0 {
+				reg = <0>;
+				label = "cx_active";
+				qcom,psci-mode = <0x0>;
+				qcom,latency-us = <270>;
+				qcom,ss-power = <455>;
+				qcom,energy-overhead = <270621>;
+				qcom,time-overhead = <500>;
+			};
+
+			qcom,pm-cluster-level@1 {
+				reg = <1>;
+				label = "cx_min";
+				qcom,psci-mode = <0x0>;
+				qcom,latency-us = <285>;
+				qcom,ss-power = <442>;
+				qcom,energy-overhead = <306621>;
+				qcom,time-overhead = <540>;
+				qcom,min-child-idx = <2>;
+				qcom,notify-rpm;
+				qcom,is-reset;
+			};
+
+			qcom,pm-cpu@0 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				qcom,psci-mode-shift = <0>;
+				qcom,psci-mode-mask = <0xf>;
+				qcom,cpu = <&CPU0>;
+
+				qcom,pm-cpu-level@0{
+					reg = <0>;
+					label = "wfi";
+					qcom,psci-cpu-mode = <0x1>;
+					qcom,latency-us = <1>;
+					qcom,ss-power = <473>;
+					qcom,energy-overhead = <100000>;
+					qcom,time-overhead = <25>;
+				};
+
+				qcom,pm-cpu-level@1 {
+					reg = <1>;
+					label ="standalone_pc";
+					qcom,psci-cpu-mode = <0x4>;
+					qcom,latency-us = <240>;
+					qcom,ss-power = <467>;
+					qcom,energy-overhead = <202781>;
+					qcom,time-overhead = <420>;
+					qcom,use-broadcast-timer;
+					qcom,is-reset;
+				};
+
+				qcom,pm-cpu-level@2 {
+					reg = <2>;
+					label = "system-pc";
+					qcom,psci-cpu-mode = <0x8>;
+					qcom,latency-us = <270>;
+					qcom,ss-power = <455>;
+					qcom,energy-overhead = <270621>;
+					qcom,time-overhead = <500>;
+					qcom,use-broadcast-timer;
+					qcom,is-reset;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
index 77e1763..ec65472 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
@@ -24,13 +24,15 @@
 		#size-cells = <1>;
 		ranges;
 
-		interrupts = <0 131 0>, <0 130 0>, <0 59 0>;
-		interrupt-names = "hs_phy_irq", "pwr_event_irq", "ss_phy_irq";
+		interrupts = <0 197 0>, <0 130 0>, <0 196 0>, <0 198 0>;
+		interrupt-names = "dp_hs_phy_irq", "pwr_event_irq",
+			"ss_phy_irq", "dm_hs_phy_irq";
 
 		USB3_GDSC-supply = <&gdsc_usb30>;
 		qcom,usb-dbm = <&dbm_1p5>;
 		qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
 		qcom,num-gsi-evt-buffs = <0x3>;
+		qcom,use-pdc-interrupts;
 
 		clocks = <&clock_gcc GCC_USB30_MASTER_CLK>,
 			 <&clock_gcc GCC_SYS_NOC_USB3_CLK>,
@@ -70,6 +72,7 @@
 			usb-phy = <&usb2_phy>, <&usb3_qmp_phy>;
 			tx-fifo-resize;
 			linux,sysdev_is_parent;
+			snps,bus-suspend-enable;
 			snps,disable-clk-gating;
 			snps,has-lpm-erratum;
 			snps,hird-threshold = /bits/ 8 <0x10>;
@@ -139,9 +142,11 @@
 	usb3_qmp_phy: ssphy@ff0000 {
 		compatible = "qcom,usb-ssphy-qmp-v2";
 		reg = <0xff0000 0x1000>,
-		    <0x01fcb244 0x4>;
+		    <0x01fcb244 0x4>,
+		    <0x00ff088c 0x4>;
 		reg-names = "qmp_phy_base",
-			"vls_clamp_reg";
+			"vls_clamp_reg",
+			"pcs_clamp_enable_reg";
 
 		vdd-supply = <&pmxpoorwills_l4>;
 		core-supply = <&pmxpoorwills_l1>;
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 5829942..d684fb2 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -23,7 +23,7 @@
 	model = "Qualcomm Technologies, Inc. SDX POORWILLS";
 	compatible = "qcom,sdxpoorwills";
 	qcom,msm-id = <334 0x0>, <335 0x0>;
-	interrupt-parent = <&intc>;
+	interrupt-parent = <&pdc>;
 
 	reserved-memory {
 		#address-cells = <1>;
@@ -70,6 +70,7 @@
 		CPU0: cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a7";
+			enable-method = "psci";
 			reg = <0x0>;
 			#cooling-cells = <2>;
 		};
@@ -81,6 +82,11 @@
 		sdhc1 = &sdhc_1; /* SDC1 eMMC/SD/SDIO slot */
 	};
 
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
 	soc: soc { };
 };
 
@@ -96,6 +102,15 @@
 		#interrupt-cells = <3>;
 		reg = <0x17800000 0x1000>,
 		      <0x17802000 0x1000>;
+		interrupt-parent = <&intc>;
+	};
+
+	pdc: interrupt-controller@b210000{
+		compatible = "qcom,pdc-sdxpoorwills";
+		reg = <0xb210000 0x30000>;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&intc>;
+		interrupt-controller;
 	};
 
 	timer {
@@ -268,6 +283,142 @@
 		reg = <0x00137004 0x4>;
 	};
 
+	pcie_ep: qcom,pcie@40002000 {
+		compatible = "qcom,pcie-ep";
+
+		reg = <0x40002000 0x1000>,
+			<0x40000000 0xf1d>,
+			<0x40000f20 0xa8>,
+			<0x40001000 0x1000>,
+			<0x01c00000 0x2000>,
+			<0x01c02000 0x1000>,
+			<0x01c04000 0x1000>;
+		reg-names = "msi", "dm_core", "elbi", "iatu", "parf",
+				"phy", "mmio";
+
+		#address-cells = <0>;
+		interrupt-parent = <&pcie_ep>;
+		interrupts = <0>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-map = <0 &intc 0 140 0>;
+		interrupt-names = "int_global";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&pcie_ep_clkreq_default &pcie_ep_perst_default
+			&pcie_ep_wake_default>;
+
+		clkreq-gpio = <&tlmm 56 0>;
+		perst-gpio = <&tlmm 57 0>;
+		wake-gpio = <&tlmm 53 0>;
+
+		gdsc-vdd-supply = <&gdsc_pcie>;
+		vreg-1.8-supply = <&pmxpoorwills_l1>;
+		vreg-0.9-supply = <&pmxpoorwills_l4>;
+
+		qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>;
+		qcom,vreg-0.9-voltage-level = <872000 872000 24000>;
+
+		clocks = <&clock_gcc GCC_PCIE_PIPE_CLK>,
+			<&clock_gcc GCC_PCIE_CFG_AHB_CLK>,
+			<&clock_gcc GCC_PCIE_MSTR_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_AUX_CLK>,
+			<&clock_gcc GCC_PCIE_0_CLKREF_CLK>,
+			<&clock_gcc GCC_PCIE_SLEEP_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_Q2A_AXI_CLK>;
+
+		clock-names = "pcie_0_pipe_clk", "pcie_0_cfg_ahb_clk",
+				"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+				"pcie_0_aux_clk", "pcie_0_ldo",
+				"pcie_0_sleep_clk",
+				"pcie_0_slv_q2a_axi_clk";
+
+		resets = <&clock_gcc GCC_PCIE_BCR>,
+			<&clock_gcc GCC_PCIE_PHY_BCR>;
+
+		reset-names = "pcie_0_core_reset",
+				"pcie_0_phy_reset";
+
+		qcom,msm-bus,name = "pcie-ep";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<45 512 0 0>,
+				<45 512 500 800>;
+
+		qcom,pcie-link-speed = <2>;
+		qcom,pcie-phy-ver = <6>;
+		qcom,pcie-active-config;
+		qcom,pcie-aggregated-irq;
+		qcom,pcie-mhi-a7-irq;
+		qcom,phy-status-reg = <0x814>;
+
+		qcom,phy-init = <0x840 0x001 0x0 0x1
+				0x094 0x000 0x0 0x1
+				0x058 0x00f 0x0 0x1
+				0x0a4 0x042 0x0 0x1
+				0x110 0x024 0x0 0x1
+				0x1bc 0x011 0x0 0x1
+				0x0bc 0x019 0x0 0x1
+				0x0b0 0x004 0x0 0x1
+				0x0ac 0x0ff 0x0 0x1
+				0x158 0x001 0x0 0x1
+				0x074 0x028 0x0 0x1
+				0x07c 0x00d 0x0 0x1
+				0x084 0x000 0x0 0x1
+				0x1b0 0x01d 0x0 0x1
+				0x1ac 0x056 0x0 0x1
+				0x04c 0x007 0x0 0x1
+				0x050 0x007 0x0 0x1
+				0x0f0 0x003 0x0 0x1
+				0x0ec 0x0fb 0x0 0x1
+				0x00c 0x002 0x0 0x1
+				0x29c 0x012 0x0 0x1
+				0x284 0x005 0x0 0x1
+				0x234 0x0d9 0x0 0x1
+				0x238 0x0cc 0x0 0x1
+				0x51c 0x003 0x0 0x1
+				0x518 0x01c 0x0 0x1
+				0x524 0x014 0x0 0x1
+				0x4ec 0x00e 0x0 0x1
+				0x4f0 0x04a 0x0 0x1
+				0x4f4 0x00f 0x0 0x1
+				0x5b4 0x004 0x0 0x1
+				0x434 0x07f 0x0 0x1
+				0x444 0x070 0x0 0x1
+				0x510 0x017 0x0 0x1
+				0x4d8 0x001 0x0 0x1
+				0x598 0x0e0 0x0 0x1
+				0x59c 0x0c8 0x0 0x1
+				0x5a0 0x0c8 0x0 0x1
+				0x5a4 0x009 0x0 0x1
+				0x5a8 0x0b1 0x0 0x1
+				0x584 0x024 0x0 0x1
+				0x588 0x0e4 0x0 0x1
+				0x58c 0x0ec 0x0 0x1
+				0x590 0x039 0x0 0x1
+				0x594 0x036 0x0 0x1
+				0x570 0x0ef 0x0 0x1
+				0x574 0x0ef 0x0 0x1
+				0x578 0x02f 0x0 0x1
+				0x57c 0x0d3 0x0 0x1
+				0x580 0x040 0x0 0x1
+				0x4fc 0x000 0x0 0x1
+				0x4f8 0x0c0 0x0 0x1
+				0x9a4 0x001 0x0 0x1
+				0x840 0x001 0x0 0x1
+				0x848 0x001 0x0 0x1
+				0x8a0 0x011 0x0 0x1
+				0x988 0x088 0x0 0x1
+				0x998 0x008 0x0 0x1
+				0x8dc 0x00d 0x0 0x1
+				0x800 0x000 0x0 0x1
+				0x844 0x003 0x0 0x1>;
+
+		status = "disabled";
+	};
+
 	gdsc_emac: qcom,gdsc@147004 {
 		compatible = "qcom,gdsc";
 		regulator-name = "gdsc_emac";
@@ -751,6 +902,15 @@
 		interrupt-names = "vbus_det_irq";
 		status = "disabled";
 	};
+
+	qcom,wdt@17817000{
+		compatible = "qcom,msm-watchdog";
+		reg = <0x17817000 0x1000>;
+		reg-names = "wdt-base";
+		interrupts = <1 3 0>, <1 2 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+	};
 };
 
 #include "pmxpoorwills.dtsi"
@@ -764,13 +924,15 @@
 #include "sdxpoorwills-audio.dtsi"
 #include "sdxpoorwills-ion.dtsi"
 #include "msm-arm-smmu-sdxpoorwills.dtsi"
+#include "sdxpoorwills-coresight.dtsi"
 
 &soc {
 	emac_hw: qcom,emac@00020000 {
 		compatible = "qcom,emac-dwc-eqos";
 		reg = <0x20000 0x10000>,
-		      <0x36000 0x100>;
-		reg-names = "emac-base", "rgmii-base";
+			<0x36000 0x100>,
+			<0x3900000 0x300000>;
+		reg-names = "emac-base", "rgmii-base", "tlmm-central-base";
 		interrupts = <0 62 4>, <0 60 4>,
 			<0 45 4>, <0 49 4>,
 			<0 50 4>, <0 51 4>,
@@ -809,3 +971,16 @@
 		};
 	};
 };
+
+#include "pmxpoorwills.dtsi"
+#include "sdxpoorwills-blsp.dtsi"
+#include "sdxpoorwills-regulator.dtsi"
+#include "sdxpoorwills-smp2p.dtsi"
+#include "sdxpoorwills-usb.dtsi"
+#include "sdxpoorwills-pcie.dtsi"
+#include "sdxpoorwills-bus.dtsi"
+#include "sdxpoorwills-thermal.dtsi"
+#include "sdxpoorwills-audio.dtsi"
+#include "sdxpoorwills-ion.dtsi"
+#include "msm-arm-smmu-sdxpoorwills.dtsi"
+#include "sdxpoorwills-pm.dtsi"
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 9d710e3..d1dc88e 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -50,6 +50,7 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 # CONFIG_VDSO is not set
 CONFIG_SMP=y
@@ -301,6 +302,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
@@ -314,6 +316,7 @@
 CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_QPNP=y
@@ -326,11 +329,15 @@
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_PROXY_CONSUMER=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_LCDB=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
 CONFIG_MEDIA_CONTROLLER=y
@@ -345,6 +352,7 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
@@ -352,7 +360,33 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -361,6 +395,21 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_PARANOID_SD_INIT=y
@@ -394,9 +443,8 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
-CONFIG_GSI=y
-CONFIG_IPA3=y
-CONFIG_RMNET_IPA3=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
 CONFIG_RNDIS_IPA=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
@@ -405,12 +453,18 @@
 CONFIG_USB_BAM=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EARLY_RANDOM=y
 CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
 CONFIG_MSM_GLINK=y
 CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
 CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
@@ -429,6 +483,7 @@
 CONFIG_MSM_PM=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
 CONFIG_ANDROID=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 03f297f..2029932 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -56,6 +56,7 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 # CONFIG_VDSO is not set
 CONFIG_SMP=y
@@ -311,6 +312,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
@@ -324,6 +326,7 @@
 CONFIG_SMB1351_USB_CHARGER=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
+CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_QPNP=y
@@ -336,11 +339,15 @@
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_PROXY_CONSUMER=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_LCDB=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
 CONFIG_MEDIA_CONTROLLER=y
@@ -356,6 +363,7 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_UHID=y
 CONFIG_HID_APPLE=y
@@ -363,7 +371,33 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -372,6 +406,21 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_QCRNDIS=y
+CONFIG_USB_CONFIGFS_RMNET_BAM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_RING_BUFFER=y
@@ -406,9 +455,8 @@
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ION=y
 CONFIG_ION_MSM=y
-CONFIG_GSI=y
-CONFIG_IPA3=y
-CONFIG_RMNET_IPA3=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
 CONFIG_RNDIS_IPA=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
@@ -419,14 +467,20 @@
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 # CONFIG_IOMMU_SUPPORT is not set
+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
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_SECURE_BUFFER=y
 CONFIG_QCOM_EARLY_RANDOM=y
 CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
 CONFIG_MSM_GLINK=y
 CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
 CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
@@ -446,6 +500,7 @@
 CONFIG_MSM_PM=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
 CONFIG_ANDROID=y
@@ -491,6 +546,7 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_PANIC_ON_SCHED_BUG=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index d3500ae..29e6335 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -286,6 +286,7 @@
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_CONFIGFS_UEVENT=y
@@ -334,6 +335,7 @@
 CONFIG_IOMMU_TESTS=y
 CONFIG_QCOM_SCM=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_MSM_SMEM=y
 CONFIG_MSM_GLINK=y
 CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index af75d1e..865406f 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -285,6 +285,7 @@
 CONFIG_USB_GADGET_DEBUG_FS=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_SERIAL=y
 CONFIG_USB_CONFIGFS_MASS_STORAGE=y
 CONFIG_USB_CONFIGFS_F_FS=y
 CONFIG_USB_CONFIGFS_UEVENT=y
@@ -333,6 +334,7 @@
 CONFIG_IOMMU_TESTS=y
 CONFIG_QCOM_SCM=y
 CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_BUS_SCALING=y
 CONFIG_QCOM_BUS_CONFIG_RPMH=y
 CONFIG_MSM_SMEM=y
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index 714da33..5d49b60 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -11,6 +11,7 @@
 CONFIG_NR_CPUS=8
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
+CONFIG_CMA=y
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
@@ -35,6 +36,7 @@
 # CONFIG_WIRELESS is not set
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_DMA_CMA=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_ATA=y
 CONFIG_AHCI_SUNXI=y
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 2206e0e..2a35c19 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -1284,7 +1284,7 @@
 		return -EFAULT;
 	}
 
-	if (is_vm_hugetlb_page(vma) && !logging_active) {
+	if (vma_kernel_pagesize(vma) && !logging_active) {
 		hugetlb = true;
 		gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT;
 	} else {
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 4952b98..5122af2 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -51,6 +51,7 @@
 	select COMMON_CLK
 	select COMMON_CLK_QCOM
 	select QCOM_GDSC
+	select GENERIC_CLOCKEVENTS_BROADCAST
 
 config ARCH_MSM8953
 	bool "Enable support for MSM8953"
@@ -64,6 +65,18 @@
 	select HAVE_CLK_PREPARE
 	select COMMON_CLK_MSM
 
+config ARCH_MSM8937
+	bool "Enable support for MSM8937"
+	select CPU_V7
+	select HAVE_ARM_ARCH_TIMER
+	select PINCTRL
+	select QCOM_SCM if SMP
+	select PM_DEVFREQ
+	select CLKDEV_LOOKUP
+	select HAVE_CLK
+	select HAVE_CLK_PREPARE
+	select COMMON_CLK_MSM
+
 config ARCH_SDM450
 	bool "Enable support for SDM450"
 	select CPU_V7
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index 828e9c9..cc06259 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -2,4 +2,5 @@
 obj-$(CONFIG_SMP)	+= platsmp.o
 obj-$(CONFIG_ARCH_SDXPOORWILLS) += board-poorwills.o
 obj-$(CONFIG_ARCH_MSM8953) += board-msm8953.o
+obj-$(CONFIG_ARCH_MSM8937) += board-msm8937.o
 obj-$(CONFIG_ARCH_SDM450) += board-sdm450.o
diff --git a/arch/arm/mach-qcom/board-msm8937.c b/arch/arm/mach-qcom/board-msm8937.c
new file mode 100644
index 0000000..b8d9c26
--- /dev/null
+++ b/arch/arm/mach-qcom/board-msm8937.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include "board-dt.h"
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+
+static const char *msm8937_dt_match[] __initconst = {
+	"qcom,msm8937",
+	NULL
+};
+
+static void __init msm8937_init(void)
+{
+	board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(MSM8937_DT,
+	"Qualcomm Technologies, Inc. MSM8937 (Flattened Device Tree)")
+	.init_machine		= msm8937_init,
+	.dt_compat		= msm8937_dt_match,
+MACHINE_END
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 32a80d6..cf5311f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -432,6 +432,20 @@
 
 	  If unsure, say Y.
 
+config ARM64_ERRATUM_1024718
+	bool "Cortex-A55: 1024718: Update of DBM/AP bits without break before make might result in incorrect update"
+	default y
+	help
+	  This option adds work around for Arm Cortex-A55 Erratum 1024718.
+
+	  Affected Cortex-A55 cores (r0p0, r0p1, r1p0) could cause incorrect
+	  update of the hardware dirty bit when the DBM/AP bits are updated
+	  without a break-before-make. The work around is to disable the usage
+	  of hardware DBM locally on the affected cores. CPUs not affected by
+	  erratum will continue to use the feature.
+
+	  If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
 	bool "Cavium erratum 22375, 24313"
 	default y
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index d35cecb..1de858e 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -154,6 +154,15 @@
 	  This enables support for the MSM8953 chipset. If you do not
 	  wish to build a kernel that runs on this chipset, say 'N' here.
 
+config ARCH_MSM8937
+	bool "Enable Support for Qualcomm Technologies Inc. MSM8937"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the MSM8937 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_SDM450
 	bool "Enable Support for Qualcomm Technologies Inc. SDM450"
 	depends on ARCH_QCOM
@@ -172,6 +181,24 @@
 	  This enables support for the sdm632 chipset. If you do not
 	  wish to build a kernel that runs on this chipset, say 'N' here.
 
+config ARCH_SDM429
+	bool "Enable Support for Qualcomm Technologies Inc. SDM429"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the sdm429 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
+config ARCH_SDM439
+	bool "Enable Support for Qualcomm Technologies Inc. SDM439"
+	depends on ARCH_QCOM
+	select CPU_FREQ_QCOM
+	select COMMON_CLK_MSM
+	help
+	  This enables support for the sdm439 chipset. If you do not
+	  wish to build a kernel that runs on this chipset, say 'N' here.
+
 config ARCH_ROCKCHIP
 	bool "Rockchip Platforms"
 	select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 80d3e82c..7e5cdf2 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -34,12 +34,14 @@
 		sda845-v2-mtp-overlay.dtbo \
 		sda845-v2-qrd-overlay.dtbo \
 		sda845-v2-hdk-overlay.dtbo \
+		sda845-v2-svr-overlay.dtbo \
 		sda845-v2-4k-panel-mtp-overlay.dtbo \
 		sda845-v2-4k-panel-cdp-overlay.dtbo \
 		sda845-v2-4k-panel-qrd-overlay.dtbo \
 		sda845-v2.1-cdp-overlay.dtbo \
 		sda845-v2.1-mtp-overlay.dtbo \
 		sda845-v2.1-qrd-overlay.dtbo \
+		sda845-v2.1-svr-overlay.dtbo \
 		sda845-v2.1-4k-panel-cdp-overlay.dtbo \
 		sda845-v2.1-4k-panel-mtp-overlay.dtbo \
 		sda845-v2.1-4k-panel-qrd-overlay.dtbo \
@@ -77,12 +79,14 @@
 sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-hdk-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-svr-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb
 sda845-v2.1-cdp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-mtp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-qrd-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-svr-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-cdp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-mtp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-qrd-overlay.dtbo-base := sda845-v2.1.dtb
@@ -169,7 +173,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
+qcs605-lc-mtp-overlay.dtbo-base := qcs605-lc.dtb
 qcs605-360camera-overlay.dtbo-base := qcs605.dtb
 
 else
@@ -201,8 +205,7 @@
 	qcs605-360camera.dtb \
 	qcs605-mtp.dtb \
 	qcs605-cdp.dtb \
-	qcs605-external-codec-mtp.dtb \
-	qcs605-lc-mtp.dtb
+	qcs605-external-codec-mtp.dtb
 endif
 
 ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
@@ -220,7 +223,15 @@
 	msm8953-cdp-overlay.dtbo \
 	msm8953-rcm-overlay.dtbo \
 	msm8953-qrd-overlay.dtbo \
-	msm8953-iot-mtp-overlay.dtbo
+	msm8953-iot-mtp-overlay.dtbo \
+	sdm450-cdp-s2-overlay.dtbo \
+	sdm450-mtp-s3-overlay.dtbo \
+	sdm450-qrd-sku4-overlay.dtbo
+
+dtbo-$(CONFIG_ARCH_SDM632) += sdm632-rumi-overlay.dtbo \
+	sdm450-cdp-s2-overlay.dtbo \
+	sdm450-mtp-s3-overlay.dtbo \
+	sdm450-qrd-sku4-overlay.dtbo
 
 msm8953-mtp-overlay.dtbo-base := sdm450.dtb \
 	msm8953.dtb \
@@ -251,6 +262,14 @@
 msm8953-ext-codec-rcm-overlay.dtbo-base := msm8953.dtb \
 	apq8053.dtb
 msm8953-cdp-1200p-overlay.dtbo-base := msm8953.dtb
+sdm450-cdp-s2-overlay.dtbo-base := sdm450-pmi632.dtb \
+	sdm632.dtb \
+	msm8953-pmi632.dtb
+sdm450-mtp-s3-overlay.dtbo-base := sdm450-pmi632.dtb \
+	sdm632.dtb
+sdm450-qrd-sku4-overlay.dtbo-base := sdm450-pmi632.dtb \
+	sdm632.dtb
+sdm632-rumi-overlay.dtbo-base := sdm632.dtb
 
 else
 dtb-$(CONFIG_ARCH_MSM8953) += msm8953-cdp.dtb \
@@ -274,7 +293,10 @@
 	msm8953-pmi8937-cdp.dtb \
 	msm8953-pmi8937-mtp.dtb \
 	msm8953-pmi8940-ext-codec-mtp.dtb \
-	msm8953-pmi8937-ext-codec-mtp.dtb
+	msm8953-pmi8937-ext-codec-mtp.dtb \
+	msm8953-pmi632-cdp-s2.dtb
+
+dtb-$(CONFIG_ARCH_MSM8937) += msm8937-pmi8950-mtp.dtb
 
 dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \
 	sdm450-cdp.dtb \
@@ -287,7 +309,10 @@
 	sdm450-pmi632-cdp-s2.dtb \
 	sdm450-pmi632-mtp-s3.dtb
 
-dtb-$(CONFIG_ARCH_SDM632) += sdm632-rumi.dtb
+dtb-$(CONFIG_ARCH_SDM632) += sdm632-rumi.dtb \
+	sdm632-cdp-s2.dtb	\
+	sdm632-mtp-s3.dtb	\
+	sdm632-qrd-sku4.dtb
 
 endif
 
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dts b/arch/arm64/boot/dts/qcom/apq8053.dts
index bf9e2f2..6bb67c3 100644
--- a/arch/arm64/boot/dts/qcom/apq8053.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "apq8053.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/dsi-adv7533-1080p.dtsi b/arch/arm64/boot/dts/qcom/dsi-adv7533-1080p.dtsi
new file mode 100644
index 0000000..7994285
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-adv7533-1080p.dtsi
@@ -0,0 +1,75 @@
+/* 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.
+ */
+
+&mdss_mdp {
+		dsi_adv7533_1080p: qcom,mdss_dsi_adv7533_1080p {
+		label = "adv7533 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_1080p";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1080>;
+		qcom,mdss-dsi-h-front-porch = <88>;
+		qcom,mdss-dsi-h-back-porch = <148>;
+		qcom,mdss-dsi-h-pulse-width = <44>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <36>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [
+				E6 38 26 00 68 6C 2A 3A 2C 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2B>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0
+			1d 1a 03 05 01 03 04 a0];
+		qcom,dba-panel;
+		qcom,bridge-name = "adv7533";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-adv7533-720p.dtsi b/arch/arm64/boot/dts/qcom/dsi-adv7533-720p.dtsi
new file mode 100644
index 0000000..b84488c0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-adv7533-720p.dtsi
@@ -0,0 +1,74 @@
+/* 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.
+ */
+
+&mdss_mdp {
+dsi_adv7533_720p: qcom,mdss_dsi_adv7533_720p {
+		label = "adv7533 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_720p";
+		qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <720>;
+		qcom,mdss-dsi-h-front-porch = <110>;
+		qcom,mdss-dsi-h-back-porch = <220>;
+		qcom,mdss-dsi-h-pulse-width = <40>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <20>;
+		qcom,mdss-dsi-v-front-porch = <5>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-panel-timings = [
+				A4 24 18 00 4E 52 1C 28 1C 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x20>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [1c 19 02 03 01 03 04 a0
+			1c 19 02 03 01 03 04 a0
+			1c 19 02 03 01 03 04 a0
+			1c 19 02 03 01 03 04 a0
+			1c 08 02 03 01 03 04 a0];
+		qcom,dba-panel;
+		qcom,bridge-name = "adv7533";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-1080p-video.dtsi
new file mode 100644
index 0000000..cbf82af
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-1080p-video.dtsi
@@ -0,0 +1,67 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_adv7533_1080p: qcom,mdss_dsi_adv7533_1080p {
+		label = "adv7533 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_1080p";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1080>;
+		qcom,mdss-dsi-h-front-porch = <88>;
+		qcom,mdss-dsi-h-back-porch = <148>;
+		qcom,mdss-dsi-h-pulse-width = <44>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <36>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6c 2a 3a
+								2c 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2B>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,dba-panel;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-720p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-720p-video.dtsi
new file mode 100644
index 0000000..55ce9f7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-adv7533-720p-video.dtsi
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_adv7533_720p: qcom,mdss_dsi_adv7533_720p {
+		label = "adv7533 720p video mode dsi panel";
+		qcom,mdss-dsi-panel-name = "dsi_adv7533_720p";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1280>;
+		qcom,mdss-dsi-panel-height = <720>;
+		qcom,mdss-dsi-h-front-porch = <110>;
+		qcom,mdss-dsi-h-back-porch = <220>;
+		qcom,mdss-dsi-h-pulse-width = <40>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <20>;
+		qcom,mdss-dsi-v-front-porch = <5>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+				05 01 00 00 c8 00 02 11 00
+				05 01 00 00 0a 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00
+				05 01 00 00 00 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-panel-timings = [a4 24 18 00 4e 52 1c 28
+								1c 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x03>;
+		qcom,mdss-dsi-t-clk-pre = <0x20>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-pan-physical-width-dimension = <160>;
+		qcom,mdss-pan-physical-height-dimension = <90>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+		qcom,mdss-dsi-always-on;
+		qcom,dba-panel;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi
index 3af01c1f..515efb8 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi
@@ -36,8 +36,6 @@
 		qcom,mdss-dsi-lane-1-state;
 		qcom,mdss-dsi-lane-2-state;
 		qcom,mdss-dsi-lane-3-state;
-		qcom,mdss-dsi-t-clk-pre = <0x30>;
-		qcom,mdss-dsi-t-clk-post = <0x0e>;
 		qcom,mdss-dsi-dma-trigger = "trigger_sw";
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-lp11-init;
@@ -50,27 +48,27 @@
 			timing@0 {
 				qcom,mdss-dsi-panel-width = <1080>;
 				qcom,mdss-dsi-panel-height = <2160>;
-				qcom,mdss-dsi-h-front-porch = <24>;
-				qcom,mdss-dsi-h-back-porch = <24>;
-				qcom,mdss-dsi-h-pulse-width = <16>;
+				qcom,mdss-dsi-h-front-porch = <42>;
+				qcom,mdss-dsi-h-back-porch = <42>;
+				qcom,mdss-dsi-h-pulse-width = <10>;
 				qcom,mdss-dsi-h-sync-skew = <0>;
-				qcom,mdss-dsi-v-back-porch = <40>;
-				qcom,mdss-dsi-v-front-porch = <36>;
-				qcom,mdss-dsi-v-pulse-width = <2>;
+				qcom,mdss-dsi-v-back-porch = <15>;
+				qcom,mdss-dsi-v-front-porch = <10>;
+				qcom,mdss-dsi-v-pulse-width = <3>;
 				qcom,mdss-dsi-panel-framerate = <60>;
 				qcom,mdss-dsi-on-command = [
 					39 01 00 00 00 00 04 B9 FF 83 99
 					39 01 00 00 00 00 02 D2 88
-					39 01 00 00 00 00 10 B1 02 04 74 94 01
-					   32 33 11 11 E6 5D 56 73 02 02
+					39 01 00 00 00 00 0c B1 02 04 72 92 01
+					   32 AA 11 11 52 57
 					39 01 00 00 00 00 10 B2 00 80 80 CC 05
 					   07 5A 11 10 10 00 1E 70 03 D4
-					39 01 00 00 00 00 2D B4 00 FF 59 59 0C
-					   AC 00 00 0C 00 07 0A 00 28 07 08 0C
-					   21 03 00 00 00 AE 87 59 59 0C AC 00
-					   00 0C 00 07 0A 00 28 07 08 0C 01 00
-					   00 AE 01
-					39 01 00 00 05 00 22 D3 00 00 01 01 00
+					39 01 00 00 00 00 2D B4 00 FF 59 59 01
+					   AB 00 00 09 00 03 05 00 28 03 0B 0D
+					   21 03 02 00 0C A3 80 59 59 02 AB 00
+					   00 09 00 03 05 00 28 03 0B 0D 02 00
+					   0C A3 01
+					39 01 00 00 05 00 22 D3 00 0C 03 03 00
 					   00 10 10 00 00 03 00 03 00 08 78 08
 					   78 00 00 00 00 00 24 02 05 05 03 00
 					   00 00 05 40
@@ -86,26 +84,25 @@
 					39 01 00 00 00 00 11 D8 AA AA AA AA AA
 					   AA AA AA AA BA AA AA AA BA AA AA
 					39 01 00 00 00 00 02 BD 01
-					39 01 00 00 00 00 11 D8 82 EA AA AA 82
-					   EA AA AA 82 EA AA AA 82 EA AA AA
+					39 01 00 00 00 00 11 D8 00 00 00 00 00
+					   00 00 00 82 EA AA AA 82 EA AA AA
 					39 01 00 00 00 00 02 BD 02
 					39 01 00 00 00 00 09 D8 FF FF C0 3F FF
 					   FF C0 3F
 					39 01 00 00 00 00 02 BD 00
-					39 01 00 00 05 00 37 E0 08 2A 39 35 74
-					   7C 87 7F 84 8A 8E 91 93 96 9B 9C 9E
-					   A5 A6 AE A1 AF B2 5C 58 63 74 08 2A
-					   39 35 74 7C 87 7F 84 8A 8E 91 93 96
-					   9B 9C 9E A5 A6 AE A1 AF B2 5C 58 63
-					   74
+					39 01 00 00 05 00 37 E0 01 21 31 2D 66
+					   6F 7B 75 7A 81 86 89 8C 90 95 97 9A
+					   A1 A2 AA 9E AD B0 5B 57 63 7A 01 21
+					   31 2D 66 6F 7B 75 7A 81 86 89 8C 90
+					   95 97 9A A1 A2 AA 9E AD B0 5B 57 63
+					   7A
 					39 01 00 00 00 00 03 B6 7E 7E
 					39 01 00 00 00 00 02 CC 08
-					39 01 00 00 00 00 06 C7 00 08 00 01 08
-					39 01 00 00 00 00 03 C0 25 5A
-					05 01 00 00 78 00 02 11 00
-					05 01 00 00 14 00 02 29 00];
-				qcom,mdss-dsi-off-command = [05 01 00 00 14 00
-				  02 28 00 05 01 00 00 78 00 02 10 00];
+					05 01 00 00 96 00 02 11 00
+					05 01 00 00 32 00 02 29 00];
+				qcom,mdss-dsi-off-command = [
+					05 01 00 00 32 00 02 28 00
+					05 01 00 00 96 00 02 10 00];
 				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 			};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
new file mode 100644
index 0000000..77f2a1d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi
@@ -0,0 +1,133 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_hx8399c_truly_vid: qcom,mdss_dsi_hx8399c_truly_video{
+		qcom,mdss-dsi-panel-name =
+			"hx8399c video mode dsi truly panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <2160>;
+		qcom,mdss-dsi-h-front-porch = <24>;
+		qcom,mdss-dsi-h-back-porch = <24>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <40>;
+		qcom,mdss-dsi-v-front-porch = <36>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			39 01 00 00 00 00 04
+				b9 ff 83 99
+			39 01 00 00 00 00 02
+				d2 88
+			39 01 00 00 00 00 10
+				b1 02 04 74 94 01 32 33
+				11 11 e6 5d 56 73 02 02
+			39 01 00 00 00 00 10
+				b2 00 80 80 cc 05 07 5a
+				11 10 10 00 1e 70 03 D4
+			39 01 00 00 00 00 2d
+				b4 00 ff 59 59 0c ac 00
+				00 0c 00 07 0a 00 28 07
+				08 0c 21 03 00 00 00 ae
+				87 59 59 0c ac 00 00 0c
+				00 07 0a 00 28 07 08 0c
+				01 00 00 ae 01
+			39 01 00 00 05 00 22
+				d3 00 00 01 01 00 00 10
+				10 00 00 03 00 03 00 08
+				78 08 78 00 00 00 00 00
+				24 02 05 05 03 00 00 00
+				05 40
+			39 01 00 00 05 00 21
+				d5 20 20 19 19 18 18 02
+				03 00 01 24 24 18 18 18
+				18 24 24 00 00 00 00 00
+				00 00 00 2f 2f 30 30 31
+				31
+			39 01 00 00 05 00 21
+				d6 24 24 18 18 19 19 01
+				00 03 02 24 24 18 18 18
+				18 20 20 40 40 40 40 40
+				40 40 40 2f 2f 30 30 31
+				31
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 00 00 11
+				d8 aa aa aa aa aa aa aa
+				aa aa ba aa aa aa ba aa
+				aa
+			39 01 00 00 00 00 02
+				bd 01
+			39 01 00 00 00 00 11
+				d8 82 ea aa aa 82 ea aa
+				aa 82 ea aa aa 82 ea aa
+				aa
+			39 01 00 00 00 00 02
+				bd 02
+			39 01 00 00 00 00 09
+				d8 ff ff c0 3f ff ff c0
+				3f
+			39 01 00 00 00 00 02
+				bd 00
+			39 01 00 00 05 00 37
+				e0 08 2a 39 35 74 7c 87
+				7f 84 8a 8e 91 93 96 9b
+				9c 9e a5 a6 ae a1 af b2
+				5c 58 63 74 08 2a 39 35
+				74 7c 87 7f 84 8a 8e 91
+				93 96 9b 9c 9e a5 a6 ae
+				a1 af b2 5c 58 63 74
+			39 01 00 00 00 00 03
+				b6 7e 7e
+			39 01 00 00 00 00 02
+				cc 08
+			39 01 00 00 00 00 06
+				c7 00 08 00 01 08
+			39 01 00 00 00 00 03
+				c0 25 5a
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 14 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-t-clk-post = <0x0e>;
+		qcom,mdss-dsi-t-clk-pre = <0x31>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-1080p-video.dtsi
new file mode 100644
index 0000000..7297d2a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-1080p-video.dtsi
@@ -0,0 +1,69 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_lt8912_1080_vid: qcom,mdss_dsi_lt8912_1080p_video {
+		qcom,mdss-dsi-panel-name = "lt8912 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1080>;
+		qcom,mdss-dsi-h-front-porch = <88>;
+		qcom,mdss-dsi-h-back-porch = <148>;
+		qcom,mdss-dsi-h-pulse-width = <44>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <36>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <5>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			05 01 00 00 a0 00 02 11 00
+			05 01 00 00 a0 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 78 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [
+			23 1e 08 09 05 03 04 a0
+			23 1e 08 09 05 03 04 a0
+			23 1e 08 09 05 03 04 a0
+			23 1e 08 09 05 03 04 a0
+			23 1a 08 09 05 03 04 a0];
+		qcom,mdss-dsi-panel-timings = [
+				e6 38 26 00 68 6c 2a 3a 2c 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2b>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-post-init-delay = <1>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-480p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-480p-video.dtsi
new file mode 100644
index 0000000..cde7fb4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-lt8912-480p-video.dtsi
@@ -0,0 +1,67 @@
+/* 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.
+ */
+
+&mdss_mdp {
+	dsi_lt8912_480_vid: qcom,mdss_dsi_lt8912_480p_video {
+		qcom,mdss-dsi-panel-name = "lt8912 480p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-destination = "display_1";
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <640>;
+		qcom,mdss-dsi-panel-height = <480>;
+		qcom,mdss-dsi-h-front-porch = <16>;
+		qcom,mdss-dsi-h-back-porch = <48>;
+		qcom,mdss-dsi-h-pulse-width = <96>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <32>;
+		qcom,mdss-dsi-v-front-porch = <15>;
+		qcom,mdss-dsi-v-pulse-width = <2>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [
+			05 01 00 00 a0 00 02 11 00
+			05 01 00 00 a0 00 02 29 00];
+		qcom,mdss-dsi-off-command = [
+			05 01 00 00 78 00 02 28 00
+			05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-panel-timings-phy-v2 = [
+			1D 1A 03 05 01 03 04 a0
+			1D 1A 03 05 01 03 04 a0
+			1D 0A 03 04 01 03 04 a0];
+		qcom,mdss-dsi-panel-timings = [
+			65 12 0C 00 34 38 10 16 0F 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2B>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-post-init-delay = <1>;
+		qcom,mdss-dsi-force-clock-lane-hs;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-cmd.dtsi
new file mode 100644
index 0000000..90d42a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-cmd.dtsi
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------
+ */
+
+&mdss_mdp {
+	dsi_r69006_1080p_cmd: qcom,mdss_dsi_r69006_1080p_cmd {
+		qcom,mdss-dsi-panel-name = "r69006 1080p cmd mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <82>;
+		qcom,mdss-dsi-h-pulse-width = <20>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <9>;
+		qcom,mdss-dsi-v-front-porch = <3>;
+		qcom,mdss-dsi-v-pulse-width = <15>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [23 01 00 00 00 00 02 B0 00
+			29 01 00 00 00 00 06
+				B3 04 10 00 00 00
+			29 01 00 00 00 00 03
+				B4 0C 00
+			29 01 00 00 00 00 04
+				B6 3B D3 00
+			23 01 00 00 00 00
+				02 C0 00
+			15 01 00 00 00 00
+				02 36 98
+			23 01 00 00 00 00
+				02 CC 04
+			29 01 00 00 00 00 20
+				C1 84 00 10 EF 8B F1 FF
+				FF DF 9C C5 9A 73 8D AD
+				63 FE FF FF CB F8 01 00
+				AA 40 02 C2 01 08 00 01
+			29 01 00 00 00 00 0A
+				CB 0D FE 1F 2C 00 00 00
+				00 00
+			29 01 00 00 00 00 0B
+				C2 01 F7 80 04 63 00 60
+				00 01 30
+			29 01 00 00 00 00 07
+				C3 55 01 00 01 00 00
+			29 01 00 00 00 00 12
+				C4 70 00 00 00 00 00 00
+				00 00 02 01 00 05 01 00
+				00 00
+			29 01 00 00 00 00 0F
+				C6 57 07 4A 07 4A 01 0E
+				01 02 01 02 09 15 07
+			29 01 00 00 00 00 1F
+				C7 00 06 0C 16 27 35 3F
+				4D 33 3C 49 5B 64 66 67
+				00 06 0C 16 27 35 3F 4D
+				33 3C 49 5B 64 66 67
+			29 01 00 00 00 00 14
+				C8 00 00 FE 01 08 E7 00
+				00 FD 02 03 A8 00 00 FC
+				E7 E9 C9 00
+			29 01 00 00 00 00 09
+				C9 1F 68 1F 68 4C 4C C4
+				11
+			29 01 00 00 00 00 11
+				D0 11 01 91 0B D9 19 19
+				00 00 00 19 99 00 00 00
+				00
+			29 01 00 00 00 00 1D
+				D3 1B 3B BB AD A5 33 33
+				33 00 80 AD A8 37 33 33
+				33 33 F7 F2 1F 7D 7C FF
+				0F 99 00 FF FF
+			29 01 00 00 00 00 04
+				D4 57 33 03
+			29 01 00 00 00 00 0C
+				D5 66 00 00 01 32 01 32
+				00 0b 00 0b
+			29 01 00 00 00 00 02 BE 04
+			29 01 00 00 00 00 11
+				CF 40 10 00 00 00 00 32
+				00 00 00 00 00 00 00 00
+				00
+			29 01 00 00 00 00 06
+				DE 00 00 3F FF 10
+			29 01 00 00 00 00 02 E9 00
+			29 01 00 00 00 00 02 F2 00
+			23 01 00 00 00 00 02 D6 01
+			39 01 00 00 00 00 02 35 00
+			39 01 00 00 00 00 02 51 FF
+			39 01 00 00 00 00 02 53 2C
+			39 01 00 00 00 00 02 55 00
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 0A 00 02 28 00
+			29 01 00 00 00 00 1d D3 13 3B BB A5 A5 33 33 33
+				00 80 A4 A8 37 33 33 33 33 F7 F2 1F 7D
+				7C FF 0F 99 00 FF FF
+			05 01 00 00 5A 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-panel-timings = [6E 3F 36 00 5A 4F 38 41 54
+			03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x1e>;
+		qcom,mdss-dsi-t-clk-pre = <0x30>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 01 0A];
+		qcom,mdss-dsi-panel-status-command-mode = "dsi_lp_mode";
+		qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+		qcom,mdss-dsi-panel-status-read-length = <1>;
+		qcom,mdss-dsi-panel-status-value = <0x1C>;
+		qcom,mdss-dsi-panel-max-error-count = <3>;
+		qcom,mdss-dsi-rx-eot-ignore;
+		qcom,mdss-dsi-tx-eot-append;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-video.dtsi
new file mode 100644
index 0000000..4cbc922
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-r69006-1080p-video.dtsi
@@ -0,0 +1,137 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------
+ */
+
+&mdss_mdp {
+	dsi_r69006_1080p_video: qcom,mdss_dsi_r69006_1080p_video {
+		qcom,mdss-dsi-panel-name = "r69006 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <100>;
+		qcom,mdss-dsi-h-back-porch = <82>;
+		qcom,mdss-dsi-h-pulse-width = <20>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <9>;
+		qcom,mdss-dsi-v-front-porch = <3>;
+		qcom,mdss-dsi-v-pulse-width = <15>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-on-command = [23 01 00 00 00 00 02 B0 00
+			29 01 00 00 00 00 06
+				B3 05 10 00 00 00
+			29 01 00 00 00 00 03 B4 0c 00
+			29 01 00 00 00 00 04 B6 3b c3 00
+			23 01 00 00 00 00 02 C0 00
+			15 01 00 00 00 00 02 36 98
+			23 01 00 00 00 00 02 CC 04
+			29 01 00 00 00 00 20
+				C1 84 00 10 EF 8B
+				F1 FF FF DF 9C C5
+				9A 73 8D AD 63 FE
+				FF FF CB F8 01 00
+				AA 40 00 C2 01 08
+				00 01
+			29 01 00 00 00 00 0A
+				CB 0D FE 1F 2C 00
+				00 00 00 00
+			29 01 00 00 00 00 0B
+				C2 01 F7 80 04 63
+				00 60 00 01 30
+			29 01 00 00 00 00 07
+				C3 55 01 00 01 00
+				00
+			29 01 00 00 00 00 12
+				C4 70 00 00 00 00
+				00 00 00 00 02 01
+				00 05 01 00 00 00
+			29 01 00 00 00 00 0F
+				C6 59 07 4a 07 4a
+				01 0E 01 02 01 02
+				09 15 07
+			29 01 00 00 00 00 1F
+				C7 00 30 32 34 42
+				4E 56 62 44 4A 54
+				62 6B 73 7F 08 30
+				32 34 42 4E 56 62
+				44 4A 54 62 6B 73
+				7F
+			29 01 00 00 00 00 14
+				C8 00 00 00 00 00
+				FC 00 00 00 00 00
+				FC 00 00 00 00 00
+				FC 00
+			29 01 00 00 00 00 09
+				C9 1F 68 1F 68 4C
+				4C C4 11
+			29 01 00 00 00 00 11
+				D0 33 01 91 0B D9
+				19 19 00 00 00 19
+				99 00 00 00 00
+			29 01 00 00 00 00 1D
+				D3 1B 3B BB AD A5
+				33 33 33 00 80 AD
+				A8 6f 6f 33 33 33
+				F7 F2 1F 7D 7C FF
+				0F 99 00 FF FF
+			29 01 00 00 00 00 04
+				D4 57 33 03
+			29 01 00 00 00 00 0C
+				D5 66 00 00 01 27
+				01 27 00 6D 00 6D
+			23 01 00 00 00 00 02 D6 81
+			05 01 00 00 78 00 02 11 00
+			05 01 00 00 78 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
+			05 01 00 00 96 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-h-sync-pulse = <1>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33
+			22 27 1e 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x20>;
+		qcom,mdss-dsi-t-clk-pre = <0x2c>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 01 0A];
+		qcom,mdss-dsi-panel-status-command-mode = "dsi_lp_mode";
+		qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+		qcom,mdss-dsi-panel-status-read-length = <1>;
+		qcom,mdss-dsi-panel-status-value = <0x1C>;
+		qcom,mdss-dsi-panel-max-error-count = <3>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
new file mode 100644
index 0000000..3a5d272
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi
@@ -0,0 +1,50 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_dual_test_cmd: qcom,mdss_dsi_test_oled_cmd {
+		qcom,mdss-dsi-panel-name =
+			"Dual test cmd mode DSI amoled non-DSC panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,adjust-timer-wakeup-ms = <1>;
+		qcom,mdss-dsi-reset-sequence = <1 2>, <0 2>, <1 2>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-hfp-power-mode;
+		qcom,mdss-dsi-hbp-power-mode;
+		qcom,mdss-dsi-hsa-power-mode;
+		qcom,mdss-dsi-display-timings {
+			timing@0{
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-cmd.dtsi
new file mode 100644
index 0000000..83b8ca0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-cmd.dtsi
@@ -0,0 +1,96 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_truly_1080_cmd: qcom,mdss_dsi_truly_1080p_cmd {
+		qcom,mdss-dsi-panel-name = "truly 1080p cmd mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <96>;
+		qcom,mdss-dsi-h-back-porch = <64>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings =
+			[e6 38 26 00 68 6e 2a 3c 44 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2d>;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-on-command = [23 01 00 00 00 00 02 d6 01
+			15 01 00 00 00 00 02 35 00
+			15 01 00 00 00 00 02 51 ff
+			15 01 00 00 00 00 02 53 2c
+			15 01 00 00 00 00 02 55 00
+			05 01 00 00 78 00 02 11 00
+			23 01 00 00 00 00 02 b0 04
+			29 01 00 00 00 00 07 b3 04 00 00 00 00 00
+			29 01 00 00 00 00 03 b6 3a d3
+			29 01 00 00 00 00 03 c0 00 00
+			29 01 00 00 00 00 23 c1 84 60 10 eb ff 6f ce ff ff 17 02
+				58 73 ae b1 20 c6 ff ff 1f f3 ff 5f 10 10 10 10
+				00 02 01 22 22 00 01
+			29 01 00 00 00 00 08 c2 31 f7 80 06 08 00 00
+			29 01 00 00 00 00 17 c4 70 00 00 00 00 04 00 00 00 0c 06
+				00 00 00 00 00 04 00 00 00 0c 06
+			29 01 00 00 00 00 29 c6 78 69 00 69 00 69 00 00 00 00 00
+				69 00 69 00 69 10 19 07 00 78 00 69 00 69 00 69
+				00 00 00 00 00 69 00 69 00 69 10 19 07
+			29 01 00 00 00 00 0a cb 31 fc 3f 8c 00 00 00 00 c0
+			23 01 00 00 00 00 02 cc 0b
+			29 01 00 00 00 00 0b d0 11 81 bb 1e 1e 4c 19 19 0c 00
+			29 01 00 00 00 00 1a d3 1b 33 bb bb b3 33 33 33 00 01 00
+				a0 d8 a0 0d 4e 4e 33 3b 22 72 07 3d bf 33
+			29 01 00 00 00 00 08 d5 06 00 00 01 51 01 32
+			29 01 00 00 00 00 1f c7 01 0a 11 18 26 33 3e 50 38 42 52
+				60 67 6e 77 01 0a 11 18 26 33 3e 50 38 42 52 60
+				67 6e 77
+			29 01 00 00 14 00 14 c8 01 00 00 00 00 fc 00 00 00 00
+				00 fc 00 00 00 00 00 fc 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00
+				 05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-post-init-delay = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-video.dtsi
new file mode 100644
index 0000000..b8a85d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-truly-1080p-video.dtsi
@@ -0,0 +1,91 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_truly_1080_vid: qcom,mdss_dsi_truly_1080p_video {
+		qcom,mdss-dsi-panel-name = "truly 1080p video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1080>;
+		qcom,mdss-dsi-panel-height = <1920>;
+		qcom,mdss-dsi-h-front-porch = <96>;
+		qcom,mdss-dsi-h-back-porch = <64>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings =
+			[e6 38 26 00 68 6e 2a 3c 44 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2d>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 35 00
+			15 01 00 00 00 00 02 51 ff
+			15 01 00 00 00 00 02 53 2c
+			15 01 00 00 00 00 02 55 00
+			05 01 00 00 78 00 02 11 00
+			23 01 00 00 00 00 02 b0 00
+			29 01 00 00 00 00 07 b3 14 00 00 00 00 00
+			29 01 00 00 00 00 03 b6 3a d3
+			29 01 00 00 00 00 03 c0 00 00
+			29 01 00 00 00 00 23 c1 84 60 10 eb ff 6f ce ff ff 17 02
+				58 73 ae b1 20 c6 ff ff 1f f3 ff 5f 10 10 10 10
+				00 02 01 22 22 00 01
+			29 01 00 00 00 00 08 c2 31 f7 80 06 08 00 00
+			29 01 00 00 00 00 17 c4 70 00 00 00 00 04 00 00 00 0c 06
+				00 00 00 00 00 04 00 00 00 0c 06
+			29 01 00 00 00 00 29 c6 00 69 00 69 00 69 00 00 00 00 00
+				69 00 69 00 69 10 19 07 00 01 00 69 00 69 00 69
+				00 00 00 00 00 69 00 69 00 69 10 19 07
+			29 01 00 00 00 00 0a cb 31 fc 3f 8c 00 00 00 00 c0
+			23 01 00 00 00 00 02 cc 0b
+			29 01 00 00 00 00 0b d0 11 81 bb 1e 1e 4c 19 19 0c 00
+			29 01 00 00 00 00 1a d3 1b 33 bb bb b3 33 33 33 00 01 00
+				a0 d8 a0 0d 4e 4e 33 3b 22 72 07 3d bf 33
+			29 01 00 00 00 00 08 d5 06 00 00 01 51 01 32
+			29 01 00 00 00 00 1f c7 01 0a 11 18 26 33 3e 50 38 42 52
+				60 67 6e 77 01 0a 11 18 26 33 3e 50 38 42 52 60
+				67 6e 77
+			29 01 00 00 14 00 14 c8 01 00 00 00 00 fc 00 00 00 00
+				00 fc 00 00 00 00 00 fc 00
+			05 01 00 00 14 00 02 29 00];
+		qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00
+				 05 01 00 00 78 00 02 10 00];
+		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-tx-eot-append;
+		qcom,mdss-dsi-post-init-delay = <1>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-truly-wuxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-truly-wuxga-video.dtsi
new file mode 100644
index 0000000..b0d13d0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-truly-wuxga-video.dtsi
@@ -0,0 +1,59 @@
+/* Copyright (c) 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.
+ */
+
+&mdss_mdp {
+	dsi_truly_wuxga_vid: qcom,mdss_dsi_truly_wuxga_video {
+		qcom,mdss-dsi-panel-name = "truly wuxga video mode dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_video_mode";
+		qcom,mdss-dsi-panel-framerate = <60>;
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-panel-width = <1920>;
+		qcom,mdss-dsi-panel-height = <1200>;
+		qcom,mdss-dsi-h-front-porch = <96>;
+		qcom,mdss-dsi-h-back-porch = <64>;
+		qcom,mdss-dsi-h-pulse-width = <16>;
+		qcom,mdss-dsi-h-sync-skew = <0>;
+		qcom,mdss-dsi-v-back-porch = <16>;
+		qcom,mdss-dsi-v-front-porch = <4>;
+		qcom,mdss-dsi-v-pulse-width = <1>;
+		qcom,mdss-dsi-h-left-border = <0>;
+		qcom,mdss-dsi-h-right-border = <0>;
+		qcom,mdss-dsi-v-top-border = <0>;
+		qcom,mdss-dsi-v-bottom-border = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-h-sync-pulse = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-panel-timings = [f3 3a 26 00 6c 6e
+						2c 3e 2f 03 04 00];
+		qcom,mdss-dsi-t-clk-post = <0x02>;
+		qcom,mdss-dsi-t-clk-pre = <0x2d>;
+		qcom,mdss-dsi-bl-min-level = <1>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00];
+		qcom,mdss-dsi-off-command = [22 01 00 00 00 00 02 00 00];
+		qcom,mdss-dsi-on-command-state = "dsi_hs_mode";
+		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
new file mode 100644
index 0000000..5c379d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-3600mah.dtsi
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,fg-gen3-batterydata-demo-3600mah {
+	qcom,faschg-current-ma = <5000>;
+	qcom,max-voltage-uv = <4350000>;
+	qcom,nom-batt-capacity-mah = <3600>;
+	qcom,batt-id-kohm = <100>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-type = "fg-gen3-batterydata-demo-3600mah";
+	qcom,checksum = <0xA401>;
+	qcom,gui-version = "PMI8998GUI - 2.0.0.54";
+	qcom,fg-profile-data = [
+		B2 1F 79 05
+		86 0A 36 06
+		8D 1D 6F F4
+		39 12 9A 14
+		DC 18 91 22
+		26 3C EB 4B
+		5D 00 00 00
+		11 00 00 00
+		00 00 78 BC
+		26 CD 48 C2
+		1E 00 08 00
+		78 C5 64 E5
+		95 FC 1D F3
+		E1 F5 ED 0B
+		33 FD 8C 2B
+		1E 06 09 20
+		27 00 14 00
+		D8 1F 77 05
+		8B 0A 57 FC
+		59 1D 8B 00
+		33 03 78 0C
+		0F 19 ED 22
+		6B 45 21 53
+		5A 00 00 00
+		0E 00 00 00
+		00 00 F7 07
+		55 C2 AA AA
+		1A 00 00 00
+		B1 EA 64 E5
+		7C 06 93 F2
+		71 FD 9E 03
+		80 0A 7A 22
+		CF 33 CC FF
+		07 10 00 00
+		6F 0E 99 45
+		1A 00 40 00
+		13 01 0A FA
+		FF 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		00 00 00 00
+		];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi
new file mode 100644
index 0000000..84f73a4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-cpu.dtsi
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU4>;
+				};
+				core1 {
+					cpu = <&CPU5>;
+				};
+				core2 {
+					cpu = <&CPU6>;
+				};
+				core3 {
+					cpu = <&CPU7>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
+		CPU0: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x100>;
+			enable-method = "psci";
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			      /* A53 L2 dump not supported */
+			      qcom,dump-size = <0x0>;
+			};
+			L1_I_100: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_100: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU1: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x101>;
+			enable-method = "psci";
+			next-level-cache = <&L2_1>;
+			L1_I_101: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_101: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU2: cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x102>;
+			enable-method = "psci";
+			next-level-cache = <&L2_1>;
+			L1_I_102: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_102: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU3: cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x103>;
+			enable-method = "psci";
+			next-level-cache = <&L2_1>;
+			L1_I_103: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_103: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU4: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0>;
+			enable-method = "psci";
+			next-level-cache = <&L2_0>;
+			L2_0: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			      qcom,dump-size = <0x0>;
+			};
+			L1_I_0: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_0: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU5: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x1>;
+			enable-method = "psci";
+			next-level-cache = <&L2_0>;
+			L1_I_1: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_1: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU6: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x2>;
+			enable-method = "psci";
+			next-level-cache = <&L2_0>;
+			L1_I_2: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_2: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+
+		CPU7: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+			enable-method = "psci";
+			next-level-cache = <&L2_0>;
+			L1_I_3: l1-icache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x8800>;
+			};
+			L1_D_3: l1-dcache {
+				compatible = "arm,arch-cache";
+				qcom,dump-size = <0x9000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi
new file mode 100644
index 0000000..823d99d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-ion.dtsi
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@8 { /* CP_MM HEAP */
+			reg = <8>;
+			memory-region = <&secure_mem>;
+			qcom,ion-heap-type = "SECURE_DMA";
+		};
+
+		qcom,ion-heap@27 { /* QSEECOM HEAP */
+			reg = <27>;
+			memory-region = <&qseecom_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
similarity index 61%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
index 194bfeb..4cd3568 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,14 +11,6 @@
  * 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>;
-
+&blsp1_uart2 {
+	status = "ok";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi
new file mode 100644
index 0000000..17ee465
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pinctrl.dtsi
@@ -0,0 +1,1525 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	tlmm: pinctrl@1000000 {
+		compatible = "qcom,msm8937-pinctrl";
+		reg = <0x1000000 0x300000>;
+		interrupts = <0 208 0>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		pmx-uartconsole {
+			uart_console_active: uart_console_active {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			uart_console_sleep: uart_console_sleep {
+				mux {
+					pins = "gpio4", "gpio5";
+					function = "blsp_uart2";
+				};
+
+				config {
+					pins = "gpio4", "gpio5";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+		};
+
+		i2c_2 {
+			i2c_2_active: i2c_2_active {
+				/* active state */
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "blsp_i2c2";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_2_sleep: i2c_2_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio6", "gpio7";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio6", "gpio7";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		i2c_3 {
+			i2c_3_active: i2c_3_active {
+				/* active state */
+				mux {
+					pins = "gpio10", "gpio11";
+					function = "blsp_i2c3";
+				};
+
+				config {
+					pins = "gpio10", "gpio11";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_3_sleep: i2c_3_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio10", "gpio11";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio10", "gpio11";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		i2c_5 {
+			i2c_5_active: i2c_5_active {
+				/* active state */
+				mux {
+					pins = "gpio18", "gpio19";
+					function = "blsp_i2c5";
+				};
+
+				config {
+					pins = "gpio18", "gpio19";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			i2c_5_sleep: i2c_5_sleep {
+				/* suspended state */
+				mux {
+					pins = "gpio18", "gpio19";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio18", "gpio19";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		pmx_rd_nfc_int {
+			/*qcom,pins = <&gp 17>;*/
+			pins = "gpio17";
+			qcom,pin-func = <0>;
+			qcom,num-grp-pins = <1>;
+			label = "pmx_nfc_int";
+
+			nfc_int_active: active {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+
+			nfc_int_suspend: suspend {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+		};
+
+		pmx_nfc_reset {
+			/*qcom,pins = <&gp 16>;*/
+			pins = "gpio16";
+			qcom,pin-func = <0>;
+			qcom,num-grp-pins = <1>;
+			label = "pmx_nfc_disable";
+
+			nfc_disable_active: active {
+				drive-strength = <6>;
+				bias-pull-up;
+			};
+
+			nfc_disable_suspend: suspend {
+				drive-strength = <6>;
+				bias-disable;
+			};
+		};
+
+		tlmm_pmi_flash_led {
+			rear_flash_led_enable: rear_flash_led_enable {
+				mux {
+					pins = "gpio33";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33";
+					drive-strength = <16>;
+					output-high;
+				};
+			};
+
+			rear_flash_led_disable: rear_flash_led_disable {
+				mux {
+					pins = "gpio33";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio33";
+					drive-strength = <2>;
+					output-low;
+				};
+			};
+
+			front_flash_led_enable: front_flash_led_enable {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio50";
+					drive-strength = <16>;
+					output-high;
+				};
+			};
+
+			front_flash_led_disable: front_flash_led_disable {
+				mux {
+					pins = "gpio50";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio50";
+					drive-strength = <2>;
+					output-low;
+				};
+			};
+		};
+
+		spi3 {
+			spi3_default: spi3_default {
+				/* active state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio8", "gpio9", "gpio11";
+					function = "blsp_spi3";
+				};
+
+				config {
+					pins = "gpio8", "gpio9", "gpio11";
+					drive-strength = <12>; /* 12 MA */
+					bias-disable = <0>; /* No PULL */
+				};
+			};
+
+			spi3_sleep: spi3_sleep {
+				/* suspended state */
+				mux {
+					/* MOSI, MISO, CLK */
+					pins = "gpio8", "gpio9", "gpio11";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio8", "gpio9", "gpio11";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+
+			spi3_cs0_active: cs0_active {
+				/* CS */
+				mux {
+					pins = "gpio10";
+					function = "blsp_spi3";
+				};
+
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+
+			spi3_cs0_sleep: cs0_sleep {
+				/* CS */
+				mux {
+					pins = "gpio10";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio10";
+					drive-strength = <2>;
+					bias-disable = <0>;
+				};
+			};
+		};
+
+		wcnss_pmux_5wire {
+			/* Active configuration of bus pins */
+			wcnss_default: wcnss_default {
+				wcss_wlan2 {
+					pins = "gpio76";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins = "gpio77";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio78";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio79", "gpio80";
+					function = "wcss_wlan";
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+
+			wcnss_sleep: wcnss_sleep {
+				wcss_wlan2 {
+					pins = "gpio76";
+					function = "wcss_wlan2";
+				};
+				wcss_wlan1 {
+					pins = "gpio77";
+					function = "wcss_wlan1";
+				};
+				wcss_wlan0 {
+					pins = "gpio78";
+					function = "wcss_wlan0";
+				};
+				wcss_wlan {
+					pins = "gpio79", "gpio80";
+					function = "wcss_wlan";
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down; /* PULL Down */
+				};
+			};
+		};
+
+		wcnss_pmux_gpio: wcnss_pmux_gpio {
+			wcnss_gpio_default: wcnss_gpio_default {
+				/* Active configuration of bus pins */
+				mux {
+					/* Uses general purpose pins */
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					       function = "gpio";
+
+				};
+
+				config {
+					pins = "gpio76", "gpio77",
+					       "gpio78", "gpio79",
+					       "gpio80";
+					drive-strength = <6>; /* 6 MA */
+					bias-pull-up; /* PULL UP */
+				};
+			};
+		};
+
+		blsp2_uart1_active: blsp2_uart1_active {
+			mux {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				function = "blsp_uart5";
+			};
+
+			config {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		blsp2_uart1_sleep: blsp2_uart1_sleep {
+			mux {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio16", "gpio17", "gpio18", "gpio19";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
+
+		pmx_adv7533_int: pmx_adv7533_int {
+			adv7533_int_active: adv7533_int_active {
+				mux {
+					pins = "gpio126";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio126";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+
+			adv7533_int_suspend: adv7533_int_suspend {
+				mux {
+					pins = "gpio126";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio126";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+
+		};
+
+		pmx_mdss: pmx_mdss {
+			mdss_dsi_active: mdss_dsi_active {
+				mux {
+					pins = "gpio60", "gpio98", "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio60", "gpio98", "gpio99";
+					drive-strength = <8>; /* 8 mA */
+					bias-disable = <0>; /* no pull */
+					output-high;
+				};
+			};
+			mdss_dsi_suspend: mdss_dsi_suspend {
+				mux {
+					pins = "gpio60", "gpio98", "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio60", "gpio98", "gpio99";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+					input-enable;
+				};
+			};
+		};
+
+		pmx_mdss_te {
+			mdss_te_active: mdss_te_active {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+				config {
+					pins = "gpio24";
+					drive-strength = <2>; /* 8 mA */
+					bias-pull-down; /* pull down*/
+				};
+			};
+
+			mdss_te_suspend: mdss_te_suspend {
+				mux {
+					pins = "gpio24";
+					function = "mdp_vsync";
+				};
+				config {
+					pins = "gpio24";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		usbc_int_default: usbc_int_default {
+			mux {
+				pins = "gpio97", "gpio131";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio97", "gpio131";
+				drive-strength = <2>;
+				bias-pull-up;
+			};
+		};
+
+		tlmm_gpio_key {
+			gpio_key_active: gpio_key_active {
+				mux {
+					pins = "gpio91", "gpio127", "gpio128";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio91", "gpio127", "gpio128";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			gpio_key_suspend: gpio_key_suspend {
+				mux {
+					pins = "gpio91", "gpio127", "gpio128";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio91", "gpio127", "gpio128";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		/* add pingrp for touchscreen */
+		pmx_ts_int_active {
+			ts_int_active: ts_int_active {
+				mux {
+					pins = "gpio65";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_int_suspend {
+			ts_int_suspend: ts_int_suspend {
+				mux {
+					pins = "gpio65";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_reset_active {
+			ts_reset_active: ts_reset_active {
+				mux {
+					pins = "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio64";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_reset_suspend {
+			ts_reset_suspend: ts_reset_suspend {
+				mux {
+					pins = "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio64";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_release {
+			ts_release: ts_release {
+				mux {
+					pins = "gpio65", "gpio64";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio65", "gpio64";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_qdsd_clk {
+			qdsd_clk_sdcard: clk_sdcard {
+				config {
+					pins = "qdsd_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+			qdsd_clk_trace: clk_trace {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_clk_swdtrc: clk_swdtrc {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_clk_spmi: clk_spmi {
+				config {
+					pins = "qdsd_clk";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_cmd {
+			qdsd_cmd_sdcard: cmd_sdcard {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_cmd_trace: cmd_trace {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_cmd_swduart: cmd_uart {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_cmd_swdtrc: cmd_swdtrc {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+
+			qdsd_cmd_jtag: cmd_jtag {
+				config {
+					pins = "qdsd_cmd";
+					bias-disable; /* NO pull */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_cmd_spmi: cmd_spmi {
+				config {
+					pins = "qdsd_cmd";
+					bias-pull-down; /* pull down */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data0 {
+			qdsd_data0_sdcard: data0_sdcard {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data0_trace: data0_trace {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data0_swduart: data0_uart {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_swdtrc: data0_swdtrc {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_jtag: data0_jtag {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data0_spmi: data0_spmi {
+				config {
+					pins = "qdsd_data0";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data1 {
+			qdsd_data1_sdcard: data1_sdcard {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data1_trace: data1_trace {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data1_swduart: data1_uart {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data1_swdtrc: data1_swdtrc {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data1_jtag: data1_jtag {
+				config {
+					pins = "qdsd_data1";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data2 {
+			qdsd_data2_sdcard: data2_sdcard {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data2_trace: data2_trace {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data2_swduart: data2_uart {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data2_swdtrc: data2_swdtrc {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-down; /* pull down */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data2_jtag: data2_jtag {
+				config {
+					pins = "qdsd_data2";
+					bias-pull-up; /* pull up */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+		};
+
+		pmx_qdsd_data3 {
+			qdsd_data3_sdcard: data3_sdcard {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data3_trace: data3_trace {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+			qdsd_data3_swduart: data3_uart {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_swdtrc: data3_swdtrc {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_jtag: data3_jtag {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+			qdsd_data3_spmi: data3_spmi {
+				config {
+					pins = "qdsd_data3";
+					bias-pull-down; /* pull down */
+					drive-strength = <8>; /* 8 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_rclk {
+			sdc1_rclk_on: sdc1_rclk_on {
+				config {
+					pins = "sdc1_rclk";
+					bias-pull-down; /* pull down */
+				};
+			};
+
+			sdc1_rclk_off: sdc1_rclk_off {
+				config {
+					pins = "sdc1_rclk";
+					bias-pull-down; /* pull down */
+				};
+			};
+		};
+
+		wcd9xxx_intr {
+			wcd_intr_default: wcd_intr_default{
+				mux {
+					pins = "gpio73";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio73";
+					drive-strength = <2>; /* 2 mA */
+					bias-pull-down; /* pull down */
+					input-enable;
+				};
+			};
+		};
+
+		cdc_reset_ctrl {
+			cdc_reset_sleep: cdc_reset_sleep {
+				mux {
+					pins = "gpio68";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio68";
+					drive-strength = <16>;
+					bias-disable;
+					output-low;
+				};
+			};
+			cdc_reset_active:cdc_reset_active {
+				mux {
+					pins = "gpio68";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio68";
+					drive-strength = <16>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+		};
+
+		cdc-pdm-2-lines {
+			cdc_pdm_lines_2_act: pdm_lines_2_on {
+				mux {
+					pins = "gpio70", "gpio71", "gpio72";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio70", "gpio71", "gpio72";
+					drive-strength = <8>;
+				};
+			};
+
+			cdc_pdm_lines_2_sus: pdm_lines_2_off {
+				mux {
+					pins = "gpio70", "gpio71", "gpio72";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio70", "gpio71", "gpio72";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cdc-pdm-lines {
+			cdc_pdm_lines_act: pdm_lines_on {
+				mux {
+					pins = "gpio69", "gpio73", "gpio74";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio69", "gpio73", "gpio74";
+					drive-strength = <8>;
+				};
+			};
+			cdc_pdm_lines_sus: pdm_lines_off {
+				mux {
+					pins = "gpio69", "gpio73", "gpio74";
+					function = "cdc_pdm0";
+				};
+
+				config {
+					pins = "gpio69", "gpio73", "gpio74";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		cross-conn-det {
+			cross_conn_det_act: lines_on {
+				mux {
+					pins = "gpio63";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <8>;
+					output-low;
+					bias-pull-down;
+				};
+			};
+
+			cross_conn_det_sus: lines_off {
+				mux {
+					pins = "gpio63";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio63";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		/* WSA VI sense */
+		wsa-vi {
+			wsa_vi_on: wsa_vi_on {
+				mux {
+					pins = "gpio94", "gpio95";
+					function = "wsa_io";
+				};
+
+				config {
+					pins = "gpio94", "gpio95";
+					drive-strength = <8>; /* 8 MA */
+					bias-disable; /* NO pull */
+				};
+			};
+
+			wsa_vi_off: wsa_vi_off {
+				mux {
+					pins = "gpio94", "gpio95";
+					function = "wsa_io";
+				};
+
+				config {
+					pins = "gpio94", "gpio95";
+					drive-strength = <2>; /* 2 MA */
+					bias-pull-down;
+				};
+			};
+		};
+
+		/* WSA Reset */
+		wsa_reset {
+			wsa_reset_on: wsa_reset_on {
+				mux {
+					pins = "gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio96";
+					drive-strength = <2>; /* 2 MA */
+					output-high;
+				};
+			};
+
+			wsa_reset_off: wsa_reset_off {
+				mux {
+					pins = "gpio96";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio96";
+					drive-strength = <2>; /* 2 MA */
+					output-low;
+				};
+			};
+		};
+
+		/* WSA CLK */
+		wsa_clk {
+			wsa_clk_on: wsa_clk_on {
+				mux {
+					pins = "gpio25";
+					function = "pri_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <8>; /* 8 MA */
+					output-high;
+				};
+			};
+
+			wsa_clk_off: wsa_clk_off {
+				mux {
+					pins = "gpio25";
+					function = "pri_mi2s_mclk_a";
+				};
+
+				config {
+					pins = "gpio25";
+					drive-strength = <2>; /* 2 MA */
+					output-low;
+					bias-pull-down;
+				};
+			};
+		};
+		pri-tlmm-lines {
+			pri_tlmm_lines_act: pri_tlmm_lines_act {
+				mux {
+					pins = "gpio85", "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85", "gpio88";
+					drive-strength = <8>;
+				};
+			};
+
+			pri_tlmm_lines_sus: pri_tlmm_lines_sus {
+				mux {
+					pins = "gpio85", "gpio88";
+					function = "pri_mi2s";
+				};
+
+				config {
+					pins = "gpio85", "gpio88";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pri-tlmm-ws-lines {
+			pri_tlmm_ws_act: pri_tlmm_ws_act {
+				mux {
+					pins = "gpio87";
+					function = "pri_mi2s_ws";
+				};
+
+				config {
+					pins = "gpio87";
+					drive-strength = <8>;
+				};
+			};
+
+			pri_tlmm_ws_sus: pri_tlmm_ws_sus {
+				mux {
+					pins = "gpio87";
+					function = "pri_mi2s_ws";
+				};
+
+				config {
+					pins = "gpio87";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_sdc1_clk {
+			sdc1_clk_on: sdc1_clk_on {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+
+			sdc1_clk_off: sdc1_clk_off {
+				config {
+					pins = "sdc1_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_cmd {
+			sdc1_cmd_on: sdc1_cmd_on {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc1_cmd_off: sdc1_cmd_off {
+				config {
+					pins = "sdc1_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc1_data {
+			sdc1_data_on: sdc1_data_on {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <10>; /* 10 MA */
+				};
+			};
+
+			sdc1_data_off: sdc1_data_off {
+				config {
+					pins = "sdc1_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		sdhc2_cd_pin {
+			sdc2_cd_on: cd_on {
+				mux {
+					pins = "gpio67";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio67";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			sdc2_cd_off: cd_off {
+				mux {
+					pins = "gpio67";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio67";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
+		pmx_sdc2_clk {
+			sdc2_clk_on: sdc2_clk_on {
+				config {
+					pins = "sdc2_clk";
+					drive-strength = <16>; /* 16 MA */
+					bias-disable; /* NO pull */
+				};
+			};
+
+			sdc2_clk_off: sdc2_clk_off {
+				config {
+					pins = "sdc2_clk";
+					bias-disable; /* NO pull */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_cmd {
+			sdc2_cmd_on: sdc2_cmd_on {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+
+			sdc2_cmd_off: sdc2_cmd_off {
+				config {
+					pins = "sdc2_cmd";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			};
+		};
+
+		pmx_sdc2_data {
+			sdc2_data_on: sdc2_data_on {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <16>; /* 16 MA */
+				};
+			};
+
+			sdc2_data_off: sdc2_data_off {
+				config {
+					pins = "sdc2_data";
+					bias-pull-up; /* pull up */
+					drive-strength = <2>; /* 2 MA */
+				};
+			 };
+		};
+
+		cci {
+			cci0_active: cci0_active {
+				/* cci0 active state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio29", "gpio30";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio29", "gpio30";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+
+			cci0_suspend: cci0_suspend {
+				/* cci0 suspended state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio29", "gpio30";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio29", "gpio30";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+
+			cci1_active: cci1_active {
+				/* cci1 active state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio31", "gpio32";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+
+			cci1_suspend: cci1_suspend {
+				/* cci1 suspended state */
+				mux {
+					/* CLK, DATA */
+					pins = "gpio31", "gpio32";
+					function = "cci_i2c";
+				};
+
+				config {
+					pins = "gpio31", "gpio32";
+					drive-strength = <2>; /* 2 MA */
+					bias-disable; /* No PULL */
+				};
+			};
+		};
+
+		/*sensors */
+		cam_sensor_mclk0_default: cam_sensor_mclk0_default {
+			/* MCLK0 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio26";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio26";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep {
+			/* MCLK0 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio26";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio26";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_default: cam_sensor_rear_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio36", "gpio35";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio36","gpio35";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_sleep: cam_sensor_rear_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio36","gpio35";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio36","gpio35";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_vdig: cam_sensor_rear_vdig {
+			/* VDIG */
+			mux {
+				pins = "gpio62";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio62";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_rear_vdig_sleep: cam_sensor_rear_vdig_sleep {
+			/* VDIG */
+			mux {
+				pins = "gpio62";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio62";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk1_default: cam_sensor_mclk1_default {
+			/* MCLK1 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio27";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio27";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk1_sleep: cam_sensor_mclk1_sleep {
+			/* MCLK1 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio27";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio27";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front_default: cam_sensor_front_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio38","gpio50";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio38","gpio50";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front_sleep: cam_sensor_front_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio38","gpio50";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio38","gpio50";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk2_default: cam_sensor_mclk2_default {
+			/* MCLK2 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio28";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio28";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_mclk2_sleep: cam_sensor_mclk2_sleep {
+			/* MCLK2 */
+			mux {
+				/* CLK, DATA */
+				pins = "gpio28";
+				function = "cam_mclk";
+			};
+
+			config {
+				pins = "gpio28";
+				bias-pull-down; /* PULL DOWN */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front1_default: cam_sensor_front1_default {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio40", "gpio39";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio40", "gpio39";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
+		cam_sensor_front1_sleep: cam_sensor_front1_sleep {
+			/* RESET, STANDBY */
+			mux {
+				pins = "gpio40", "gpio39";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio40", "gpio39";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dts
new file mode 100644
index 0000000..b841a44
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8937.dtsi"
+#include "msm8937-pmi8950-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8937-PMI8950 MTP";
+	compatible = "qcom,msm8937-mtp", "qcom,msm8937", "qcom,mtp";
+	qcom,board-id= <8 0>;
+	qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
new file mode 100644
index 0000000..3da16e4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-pmi8950-mtp.dtsi
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "pmi8950.dtsi"
+#include "msm8937-mtp.dtsi"
+
+&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>;
+	};
+};
+
+&vendor {
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+	/delete-property/ dpdm-supply;
+};
+
+&labibb {
+	status = "ok";
+	qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&ibb_regulator {
+	qcom,qpnp-ibb-discharge-resistor = <32>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
new file mode 100644
index 0000000..d5537e9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937-smp2p.dtsi
@@ -0,0 +1,229 @@
+/* Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 {
+	qcom,smp2p-modem@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-wcnss@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	qcom,smp2p-adsp@0xb011008 {
+		compatible = "qcom,smp2p";
+		reg = <0xb011008 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 291 1>;
+	};
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* ssr - inbound entry from mss. */
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to mss */
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from wcnss. */
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to wcnss */
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
new file mode 100644
index 0000000..baa6ad5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -0,0 +1,792 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "skeleton64.dtsi"
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8937";
+	compatible = "qcom,msm8937";
+	qcom,msm-id = <294 0x0>;
+	interrupt-parent = <&intc>;
+
+	chosen {
+		bootargs = "sched_enable_hmp=1";
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		other_ext_mem: other_ext_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x85b00000 0x0 0xd00000>;
+		};
+
+		modem_mem: modem_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x86800000 0x0 0x5000000>;
+		};
+
+		adsp_fw_mem: adsp_fw_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x8b800000 0x0 0x1100000>;
+		};
+
+		wcnss_fw_mem: wcnss_fw_region@0 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0x0 0x8c900000 0x0 0x700000>;
+		};
+
+
+		venus_mem: venus_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alloc-ranges = <0x0 0x80000000 0x0 0x10000000>;
+			alignment = <0 0x400000>;
+			size = <0 0x0800000>;
+		};
+
+		secure_mem: secure_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x7000000>;
+		};
+
+		qseecom_mem: qseecom_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x1000000>;
+		};
+
+		adsp_mem: adsp_region@0 {
+			compatible = "shared-dma-pool";
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x400000>;
+		};
+
+		cont_splash_mem: splash_region@83000000 {
+			reg = <0x0 0x90000000 0x0 0x1400000>;
+		};
+
+	};
+
+	aliases {
+		/* smdtty devices */
+		smd1 = &smdtty_apps_fm;
+		smd2 = &smdtty_apps_riva_bt_acl;
+		smd3 = &smdtty_apps_riva_bt_cmd;
+		smd4 = &smdtty_mbalbridge;
+		smd5 = &smdtty_apps_riva_ant_cmd;
+		smd6 = &smdtty_apps_riva_ant_data;
+		smd7 = &smdtty_data1;
+		smd8 = &smdtty_data4;
+		smd11 = &smdtty_data11;
+		smd21 = &smdtty_data21;
+		smd36 = &smdtty_loopback;
+	};
+
+	soc: soc { };
+
+	vendor: vendor {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0xffffffff>;
+		compatible = "simple-bus";
+	};
+
+
+};
+
+#include "msm8937-pinctrl.dtsi"
+#include "msm8937-cpu.dtsi"
+#include "msm8937-ion.dtsi"
+#include "msm8937-smp2p.dtsi"
+
+&soc {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0 0 0 0xffffffff>;
+	compatible = "simple-bus";
+
+	intc: interrupt-controller@b000000 {
+		compatible = "qcom,msm-qgic2";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		reg = <0x0b000000 0x1000>,
+		      <0x0b002000 0x1000>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 2 0xff08>,
+			     <1 3 0xff08>,
+			     <1 4 0xff08>,
+			     <1 1 0xff08>;
+		clock-frequency = <19200000>;
+	};
+
+	timer@b120000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "arm,armv7-timer-mem";
+		reg = <0xb120000 0x1000>;
+		clock-frequency = <19200000>;
+
+		frame@b121000 {
+			frame-number = <0>;
+			interrupts = <0 8 0x4>,
+				     <0 7 0x4>;
+			reg = <0xb121000 0x1000>,
+			      <0xb122000 0x1000>;
+		};
+
+		frame@b123000 {
+			frame-number = <1>;
+			interrupts = <0 9 0x4>;
+			reg = <0xb123000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b124000 {
+			frame-number = <2>;
+			interrupts = <0 10 0x4>;
+			reg = <0xb124000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b125000 {
+			frame-number = <3>;
+			interrupts = <0 11 0x4>;
+			reg = <0xb125000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b126000 {
+			frame-number = <4>;
+			interrupts = <0 12 0x4>;
+			reg = <0xb126000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b127000 {
+			frame-number = <5>;
+			interrupts = <0 13 0x4>;
+			reg = <0xb127000 0x1000>;
+			status = "disabled";
+		};
+
+		frame@b128000 {
+			frame-number = <6>;
+			interrupts = <0 14 0x4>;
+			reg = <0xb128000 0x1000>;
+			status = "disabled";
+		};
+	};
+
+	qcom,rmtfs_sharedmem@00000000 {
+		compatible = "qcom,sharedmem-uio";
+		reg = <0x00000000 0x00180000>;
+		reg-names = "rmtfs";
+		qcom,client-id = <0x00000001>;
+	};
+
+	restart@4ab000 {
+		compatible = "qcom,pshold";
+		reg = <0x4ab000 0x4>,
+			<0x193d100 0x4>;
+		reg-names = "pshold-base", "tcsr-boot-misc-detect";
+	};
+
+	qcom,mpm2-sleep-counter@4a3000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0x4a3000 0x1000>;
+		clock-frequency = <32768>;
+	};
+
+	cpu-pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <1 7 0xff00>;
+	};
+
+	qcom,sps {
+		compatible = "qcom,msm_sps_4k";
+		qcom,pipe-attr-ee;
+	};
+
+	thermal_zones: thermal-zones {
+		aoss0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 0>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		mdm-core-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 1>;
+			trips {
+				active-config0 {
+						temperature = <125000>;
+						hysteresis = <1000>;
+						type = "passive";
+				};
+			};
+		};
+
+		mdss-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 2>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		camera-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-governor = "user_space";
+			thermal-sensors = <&tsens0 3>;
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		cpuss-0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 4>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu1-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 5>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu2-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 6>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu3-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 7>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc1_cpu4-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 8>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		apc0_cpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 9>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+
+		gpu0-usr {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens0 10>;
+			thermal-governor = "user_space";
+			trips {
+				active-config0 {
+					temperature = <125000>;
+					hysteresis = <1000>;
+					type = "passive";
+				};
+			};
+		};
+	};
+
+	tsens0: tsens@4a8000 {
+		compatible = "qcom,msm8937-tsens";
+		reg = <0x4a8000 0x1000>,
+			<0x4a9000 0x1000>,
+			<0xa4000  0x1000>;
+		reg-names = "tsens_srot_physical",
+			"tsens_tm_physical", "tsens_eeprom_physical";
+		interrupts = <0 184 0>;
+		interrupt-names = "tsens-upper-lower";
+		#thermal-sensor-cells = <1>;
+	};
+
+	slim_msm: slim@c140000{
+		cell-index = <1>;
+		compatible = "qcom,slim-ngd";
+		reg = <0xc140000 0x2c000>,
+		      <0xc104000 0x2a000>;
+		reg-names = "slimbus_physical", "slimbus_bam_physical";
+		interrupts = <0 163 0>, <0 180 0>;
+		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+		qcom,apps-ch-pipes = <0x600000>;
+		qcom,ea-pc = <0x230>;
+		status = "disabled";
+	};
+
+	blsp1_uart2: serial@78b0000 {
+		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+		reg = <0x78b0000 0x200>;
+		interrupts = <0 108 0>;
+		status = "disabled";
+	};
+
+	dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
+		#dma-cells = <4>;
+		compatible = "qcom,sps-dma";
+		reg = <0x7884000 0x1f000>;
+		interrupts = <0 238 0>;
+		qcom,summing-threshold = <10>;
+	};
+
+	dma_blsp2: qcom,sps-dma@7ac4000 { /* BLSP2 */
+		#dma-cells = <4>;
+		compatible = "qcom,sps-dma";
+		reg = <0x7ac4000 0x1f000>;
+		interrupts = <0 239 0>;
+		qcom,summing-threshold = <10>;
+	};
+
+
+	cpubw: qcom,cpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<   769 /*  100.8 MHz */ >,
+			<  1611 /*  211.2 MHz */ >,
+			<  2124 /*  278.4 MHz */ >,
+			<  2929 /*  384   MHz */ >,	/* SVS	*/
+			<  4101 /*  537.6 MHz */ >,
+			<  4248 /*  556.8 MHz */ >,
+			<  5053 /*  662.4 MHz */ >,	/* SVS+	 */
+			<  5712 /*  748.8 MHz */ >,     /* NOM   */
+			<  6152 /*  806.4 MHz */ >,     /* NOM+  */
+			<  7031 /*  921.6 MHz */ >;     /* TURBO */
+	};
+
+	qcom,cpu-bwmon {
+		compatible = "qcom,bimc-bwmon2";
+		reg = <0x408000 0x300>, <0x401000 0x200>;
+		reg-names = "base", "global_base";
+		interrupts = <0 183 4>;
+		qcom,mport = <0>;
+		qcom,target-dev = <&cpubw>;
+	};
+
+	mincpubw: qcom,mincpubw {
+		compatible = "qcom,devbw";
+		governor = "cpufreq";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<   769 /*  100.8 MHz */ >,
+			<  1611 /*  211.2 MHz */ >,
+			<  2124 /*  278.4 MHz */ >,
+			<  2929 /*  384   MHz */ >,	/* SVS	*/
+			<  4101 /*  537.6 MHz */ >,
+			<  4248 /*  556.8 MHz */ >,
+			<  5053 /*  662.4 MHz */ >,	/* SVS+	 */
+			<  5712 /*  748.8 MHz */ >,     /* NOM   */
+			<  6152 /*  806.4 MHz */ >,     /* NOM+  */
+			<  7031 /*  921.6 MHz */ >;     /* TURBO */
+	};
+
+	qcom,ipc-spinlock@1905000 {
+		compatible = "qcom,ipc-spinlock-sfpb";
+		reg = <0x1905000 0x8000>;
+		qcom,num-locks = <8>;
+	};
+
+	qcom,smem@86300000 {
+		compatible = "qcom,smem";
+		reg = <0x86300000 0x100000>,
+			<0xb011008 0x4>,
+			<0x60000 0x8000>,
+			<0x193d000 0x8>;
+		reg-names = "smem", "irq-reg-base", "aux-mem1",
+				"smem_targ_info_reg";
+		qcom,mpu-enabled;
+
+		qcom,smd-modem {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <0>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1000>;
+			interrupts = <0 25 1>;
+			label = "modem";
+			qcom,not-loadable;
+		};
+
+		qcom,smsm-modem {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <0>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x2000>;
+			interrupts = <0 26 1>;
+		};
+
+		qcom,smd-wcnss {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <6>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x20000>;
+			interrupts = <0 142 1>;
+			label = "wcnss";
+		};
+
+		qcom,smsm-wcnss {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <6>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x80000>;
+			interrupts = <0 144 1>;
+		};
+
+		qcom,smd-adsp {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <1>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x100>;
+			interrupts = <0 289 1>;
+			label = "adsp";
+		};
+
+		qcom,smsm-adsp {
+			compatible = "qcom,smsm";
+			qcom,smsm-edge = <1>;
+			qcom,smsm-irq-offset = <0x0>;
+			qcom,smsm-irq-bitmask = <0x200>;
+			interrupts = <0 290 1>;
+		};
+
+		qcom,smd-rpm {
+			compatible = "qcom,smd";
+			qcom,smd-edge = <15>;
+			qcom,smd-irq-offset = <0x0>;
+			qcom,smd-irq-bitmask = <0x1>;
+			interrupts = <0 168 1>;
+			label = "rpm";
+			qcom,irq-no-suspend;
+			qcom,not-loadable;
+		};
+	};
+
+	rpm_bus: qcom,rpm-smd {
+		compatible = "qcom,rpm-smd";
+		rpm-channel-name = "rpm_requests";
+		rpm-channel-type = <15>; /* SMD_APPS_RPM */
+	};
+
+	qcom,wdt@b017000 {
+		compatible = "qcom,msm-watchdog";
+		reg = <0xb017000 0x1000>;
+		reg-names = "wdt-base";
+		interrupts = <0 3 0>, <0 4 0>;
+		qcom,bark-time = <11000>;
+		qcom,pet-time = <10000>;
+		qcom,ipi-ping;
+		qcom,wakeup-enable;
+		status = "okay";
+	};
+
+	spmi_bus: qcom,spmi@200f000 {
+		compatible = "qcom,spmi-pmic-arb";
+		reg = <0x200f000 0x1000>,
+			<0x2400000 0x800000>,
+			<0x2c00000 0x800000>,
+			<0x3800000 0x200000>,
+			<0x200a000 0x2100>;
+		reg-names = "core", "chnls", "obsrvr", "intr", "cnfg";
+		interrupt-names = "periph_irq";
+		interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
+		qcom,ee = <0>;
+		qcom,channel = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		interrupt-controller;
+		#interrupt-cells = <4>;
+		cell-index = <0>;
+	};
+
+	qcom,chd {
+		compatible = "qcom,core-hang-detect";
+		qcom,threshold-arr = <0xb088094 0xb098094 0xb0a8094
+			0xb0b8094 0xb188094 0xb198094 0xb1a8094 0xb1a8094>;
+		qcom,config-arr = <0xb08809c 0xb09809c 0xb0a809c
+			0xb0b809c 0xb18809c 0xb19809c 0xb1a809c 0xb1b809c>;
+	};
+
+	qcom,msm-rtb {
+		compatible = "qcom,msm-rtb";
+		qcom,rtb-size = <0x100000>; /* 1M EBI1 buffer */
+	};
+
+	qcom,msm-imem@8600000 {
+		compatible = "qcom,msm-imem";
+		reg = <0x08600000 0x1000>; /* Address and size of IMEM */
+		ranges = <0x0 0x08600000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		mem_dump_table@10 {
+			compatible = "qcom,msm-imem-mem_dump_table";
+			reg = <0x10 8>;
+		};
+
+		dload_type@18 {
+			compatible = "qcom,msm-imem-dload-type";
+			reg = <0x18 4>;
+		};
+
+		restart_reason@65c {
+			compatible = "qcom,msm-imem-restart_reason";
+			reg = <0x65c 4>;
+		};
+
+		boot_stats@6b0 {
+			compatible = "qcom,msm-imem-boot_stats";
+			reg = <0x6b0 32>;
+		};
+
+		pil@94c {
+			compatible = "qcom,msm-imem-pil";
+			reg = <0x94c 200>;
+		};
+	};
+
+	qcom,smdtty {
+		compatible = "qcom,smdtty";
+
+		smdtty_apps_fm: qcom,smdtty-apps-fm {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_FM";
+		};
+
+		smdtty_apps_riva_bt_acl: smdtty-apps-riva-bt-acl {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_ACL";
+		};
+
+		smdtty_apps_riva_bt_cmd: qcom,smdtty-apps-riva-bt-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_BT_CMD";
+		};
+
+		smdtty_mbalbridge: qcom,smdtty-mbalbridge {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "MBALBRIDGE";
+		};
+
+		smdtty_apps_riva_ant_cmd: smdtty-apps-riva-ant-cmd {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_CMD";
+		};
+
+		smdtty_apps_riva_ant_data: smdtty-apps-riva-ant-data {
+			qcom,smdtty-remote = "wcnss";
+			qcom,smdtty-port-name = "APPS_RIVA_ANT_DATA";
+		};
+
+		smdtty_data1: qcom,smdtty-data1 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA1";
+		};
+
+		smdtty_data4: qcom,smdtty-data4 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA4";
+		};
+
+		smdtty_data11: qcom,smdtty-data11 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA11";
+		};
+
+		smdtty_data21: qcom,smdtty-data21 {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "DATA21";
+		};
+
+		smdtty_loopback: smdtty-loopback {
+			qcom,smdtty-remote = "modem";
+			qcom,smdtty-port-name = "LOOPBACK";
+			qcom,smdtty-dev-name = "LOOPBACK_TTY";
+		};
+	};
+
+	qcom,smdpkt {
+		compatible = "qcom,smdpkt";
+
+		qcom,smdpkt-data5-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA5_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl0";
+		};
+
+		qcom,smdpkt-data22 {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA22";
+			qcom,smdpkt-dev-name = "smd22";
+		};
+
+		qcom,smdpkt-data40-cntl {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "DATA40_CNTL";
+			qcom,smdpkt-dev-name = "smdcntl8";
+		};
+
+		qcom,smdpkt-apr-apps2 {
+			qcom,smdpkt-remote = "adsp";
+			qcom,smdpkt-port-name = "apr_apps2";
+			qcom,smdpkt-dev-name = "apr_apps2";
+		};
+
+		qcom,smdpkt-loopback {
+			qcom,smdpkt-remote = "modem";
+			qcom,smdpkt-port-name = "LOOPBACK";
+			qcom,smdpkt-dev-name = "smd_pkt_loopback";
+		};
+	};
+
+	qcom_tzlog: tz-log@08600720 {
+		compatible = "qcom,tz-log";
+		reg = <0x08600720 0x2000>;
+	};
+
+	qcom,ipc_router {
+		compatible = "qcom,ipc_router";
+		qcom,node-id = <1>;
+	};
+
+	qcom,ipc_router_modem_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "modem";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+		qcom,disable-pil-loading;
+	};
+
+	qcom,ipc_router_q6_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "adsp";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,ipc_router_wcnss_xprt {
+		compatible = "qcom,ipc_router_smd_xprt";
+		qcom,ch-name = "IPCRTR";
+		qcom,xprt-remote = "wcnss";
+		qcom,xprt-linkid = <1>;
+		qcom,xprt-version = <1>;
+		qcom,fragmented-data;
+	};
+
+	qcom,adsprpc-mem {
+		compatible = "qcom,msm-adsprpc-mem-region";
+		memory-region = <&adsp_mem>;
+	};
+
+};
+
+#include "pm8937-rpm-regulator.dtsi"
+#include "msm8937-regulator.dtsi"
+#include "pm8937.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
index 87b8c74..8212cc8 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -74,3 +74,51 @@
 
 	status = "ok";
 };
+
+#include "msm8953-mdss-panels.dtsi"
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_1080_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+		qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+	qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,pluggable;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&dsi_truly_1080_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_1080_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,ulps-enabled;
+	qcom,partial-update-enabled;
+	qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
new file mode 100644
index 0000000..28a6b74
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -0,0 +1,133 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "dsi-panel-sim-video.dtsi"
+#include "dsi-panel-sim-dualmipi-video.dtsi"
+#include "dsi-panel-sim-cmd.dtsi"
+#include "dsi-panel-sim-dualmipi-cmd.dtsi"
+#include "dsi-panel-truly-1080p-video.dtsi"
+#include "dsi-panel-truly-1080p-cmd.dtsi"
+#include "dsi-adv7533-1080p.dtsi"
+#include "dsi-adv7533-720p.dtsi"
+#include "dsi-panel-r69006-1080p-video.dtsi"
+#include "dsi-panel-r69006-1080p-cmd.dtsi"
+#include "dsi-panel-truly-wuxga-video.dtsi"
+#include "dsi-panel-lt8912-480p-video.dtsi"
+#include "dsi-panel-lt8912-1080p-video.dtsi"
+#include "dsi-panel-hx8399c-fhd-plus-video.dtsi"
+
+&soc {
+	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,panel-supply-entry@0 {
+			reg = <0>;
+			qcom,supply-name = "vdd";
+			qcom,supply-min-voltage = <2850000>;
+			qcom,supply-max-voltage = <2850000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@1 {
+			reg = <1>;
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1800000>;
+			qcom,supply-max-voltage = <1800000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+	};
+};
+
+&dsi_truly_1080_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1a 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+
+};
+
+&dsi_truly_1080_cmd {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1e 08 09 05 03 04 a0
+		23 1a 08 09 05 03 04 a0];
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+};
+
+&dsi_r69006_1080p_video {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1b 08 09 05 03 04 a0];
+};
+
+&dsi_r69006_1080p_cmd{
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1b 08 09 05 03 04 a0];
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1c 08 09 05 03 04 a0];
+	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_lp_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-status-read-length = <4>;
+	qcom,mdss-dsi-panel-max-error-count = <3>;
+	qcom,mdss-dsi-min-refresh-rate = <55>;
+	qcom,mdss-dsi-max-refresh-rate = <60>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update =
+		"dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_adv7533_1080p {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1b 08 09 05 03 04 a0];
+};
+
+&dsi_adv7533_720p {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [1e 1b 04 06 02 03 04 a0
+		1e 1b 04 06 02 03 04 a0
+		1e 1b 04 06 02 03 04 a0
+		1e 1b 04 06 02 03 04 a0
+		1e 0e 04 05 02 03 04 a0];
+};
+
+&dsi_truly_wuxga_vid {
+	qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1f 08 09 05 03 04 a0
+		24 1c 08 09 05 03 04 a0];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-pll.dtsi
new file mode 100644
index 0000000..a279453
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-pll.dtsi
@@ -0,0 +1,84 @@
+/* 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.
+ */
+
+&soc {
+	mdss_dsi0_pll: qcom,mdss_dsi_pll@994400 {
+		compatible = "qcom,mdss_dsi_pll_8953";
+		label = "MDSS DSI 0 PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <0x01a94400 0x588>,
+		      <0x0184d074 0x8>,
+		      <0x01a94200 0x98>;
+		reg-names = "pll_base", "gdsc_base", "dynamic_pll_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		/* Memory region for passing dynamic refresh pll codes */
+		memory-region = <&dfps_data_mem>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+	};
+
+	mdss_dsi1_pll: qcom,mdss_dsi_pll@996400 {
+		compatible = "qcom,mdss_dsi_pll_8953";
+		label = "MDSS DSI 1 PLL";
+		cell-index = <1>;
+		#clock-cells = <1>;
+
+		reg = <0x01a96400 0x588>,
+		      <0x0184d074 0x8>,
+		      <0x01a96200 0x98>;
+		reg-names = "pll_base", "gdsc_base", "dynamic_pll_base";
+
+		gdsc-supply = <&gdsc_mdss>;
+
+		qcom,dsi-pll-ssc-en;
+		qcom,dsi-pll-ssc-mode = "down-spread";
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss.dtsi
new file mode 100644
index 0000000..310da1f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss.dtsi
@@ -0,0 +1,434 @@
+/* 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.
+ */
+
+&soc {
+	mdss_mdp: qcom,mdss_mdp@1a00000 {
+		compatible = "qcom,mdss_mdp";
+		reg = <0x01a00000 0x90000>,
+		      <0x01ab0000 0x1040>;
+		reg-names = "mdp_phys", "vbif_phys";
+		interrupts = <0 72 0>;
+		vdd-supply = <&gdsc_mdss>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_mdp";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		/* Fudge factors */
+		qcom,mdss-ab-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-ib-factor = <1 1>;		/* 1 time  */
+		qcom,mdss-clk-factor = <105 100>;	/* 1.05 times */
+
+		qcom,max-mixer-width = <2048>;
+		qcom,max-pipe-width = <2048>;
+
+		/* VBIF QoS remapper settings*/
+		qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>;
+		qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>;
+
+		qcom,mdss-has-panic-ctrl;
+		qcom,mdss-per-pipe-panic-luts = <0x000f>,
+						<0xffff>,
+						<0xfffc>,
+						<0xff00>;
+
+		qcom,mdss-mdp-reg-offset = <0x00001000>;
+		qcom,max-bandwidth-low-kbps = <3400000>;
+		qcom,max-bandwidth-high-kbps = <3400000>;
+		qcom,max-bandwidth-per-pipe-kbps = <2300000>;
+		qcom,max-clk-rate = <400000000>;
+		qcom,mdss-default-ot-rd-limit = <32>;
+		qcom,mdss-default-ot-wr-limit = <16>;
+
+		/* Bandwidth limit settings */
+		qcom,max-bw-settings = <1 3400000>,	/* Default */
+				       <2 3100000>;	/* Camera */
+
+		qcom,mdss-pipe-vig-off = <0x00005000>;
+		qcom,mdss-pipe-rgb-off = <0x00015000 0x00017000>;
+		qcom,mdss-pipe-dma-off = <0x00025000>;
+		qcom,mdss-pipe-cursor-off = <0x00035000>;
+
+		qcom,mdss-pipe-vig-xin-id = <0>;
+		qcom,mdss-pipe-rgb-xin-id = <1 5>;
+		qcom,mdss-pipe-dma-xin-id = <2>;
+		qcom,mdss-pipe-cursor-xin-id = <7>;
+
+		/* Offsets relative to "mdp_phys + mdp-reg-offset" address */
+		qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x2aC 0 0>;
+		qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x2aC 4 8>,
+						      <0x2b4 4 8>;
+		qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2ac 8 12>;
+		qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3a8 16 15>;
+
+
+		qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400>;
+		qcom,mdss-mixer-intf-off = <0x00045000 0x00046000>;
+		qcom,mdss-dspp-off = <0x00055000>;
+		qcom,mdss-wb-off = <0x00065000 0x00066000>;
+		qcom,mdss-intf-off = <0x0006b000 0x0006b800 0x0006c000>;
+		qcom,mdss-pingpong-off = <0x00071000 0x00071800>;
+		qcom,mdss-slave-pingpong-off = <0x00073000>;
+		qcom,mdss-cdm-off = <0x0007a200>;
+		qcom,mdss-wfd-mode = "intf";
+		qcom,mdss-highest-bank-bit = <0x1>;
+		qcom,mdss-has-decimation;
+		qcom,mdss-has-non-scalar-rgb;
+		qcom,mdss-has-rotator-downscale;
+		qcom,mdss-rot-downscale-min = <2>;
+		qcom,mdss-rot-downscale-max = <16>;
+		qcom,mdss-idle-power-collapse-enabled;
+		qcom,mdss-rot-block-size = <64>;
+		qcom,mdss-ppb-off = <0x00000330>;
+		qcom,mdss-has-pingpong-split;
+
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			 <&clock_gcc clk_gcc_mdss_axi_clk>,
+			 <&clock_gcc clk_mdp_clk_src>,
+			 <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			 <&clock_gcc clk_gcc_mdss_vsync_clk>;
+		clock-names = "iface_clk", "bus_clk", "core_clk_src",
+				"core_clk", "vsync_clk";
+
+		qcom,mdp-settings = <0x0506c 0x00000000>,
+				    <0x1506c 0x00000000>,
+				    <0x1706c 0x00000000>,
+				    <0x2506c 0x00000000>;
+
+		qcom,vbif-settings = <0x0d0 0x00000010>;
+
+		qcom,regs-dump-mdp = <0x01000 0x01454>,
+				     <0x02000 0x02064>,
+				     <0x02200 0x02264>,
+				     <0x02400 0x02464>,
+				     <0x05000 0x05150>,
+				     <0x05200 0x05230>,
+				     <0x15000 0x15150>,
+				     <0x17000 0x17150>,
+				     <0x25000 0x25150>,
+				     <0x35000 0x35150>,
+				     <0x45000 0x452bc>,
+				     <0x46000 0x462bc>,
+				     <0x55000 0x5522c>,
+				     <0x65000 0x652c0>,
+				     <0x66000 0x662c0>,
+				     <0x6b800 0x6ba68>,
+				     <0x6c000 0x6c268>,
+				     <0x71000 0x710d4>,
+				     <0x71800 0x718d4>;
+
+		qcom,regs-dump-names-mdp = "MDP",
+			"CTL_0",    "CTL_1", "CTL_2",
+			"VIG0_SSPP", "VIG0",
+			"RGB0_SSPP", "RGB1_SSPP",
+			"DMA0_SSPP",
+			"CURSOR0_SSPP",
+			"LAYER_0", "LAYER_1",
+			"DSPP_0",
+			"WB_0",    "WB_2",
+			"INTF_1",  "INTF_2",
+			"PP_0",    "PP_1";
+
+		/* buffer parameters to calculate prefill bandwidth */
+		qcom,mdss-prefill-outstanding-buffer-bytes = <0>;
+		qcom,mdss-prefill-y-buffer-bytes = <0>;
+		qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+		qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+		qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>;
+		qcom,mdss-prefill-pingpong-buffer-pixels = <4096>;
+
+		qcom,mdss-pp-offsets {
+			qcom,mdss-sspp-mdss-igc-lut-off = <0x2000>;
+			qcom,mdss-sspp-vig-pcc-off = <0x1780>;
+			qcom,mdss-sspp-rgb-pcc-off = <0x380>;
+			qcom,mdss-sspp-dma-pcc-off = <0x380>;
+			qcom,mdss-lm-pgc-off = <0x3c0>;
+			qcom,mdss-dspp-pcc-off = <0x1700>;
+			qcom,mdss-dspp-pgc-off = <0x17c0>;
+		};
+
+		qcom,mdss-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_reg";
+			qcom,msm-bus,num-cases = <4>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>,
+				<1 590 0 160000>,
+				<1 590 0 320000>;
+		};
+
+		qcom,mdss-hw-rt-bus {
+			/* Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_hw_rt";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,vectors-KBps =
+				<22 512 0 0>,
+				<22 512 0 1000>;
+		};
+
+		smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
+			compatible = "qcom,smmu_mdp_unsec";
+			iommus = <&apps_iommu 0xC00 0>; /* For NS ctx bank */
+		};
+		smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
+			compatible = "qcom,smmu_mdp_sec";
+			iommus = <&apps_iommu 0xC01 0>; /* For SEC Ctx Bank */
+		};
+
+		mdss_fb0: qcom,mdss_fb_primary {
+			cell-index = <0>;
+			compatible = "qcom,mdss-fb";
+			qcom,cont-splash-memory {
+				linux,contiguous-region = <&cont_splash_mem>;
+			};
+		};
+
+		mdss_fb1: qcom,mdss_fb_wfd {
+			cell-index = <1>;
+			compatible = "qcom,mdss-fb";
+		};
+
+		mdss_fb2: qcom,mdss_fb_secondary {
+			cell-index = <2>;
+			compatible = "qcom,mdss-fb";
+		};
+	};
+
+	mdss_dsi: qcom,mdss_dsi@0 {
+		compatible = "qcom,mdss-dsi";
+		hw-config = "single_dsi";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		gdsc-supply = <&gdsc_mdss>;
+		vdda-supply = <&pm8953_s3>;
+		vcca-supply = <&pm8953_l3>;
+
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_dsi";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 1000>;
+
+		ranges = <0x1a94000 0x1a94000 0x400
+			0x1a94400 0x1a94400 0x588
+			0x193e000 0x193e000 0x30
+			0x1a96000 0x1a96000 0x400
+			0x1a96400 0x1a96400 0x588
+			0x193e000 0x193e000 0x30>;
+
+		clocks = <&clock_gcc_mdss clk_mdss_mdp_vote_clk>,
+			<&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc clk_gcc_mdss_axi_clk>,
+			<&clock_gcc_mdss clk_ext_byte0_clk_src>,
+			<&clock_gcc_mdss clk_ext_byte1_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk0_clk_src>,
+			<&clock_gcc_mdss clk_ext_pclk1_clk_src>;
+		clock-names = "mdp_core_clk", "iface_clk", "bus_clk",
+			"ext_byte0_clk", "ext_byte1_clk", "ext_pixel0_clk",
+			"ext_pixel1_clk";
+
+		qcom,mmss-ulp-clamp-ctrl-offset = <0x20>;
+		qcom,mmss-phyreset-ctrl-offset = <0x24>;
+
+		qcom,mdss-fb-map-prim = <&mdss_fb0>;
+		qcom,mdss-fb-map-sec = <&mdss_fb2>;
+
+		qcom,core-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,core-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda";
+				qcom,supply-min-voltage = <1225000>;
+				qcom,supply-max-voltage = <1225000>;
+				qcom,supply-enable-load = <18160>;
+				qcom,supply-disable-load = <1>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vcca";
+				qcom,supply-min-voltage = <925000>;
+				qcom,supply-max-voltage = <925000>;
+				qcom,supply-enable-load = <17000>;
+				qcom,supply-disable-load = <32>;
+			};
+		};
+
+		mdss_dsi0: qcom,mdss_dsi_ctrl0@1a94000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->0";
+			cell-index = <0>;
+			reg = <0x1a94000 0x400>,
+				<0x1a94400 0x580>,
+				<0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
+
+			qcom,timing-db-mode;
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8953_l17>;
+			vddio-supply = <&pm8953_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte0_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk0_clk>,
+				<&clock_gcc clk_gcc_mdss_esc0_clk>,
+				<&clock_gcc_mdss clk_byte0_clk_src>,
+				<&clock_gcc_mdss clk_pclk0_clk_src>,
+				<&mdss_dsi0_pll clk_dsi0pll_byte_clk_mux>,
+				<&mdss_dsi0_pll clk_dsi0pll_pixel_clk_mux>,
+				<&mdss_dsi0_pll clk_dsi0pll_byte_clk_src>,
+				<&mdss_dsi0_pll clk_dsi0pll_pixel_clk_src>,
+				<&mdss_dsi0_pll
+					clk_dsi0pll_shadow_byte_clk_src>,
+				<&mdss_dsi0_pll
+					clk_dsi0pll_shadow_pixel_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg",
+				"pll_byte_clk_mux", "pll_pixel_clk_mux",
+				"pll_byte_clk_src", "pll_pixel_clk_src",
+				"pll_shadow_byte_clk_src",
+				"pll_shadow_pixel_clk_src";
+
+			qcom,platform-strength-ctrl = [ff 06
+							ff 06
+							ff 06
+							ff 06
+							ff 00];
+			qcom,platform-regulator-settings = [1d
+							1d 1d 1d 1d];
+			qcom,platform-lane-config = [00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 8f];
+		};
+
+		mdss_dsi1: qcom,mdss_dsi_ctrl1@1a96000 {
+			compatible = "qcom,mdss-dsi-ctrl";
+			label = "MDSS DSI CTRL->1";
+			cell-index = <1>;
+			reg = <0x1a96000 0x400>,
+			      <0x1a96400 0x588>,
+			      <0x193e000 0x30>;
+			reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
+
+			qcom,mdss-mdp = <&mdss_mdp>;
+			vdd-supply = <&pm8953_l17>;
+			vddio-supply = <&pm8953_l6>;
+
+			clocks = <&clock_gcc_mdss clk_gcc_mdss_byte1_clk>,
+				<&clock_gcc_mdss clk_gcc_mdss_pclk1_clk>,
+				<&clock_gcc clk_gcc_mdss_esc1_clk>,
+				<&clock_gcc_mdss clk_byte1_clk_src>,
+				<&clock_gcc_mdss clk_pclk1_clk_src>,
+				<&mdss_dsi1_pll clk_dsi1pll_byte_clk_mux>,
+				<&mdss_dsi1_pll clk_dsi1pll_pixel_clk_mux>,
+				<&mdss_dsi1_pll clk_dsi1pll_byte_clk_src>,
+				<&mdss_dsi1_pll clk_dsi1pll_pixel_clk_src>,
+				<&mdss_dsi1_pll
+					clk_dsi1pll_shadow_byte_clk_src>,
+				<&mdss_dsi1_pll
+					clk_dsi1pll_shadow_pixel_clk_src>;
+			clock-names = "byte_clk", "pixel_clk", "core_clk",
+				"byte_clk_rcg", "pixel_clk_rcg",
+				"pll_byte_clk_mux", "pll_pixel_clk_mux",
+				"pll_byte_clk_src", "pll_pixel_clk_src",
+				"pll_shadow_byte_clk_src",
+				"pll_shadow_pixel_clk_src";
+
+			qcom,timing-db-mode;
+			qcom,platform-strength-ctrl = [ff 06
+							ff 06
+							ff 06
+							ff 06
+							ff 00];
+			qcom,platform-regulator-settings = [1d
+							1d 1d 1d 1d];
+			qcom,platform-lane-config = [00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 0f
+						00 00 10 8f];
+		};
+	};
+
+	qcom,mdss_wb_panel {
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <640 640>;
+		qcom,mdss_pan_bpp = <24>;
+		qcom,mdss-fb-map = <&mdss_fb1>;
+	};
+
+	mdss_rotator: qcom,mdss_rotator {
+		compatible = "qcom,mdss_rotator";
+		qcom,mdss-wb-count = <1>;
+		qcom,mdss-has-downscale;
+		qcom,mdss-has-ubwc;
+		/* Bus Scale Settings */
+		qcom,msm-bus,name = "mdss_rotator";
+		qcom,msm-bus,num-cases = <3>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<22 512 0 0>,
+			<22 512 0 6400000>,
+			<22 512 0 6400000>;
+
+		rot-vdd-supply = <&gdsc_mdss>;
+		qcom,supply-names = "rot-vdd";
+		qcom,mdss-has-reg-bus;
+		clocks = <&clock_gcc clk_gcc_mdss_ahb_clk>,
+			<&clock_gcc_mdss clk_mdss_rotator_vote_clk>;
+		clock-names = "iface_clk", "rot_core_clk";
+
+		qcom,mdss-rot-reg-bus {
+			/* Reg Bus Scale Settings */
+			qcom,msm-bus,name = "mdss_rot_reg";
+			qcom,msm-bus,num-cases = <2>;
+			qcom,msm-bus,num-paths = <1>;
+			qcom,msm-bus,active-only;
+			qcom,msm-bus,vectors-KBps =
+				<1 590 0 0>,
+				<1 590 0 76800>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
index 49956df..c6ae512 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
@@ -20,3 +20,21 @@
 	model = "MTP";
 	qcom,board-id = <8 0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index b53f7b8..97c6db3 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,16 +33,12 @@
 	};
 };
 
-&pmi8950_fg {
+&qpnp_fg {
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,battery-data = <&mtp_batterydata>;
 	qcom,chg-led-sw-controls;
 	qcom,chg-led-support;
 };
-
-&usb3 {
-	extcon = <&pmi8950_charger>;
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
index 87b8c74..8212cc8 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -74,3 +74,51 @@
 
 	status = "ok";
 };
+
+#include "msm8953-mdss-panels.dtsi"
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	qcom,dsi-pref-prim-pan = <&dsi_truly_1080_vid>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+		qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+	qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+	qcom,pluggable;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+	qcom,platform-bklight-en-gpio = <&tlmm 59 0>;
+};
+
+&dsi_truly_1080_vid {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-pan-enable-dynamic-fps;
+	qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_1080_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,ulps-enabled;
+	qcom,partial-update-enabled;
+	qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts
new file mode 100644
index 0000000..78ff97f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi632-cdp-s2.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+#include "sdm450-pmi632-cdp-s2.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. msm8953 + PMI632 CDP S2";
+	compatible = "qcom,msm8953-cdp", "qcom,msm8953", "qcom,cdp";
+	qcom,board-id = <1 2>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi632.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/msm8953-pmi632.dts
index 194bfeb..2ffb0ab 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi632.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,12 +13,12 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "msm8953.dtsi"
+#include "sdm450-pmi632.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. msm8953 + PMI632 SOC";
+	compatible = "qcom,msm8953";
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+	qcom,pmic-name = "PMI632";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
index a9f64a4..5ec92ae 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
index a178aa1..80050c4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dtsi
@@ -24,9 +24,10 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8937_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
index e9c80a0d..ba5c3c7 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
index 71d6941..c36dd1b 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dtsi
@@ -24,6 +24,7 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
+	extcon = <&qpnp_smbcharger>;
 };
 
 &labibb {
@@ -35,7 +36,7 @@
 	qcom,qpnp-ibb-discharge-resistor = <32>;
 };
 
-&pmi8940_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
index b9c2a18..d81a0a5 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -29,10 +29,20 @@
 
 &usb3 {
 	vbus_dwc3-supply = <&smbcharger_charger_otg>;
+	extcon = <&qpnp_smbcharger>;
 };
 
-&pmi8950_charger {
+&qpnp_smbcharger {
 	qcom,external-typec;
 	qcom,typec-psy-name = "typec";
 };
 
+&mdss_dsi0 {
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
index 87b8c74..b29e447 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-qrd.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,6 +11,45 @@
  * GNU General Public License for more details.
  */
 
+
+&soc {
+	i2c@78b7000 { /* BLSP1 QUP3 */
+		status = "okay";
+		synaptics@4b {
+			compatible = "synaptics,dsx-i2c";
+			reg = <0x4b>;
+			interrupt-parent = <&tlmm>;
+			interrupts = <65 0x2008>;
+			vdd_ana-supply = <&vdd_vreg>;
+			vcc_i2c-supply = <&pm8953_l6>;
+			synaptics,pwr-reg-name = "vdd_ana";
+			synaptics,bus-reg-name = "vcc_i2c";
+			synaptics,irq-gpio = <&tlmm 65 0x2008>;
+			synaptics,irq-on-state = <0>;
+			synaptics,irq-flags = <0x2008>;
+			synaptics,power-delay-ms = <200>;
+			synaptics,reset-delay-ms = <200>;
+			synaptics,max-y-for-2d = <1919>;
+			synaptics,cap-button-codes = <139 158 172>;
+			synaptics,vir-button-codes = <139 180 2000 320 160
+						      158 540 2000 320 160
+						      172 900 2000 320 160>;
+			synaptics,resume-in-workqueue;
+			/* Underlying clocks used by secure touch */
+			clock-names = "iface_clk", "core_clk";
+			clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+				 <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
+		};
+	};
+
+	vdd_vreg: vdd_vreg {
+		compatible = "regulator-fixed";
+		status = "ok";
+		regulator-name = "vdd_vreg";
+	};
+
+};
+
 &blsp1_uart0 {
 	status = "ok";
 	pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
new file mode 100644
index 0000000..e82e2c8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-smp2p.dtsi
@@ -0,0 +1,227 @@
+/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+&soc {
+	qcom,smp2p-modem@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <1>;
+		qcom,irq-bitmask = <0x4000>;
+		interrupts = <0 27 1>;
+	};
+
+	qcom,smp2p-wcnss@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <4>;
+		qcom,irq-bitmask = <0x40000>;
+		interrupts = <0 143 1>;
+	};
+
+	qcom,smp2p-adsp@0x0b011008 {
+		compatible = "qcom,smp2p";
+		reg = <0x0b011008 0x4>;
+		qcom,remote-pid = <2>;
+		qcom,irq-bitmask = <0x400>;
+		interrupts = <0 291 1>;
+	};
+
+	smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_in";
+		gpios = <&smp2pgpio_smp2p_15_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <15>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_15_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_15_out";
+		gpios = <&smp2pgpio_smp2p_15_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_in";
+		gpios = <&smp2pgpio_smp2p_1_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_1_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_1_out";
+		gpios = <&smp2pgpio_smp2p_1_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_in: qcom,smp2pgpio-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_in";
+		gpios = <&smp2pgpio_smp2p_4_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_4_out: qcom,smp2pgpio-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_4_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_4_out";
+		gpios = <&smp2pgpio_smp2p_4_out 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_in {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_in";
+		gpios = <&smp2pgpio_smp2p_2_in 0 0>;
+	};
+
+	smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "smp2p";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_test_smp2p_2_out {
+		compatible = "qcom,smp2pgpio_test_smp2p_2_out";
+		gpios = <&smp2pgpio_smp2p_2_out 0 0>;
+	};
+
+	/* ssr - inbound entry from mss. */
+	smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to mss */
+	smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - inbound entry from lpass. */
+	smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ssr - outbound entry to lpass */
+	smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_in: qcom,smp2pgpio-ssr-smp2p-4-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "slave-kernel";
+		qcom,remote-pid = <4>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	smp2pgpio_ssr_smp2p_4_out: qcom,smp2pgpio-ssr-smp2p-4-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "master-kernel";
+		qcom,remote-pid = <4>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
new file mode 100644
index 0000000..cb8cdf2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-vidc.dtsi
@@ -0,0 +1,197 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 {
+	qcom,vidc@1d00000 {
+		compatible = "qcom,msm-vidc";
+		reg = <0x01d00000 0xff000>,
+			<0x000a4124 0x4>,
+			<0x000a0164 0x4>;
+		reg-names = "vidc", "efuse", "efuse2";
+		qcom,platform-version = <0x00180000 0x13>;
+		qcom,capability-version = <0x00002000 0x0d>;
+		interrupts = <0 44 0>;
+		/* Regulators */
+		venus-supply = <&gdsc_venus>;
+		venus-core0-supply = <&gdsc_venus_core0>;
+		/* Clocks */
+		clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>,
+			<&clock_gcc clk_gcc_venus0_ahb_clk>,
+			<&clock_gcc clk_gcc_venus0_axi_clk>;
+		clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk";
+		qcom,clock-configs = <0x1 0x0 0x0 0x0 0x0>;
+		qcom,hfi = "venus";
+		qcom,hfi-version = "3xx";
+		qcom,reg-presets = <0xe0020 0x05555556>,
+			<0xe0024 0x05555556>,
+			<0x80124 0x00000003>;
+		qcom,qdss-presets = <0x825000 0x1000>,
+			<0x826000 0x1000>,
+			<0x821000 0x1000>,
+			<0x802000 0x1000>,
+			<0x9180000 0x1000>,
+			<0x9181000 0x1000>;
+		qcom,max-hw-load = <1044480>; /* 4096 x 2176 @ 30 fps */
+		qcom,slave-side-cp;
+		qcom,sw-power-collapse;
+		qcom,firmware-name = "venus";
+		qcom,pm-qos-latency-us = <213>;
+		qcom,dcvs-tbl =
+			/* Dec UHD@30 H.264, HEVC, VP8, VP9 - NOM to NOM+*/
+			<816000 816000 979200 0x3f00000c>,
+
+			/* Enc 3840x1920@30 H.264/HEVC Turbo to Nom+ */
+			<855000 821100 979200 0x4000004>,
+
+			/* Enc True4K@24 H.264/HEVC Nom to Nom+ */
+			<816000 720000 835584 0x4000004>;
+		qcom,dcvs-limit =
+			<28800 24>, /* Encoder 3840x1920 */
+			<32400 24>; /* Decoder UHD */
+		qcom,allowed-clock-rates = <465000000 400000000
+			360000000 310000000 228570000 114290000>;
+		qcom,clock-freq-tbl {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,cycles-per-mb = <863>;
+				qcom,low-power-mode-factor = <35616>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xf3ffffff>;
+				qcom,cycles-per-mb = <355>;
+			};
+			qcom,profile-hevcdec {
+				qcom,codec-mask = <0x0c000000>;
+				qcom,cycles-per-mb = <400>;
+			};
+		};
+
+		/* MMUs */
+		non_secure_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_ns";
+			iommus = <&apps_iommu 0x800 0x01>,
+				<&apps_iommu 0x807 0x00>,
+				<&apps_iommu 0x808 0x07>,
+				<&apps_iommu 0x810 0x01>,
+				<&apps_iommu 0x828 0x01>,
+				<&apps_iommu 0x82c 0x01>,
+				<&apps_iommu 0x821 0x10>;
+			buffer-types = <0xfff>;
+			virtual-addr-pool = <0x5dc00000 0x7f000000
+				0xdcc00000 0x1000000>;
+		};
+
+		secure_bitstream_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_bitstream";
+			 iommus = <&apps_iommu 0x900 0x0>,
+				<&apps_iommu 0x902 0x8>,
+				<&apps_iommu 0x909 0x2>,
+				<&apps_iommu 0x90e 0x0>,
+				<&apps_iommu 0x926 0x0>,
+				<&apps_iommu 0x929 0x2>;
+			buffer-types = <0x241>;
+			virtual-addr-pool = <0x4b000000 0x12c00000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_pixel";
+			iommus = <&apps_iommu 0x904 0x8>,
+				<&apps_iommu 0x910 0x0>,
+				<&apps_iommu 0x92c 0x0>;
+			buffer-types = <0x106>;
+			virtual-addr-pool = <0x25800000 0x25800000>;
+			qcom,secure-context-bank;
+		};
+
+		secure_non_pixel_cb {
+			compatible = "qcom,msm-vidc,context-bank";
+			label = "venus_sec_non_pixel";
+			iommus = <&apps_iommu 0x908 0x0>,
+				<&apps_iommu 0x905 0xa>,
+				<&apps_iommu 0x925 0x8>,
+				<&apps_iommu 0x928 0x0>;
+			buffer-types = <0x480>;
+			virtual-addr-pool = <0x1000000 0x24800000>;
+			qcom,secure-context-bank;
+		};
+
+		/* Buses */
+		venus_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "venus-ddr-gov";
+			qcom,bus-range-kbps = <1000 2365000>;
+		};
+
+		arm9_bus_ddr {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-arm9-ddr";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+			qcom,bus-governor = "performance";
+			qcom,bus-range-kbps = <1 1>;
+		};
+	};
+
+	venus-ddr-gov {
+		compatible = "qcom,msm-vidc,governor,table";
+		name = "venus-ddr-gov";
+		status = "ok";
+		qcom,bus-freq-table {
+			qcom,profile-enc {
+				qcom,codec-mask = <0x55555555>;
+				qcom,load-busfreq-tbl =
+					<979200 1044000>,  /* UHD30E     */
+					<864000 887000>,   /* 720p240LPE */
+					<489600 666000>,   /* 1080p60E   */
+					<432000 578000>,   /* 720p120E   */
+					<244800 346000>,   /* 1080p30E   */
+					<216000 293000>,   /* 720p60E    */
+					<108000 151000>,   /* 720p30E    */
+					<0 0>;
+			};
+			qcom,profile-dec {
+				qcom,codec-mask = <0xffffffff>;
+				qcom,load-busfreq-tbl =
+					<979200 2365000>,  /* UHD30D     */
+					<864000 1978000>,  /* 720p240D   */
+					<489600 1133000>,  /* 1080p60D   */
+					<432000 994000>,   /* 720p120D   */
+					<244800 580000>,   /* 1080p30D   */
+					<216000 501000>,   /* 720p60E    */
+					<108000 255000>,   /* 720p30D    */
+					<0 0>;
+			};
+			qcom,profile-dec-ubwc {
+				qcom,codec-mask = <0xffffffff>;
+				qcom,ubwc-mode;
+				qcom,load-busfreq-tbl =
+					<979200 1892000>,  /* UHD30D     */
+					<864000 1554000>,  /* 720p240D   */
+					<489600 895000>,   /* 1080p60D   */
+					<432000 781000>,   /* 720p120D   */
+					<244800 460000>,   /* 1080p30D   */
+					<216000 301000>,   /* 720p60E    */
+					<108000 202000>,   /* 720p30D    */
+					<0 0>;
+			};
+		};
+	};
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts
index ddf2218..2f6cbc4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 596bde4..23ab67d 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -113,8 +113,9 @@
 		};
 
 		dfps_data_mem: dfps_data_mem@90000000 {
-		       reg = <0 0x90000000 0 0x1000>;
-		       label = "dfps_data_mem";
+			reg = <0 0x90000000 0 0x1000>;
+			label = "dfps_data_mem";
+			status = "disabled";
 		};
 
 		cont_splash_mem: splash_region@0x90001000 {
@@ -163,7 +164,11 @@
 #include "msm8953-coresight.dtsi"
 #include "msm8953-ion.dtsi"
 #include "msm-arm-smmu-8953.dtsi"
+#include "msm8953-vidc.dtsi"
 #include "msm8953-gpu.dtsi"
+#include "msm8953-mdss.dtsi"
+#include "msm8953-mdss-pll.dtsi"
+#include "msm8953-smp2p.dtsi"
 
 &soc {
 	#address-cells = <1>;
@@ -651,6 +656,19 @@
 		status = "disabled";
 	};
 
+	clock_gcc_mdss: qcom,gcc-mdss@1800000 {
+		compatible = "qcom,gcc-mdss-8953";
+		reg = <0x1800000 0x80000>;
+		reg-names = "cc_base";
+		clock-names = "pclk0_src", "pclk1_src",
+			"byte0_src", "byte1_src";
+		clocks = <&mdss_dsi0_pll clk_dsi0pll_pixel_clk_mux>,
+			<&mdss_dsi1_pll clk_dsi1pll_pixel_clk_mux>,
+			<&mdss_dsi0_pll clk_dsi0pll_byte_clk_mux>,
+			<&mdss_dsi1_pll clk_dsi1pll_byte_clk_mux>;
+		#clock-cells = <1>;
+	};
+
 	clock_gcc: qcom,gcc@1800000 {
 		compatible = "qcom,gcc-8953";
 		reg = <0x1800000 0x80000>,
@@ -1144,6 +1162,11 @@
 			reg = <0x94c 200>;
 
 		};
+
+		diag_dload@c8 {
+			compatible = "qcom,msm-imem-diag-dload";
+			reg = <0xc8 200>;
+		};
 	};
 
 	qcom,memshare {
@@ -1164,10 +1187,11 @@
 			label = "modem";
 		};
 
-		mem_client_3_size: qcom,client_3 {
+		qcom,client_3 {
 			compatible = "qcom,memshare-peripheral";
-			qcom,peripheral-size = <0x0>;
+			qcom,peripheral-size = <0x500000>;
 			qcom,client-id = <1>;
+			qcom,allocate-boot-time;
 			label = "modem";
 		};
 	};
@@ -1281,6 +1305,22 @@
 		status = "disabled";
 	};
 
+	qcom,msm-adsprpc-mem {
+		compatible = "qcom,msm-adsprpc-mem-region";
+		memory-region = <&adsp_mem>;
+	};
+
+	qcom,msm_fastrpc {
+		compatible = "qcom,msm-fastrpc-legacy-compute";
+		qcom,msm_fastrpc_compute_cb {
+			compatible = "qcom,msm-fastrpc-legacy-compute-cb";
+			label = "adsprpc-smd";
+			iommus = <&apps_iommu 0x2408 0x7>;
+			sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>;
+		};
+	};
+
+
 	ipa_hw: qcom,ipa@07900000 {
 		compatible = "qcom,ipa";
 		reg = <0x07900000 0x4effc>, <0x07904000 0x26934>;
@@ -1729,6 +1769,7 @@
 
 		vdd-supply = <&gdsc_venus>;
 		qcom,proxy-reg-names = "vdd";
+		qcom,mas-crypto = <&mas_crypto>;
 
 		clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
 			<&clock_gcc clk_gcc_venus0_ahb_clk>,
@@ -1842,6 +1883,11 @@
 		qcom,wcnss-adc_tm = <&pm8953_adc_tm>;
 	};
 
+	ssc_sensors: qcom,msm-ssc-sensors {
+		compatible = "qcom,msm-ssc-sensors";
+		status = "ok";
+	};
+
 };
 
 #include "pm8953-rpm-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 4830af4..7724714 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -218,7 +218,6 @@
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
 			};
 
 			chan@4f {
@@ -230,7 +229,6 @@
 				qcom,scale-function = <2>;
 				qcom,hw-settle-time = <2>;
 				qcom,fast-avg-setup = <0>;
-				qcom,vadc-thermal-node;
 			};
 
 			chan@1d {
@@ -504,7 +502,7 @@
 
 		trips {
 			pm660_vbat_adc: vbat-adc {
-				temperature = <3300>;
+				temperature = <3200>;
 				hysteresis = <100>;
 				type = "passive";
 			};
@@ -534,7 +532,7 @@
 
 		trips {
 			vbat-low {
-				temperature = <3100>;
+				temperature = <2800>;
 				hysteresis = <0>;
 				type = "passive";
 			};
@@ -550,7 +548,7 @@
 
 		trips {
 			vbat-too-low {
-				temperature = <2900>;
+				temperature = <2600>;
 				hysteresis = <0>;
 				type = "passive";
 			};
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index 074b7da..3561656 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -214,6 +214,151 @@
 			#gpio-cells = <2>;
 			qcom,gpios-disallowed = <1>;
 		};
+
+		pmi632_charger: qcom,qpnp-smb5 {
+			compatible = "qcom,qpnp-smb5";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qcom,pmic-revid = <&pmi632_revid>;
+			dpdm-supply = <&qusb_phy>;
+
+			qcom,chgr@1000 {
+				reg = <0x1000 0x100>;
+				interrupts =
+					<0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x10 0x6 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x10 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+				interrupt-names = "chgr-error",
+						  "chg-state-change",
+						  "step-chg-state-change",
+						  "step-chg-soc-update-fail",
+						  "step-chg-soc-update-req",
+						  "fg-fvcal-qualified",
+						  "vph-alarm",
+						  "vph-drop-prechg";
+			};
+
+			qcom,dcdc@1100 {
+				reg = <0x1100 0x100>;
+				interrupts =
+					<0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+				interrupt-names = "otg-fail",
+						  "otg-oc-disable-sw",
+						  "otg-oc-hiccup",
+						  "bsm-active",
+						  "high-duty-cycle",
+						  "input-current-limiting",
+						  "concurrent-mode-disable",
+						  "switcher-power-ok";
+			};
+
+			qcom,batif@1200 {
+				reg = <0x1200 0x100>;
+				interrupts =
+					<0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x12 0x7 IRQ_TYPE_LEVEL_HIGH>;
+
+				interrupt-names = "bat-temp",
+						  "all-chnl-conv-done",
+						  "bat-ov",
+						  "bat-low",
+						  "bat-therm-or-id-missing",
+						  "bat-terminal-missing",
+						  "buck-oc",
+						  "vph-ov";
+			};
+
+			qcom,usb@1300 {
+				reg = <0x1300 0x100>;
+				interrupts =
+					<0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x13 0x4 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x13 0x5 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "usbin-collapse",
+						  "usbin-vashdn",
+						  "usbin-uv",
+						  "usbin-ov",
+						  "usbin-plugin",
+						  "usbin-revi-change",
+						  "usbin-src-change",
+						  "usbin-icl-change";
+			};
+
+			qcom,typec@1500 {
+				reg = <0x1500 0x100>;
+				interrupts =
+					<0x2 0x15 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x2 0x15 0x1 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x15 0x6 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "typec-or-rid-detect-change",
+						  "typec-vpd-detect",
+						  "typec-cc-state-change",
+						  "typec-vconn-oc",
+						  "typec-vbus-change",
+						  "typec-attach-detach",
+						  "typec-legacy-cable-detect",
+						  "typec-try-snk-src-detect";
+			};
+
+			qcom,misc@1600 {
+				reg = <0x1600 0x100>;
+				interrupts =
+					<0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x2 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x3 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x4 IRQ_TYPE_LEVEL_HIGH>,
+					<0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>,
+					<0x2 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+					<0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>;
+
+				interrupt-names = "wdog-snarl",
+						  "wdog-bark",
+						  "aicl-fail",
+						  "aicl-done",
+						  "smb-en",
+						  "imp-trigger",
+						  "temp-change",
+						  "temp-change-smb";
+			};
+
+			smb5_vbus: qcom,smb5-vbus {
+				regulator-name = "smb5-vbus";
+			};
+		};
 	};
 
 	pmi632_3: qcom,pmi632@3 {
@@ -225,9 +370,8 @@
 		pmi632_vib: qcom,vibrator@5700 {
 			compatible = "qcom,qpnp-vibrator-ldo";
 			reg = <0x5700 0x100>;
-			qcom,vib-ldo-volt-uv = <1504000>;
+			qcom,vib-ldo-volt-uv = <3000000>;
 			qcom,vib-overdrive-volt-uv = <3544000>;
-			status = "disabled";
 		};
 
 		pmi632_pwm_1: pwm@b300 {
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index a7aa08a..c72225d 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -153,7 +153,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8937_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -268,7 +268,7 @@
 			};
 		};
 
-		pmi8937_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
index c6d5c87..d83145c 100644
--- a/arch/arm64/boot/dts/qcom/pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
@@ -152,7 +152,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8940_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -264,7 +264,7 @@
 			};
 		};
 
-		pmi8940_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index 97be32de..e3388c1 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -11,6 +11,8 @@
  */
 
 #include <dt-bindings/msm/power-on.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
 
 &spmi_bus {
 	qcom,pmi8950@2 {
@@ -166,7 +168,7 @@
 			#gpio-cells = <2>;
 		};
 
-		pmi8950_charger: qcom,qpnp-smbcharger {
+		qpnp_smbcharger: qcom,qpnp-smbcharger {
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -282,7 +284,7 @@
 			};
 		};
 
-		pmi8950_fg: qcom,fg {
+		qpnp_fg: qcom,fg {
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -585,26 +587,23 @@
 		};
 
 		pmi_haptic: qcom,haptic@c000 {
-			compatible = "qcom,qpnp-haptic";
+			compatible = "qcom,qpnp-haptics";
 			reg = <0xc000 0x100>;
 			interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
 					<0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
-			interrupt-names = "sc-irq", "play-irq";
+			interrupt-names = "hap-sc-irq", "hap-play-irq";
 			qcom,pmic-revid = <&pmi8950_revid>;
-			vcc_pon-supply = <&pon_perph_reg>;
 			qcom,play-mode = "direct";
 			qcom,wave-play-rate-us = <5263>;
-			qcom,actuator-type = "erm";
+			qcom,actuator-type = <0>;
 			qcom,wave-shape = "square";
 			qcom,vmax-mv = <2000>;
 			qcom,ilim-ma = <800>;
 			qcom,sc-deb-cycles = <8>;
-			qcom,int-pwm-freq-khz = <505>;
 			qcom,en-brake;
-			qcom,brake-pattern = [03 03 00 00];
-			qcom,use-play-irq;
-			qcom,use-sc-irq;
-			qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e];
+			qcom,brake-pattern = <0x3 0x3 0x0 0x0>;
+			qcom,wave-samples = <0x3e 0x3e 0x3e 0x3e 0x3e
+							0x3e 0x3e 0x3e>;
 			qcom,wave-rep-cnt = <1>;
 			qcom,wave-samp-rep-cnt = <1>;
 		};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
index 0983acf..bf2241a 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
@@ -172,6 +172,8 @@
 				&wifi_led_green_default
 				&wifi_led_red_default>;
 		status = "okay";
+		vdd_ldo_1-supply = <&pm660_l15>;
+		vdd_ldo_2-supply = <&pm660_l17>;
 
 		led@1 {
 			label = "PWR_LED:red:106";
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
index 01471b6..1429880 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp-overlay.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,3 +32,47 @@
 		       <0x0001001b 0x0102001a 0x0 0x0>,
 		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
+
+&cam_cci {
+	/delete-node/ qcom,cam-sensor@1;
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vio-supply = <&camera_vio_ldo>;
+		cam_vana-supply = <&camera_vana_ldo>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1352000 1800000 2850000 0>;
+		rgltr-max-voltage = <1352000 1800000 2850000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 28 0>;
+		gpio-reset = <1>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
index ea10fa0..6c6012e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-cdp.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,3 +26,47 @@
 		       <0x0001001b 0x0102001a 0x0 0x0>,
 		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
+
+&cam_cci {
+	/delete-node/ qcom,cam-sensor@1;
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vio-supply = <&camera_vio_ldo>;
+		cam_vana-supply = <&camera_vana_ldo>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1352000 1800000 2850000 0>;
+		rgltr-max-voltage = <1352000 1800000 2850000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 28 0>;
+		gpio-reset = <1>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
index 025d9a2..d0b5bf3 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,196 +10,16 @@
  * GNU General Public License for more details.
  */
 
-#include "pm8005.dtsi"
-#include "sdm670-pmic-overlay.dtsi"
-#include "qcs605-pm660-pm8005-regulator.dtsi"
+#include "qcs605-lc-pmic-overlay.dtsi"
 
-/ {
-	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;
-			};
-		};
-	};
-
-
+&qupv3_se9_2uart {
+	status = "disabled";
 };
 
-&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>;
-			};
-		};
-	};
+&qupv3_se12_2uart {
+	status = "ok";
 };
 
-&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;
-		};
-	};
-};
-
-&spmi_bus {
-	/delete-node/ qcom,pm660l@2;
-	/delete-node/ qcom,pm660l@3;
-};
-
-&thermal_zones {
-	pm660l_tz {
-		/delete-property/ thermal-sensors;
-	};
-};
-
-&soc {
-	qcom,turing@8300000 {
-		/delete-property/ vdd_cx-supply;
-	};
-
-	qcom,lpass@62400000 {
-		/delete-property/ vdd_cx-supply;
-	};
-};
-
-&clock_cpucc {
-	/delete-property/ vdd_l3_mx_ao-supply;
-	/delete-property/ vdd_pwrcl_mx_ao-supply;
-};
-
-&clock_gcc {
-	/delete-property/ vdd_cx-supply;
-	/delete-property/ vdd_cx_ao-supply;
-};
-
-&clock_videocc {
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_camcc {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_dispcc {
-	/delete-property/ vdd_cx-supply;
-};
-
-&clock_gpucc {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-};
-
-&pil_modem {
-	/delete-property/ vdd_mx-supply;
-	/delete-property/ vdd_cx-supply;
-	/delete-property/ vdd_mss-supply;
-};
-
-&clock_gfx {
-	/delete-property/ vdd_gfx-supply;
-};
-
-&gpu_gx_gdsc {
-	/delete-property/ parent-supply;
-};
-
-&mdss_dsi_phy0 {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&mdss_dsi_phy1 {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&sde_dp {
-	/delete-property/ vdda-0p9-supply;
-};
-
-&qusb_phy0 {
-	/delete-property/ vdd-supply;
-	/delete-property/ vdda33-supply;
-};
-
-&usb_qmp_dp_phy {
-	/delete-property/ vdd-supply;
-};
-
-&pm660_pdphy {
-	/delete-property/ vdd-pdphy-supply;
+&qupv3_se8_spi {
+	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
new file mode 100644
index 0000000..2436687
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-pmic-overlay.dtsi
@@ -0,0 +1,260 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&pm660_0 {
+	pm660_charger: qcom,qpnp-smb2 {
+		compatible = "qcom,qpnp-smb2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#cooling-cells = <2>;
+
+		qcom,pmic-revid = <&pm660_revid>;
+
+		io-channels = <&pm660_rradc 8>,
+			      <&pm660_rradc 10>,
+			      <&pm660_rradc 3>,
+			      <&pm660_rradc 4>;
+		io-channel-names = "charger_temp",
+				   "charger_temp_max",
+				   "usbin_i",
+				   "usbin_v";
+
+		qcom,wipower-max-uw = <5000000>;
+
+		dpdm-supply = <&qusb_phy0>;
+
+		qcom,thermal-mitigation
+				= <3000000 2500000 2000000 1500000
+					1000000 500000>;
+		qcom,auto-recharge-soc;
+
+		qcom,chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts =
+				<0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "chg-error",
+					  "chg-state-change",
+					  "step-chg-state-change",
+					  "step-chg-soc-update-fail",
+					  "step-chg-soc-update-request";
+		};
+
+		qcom,otg@1100 {
+			reg = <0x1100 0x100>;
+			interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "otg-fail",
+					  "otg-overcurrent",
+					  "otg-oc-dis-sw-sts",
+					  "testmode-change-detect";
+		};
+
+		qcom,bat-if@1200 {
+			reg = <0x1200 0x100>;
+			interrupts =
+				<0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "bat-temp",
+					  "bat-ocp",
+					  "bat-ov",
+					  "bat-low",
+					  "bat-therm-or-id-missing",
+					  "bat-terminal-missing";
+		};
+
+		qcom,usb-chgpth@1300 {
+			reg = <0x1300 0x100>;
+			interrupts =
+				<0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "usbin-collapse",
+					  "usbin-lt-3p6v",
+					  "usbin-uv",
+					  "usbin-ov",
+					  "usbin-plugin",
+					  "usbin-src-change",
+					  "usbin-icl-change",
+					  "type-c-change";
+		};
+
+		qcom,dc-chgpth@1400 {
+			reg = <0x1400 0x100>;
+			interrupts =
+				<0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "dcin-collapse",
+					  "dcin-lt-3p6v",
+					  "dcin-uv",
+					  "dcin-ov",
+					  "dcin-plugin",
+					  "div2-en-dg",
+					  "dcin-icl-change";
+		};
+
+		qcom,chgr-misc@1600 {
+			reg = <0x1600 0x100>;
+			interrupts =
+				<0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+				<0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "wdog-snarl",
+					  "wdog-bark",
+					  "aicl-fail",
+					  "aicl-done",
+					  "high-duty-cycle",
+					  "input-current-limiting",
+					  "temperature-change",
+					  "switcher-power-ok";
+		};
+		smb2_vbus: qcom,smb2-vbus {
+			regulator-name = "smb2-vbus";
+		};
+
+		smb2_vconn: qcom,smb2-vconn {
+			regulator-name = "smb2-vconn";
+		};
+	};
+
+	pm660_rradc: rradc@4500 {
+		compatible = "qcom,rradc";
+		reg = <0x4500 0x100>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#io-channel-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+	};
+
+	pm660_fg: qpnp,fg {
+		compatible = "qcom,fg-gen3";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+		io-channels = <&pm660_rradc 0>,
+			      <&pm660_rradc 7>;
+		io-channel-names = "rradc_batt_id",
+				   "rradc_die_temp";
+		qcom,rradc-base = <0x4500>;
+		qcom,fg-esr-timer-awake = <64 96>;
+		qcom,fg-esr-timer-asleep = <224 256>;
+		qcom,fg-esr-timer-charging = <0 96>;
+		qcom,cycle-counter-en;
+		qcom,hold-soc-while-full;
+		qcom,fg-auto-recharge-soc;
+		qcom,fg-recharge-soc-thr = <98>;
+		status = "okay";
+
+		qcom,fg-batt-soc@4000 {
+			status = "okay";
+			reg = <0x4000 0x100>;
+			interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x2
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x3
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x5
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "soc-update",
+					  "soc-ready",
+					  "bsoc-delta",
+					  "msoc-delta",
+					  "msoc-low",
+					  "msoc-empty",
+					  "msoc-high",
+					  "msoc-full";
+		};
+
+		qcom,fg-batt-info@4100 {
+			status = "okay";
+			reg = <0x4100 0x100>;
+			interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "vbatt-pred-delta",
+					  "vbatt-low",
+					  "esr-delta",
+					  "batt-missing",
+					  "batt-temp-delta";
+		};
+
+		qcom,fg-memif@4400 {
+			status = "okay";
+			reg = <0x4400 0x100>;
+			interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "ima-rdy",
+					  "mem-xcp",
+					  "dma-grant";
+		};
+	};
+};
+
+&pm660_1 {
+	pm660_haptics: qcom,haptics@c000 {
+		compatible = "qcom,qpnp-haptics";
+		reg = <0xc000 0x100>;
+		interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "hap-sc-irq", "hap-play-irq";
+		qcom,pmic-revid = <&pm660_revid>;
+		qcom,pmic-misc = <&pm660_misc>;
+		qcom,misc-clk-trim-error-reg = <0xf3>;
+		qcom,actuator-type = <0>;
+		qcom,play-mode = "direct";
+		qcom,vmax-mv = <3200>;
+		qcom,ilim-ma = <800>;
+		qcom,sc-dbc-cycles = <8>;
+		qcom,wave-play-rate-us = <6667>;
+		qcom,en-brake;
+		qcom,lra-high-z = "opt0";
+		qcom,lra-auto-res-mode = "qwd";
+		qcom,lra-res-cal-period = <4>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc.dts
similarity index 67%
rename from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
rename to arch/arm64/boot/dts/qcom/qcs605-lc.dts
index 194bfeb..88d838e 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,12 +13,10 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "qcs605-lc.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+	model = "Qualcomm Technologies, Inc. QCS605 LC SoC";
+	compatible = "qcom,qcs605";
 	qcom,board-id = <8 4>;
-
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
new file mode 100644
index 0000000..2db6129
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "qcs605.dtsi"
+#include "pm8005.dtsi"
+#include "qcs605-pm660-pm8005-regulator.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. QCS605 SoC";
+	compatible = "qcom,qcs605";
+
+	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;
+		};
+	};
+};
+
+&spmi_bus {
+	/delete-node/ qcom,pm660l@2;
+	/delete-node/ qcom,pm660l@3;
+};
+
+&thermal_zones {
+	pm660l_tz {
+		/delete-property/ thermal-sensors;
+	};
+};
+
+&soc {
+	qcom,turing@8300000 {
+		/delete-property/ vdd_cx-supply;
+	};
+
+	qcom,lpass@62400000 {
+		/delete-property/ vdd_cx-supply;
+	};
+};
+
+&clock_cpucc {
+	/delete-property/ vdd_l3_mx_ao-supply;
+	/delete-property/ vdd_pwrcl_mx_ao-supply;
+};
+
+&clock_gcc {
+	/delete-property/ vdd_cx-supply;
+	/delete-property/ vdd_cx_ao-supply;
+};
+
+&clock_videocc {
+	/delete-property/ vdd_cx-supply;
+};
+
+&clock_camcc {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+};
+
+&clock_dispcc {
+	/delete-property/ vdd_cx-supply;
+};
+
+&clock_gpucc {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+};
+
+&pil_modem {
+	/delete-property/ vdd_mx-supply;
+	/delete-property/ vdd_cx-supply;
+	/delete-property/ vdd_mss-supply;
+};
+
+&clock_gfx {
+	/delete-property/ vdd_gfx-supply;
+};
+
+&gpu_gx_gdsc {
+	/delete-property/ parent-supply;
+};
+
+&mdss_dsi_phy0 {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&mdss_dsi_phy1 {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&sde_dp {
+	/delete-property/ vdda-0p9-supply;
+};
+
+&qusb_phy0 {
+	/delete-property/ vdd-supply;
+	/delete-property/ vdda33-supply;
+};
+
+&usb_qmp_dp_phy {
+	/delete-property/ vdd-supply;
+};
+
+&pm660_pdphy {
+	/delete-property/ vdd-pdphy-supply;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
index 6cf9a82..fcde397 100644
--- a/arch/arm64/boot/dts/qcom/qcs605.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,30 @@
 	qcom,msm-id = <347 0x0>;
 };
 
+&pil_modem_mem {
+	reg = <0 0x8b000000 0 0x3c00000>;
+};
+
+&pil_video_mem {
+	reg = <0 0x8ec00000 0 0x500000>;
+};
+
+&wlan_msa_mem {
+	reg = <0 0x8f100000 0 0x100000>;
+};
+
+&pil_cdsp_mem {
+	reg = <0 0x8f200000 0 0x800000>;
+};
+
+&pil_mba_mem {
+	reg = <0 0x8fa00000 0 0x200000>;
+};
+
+&pil_adsp_mem {
+	reg = <0 0x8fc00000 0 0x1e00000>;
+};
+
 &soc {
 	qcom,rmnet-ipa {
 		status = "disabled";
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
new file mode 100644
index 0000000..c76ef2b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr-pinctrl-overlay.dtsi
@@ -0,0 +1,97 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&cam_sensor_mclk0_active{
+	/* MCLK0 */
+	mux {
+		pins = "gpio13";
+		function = "cam_mclk";
+	};
+
+	config {
+		pins = "gpio13";
+		bias-disable; /* No PULL */
+		drive-strength = <8>; /* 2 MA */
+	};
+};
+
+&cam_sensor_mclk0_suspend {
+	/* MCLK0 */
+	mux {
+		pins = "gpio13";
+		function = "cam_mclk";
+	};
+
+	config {
+		pins = "gpio13";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <8>; /* 2 MA */
+	};
+};
+
+&cam_sensor_rear_active {
+	/* RESET, AVDD LDO */
+	mux {
+		pins = "gpio8","gpio79";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio8","gpio79";
+		bias-disable; /* No PULL */
+		drive-strength = <2>; /* 2 MA */
+	};
+};
+
+&cam_sensor_rear_suspend {
+	/* RESET, AVDD LDO */
+	mux {
+		pins = "gpio8","gpio79";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio8","gpio79";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <2>; /* 2 MA */
+		output-low;
+	};
+};
+
+&cam_sensor_front_active{
+	/* RESET  AVDD_LDO*/
+	mux {
+		pins = "gpio26", "gpio8";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio26", "gpio8";
+		bias-disable; /* No PULL */
+		drive-strength = <2>; /* 2 MA */
+	};
+};
+
+&cam_sensor_front_suspend{
+	/* RESET */
+	mux {
+		pins = "gpio26", "gpio8";
+		function = "gpio";
+	};
+
+	config {
+		pins = "gpio26", "gpio8";
+		bias-pull-down; /* PULL DOWN */
+		drive-strength = <2>; /* 2 MA */
+		output-low;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
new file mode 100644
index 0000000..fa82be2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
@@ -0,0 +1,548 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+#include "sda845-svr-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-svr.dtsi"
+#include "smb1355.dtsi"
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+
+&vendor {
+	bluetooth: bt_wcn3990 {
+		compatible = "qca,wcn3990";
+		qca,bt-vdd-io-supply = <&pm8998_s3>;
+		qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+		qca,bt-vdd-core-supply = <&pm8998_l7>;
+		qca,bt-vdd-pa-supply = <&pm8998_l17>;
+		qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+		qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+		qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+		qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+		qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+		qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+		qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+	};
+
+	svr_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "fg-gen3-batterydata-demo-3600mah.dtsi"
+	};
+};
+
+&pmi8998_pdphy {
+	vbus-supply = <&smb2_vbus>;
+};
+
+&qupv3_se6_4uart {
+	status = "ok";
+};
+
+&pmi8998_fg {
+	qcom,battery-data = <&svr_batterydata>;
+	qcom,fg-bmd-en-delay-ms = <300>;
+};
+
+&pmi8998_charger {
+	qcom,battery-data = <&svr_batterydata>;
+	qcom,sw-jeita-enable;
+};
+
+&qupv3_se10_i2c {
+	status = "ok";
+};
+
+&smb1355_charger_0 {
+	status = "ok";
+	qcom,disable-ctm;
+};
+
+&smb1355_charger_1 {
+	status = "ok";
+	qcom,disable-ctm;
+};
+
+&soc {
+	qcom,qbt1000 {
+		status = "disabled";
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+		label = "gpio-keys";
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_vol_up_default
+				&key_home_default
+				&key_cam_focus_default>;
+
+		vol_up {
+			label = "volume_up";
+			gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <115>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+
+		home {
+			label = "home"; /* BACK Key*/
+			gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <158>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+		key_cam_focus {
+			label = "Confirm"; /* Confirm Key*/
+			gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+			linux,input-type = <1>;
+			linux,code = <28>;
+			gpio-key,wakeup;
+			debounce-interval = <15>;
+			linux,can-disable;
+		};
+	};
+
+	dsi_panel_pwr_supply_amoled: dsi_panel_pwr_supply_amoled {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,panel-supply-entry@0 {
+			reg = <0>;
+			qcom,supply-name = "vddio";
+			qcom,supply-min-voltage = <1880000>;
+			qcom,supply-max-voltage = <1880000>;
+			qcom,supply-enable-load = <62000>;
+			qcom,supply-disable-load = <80>;
+			qcom,supply-post-on-sleep = <20>;
+		};
+
+		qcom,panel-supply-entry@1 {
+			reg = <1>;
+			qcom,supply-name = "lab";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+		};
+
+		qcom,panel-supply-entry@2 {
+			reg = <2>;
+			qcom,supply-name = "ibb";
+			qcom,supply-min-voltage = <4600000>;
+			qcom,supply-max-voltage = <6000000>;
+			qcom,supply-enable-load = <100000>;
+			qcom,supply-disable-load = <100>;
+			qcom,supply-post-on-sleep = <20>;
+		};
+		qcom,panel-supply-entry@3 {
+			reg = <3>;
+			qcom,supply-name = "oled-vdda";
+			qcom,supply-min-voltage = <3312000>;
+			qcom,supply-max-voltage = <3312000>;
+			qcom,supply-enable-load = <857000>;
+			qcom,supply-disable-load = <0>;
+			qcom,supply-post-on-sleep = <0>;
+		};
+	};
+};
+
+&sde_rscc {
+	status = "disabled";
+};
+
+&mdss_dsi0 {
+	oled-vdda-supply = <&pm8998_l22>;
+};
+
+&mdss_dsi1 {
+	oled-vdda-supply = <&pm8998_l22>;
+};
+
+&pmi8998_wled {
+	status = "ok";
+	qcom,disp-type-amoled;
+	qcom,avdd-target-voltage-mv = <7600>;
+};
+
+&labibb {
+	status = "ok";
+	qcom,qpnp-labibb-mode = "amoled";
+	qcom,swire-control;
+};
+
+&ibb_regulator {
+	status = "ok";
+	qcom,qpnp-ibb-init-amoled-voltage = <4600000>;
+	qcom,qpnp-ibb-discharge-resistor = <300>;
+};
+
+&lab_regulator {
+	status = "ok";
+	qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+};
+
+&mdss_mdp {
+	connectors = <&sde_wb &sde_dp>;
+};
+
+&dsi_dual_test_cmd {
+	qcom,mdss-dsi-t-clk-post = <0x0e>;
+	qcom,mdss-dsi-t-clk-pre = <0x35>;
+	qcom,mdss-dsi-display-timings {
+		timing@0{
+			qcom,mdss-dsi-panel-phy-timings =
+				[00 24 09 09 26 24 09 09 06 03 04 00];
+			qcom,display-topology = <2 0 2>,
+						<2 0 2>;
+			qcom,default-topology-index = <0>;
+		};
+	};
+};
+
+&dsi_dual_test_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply_amoled>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <255>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_dual_test_cmd_display {
+	qcom,dsi-display-active;
+};
+
+&snd_934x {
+	qcom,msm-mbhc-hphl-swh = <0>;
+};
+
+&pmi8998_haptics {
+	qcom,vmax-mv = <2400>;
+	qcom,lra-auto-mode;
+	status = "okay";
+};
+
+&qupv3_se9_2uart {
+	status = "ok";
+};
+
+&mdss_mdp {
+	#cooling-cells = <2>;
+};
+
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l20>;
+	vcc-voltage-level = <2950000 2960000>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm8998_l21>;
+	qcom,vdd-voltage-level = <2950000 2960000>;
+	qcom,vdd-current-level = <200 800000>;
+
+	vdd-io-supply = <&pm8998_l13>;
+	qcom,vdd-io-voltage-level = <1808000 2960000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep", "ds_400KHz",
+			"ds_50MHz", "ds_100MHz", "ds_200MHz";
+	pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &sdc2_data_on &storage_cd>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>;
+	pinctrl-2 = <&sdc2_clk_ds_400KHz
+			&sdc2_cmd_ds_400KHz &sdc2_data_ds_400KHz>;
+	pinctrl-3 = <&sdc2_clk_ds_50MHz
+			&sdc2_cmd_ds_50MHz &sdc2_data_ds_50MHz>;
+	pinctrl-4 = <&sdc2_clk_ds_100MHz
+			&sdc2_cmd_ds_100MHz &sdc2_data_ds_100MHz>;
+	pinctrl-5 = <&sdc2_clk_ds_200MHz
+			&sdc2_cmd_ds_200MHz &sdc2_data_ds_200MHz>;
+
+	cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>;
+
+	status = "ok";
+};
+
+&pmi8998_switch1 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_front_en>;
+	pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_switch2 {
+	pinctrl-names = "led_enable", "led_disable";
+	pinctrl-0 = <&flash_led3_iris_en>;
+	pinctrl-1 = <&flash_led3_iris_dis>;
+};
+
+&vendor {
+	extcon_usb1: extcon_usb1 {
+		compatible = "linux,extcon-usb-gpio";
+		vbus-gpio = <&pmi8998_gpios 8 GPIO_ACTIVE_HIGH>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_vbus_det_default>;
+	};
+};
+
+&qupv3_se9_2uart {
+	status = "ok";
+};
+
+&qupv3_se8_spi {
+	status = "ok";
+};
+
+&qupv3_se10_i2c {
+	status = "ok";
+};
+
+&qupv3_se6_4uart {
+	status = "ok";
+};
+
+&usb1 {
+	status = "okay";
+	extcon = <&extcon_usb1>;
+};
+
+&qusb_phy1 {
+	status = "okay";
+};
+
+&ext_5v_boost {
+	status = "ok";
+};
+
+&usb_qmp_phy {
+	status = "okay";
+};
+
+&pm8998_vadc {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@85 {
+		label = "vcoin";
+		reg = <0x85>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,decimation = <2>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,fast-avg-setup = <0>;
+	};
+};
+
+&pm8998_adc_tm {
+	chan@83 {
+		label = "vph_pwr";
+		reg = <0x83>;
+		qcom,pre-div-channel-scaling = <1>;
+		qcom,calibration-type = "absolute";
+		qcom,scale-function = <0>;
+		qcom,hw-settle-time = <0>;
+		qcom,btm-channel-number = <0x60>;
+	};
+
+	chan@4c {
+		label = "xo_therm";
+		reg = <0x4c>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <4>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x68>;
+		qcom,thermal-node;
+	};
+
+	chan@4d {
+		label = "msm_therm";
+		reg = <0x4d>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x70>;
+		qcom,thermal-node;
+	};
+
+	chan@4f {
+		label = "pa_therm1";
+		reg = <0x4f>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x78>;
+		qcom,thermal-node;
+	};
+
+	chan@51 {
+		label = "quiet_therm";
+		reg = <0x51>;
+		qcom,pre-div-channel-scaling = <0>;
+		qcom,calibration-type = "ratiometric";
+		qcom,scale-function = <2>;
+		qcom,hw-settle-time = <2>;
+		qcom,btm-channel-number = <0x80>;
+		qcom,thermal-node;
+	};
+};
+
+&thermal_zones {
+	xo-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4c>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	msm-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4d>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	pa-therm1-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x4f>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	quiet-therm-adc {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8998_adc_tm 0x51>;
+		thermal-governor = "user_space";
+
+		trips {
+			active-config0 {
+				temperature = <65000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+};
+
+&wil6210 {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
new file mode 100644
index 0000000..1c6db6f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr-overlay.dts
@@ -0,0 +1,31 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
similarity index 60%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
index 194bfeb..1d7bf7d 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-svr.dts
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,14 +10,16 @@
  * GNU General Public License for more details.
  */
 
+
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sda845-v2.dtsi"
+#include "sdm845-sde-display.dtsi"
+#include "sda845-svr.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDA845 V2 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 2>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
new file mode 100644
index 0000000..b4326a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-svr-overlay.dts
@@ -0,0 +1,32 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "sda845-svr.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sda845 v2.1 SVR";
+	compatible = "qcom,sda845-svr", "qcom,sda845", "qcom,svr";
+	qcom,msm-id = <341 0x20001>;
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
similarity index 64%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
index 194bfeb..e12ad51 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,13 +12,13 @@
  */
 
 /dts-v1/;
+/plugin/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdm450-pmi632-cdp-s2.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "CDP S2";
+	compatible = "qcom,cdp";
+	qcom,board-id = <1 2>;
 };
+
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
similarity index 64%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
index 194bfeb..ae522a5 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,13 +12,13 @@
  */
 
 /dts-v1/;
+/plugin/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "MTP S3";
+	compatible = "qcom,mtp";
+	qcom,board-id = <8 3>;
 };
+
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
index 040b4ba..5744390 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp.dts
@@ -24,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"
+	};
+};
+
+&qpnp_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sdm450-pmi632.dts
index 194bfeb..4f6e7f5 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,12 +13,12 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdm450.dtsi"
+#include "sdm450-pmi632.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDM450 + PMI632 SOC";
+	compatible = "qcom,sdm450";
+	qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+	qcom,pmic-name = "PMI632";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
index 700e950..eb6a692 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8937.dtsi"
+#include "msm8953-pmi8937.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
index f50d177..cfdd4e9 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8940.dtsi"
+#include "msm8953-pmi8940.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC";
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
similarity index 64%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
index 194bfeb..558c3c6 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,13 +12,13 @@
  */
 
 /dts-v1/;
+/plugin/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdm450-qrd-sku4.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "QRD SKU4";
+	compatible = "qcom,qrd";
+	qcom,board-id = <0xb 1>;
 };
+
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 0a98528..9e2981a 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -12,8 +12,98 @@
  */
 
 #include "msm8953-qrd.dtsi"
+#include "msm8953-mdss-panels.dtsi"
+
+&qusb_phy {
+	qcom,qusb-phy-init-seq = <0x78 0x80
+				0xb3 0x84
+				0x83 0x88
+				0xc7 0x8c
+				0x14 0x9c
+				0x30 0x08
+				0x79 0x0c
+				0x21 0x10
+				0x00 0x90
+				0x9f 0x1c
+				0x00 0x18>;
+};
 
 &i2c_3 {
 	status = "disabled";
 };
 
+&tlmm {
+	pmx_mdss {
+		mdss_dsi_active: mdss_dsi_active {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+		mdss_dsi_suspend: mdss_dsi_suspend {
+			mux {
+				pins = "gpio61";
+			};
+			config {
+				pins = "gpio61";
+			};
+		};
+	};
+};
+
+&dsi_panel_pwr_supply {
+	qcom,panel-supply-entry@2 {
+		reg = <2>;
+		qcom,supply-name = "lab";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@3 {
+		reg = <3>;
+		qcom,supply-name = "ibb";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6000000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+		qcom,supply-post-on-sleep = <10>;
+	};
+};
+
+&mdss_mdp {
+	qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+	hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+	lab-supply = <&lcdb_ldo_vreg>;
+	ibb-supply = <&lcdb_ncp_vreg>;
+	/delete-property/ vdd-supply;
+
+	qcom,dsi-pref-prim-pan = <&dsi_hx8399c_truly_vid>;
+	qcom,platform-bklight-en-gpio = <&pm8953_gpios 4 0>;
+	pinctrl-names = "mdss_default", "mdss_sleep";
+	pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+	pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+	qcom,platform-te-gpio = <&tlmm 24 0>;
+	qcom,platform-reset-gpio = <&tlmm 61 0>;
+};
+
+&mdss_dsi1 {
+	status = "disabled";
+};
+
+&dsi_hx8399c_truly_vid {
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+	qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+	qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+	qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts
index b829b81..6cdf897 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450.dts
@@ -14,6 +14,8 @@
 /dts-v1/;
 
 #include "sdm450.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC";
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dtsi b/arch/arm64/boot/dts/qcom/sdm450.dtsi
index 3e24714..38eacd1 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450.dtsi
@@ -48,3 +48,86 @@
 		< 560000000   6 >,  /* Nom Plus  */
 		< 600000000   7 >;  /* Turbo     */
 };
+
+/* GPU Overrides*/
+&msm_gpu {
+
+	/delete-node/qcom,gpu-pwrlevels;
+
+	qcom,gpu-pwrlevels {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "qcom,gpu-pwrlevels";
+
+		/* TURBO */
+		qcom,gpu-pwrlevel@0 {
+			reg = <0>;
+			qcom,gpu-freq = <600000000>;
+			qcom,bus-freq = <10>;
+			qcom,bus-min = <10>;
+			qcom,bus-max = <10>;
+		};
+
+		/* NOM+ */
+		qcom,gpu-pwrlevel@1 {
+			reg = <1>;
+			qcom,gpu-freq = <560000000>;
+			qcom,bus-freq = <10>;
+			qcom,bus-min = <8>;
+			qcom,bus-max = <10>;
+		};
+
+		/* NOM */
+		qcom,gpu-pwrlevel@2 {
+			reg = <2>;
+			qcom,gpu-freq = <510000000>;
+			qcom,bus-freq = <9>;
+			qcom,bus-min = <6>;
+			qcom,bus-max = <10>;
+		};
+
+		/* SVS+ */
+		qcom,gpu-pwrlevel@3 {
+			reg = <3>;
+			qcom,gpu-freq = <400000000>;
+			qcom,bus-freq = <7>;
+			qcom,bus-min = <5>;
+			qcom,bus-max = <8>;
+		};
+
+		/* SVS */
+		qcom,gpu-pwrlevel@4 {
+			reg = <4>;
+			qcom,gpu-freq = <320000000>;
+			qcom,bus-freq = <4>;
+			qcom,bus-min = <2>;
+			qcom,bus-max = <6>;
+		};
+
+		/* Low SVS */
+		qcom,gpu-pwrlevel@5 {
+			reg = <5>;
+			qcom,gpu-freq = <216000000>;
+			qcom,bus-freq = <1>;
+			qcom,bus-min = <1>;
+			qcom,bus-max = <4>;
+		};
+
+		/* Min SVS */
+		qcom,gpu-pwrlevel@6 {
+			reg = <6>;
+			qcom,gpu-freq = <133300000>;
+			qcom,bus-freq = <1>;
+			qcom,bus-min = <1>;
+			qcom,bus-max = <4>;
+		};
+		/* XO */
+		qcom,gpu-pwrlevel@7 {
+			reg = <7>;
+			qcom,gpu-freq = <19200000>;
+			qcom,bus-freq = <0>;
+			qcom,bus-min = <0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
new file mode 100644
index 0000000..903b432
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm450-pmi632-cdp-s2.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 CDP S2";
+	compatible = "qcom,sdm632-cdp", "qcom,sdm632", "qcom,cdp";
+	qcom,board-id = <1 2>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
new file mode 100644
index 0000000..6339c3c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 MTP S3";
+	compatible = "qcom,sdm632-mtp", "qcom,sdm632", "qcom,mtp";
+	qcom,board-id = <8 3>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts b/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts
new file mode 100644
index 0000000..9f33721
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-qrd-sku4.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm450-qrd-sku4.dtsi"
+#include "sdm450-pmi632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 + PMI8004 QRD SKU4";
+	compatible = "qcom,sdm632-qrd", "qcom,sdm632", "qcom,qrd";
+	qcom,board-id = <0xb 1>;
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm632-rumi-overlay.dts
similarity index 64%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sdm632-rumi-overlay.dts
index 194bfeb..4d8ce5c 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-rumi-overlay.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,13 +12,13 @@
  */
 
 /dts-v1/;
+/plugin/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdm632-rumi.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "RUMI";
+	compatible = "qcom,rumi";
+	qcom,board-id = <15 0>;
+	qcom,pmic-id = <0 0 0 0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm632.dts
similarity index 63%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to arch/arm64/boot/dts/qcom/sdm632.dts
index 194bfeb..dab409c 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,12 +13,12 @@
 
 /dts-v1/;
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+#include "sdm632.dtsi"
+#include "sdm450-pmi632.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
+	model = "Qualcomm Technologies, Inc. SDM632 + PMI632 SOC";
+	compatible = "qcom,sdm450";
+	qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
+	qcom,pmic-name = "PMI632";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
index 3ebd50e..5100f28 100644
--- a/arch/arm64/boot/dts/qcom/sdm632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -18,5 +18,17 @@
 	model = "Qualcomm Technologies, Inc. SDM632";
 	compatible = "qcom,sdm632";
 	qcom,msm-id = <349 0x0>;
+	qcom,msm-name = "SDM632";
 };
 
+&clock_gcc {
+	compatible = "qcom,gcc-sdm632";
+};
+
+&clock_debug {
+	compatible = "qcom,cc-debug-sdm632";
+};
+
+&clock_gcc_gfx {
+	compatible = "qcom,gcc-gfx-sdm632";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
index 4f5a9b1..aa7cc97 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -669,35 +669,6 @@
 			qcom,bcms = <&bcm_cn0>;
 		};
 
-		mas_qhm_tic: mas-qhm-tic {
-			cell-id = <MSM_BUS_MASTER_TIC>;
-			label = "mas-qhm-tic";
-			qcom,buswidth = <4>;
-			qcom,agg-ports = <1>;
-			qcom,connections = <&slv_qhs_tlmm_south
-				&slv_qhs_camera_cfg &slv_qhs_sdc4
-				&slv_qhs_sdc2 &slv_qhs_mnoc_cfg
-				&slv_qhs_ufs_mem_cfg &slv_qhs_glm
-				&slv_qhs_pdm &slv_qhs_a2_noc_cfg
-				&slv_qhs_qdss_cfg &slv_qhs_display_cfg
-				&slv_qhs_tcsr &slv_qhs_dcc_cfg
-				&slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
-				&slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south
-				&slv_qhs_gpuss_cfg &slv_qhs_venus_cfg
-				&slv_qhs_tsif &slv_qhs_compute_dsp_cfg
-				&slv_qhs_aop &slv_qhs_qupv3_north
-				&slv_srvc_cnoc &slv_qhs_usb3_0
-				&slv_qhs_ipa &slv_qhs_cpr_cx
-				&slv_qhs_a1_noc_cfg &slv_qhs_aoss
-				&slv_qhs_prng &slv_qhs_vsense_ctrl_cfg
-				&slv_qhs_emmc_cfg &slv_qhs_qupv3_south
-				&slv_qhs_spdm &slv_qhs_crypto0_cfg
-				&slv_qhs_pimem_cfg &slv_qhs_tlmm_north
-				&slv_qhs_clk_ctl &slv_qhs_imem_cfg>;
-			qcom,bus-dev = <&fab_config_noc>;
-			qcom,bcms = <&bcm_cn0>;
-		};
-
 		mas_qnm_snoc: mas-qnm-snoc {
 			cell-id = <MSM_BUS_SNOC_CNOC_MAS>;
 			label = "mas-qnm-snoc";
@@ -727,36 +698,6 @@
 			qcom,bcms = <&bcm_cn0>;
 		};
 
-		mas_xm_qdss_dap: mas-xm-qdss-dap {
-			cell-id = <MSM_BUS_MASTER_QDSS_DAP>;
-			label = "mas-xm-qdss-dap";
-			qcom,buswidth = <8>;
-			qcom,agg-ports = <1>;
-			qcom,connections = <&slv_qhs_tlmm_south
-				&slv_qhs_camera_cfg
-				&slv_qhs_sdc4
-				&slv_qhs_sdc2 &slv_qhs_mnoc_cfg
-				&slv_qhs_ufs_mem_cfg &slv_qhs_glm
-				&slv_qhs_pdm &slv_qhs_a2_noc_cfg
-				&slv_qhs_qdss_cfg &slv_qhs_display_cfg
-				&slv_qhs_tcsr &slv_qhs_dcc_cfg
-				&slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
-				&slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south
-				&slv_qhs_gpuss_cfg &slv_qhs_venus_cfg
-				&slv_qhs_tsif &slv_qhs_compute_dsp_cfg
-				&slv_qhs_aop &slv_qhs_qupv3_north
-				&slv_srvc_cnoc &slv_qhs_usb3_0
-				&slv_qhs_ipa &slv_qhs_cpr_cx
-				&slv_qhs_a1_noc_cfg &slv_qhs_aoss
-				&slv_qhs_prng &slv_qhs_vsense_ctrl_cfg
-				&slv_qhs_qupv3_south &slv_qhs_spdm
-				&slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg
-				&slv_qhs_tlmm_north &slv_qhs_clk_ctl
-				&slv_qhs_imem_cfg>;
-			qcom,bus-dev = <&fab_config_noc>;
-			qcom,bcms = <&bcm_cn0>;
-		};
-
 		mas_qhm_cnoc: mas-qhm-cnoc {
 			cell-id = <MSM_BUS_MASTER_CNOC_DC_NOC>;
 			label = "mas-qhm-cnoc";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-cdp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,10 +22,20 @@
 		status = "ok";
 	};
 
-	led_flash_front: qcom,camera-flash@1 {
+	led_flash_rear_aux: qcom,camera-flash@1 {
 		cell-index = <1>;
 		reg = <0x01 0x00>;
 		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
 		flash-source = <&pm660l_flash2>;
 		torch-source = <&pm660l_torch2>;
 		switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&camera_vio_ldo>;
 		cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
index 8b94ca2..3cad0e2 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-mtp.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,10 +22,20 @@
 		status = "ok";
 	};
 
-	led_flash_front: qcom,camera-flash@1 {
+	led_flash_rear_aux: qcom,camera-flash@1 {
 		cell-index = <1>;
 		reg = <0x01 0x00>;
 		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
 		flash-source = <&pm660l_flash2>;
 		torch-source = <&pm660l_torch2>;
 		switch-source = <&pm660l_switch1>;
@@ -309,6 +319,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&camera_vio_ldo>;
 		cam_vana-supply = <&camera_vana_ldo>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
index 7ab99a3..c8f7ac0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -22,6 +22,16 @@
 		status = "ok";
 	};
 
+	led_flash_rear_aux: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pm660l_flash0 &pm660l_flash1>;
+		torch-source = <&pm660l_torch0 &pm660l_torch1>;
+		switch-source = <&pm660l_switch0>;
+		status = "ok";
+	};
+
 	actuator_regulator: gpio-regulator@0 {
 		compatible = "regulator-fixed";
 		reg = <0x00 0x00>;
@@ -386,7 +396,7 @@
 		sensor-position-roll = <90>;
 		sensor-position-pitch = <0>;
 		sensor-position-yaw = <180>;
-		led-flash-src = <&led_flash_rear>;
+		led-flash-src = <&led_flash_rear_aux>;
 		actuator-src = <&actuator_rear_aux>;
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vio-supply = <&cam_iovdd_gpio_regulator>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 715affd..96c4640 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -892,7 +892,7 @@
 			<0 0 200000000 0 0 0 0 600000000>;
 		clock-cntl-level = "svs", "turbo";
 		fw_name = "CAMERA_ICP.elf";
-		ubwc-cfg = <0x77 0x1DF>;
+		ubwc-cfg = <0x73 0x1CF>;
 		status = "ok";
 	};
 
@@ -913,12 +913,12 @@
 				<&clock_camcc CAM_CC_IPE_0_CLK>,
 				<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 240000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -940,12 +940,12 @@
 				<&clock_camcc CAM_CC_IPE_1_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 240000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -967,12 +967,12 @@
 				<&clock_camcc CAM_CC_BPS_CLK>,
 				<&clock_camcc CAM_CC_BPS_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 200000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 600000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index 75a2762..9acef75 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -134,6 +134,28 @@
 
 		qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>;
 
+		qcom,soc-hw-rev-efuse = <0x414c 28 0x3>;
+
+		qcom,soc-hw-revisions {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "qcom,soc-hw-revisions";
+
+			qcom,soc-hw-revision-0 {
+				qcom,soc-hw-revision = <0>;
+				qcom,chipid = <0x06010500>;
+				qcom,gpu-quirk-hfi-use-reg;
+				qcom,gpu-quirk-limit-uche-gbif-rw;
+				qcom,gpu-quirk-mmu-secure-cb-alt;
+			};
+
+			qcom,soc-hw-revision-1 {
+				qcom,soc-hw-revision = <1>;
+				qcom,chipid = <0x06010501>;
+				qcom,gpu-quirk-hfi-use-reg;
+			};
+		};
+
 		qcom,gpu-coresights {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -485,6 +507,11 @@
 
 		gfx3d_secure: gfx3d_secure {
 			compatible = "qcom,smmu-kgsl-cb";
+			iommus = <&kgsl_smmu 2>;
+		};
+
+		gfx3d_secure_alt: gfx3d_secure_alt {
+			compatible = "qcom,smmu-kgsl-cb";
 			iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>;
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index 5d3975c..6652ba5 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -175,8 +175,8 @@
 		io-channel-names = "rradc_batt_id",
 				   "rradc_die_temp";
 		qcom,rradc-base = <0x4500>;
-		qcom,fg-esr-timer-awake = <96 96>;
-		qcom,fg-esr-timer-asleep = <256 256>;
+		qcom,fg-esr-timer-awake = <64 96>;
+		qcom,fg-esr-timer-asleep = <224 256>;
 		qcom,fg-esr-timer-charging = <0 96>;
 		qcom,cycle-counter-en;
 		qcom,hold-soc-while-full;
@@ -395,27 +395,22 @@
 
 		trips {
 			batt_trip1: batt-trip1 {
-				temperature = <40000>;
-				hysteresis = <2000>;
+				temperature = <50000>;
+				hysteresis = <4000>;
 				type = "passive";
 			};
 			batt_trip2: batt-trip2 {
-				temperature = <45000>;
+				temperature = <52000>;
 				hysteresis = <2000>;
 				type = "passive";
 			};
 			batt_trip3: batt-trip3 {
-				temperature = <48000>;
-				hysteresis = <3000>;
-				type = "passive";
-			};
-			batt_trip4: batt-trip4 {
-				temperature = <50000>;
+				temperature = <54000>;
 				hysteresis = <2000>;
 				type = "passive";
 			};
-			batt_trip5: batt-trip5 {
-				temperature = <52000>;
+			batt_trip4: batt-trip4 {
+				temperature = <56000>;
 				hysteresis = <2000>;
 				type = "passive";
 			};
@@ -432,14 +427,10 @@
 			};
 			battery_lvl3 {
 				trip = <&batt_trip3>;
-				cooling-device = <&pm660_charger 3 3>;
+				cooling-device = <&pm660_charger 4 4>;
 			};
 			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-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
index 9a7e742..43f1465 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
@@ -75,6 +75,7 @@
 &pm660_fg {
 	qcom,battery-data = <&qrd_batterydata>;
 	qcom,fg-bmd-en-delay-ms = <300>;
+	qcom,fg-jeita-thresholds = <0 15 45 55>;
 };
 
 &pm660_charger {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 6b24593..9d3f37d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -684,6 +684,5 @@
 		regulator-enable-ramp-delay = <5>;
 		proxy-supply = <&refgen>;
 		qcom,proxy-consumer-enable;
-		regulator-always-on;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index 007f937..a3f7b8e 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -831,7 +831,7 @@
 	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-command-state = "dsi_lp_mode";
 	qcom,mdss-dsi-panel-status-value = <0x9c>;
 	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
 	qcom,mdss-dsi-panel-status-read-length = <1>;
@@ -849,6 +849,18 @@
 &dsi_hx8399_truly_cmd {
 	qcom,mdss-dsi-t-clk-post = <0x0E>;
 	qcom,mdss-dsi-t-clk-pre = <0x30>;
+	qcom,mdss-dsi-min-refresh-rate = <55>;
+	qcom,mdss-dsi-max-refresh-rate = <60>;
+	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_lp_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+	qcom,mdss-dsi-panel-status-read-length = <4>;
 	qcom,mdss-dsi-display-timings {
 		timing@0 {
 			qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
index a0fa9cf..f259838 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -584,12 +584,12 @@
 
 		trips {
 			gold_trip0: gold-trip0 {
-				temperature = <45000>;
+				temperature = <47000>;
 				hysteresis = <0>;
 				type = "passive";
 			};
 			silver_trip1: silver-trip1 {
-				temperature = <50000>;
+				temperature = <52000>;
 				hysteresis = <0>;
 				type = "passive";
 			};
@@ -645,23 +645,23 @@
 
 		trips {
 			modem_trip0: modem-trip0 {
-				temperature = <44000>;
+				temperature = <48000>;
 				hysteresis = <4000>;
 				type = "passive";
 			};
 			modem_trip1: modem-trip1 {
-				temperature = <46000>;
-				hysteresis = <3000>;
+				temperature = <50000>;
+				hysteresis = <4000>;
 				type = "passive";
 			};
 			modem_trip2: modem-trip2 {
-				temperature = <48000>;
-				hysteresis = <3000>;
+				temperature = <52000>;
+				hysteresis = <2000>;
 				type = "passive";
 			};
 			modem_trip3: modem-trip3 {
-				temperature = <55000>;
-				hysteresis = <5000>;
+				temperature = <56000>;
+				hysteresis = <4000>;
 				type = "passive";
 			};
 		};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
index 32864a0..3df6d09 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
@@ -27,8 +27,6 @@
 };
 
 &usb0 {
-	/delete-property/ iommus;
-	/delete-property/ qcom,smmu-s1-bypass;
 	qcom,pm-qos-latency = <601>; /* CPU-CLUSTER-WFI-LVL latency +1 */
 	extcon = <0>, <0>, <&eud>, <0>, <0>;
 };
@@ -57,6 +55,8 @@
 			    0x03 0x250 /* TUNE5 */
 			    0x00 0x23c /* CHG_CTRL2 */
 			    0x22 0x210>; /* PWR_CTRL1 */
+	nvmem-cells = <&minor_rev>;
+	nvmem-cell-names = "minor_rev";
 };
 
 &usb_qmp_dp_phy {
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 3f8a36a..8993e1f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -585,8 +585,8 @@
 			size = <0 0x5c00000>;
 		};
 
-		cont_splash_memory: cont_splash_region@9d400000 {
-			reg = <0x0 0x9d400000 0x0 0x02400000>;
+		cont_splash_memory: cont_splash_region@9c000000 {
+			reg = <0x0 0x9c000000 0x0 0x02400000>;
 			label = "cont_splash_region";
 		};
 
@@ -2139,6 +2139,8 @@
 		compatible = "qcom,pil-tz-generic";
 		qcom,pas-id = <0xf>;
 		qcom,firmware-name = "ipa_fws";
+		qcom,pil-force-shutdown;
+		memory-region = <&pil_ipa_fw_mem>;
 	};
 
 	pil_modem: qcom,mss@4080000 {
@@ -2365,6 +2367,8 @@
 		qcom,ddr-config = <0xC3040873>;
 
 		qcom,nonremovable;
+		nvmem-cells = <&minor_rev>;
+		nvmem-cell-names = "minor_rev";
 
 		status = "disabled";
 	};
@@ -2438,6 +2442,7 @@
 	qcom,msm-adsprpc-mem {
 		compatible = "qcom,msm-adsprpc-mem-region";
 		memory-region = <&adsp_mem>;
+		restrict-access;
 	};
 
 	qcom,msm_fastrpc {
@@ -2834,14 +2839,14 @@
 
 	qfprom: qfprom@0x780000 {
 		compatible	= "qcom,qfprom";
-		reg		= <0x00780000 0x1000>;
+		reg		= <0x00784000 0x1000>;
 		#address-cells	= <1>;
 		#size-cells	= <1>;
 		ranges;
 
-		minor_rev: minor_rev@0x78014c {
+		minor_rev: minor_rev@0x78414c {
 			reg = <0x14c 0x4>;
-			bits = <0x1c 0x2>;
+			bits = <0 30>; /* Access 30 bits from bit offset 0 */
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
new file mode 100644
index 0000000..365b383
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-qrd.dtsi
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	led_flash_rear: qcom,camera-flash@0 {
+		cell-index = <0>;
+		reg = <0x00 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch1>;
+		status = "ok";
+	};
+
+	actuator_regulator: gpio-regulator@0 {
+		compatible = "regulator-fixed";
+		reg = <0x00 0x00>;
+		regulator-name = "actuator_regulator";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 27 0>;
+		vin-supply = <&pmi8998_bob>;
+	};
+
+	camera_rear_ldo: gpio-regulator@1 {
+		compatible = "regulator-fixed";
+		reg = <0x01 0x00>;
+		regulator-name = "camera_rear_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <135>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 12 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_rear_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+
+	camera_ldo: gpio-regulator@2 {
+		compatible = "regulator-fixed";
+		reg = <0x02 0x00>;
+		regulator-name = "camera_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <233>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 9 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+};
+
+&cam_cci {
+	actuator_rear: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_front: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	ois_rear: qcom,ois@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,ois";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+		status = "ok";
+	};
+
+	eeprom_rear: qcom,eeprom@0 {
+		cell-index = <0>;
+		reg = <0>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>,
+			<&tlmm 27 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vaf = <3>;
+		gpio-req-tbl-num = <0 1 2 3>;
+		gpio-req-tbl-flags = <1 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA0",
+					"CAM_VAF";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_rear_aux: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,eeprom";
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_front: qcom,eeprom@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 2812000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA1";
+		sensor-position = <1>;
+		sensor-mode = <1>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@0 {
+		cell-index = <0>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x0>;
+		csiphy-sd-index = <0>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear>;
+		actuator-src = <&actuator_rear>;
+		ois-src = <&ois_rear>;
+		eeprom-src = <&eeprom_rear>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA";
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&cam_sensor_front_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@2 {
+		cell-index = <2>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x02>;
+		csiphy-sd-index = <2>;
+		sensor-position-roll = <90>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		eeprom-src = <&eeprom_front>;
+		actuator-src = <&actuator_front>;
+		led-flash-src = <&led_flash_front>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 2812000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA1";
+		sensor-mode = <1>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
new file mode 100644
index 0000000..d387f93
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-svr.dtsi
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	led_flash_rear: qcom,camera-flash@0 {
+		cell-index = <0>;
+		reg = <0x00 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_rear_aux: qcom,camera-flash@1 {
+		cell-index = <1>;
+		reg = <0x01 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
+		torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
+		switch-source = <&pmi8998_switch0>;
+		status = "ok";
+	};
+
+	led_flash_front: qcom,camera-flash@2 {
+		cell-index = <2>;
+		reg = <0x02 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch1>;
+		status = "ok";
+	};
+
+	led_flash_iris: qcom,camera-flash@3 {
+		cell-index = <3>;
+		reg = <0x03 0x00>;
+		compatible = "qcom,camera-flash";
+		flash-source = <&pmi8998_flash2>;
+		torch-source = <&pmi8998_torch2>;
+		switch-source = <&pmi8998_switch2>;
+		status = "ok";
+	};
+
+	actuator_regulator: gpio-regulator@0 {
+		compatible = "regulator-fixed";
+		reg = <0x00 0x00>;
+		regulator-name = "actuator_regulator";
+		regulator-min-microvolt = <2800000>;
+		regulator-max-microvolt = <2800000>;
+		regulator-enable-ramp-delay = <100>;
+		enable-active-high;
+		gpio = <&tlmm 27 0>;
+		vin-supply = <&pmi8998_bob>;
+	};
+
+	camera_rear_ldo: gpio-regulator@1 {
+		compatible = "regulator-fixed";
+		reg = <0x01 0x00>;
+		regulator-name = "camera_rear_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <135>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 12 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_rear_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+
+	camera_ldo: gpio-regulator@2 {
+		compatible = "regulator-fixed";
+		reg = <0x02 0x00>;
+		regulator-name = "camera_ldo";
+		regulator-min-microvolt = <1050000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-enable-ramp-delay = <233>;
+		enable-active-high;
+		gpio = <&pm8998_gpios 9 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&camera_dvdd_en_default>;
+		vin-supply = <&pm8998_s3>;
+	};
+};
+
+&cam_cci {
+	qcom,cam-res-mgr {
+		compatible = "qcom,cam-res-mgr";
+		status = "ok";
+		shared-gpios = <9>;
+		pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend";
+		pinctrl-0 = <&cam_res_mgr_active>;
+		pinctrl-1 = <&cam_res_mgr_suspend>;
+	};
+
+	actuator_rear: qcom,actuator@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,actuator";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_rear_aux: qcom,actuator@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	actuator_front: qcom,actuator@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,actuator";
+		cci-master = <1>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+	};
+
+	ois_rear: qcom,ois@0 {
+		cell-index = <0>;
+		reg = <0x0>;
+		compatible = "qcom,ois";
+		cci-master = <0>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <2800000>;
+		rgltr-max-voltage = <2800000>;
+		rgltr-load-current = <0>;
+		status = "ok";
+	};
+
+	eeprom_rear: qcom,eeprom@0 {
+		cell-index = <0>;
+		reg = <0>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_rear_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+		rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+		rgltr-load-current = <0 80000 105000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 80 0>,
+			<&tlmm 79 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VANA0";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_rear_aux: qcom,eeprom@1 {
+		cell-index = <1>;
+		reg = <0x1>;
+		compatible = "qcom,eeprom";
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0 2800000>;
+		rgltr-max-voltage = <1050000 0 3600000 0 2800000>;
+		rgltr-load-current = <105000 0 80000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				 &cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				 &cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-position = <0>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	eeprom_front: qcom,eeprom@2 {
+		cell-index = <2>;
+		reg = <0x2>;
+		compatible = "qcom,eeprom";
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		cam_vaf-supply = <&actuator_regulator>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk", "cam_vaf";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0 2800000>;
+		rgltr-max-voltage = <0 3600000 1050000 0 2800000>;
+		rgltr-load-current = <0 80000 105000 0 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				 &cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				 &cam_sensor_front_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 28 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK2",
+					"CAM_RESET2",
+					"CAM_VANA2";
+		sensor-position = <1>;
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@0 {
+		cell-index = <0>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x0>;
+		csiphy-sd-index = <0>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		led-flash-src = <&led_flash_rear>;
+		actuator-src = <&actuator_rear>;
+		ois-src = <&ois_rear>;
+		eeprom-src = <&eeprom_rear>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_l9>;
+		cam_vio-supply = <&pm8998_l8>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1704000 1200000>;
+		rgltr-max-voltage = <0 3600000 2928000 1248000>;
+		rgltr-load-current = <0 80000 105000 1200000>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk1_active
+				&cam_sensor_rear_active>;
+		pinctrl-1 = <&cam_sensor_mclk1_suspend
+				&cam_sensor_rear_suspend>;
+		gpios = <&tlmm 14 0>,
+			<&tlmm 8 0>,
+			<&tlmm 115 0>,
+			<&tlmm 95 0 >,
+			<&tlmm 97 0>;
+		gpio-reset = <1>;
+		gpio-vio = <2>;
+		gpio-vana = <3>;
+		gpio-vdig = <4>;
+		gpio-req-tbl-num = <0 1 2 3 4>;
+		gpio-req-tbl-flags = <1 0 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET0",
+					"CAM_VIO",
+					"CAM_VANA",
+					"CAM_VDIG";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK1_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@1 {
+		cell-index = <1>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x1>;
+		csiphy-sd-index = <1>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <180>;
+		actuator-src = <&actuator_rear_aux>;
+		led-flash-src = <&led_flash_rear_aux>;
+		eeprom-src = <&eeprom_rear_aux>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <1050000 0 3312000 0>;
+		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-load-current = <105000 0 80000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk2_active
+				&cam_sensor_rear2_active>;
+		pinctrl-1 = <&cam_sensor_mclk2_suspend
+				&cam_sensor_rear2_suspend>;
+		gpios = <&tlmm 15 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK1",
+					"CAM_RESET1",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "disabled";
+		clocks = <&clock_camcc CAM_CC_MCLK2_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@2 {
+		cell-index = <2>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x02>;
+		csiphy-sd-index = <2>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		eeprom-src = <&eeprom_front>;
+		actuator-src = <&actuator_front>;
+		led-flash-src = <&led_flash_front>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&pm8998_lvs1>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1800000 0>;
+		rgltr-max-voltage = <0 3600000 1800000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk0_active
+				 &cam_sensor_front_active>;
+		pinctrl-1 = <&cam_sensor_mclk0_suspend
+				 &cam_sensor_front_suspend>;
+		gpios = <&tlmm 13 0>,
+			<&tlmm 26 0>,
+			<&tlmm 132 0>,
+			<&tlmm 133 0>,
+			<&tlmm 90 0>,
+			<&tlmm 40 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-vdig = <3>;
+		gpio-vio = <4>;
+		gpio-standby = <5>;
+		gpio-req-tbl-num = <0 1 2 3 4 5>;
+		gpio-req-tbl-flags = <1 0 0 0 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK0",
+					"CAM_RESET2",
+					"CAM_VANA2",
+					"CAM_VDIG2",
+					"CAM_VIO2",
+					"CAM_STANDBY2";
+		sensor-mode = <0>;
+		cci-master = <0>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+
+	qcom,cam-sensor@3 {
+		cell-index = <3>;
+		compatible = "qcom,cam-sensor";
+		reg = <0x03>;
+		csiphy-sd-index = <3>;
+		sensor-position-roll = <270>;
+		sensor-position-pitch = <0>;
+		sensor-position-yaw = <0>;
+		led-flash-src = <&led_flash_iris>;
+		cam_vio-supply = <&pm8998_lvs1>;
+		cam_vana-supply = <&pmi8998_bob>;
+		cam_vdig-supply = <&camera_ldo>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		rgltr-cntrl-support;
+		rgltr-min-voltage = <0 3312000 1050000 0>;
+		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-load-current = <0 80000 105000 0>;
+		gpio-no-mux = <0>;
+		pinctrl-names = "cam_default", "cam_suspend";
+		pinctrl-0 = <&cam_sensor_mclk3_active
+				 &cam_sensor_iris_active>;
+		pinctrl-1 = <&cam_sensor_mclk3_suspend
+				 &cam_sensor_iris_suspend>;
+		gpios = <&tlmm 16 0>,
+			<&tlmm 9 0>,
+			<&tlmm 8 0>;
+		gpio-reset = <1>;
+		gpio-vana = <2>;
+		gpio-req-tbl-num = <0 1 2>;
+		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-label = "CAMIF_MCLK3",
+					"CAM_RESET3",
+					"CAM_VANA1";
+		sensor-mode = <0>;
+		cci-master = <1>;
+		status = "ok";
+		clocks = <&clock_camcc CAM_CC_MCLK3_CLK>;
+		clock-names = "cam_clk";
+		clock-cntl-level = "turbo";
+		clock-rates = <24000000>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 35a7774..ec1e9c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -863,7 +863,7 @@
 			<0 0 200000000 0 0 0 0 600000000>;
 		clock-cntl-level = "svs", "turbo";
 		fw_name = "CAMERA_ICP.elf";
-		ubwc-cfg = <0x7F 0x1FF>;
+		ubwc-cfg = <0x7B 0x1EF>;
 		status = "ok";
 	};
 
@@ -885,12 +885,11 @@
 				<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
 
 		clock-rates =
-			<0 0 0 0 240000000>,
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -912,12 +911,12 @@
 				<&clock_camcc CAM_CC_IPE_1_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 240000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 538000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
@@ -939,12 +938,12 @@
 				<&clock_camcc CAM_CC_BPS_CLK>,
 				<&clock_camcc CAM_CC_BPS_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 200000000>,
+		clock-rates =
 			<0 0 0 0 404000000>,
 			<0 0 0 0 480000000>,
 			<0 0 0 0 600000000>,
 			<0 0 0 0 600000000>;
-		clock-cntl-level = "lowsvs", "svs",
+		clock-cntl-level = "svs",
 			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 5a88dc2..2c38f51 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -320,7 +320,6 @@
 		qcom,nq-clkreq = <&pm8998_gpios 21 0x00>;
 		qcom,nq-esepwr = <&tlmm 116 0x00>;
 		interrupt-parent = <&tlmm>;
-		qcom,clk-src = "BBCLK3";
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
@@ -328,8 +327,6 @@
 			     &nfc_enable_active
 			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
-		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
-		clock-names = "ref_clk";
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index 1c7269a..d6be6d4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -72,6 +72,13 @@
 	ibb-supply = <&lcdb_ncp_vreg>;
 };
 
+&dsi_dual_test_cmd_display {
+	/delete-property/ vddio-supply;
+	/delete-property/ lab-supply;
+	/delete-property/ ibb-supply;
+	/delete-property/ oled-vdda-supply;
+};
+
 &sde_dp {
 	status = "disabled";
 	/delete-property/ vdda-1p2-supply;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index fc4b674..349c4c0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -319,7 +319,6 @@
 		qcom,nq-clkreq = <&pm8998_gpios 21 0x00>;
 		qcom,nq-esepwr = <&tlmm 116 0x00>;
 		interrupt-parent = <&tlmm>;
-		qcom,clk-src = "BBCLK3";
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
@@ -327,8 +326,6 @@
 			     &nfc_enable_active
 			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
-		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
-		clock-names = "ref_clk";
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 78be790..5aaef8d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2228,33 +2228,41 @@
 		};
 
 		qupv3_se6_4uart_pins: qupv3_se6_4uart_pins {
-			qupv3_se6_4uart_active: qupv3_se6_4uart_active {
+			qupv3_se6_ctsrx: qupv3_se6_ctsrx {
 				mux {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
+					pins = "gpio45", "gpio48";
 					function = "qup6";
 				};
 
 				config {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
+					pins = "gpio45", "gpio48";
 					drive-strength = <2>;
-					bias-disable;
+					bias-no-pull;
 				};
 			};
 
-			qupv3_se6_4uart_sleep: qupv3_se6_4uart_sleep {
+			qupv3_se6_rts: qupv3_se6_rts {
 				mux {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
-					function = "gpio";
+					pins = "gpio46";
+					function = "qup6";
 				};
 
 				config {
-					pins = "gpio45", "gpio46", "gpio47",
-								"gpio48";
+					pins = "gpio46";
 					drive-strength = <2>;
-					bias-disable;
+					bias-pull-down;
+				};
+			};
+			qupv3_se6_tx: qupv3_se6_tx {
+				mux {
+					pins = "gpio47";
+					function = "qup6";
+				};
+
+				config {
+					pins = "gpio47";
+					drive-strength = <2>;
+					bias-pull-up;
 				};
 			};
 		};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 3ee0138..6034b6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -12,6 +12,7 @@
 
 #include "sdm845-pmic-overlay.dtsi"
 #include "sdm845-pinctrl-overlay.dtsi"
+#include "sdm845-camera-sensor-qrd.dtsi"
 #include "smb1355.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 
@@ -82,7 +83,6 @@
 		qcom,nq-clkreq = <&pm8998_gpios 21 0x00>;
 		qcom,nq-esepwr = <&tlmm 116 0x00>;
 		interrupt-parent = <&tlmm>;
-		qcom,clk-src = "BBCLK3";
 		interrupts = <63 0>;
 		interrupt-names = "nfc_irq";
 		pinctrl-names = "nfc_active", "nfc_suspend";
@@ -90,8 +90,6 @@
 			     &nfc_enable_active
 			     &nfc_clk_default>;
 		pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>;
-		clocks = <&clock_rpmh RPMH_LN_BB_CLK3>;
-		clock-names = "ref_clk";
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
index 5fce5ff..097c3ac 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
@@ -40,8 +40,10 @@
 			<&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
 			<&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
 		pinctrl-names = "default", "sleep";
-		pinctrl-0 = <&qupv3_se6_4uart_active>;
-		pinctrl-1 = <&qupv3_se6_4uart_sleep>;
+		pinctrl-0 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>,
+							<&qupv3_se6_tx> ;
+		pinctrl-1 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>,
+							<&qupv3_se6_tx> ;
 		interrupts-extended = <&pdc GIC_SPI 607 0>,
 				<&tlmm 48 0>;
 		status = "disabled";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index dd4e0b1..8b67649 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
 #include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi"
 #include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi"
 #include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi"
+#include "dsi-panel-test-dualmipi-oled-cmd.dtsi"
 #include <dt-bindings/clock/mdss-10nm-pll-clk.h>
 
 &soc {
@@ -476,6 +477,31 @@
 		ibb-supply = <&ibb_regulator>;
 	};
 
+	dsi_dual_test_cmd_display: qcom,dsi-display@17 {
+		compatible = "qcom,dsi-display";
+		label = "dsi_dual_test_cmd";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+				<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+		clock-names = "src_byte_clk", "src_pixel_clk";
+
+		pinctrl-names = "panel_active", "panel_suspend";
+		pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+		qcom,platform-te-gpio = <&tlmm 10 0>;
+		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
+
+		qcom,dsi-panel = <&dsi_dual_test_cmd>;
+		vddio-supply = <&pm8998_l14>;
+		lab-supply = <&lab_regulator>;
+		ibb-supply = <&ibb_regulator>;
+		oled-vdda-supply = <&pm8998_l22>;
+	};
+
 	sde_wb: qcom,wb-display@0 {
 		compatible = "qcom,wb-display";
 		cell-index = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 947d28b..1551952 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -51,6 +51,7 @@
 			compatible = "qcom,memshare-peripheral";
 			qcom,peripheral-size = <0x500000>;
 			qcom,client-id = <1>;
+			qcom,allocate-boot-time;
 			label = "modem";
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 7832165..f158f07 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3080,6 +3080,7 @@
 			     <0 425 0 /* CE11 */ >;
 		qcom,wlan-msa-memory = <0x100000>;
 		qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>;
+		qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>;
 
 		vdd-0.8-cx-mx-supply = <&pm8998_l5>;
 		vdd-1.8-xo-supply = <&pm8998_l7>;
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 801c66a..4f4f1ae 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -52,8 +52,11 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
 CONFIG_PREEMPT=y
@@ -292,9 +295,12 @@
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MSM_V2=y
@@ -305,6 +311,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
@@ -317,6 +324,7 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
 CONFIG_MSM_APM=y
@@ -335,6 +343,7 @@
 CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR=y
 CONFIG_REGULATOR_CPR4_APSS=y
 CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_MEM_ACC=y
@@ -350,14 +359,19 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
 CONFIG_QCOM_KGSL=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -422,6 +436,7 @@
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -464,6 +479,7 @@
 CONFIG_QPNP_COINCELL=y
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
@@ -495,6 +511,8 @@
 CONFIG_MSM_PM=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index 009c420..50f3754 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -56,8 +56,11 @@
 # CONFIG_IOSCHED_DEADLINE is not set
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_MSM8953=y
+CONFIG_ARCH_MSM8937=y
 CONFIG_ARCH_SDM450=y
 CONFIG_ARCH_SDM632=y
+CONFIG_ARCH_SDM429=y
+CONFIG_ARCH_SDM439=y
 CONFIG_SCHED_MC=y
 CONFIG_NR_CPUS=8
 CONFIG_PREEMPT=y
@@ -302,9 +305,12 @@
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_HS=y
 CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_DIAG_USES_SMD=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_MSM_V2=y
@@ -315,6 +321,7 @@
 CONFIG_SPMI=y
 CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
 CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8937=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
@@ -327,6 +334,7 @@
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
 CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMB5=y
 CONFIG_QPNP_SMBCHARGER=y
 CONFIG_QPNP_TYPEC=y
 CONFIG_MSM_APM=y
@@ -345,6 +353,7 @@
 CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR=y
 CONFIG_REGULATOR_CPR4_APSS=y
 CONFIG_REGULATOR_CPRH_KBSS=y
 CONFIG_REGULATOR_MEM_ACC=y
@@ -360,8 +369,8 @@
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_MSM_VIDC_V4L2=y
-CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
 CONFIG_QCOM_KGSL=y
@@ -369,6 +378,11 @@
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
 CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_LOGO=y
@@ -433,6 +447,7 @@
 CONFIG_USB_CONFIGFS_UEVENT=y
 CONFIG_USB_CONFIGFS_F_HID=y
 CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -476,6 +491,7 @@
 CONFIG_QPNP_COINCELL=y
 CONFIG_QPNP_REVID=y
 CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
@@ -514,9 +530,11 @@
 CONFIG_QCOM_DCC=y
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
 CONFIG_WCNSS_CORE=y
 CONFIG_WCNSS_CORE_PRONTO=y
 CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
 CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
@@ -565,6 +583,7 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_PANIC_ON_SCHED_BUG=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 8022e88..667377f 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -621,7 +621,6 @@
 CONFIG_DEBUG_OBJECTS_FREE=y
 CONFIG_DEBUG_OBJECTS_TIMERS=y
 CONFIG_DEBUG_OBJECTS_WORK=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
 CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 CONFIG_SLUB_DEBUG_ON=y
 CONFIG_DEBUG_KMEMLEAK=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index f7ef61e..ff3bb70 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -290,6 +290,11 @@
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -568,6 +573,8 @@
 CONFIG_EXT4_ENCRYPTION=y
 CONFIG_EXT4_FS_ENCRYPTION=y
 CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index a4f0ffa..01687f5 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -294,6 +294,11 @@
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
 CONFIG_INPUT_QPNP_POWER_ON=y
@@ -585,6 +590,8 @@
 CONFIG_EXT4_ENCRYPTION=y
 CONFIG_EXT4_FS_ENCRYPTION=y
 CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 CONFIG_QFMT_V2=y
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 46d0448..88a4d1e 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -25,6 +25,7 @@
 
 #include <asm/asm-offsets.h>
 #include <asm/cpufeature.h>
+#include <asm/cputype.h>
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/ptrace.h>
@@ -452,4 +453,43 @@
 	mrs	\rd, sp_el0
 	.endm
 
+/*
+ * Check the MIDR_EL1 of the current CPU for a given model and a range of
+ * variant/revision. See asm/cputype.h for the macros used below.
+ *
+ *	model:		MIDR_CPU_MODEL of CPU
+ *	rv_min:		Minimum of MIDR_CPU_VAR_REV()
+ *	rv_max:		Maximum of MIDR_CPU_VAR_REV()
+ *	res:		Result register.
+ *	tmp1, tmp2, tmp3: Temporary registers
+ *
+ * Corrupts: res, tmp1, tmp2, tmp3
+ * Returns:  0, if the CPU id doesn't match. Non-zero otherwise
+ */
+	.macro	cpu_midr_match model, rv_min, rv_max, res, tmp1, tmp2, tmp3
+	mrs		\res, midr_el1
+	mov_q		\tmp1, (MIDR_REVISION_MASK | MIDR_VARIANT_MASK)
+	mov_q		\tmp2, MIDR_CPU_MODEL_MASK
+	and		\tmp3, \res, \tmp2	// Extract model
+	and		\tmp1, \res, \tmp1	// rev & variant
+	mov_q		\tmp2, \model
+	cmp		\tmp3, \tmp2
+	cset		\res, eq
+	cbz		\res, .Ldone\@		// Model matches ?
+
+	.if (\rv_min != 0)			// Skip min check if rv_min == 0
+	mov_q		\tmp3, \rv_min
+	cmp		\tmp1, \tmp3
+	cset		\res, ge
+	.endif					// \rv_min != 0
+	/* Skip rv_max check if rv_min == rv_max && rv_min != 0 */
+	.if ((\rv_min != \rv_max) || \rv_min == 0)
+	mov_q		\tmp2, \rv_max
+	cmp		\tmp1, \tmp2
+	cset		\tmp2, le
+	and		\res, \res, \tmp2
+	.endif
+.Ldone\@:
+	.endm
+
 #endif	/* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index ddbf3b1..c088c4f 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -56,6 +56,9 @@
 	(0xf			<< MIDR_ARCHITECTURE_SHIFT) | \
 	((partnum)		<< MIDR_PARTNUM_SHIFT))
 
+#define MIDR_CPU_VAR_REV(var, rev) \
+	(((var)	<< MIDR_VARIANT_SHIFT) | (rev))
+
 #define MIDR_CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
 			     MIDR_ARCHITECTURE_MASK)
 
@@ -79,7 +82,9 @@
 #define ARM_CPU_PART_CORTEX_A53		0xD03
 #define ARM_CPU_PART_CORTEX_A73		0xD09
 #define ARM_CPU_PART_CORTEX_A75		0xD0A
+#define ARM_CPU_PART_KRYO3S		0x803
 #define ARM_CPU_PART_KRYO3G		0x802
+#define ARM_CPU_PART_CORTEX_A55		0xD05
 
 #define APM_CPU_PART_POTENZA		0x000
 
@@ -93,7 +98,9 @@
 #define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
 #define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
 #define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
+#define MIDR_KRYO3S	MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3S)
 #define MIDR_KRYO3G	MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO3G)
+#define MIDR_CORTEX_A55 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A55)
 #define MIDR_THUNDERX	MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
 
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index 4e7eec7..ea06f3f 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -82,19 +82,21 @@
 		if (mm != current->active_mm) {
 			/*
 			 * Update the current thread's saved ttbr0 since it is
-			 * restored as part of a return from exception. Set
-			 * the hardware TTBR0_EL1 using cpu_switch_mm()
-			 * directly to enable potential errata workarounds.
+			 * restored as part of a return from exception. Enable
+			 * access to the valid TTBR0_EL1 and invoke the errata
+			 * workaround directly since there is no return from
+			 * exception when invoking the EFI run-time services.
 			 */
 			update_saved_ttbr0(current, mm);
-			cpu_switch_mm(mm->pgd, mm);
+			uaccess_ttbr0_enable();
+			post_ttbr_update_workaround();
 		} else {
 			/*
 			 * Defer the switch to the current thread's TTBR0_EL1
 			 * until uaccess_enable(). Restore the current
 			 * thread's saved ttbr0 corresponding to its active_mm
 			 */
-			cpu_set_reserved_ttbr0();
+			uaccess_ttbr0_disable();
 			update_saved_ttbr0(current, current->active_mm);
 		}
 	}
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index af0215a..a0fac5c 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -177,7 +177,7 @@
 	else
 		ttbr = virt_to_phys(mm->pgd) | ASID(mm) << 48;
 
-	task_thread_info(tsk)->ttbr0 = ttbr;
+	WRITE_ONCE(task_thread_info(tsk)->ttbr0, ttbr);
 }
 #else
 static inline void update_saved_ttbr0(struct task_struct *tsk,
@@ -232,5 +232,6 @@
 #define activate_mm(prev,next)	switch_mm(prev, next, current)
 
 void verify_cpu_asid_bits(void);
+void post_ttbr_update_workaround(void);
 
 #endif
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 8b38b0d..9311547 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -132,16 +132,18 @@
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 static inline void __uaccess_ttbr0_disable(void)
 {
-	unsigned long ttbr;
+	unsigned long flags, ttbr;
 
+	local_irq_save(flags);
 	ttbr = read_sysreg(ttbr1_el1);
+	ttbr &= ~TTBR_ASID_MASK;
 	/* reserved_ttbr0 placed at the end of swapper_pg_dir */
 	write_sysreg(ttbr + SWAPPER_DIR_SIZE, ttbr0_el1);
 	isb();
 	/* Set reserved ASID */
-	ttbr &= ~TTBR_ASID_MASK;
 	write_sysreg(ttbr, ttbr1_el1);
 	isb();
+	local_irq_restore(flags);
 }
 
 static inline void __uaccess_ttbr0_enable(void)
@@ -154,10 +156,11 @@
 	 * roll-over and an update of 'ttbr0'.
 	 */
 	local_irq_save(flags);
-	ttbr0 = current_thread_info()->ttbr0;
+	ttbr0 = READ_ONCE(current_thread_info()->ttbr0);
 
 	/* Restore active ASID */
 	ttbr1 = read_sysreg(ttbr1_el1);
+	ttbr1 &= ~TTBR_ASID_MASK;		/* safety measure */
 	ttbr1 |= ttbr0 & TTBR_ASID_MASK;
 	write_sysreg(ttbr1, ttbr1_el1);
 	isb();
@@ -450,11 +453,11 @@
 #ifdef CONFIG_ARM64_SW_TTBR0_PAN
 	.macro	__uaccess_ttbr0_disable, tmp1
 	mrs	\tmp1, ttbr1_el1		// swapper_pg_dir
+	bic     \tmp1, \tmp1, #TTBR_ASID_MASK
 	add	\tmp1, \tmp1, #SWAPPER_DIR_SIZE	// reserved_ttbr0 at the end of swapper_pg_dir
 	msr	ttbr0_el1, \tmp1		// set reserved TTBR0_EL1
 	isb
 	sub     \tmp1, \tmp1, #SWAPPER_DIR_SIZE
-	bic     \tmp1, \tmp1, #TTBR_ASID_MASK
 	msr     ttbr1_el1, \tmp1                // set reserved ASID
 	isb
 	.endm
@@ -471,9 +474,11 @@
 	isb
 	.endm
 
-	.macro	uaccess_ttbr0_disable, tmp1
+	.macro	uaccess_ttbr0_disable, tmp1, tmp2
 alternative_if_not ARM64_HAS_PAN
+	save_and_disable_irq \tmp2		// avoid preemption
 	__uaccess_ttbr0_disable \tmp1
+	restore_irq \tmp2
 alternative_else_nop_endif
 	.endm
 
@@ -485,7 +490,7 @@
 alternative_else_nop_endif
 	.endm
 #else
-	.macro	uaccess_ttbr0_disable, tmp1
+	.macro	uaccess_ttbr0_disable, tmp1, tmp2
 	.endm
 
 	.macro	uaccess_ttbr0_enable, tmp1, tmp2, tmp3
@@ -495,8 +500,8 @@
 /*
  * These macros are no-ops when UAO is present.
  */
-	.macro	uaccess_disable_not_uao, tmp1
-	uaccess_ttbr0_disable \tmp1
+	.macro	uaccess_disable_not_uao, tmp1, tmp2
+	uaccess_ttbr0_disable \tmp1, \tmp2
 alternative_if ARM64_ALT_PAN_NOT_UAO
 	SET_PSTATE_PAN(1)
 alternative_else_nop_endif
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 653359b..c7b3ba68 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -180,8 +180,9 @@
 	/* Cortex-A57 r0p0 - r1p2 */
 		.desc = "ARM erratum 832075",
 		.capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
-		MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 2),
+		MIDR_RANGE(MIDR_CORTEX_A57,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 2)),
 	},
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_834220
@@ -189,8 +190,9 @@
 	/* Cortex-A57 r0p0 - r1p2 */
 		.desc = "ARM erratum 834220",
 		.capability = ARM64_WORKAROUND_834220,
-		MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 2),
+		MIDR_RANGE(MIDR_CORTEX_A57,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 2)),
 	},
 #endif
 #ifdef CONFIG_ARM64_ERRATUM_845719
@@ -214,8 +216,9 @@
 	/* Cavium ThunderX, T88 pass 1.x - 2.1 */
 		.desc = "Cavium erratum 27456",
 		.capability = ARM64_WORKAROUND_CAVIUM_27456,
-		MIDR_RANGE(MIDR_THUNDERX, 0x00,
-			   (1 << MIDR_VARIANT_SHIFT) | 1),
+		MIDR_RANGE(MIDR_THUNDERX,
+			   MIDR_CPU_VAR_REV(0, 0),
+			   MIDR_CPU_VAR_REV(1, 1)),
 	},
 	{
 	/* Cavium ThunderX, T81 pass 1.0 */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 80ff3df5..5cf4c64 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -722,13 +722,11 @@
 static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused)
 {
 	u32 midr = read_cpuid_id();
-	u32 rv_min, rv_max;
 
 	/* Cavium ThunderX pass 1.x and 2.x */
-	rv_min = 0;
-	rv_max = (1 << MIDR_VARIANT_SHIFT) | MIDR_REVISION_MASK;
-
-	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX, rv_min, rv_max);
+	return MIDR_IS_CPU_MODEL_RANGE(midr, MIDR_THUNDERX,
+		MIDR_CPU_VAR_REV(0, 0),
+		MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK));
 }
 
 static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 8030583..3b22fa3 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -150,7 +150,7 @@
 alternative_else_nop_endif
 
 	.if	\el != 0
-	mrs	x21, ttbr1_el1
+	mrs	x21, ttbr0_el1
 	tst	x21, #TTBR_ASID_MASK		// Check for the reserved ASID
 	orr	x23, x23, #PSR_PAN_BIT		// Set the emulated PAN in the saved SPSR
 	b.eq	1f				// TTBR0 access already disabled
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 85baada..2e6e9e9 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -44,7 +44,7 @@
 
 	ret = kvm_psci_call(vcpu);
 	if (ret < 0) {
-		kvm_inject_undefined(vcpu);
+		vcpu_set_reg(vcpu, 0, ~0UL);
 		return 1;
 	}
 
@@ -53,7 +53,7 @@
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-	kvm_inject_undefined(vcpu);
+	vcpu_set_reg(vcpu, 0, ~0UL);
 	return 1;
 }
 
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S
index dd65ca2..07c7ad9 100644
--- a/arch/arm64/lib/clear_user.S
+++ b/arch/arm64/lib/clear_user.S
@@ -50,7 +50,7 @@
 	b.mi	5f
 uao_user_alternative 9f, strb, sttrb, wzr, x0, 0
 5:	mov	x0, #0
-	uaccess_disable_not_uao x2
+	uaccess_disable_not_uao x2, x3
 	ret
 ENDPROC(__clear_user)
 
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S
index 7e7e687..c7a7d96 100644
--- a/arch/arm64/lib/copy_from_user.S
+++ b/arch/arm64/lib/copy_from_user.S
@@ -67,7 +67,7 @@
 	uaccess_enable_not_uao x3, x4, x5
 	add	end, x0, x2
 #include "copy_template.S"
-	uaccess_disable_not_uao x3
+	uaccess_disable_not_uao x3, x4
 	mov	x0, #0				// Nothing to copy
 	ret
 ENDPROC(__arch_copy_from_user)
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
index 074d52f..e8bfaf1 100644
--- a/arch/arm64/lib/copy_in_user.S
+++ b/arch/arm64/lib/copy_in_user.S
@@ -68,7 +68,7 @@
 	uaccess_enable_not_uao x3, x4, x5
 	add	end, x0, x2
 #include "copy_template.S"
-	uaccess_disable_not_uao x3
+	uaccess_disable_not_uao x3, x4
 	mov	x0, #0
 	ret
 ENDPROC(__copy_in_user)
diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S
index 6711844..f6cfcc0 100644
--- a/arch/arm64/lib/copy_to_user.S
+++ b/arch/arm64/lib/copy_to_user.S
@@ -66,7 +66,7 @@
 	uaccess_enable_not_uao x3, x4, x5
 	add	end, x0, x2
 #include "copy_template.S"
-	uaccess_disable_not_uao x3
+	uaccess_disable_not_uao x3, x4
 	mov	x0, #0
 	ret
 ENDPROC(__arch_copy_to_user)
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 9dd6d32..b98b3fc 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -145,7 +145,7 @@
 	isb
 	mov	x0, #0
 1:
-	uaccess_ttbr0_disable x1
+	uaccess_ttbr0_disable x1, x2
 	ret
 9:
 	mov	x0, #-EFAULT
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index fa20d13..2e69a14 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -186,6 +186,9 @@
 ENTRY(cpu_do_switch_mm)
 	mrs	x2, ttbr1_el1
 	mmid	x1, x1				// get mm->context.id
+#ifdef CONFIG_ARM64_SW_TTBR0_PAN
+	bfi	x0, x1, #48, #16		// set the ASID field in TTBR0
+#endif
 	bfi	x2, x1, #48, #16		// set the ASID
 	msr	ttbr1_el1, x2			// in TTBR1 (since TCR.A1 is set)
 	isb
@@ -290,6 +293,12 @@
 	cbz	x9, 2f
 	cmp	x9, #2
 	b.lt	1f
+#ifdef CONFIG_ARM64_ERRATUM_1024718
+	/* Disable hardware DBM on Kryo3S */
+	cpu_midr_match MIDR_KRYO3S, MIDR_CPU_VAR_REV(7, 12), \
+			MIDR_CPU_VAR_REV(7, 13), x1, x2, x3, x4
+	cbnz	x1, 1f
+#endif
 	orr	x10, x10, #TCR_HD		// hardware Dirty flag update
 1:	orr	x10, x10, #TCR_HA		// hardware Access flag update
 2:
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S
index f542252..69711f2 100644
--- a/arch/arm64/xen/hypercall.S
+++ b/arch/arm64/xen/hypercall.S
@@ -106,6 +106,6 @@
 	/*
 	 * Disable userspace access from kernel once the hyp call completed.
 	 */
-	uaccess_ttbr0_disable x6
+	uaccess_ttbr0_disable x6, x7
 	ret
 ENDPROC(privcmd_call);
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
index 3446b6f..9da4e22 100644
--- a/arch/mips/ar7/platform.c
+++ b/arch/mips/ar7/platform.c
@@ -576,7 +576,7 @@
 	uart_port.type		= PORT_AR7;
 	uart_port.uartclk	= clk_get_rate(bus_clk) / 2;
 	uart_port.iotype	= UPIO_MEM32;
-	uart_port.flags		= UPF_FIXED_TYPE;
+	uart_port.flags		= UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF;
 	uart_port.regshift	= 2;
 
 	uart_port.line		= 0;
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 0ca46ede..9c150cc 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -117,7 +117,7 @@
 archprepare: include/generated/user_constants.h
 
 LINK-$(CONFIG_LD_SCRIPT_STATIC) += -static
-LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib
+LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib $(call cc-option, -no-pie)
 
 CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) \
 	$(call cc-option, -fno-stack-protector,) \
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index aa8b067..d9ae404 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -906,7 +906,7 @@
 
 	if (sg_is_last(req->src) &&
 	    req->src->offset + req->src->length <= PAGE_SIZE &&
-	    sg_is_last(req->dst) &&
++	    sg_is_last(req->dst) && req->dst->length &&
 	    req->dst->offset + req->dst->length <= PAGE_SIZE) {
 		one_entry_in_sg = 1;
 		scatterwalk_start(&src_sg_walk, req->src);
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index bdc9aea..a76dc73 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -229,6 +229,17 @@
 	movl	%ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset
 #endif
 
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * When switching from a shallower to a deeper call stack
+	 * the RSB may either underflow or use entries populated
+	 * with userspace addresses. On CPUs where those concerns
+	 * exist, overwrite the RSB with entries which capture
+	 * speculative execution to prevent attack.
+	 */
+	FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
+#endif
+
 	/* restore callee-saved registers */
 	popl	%esi
 	popl	%edi
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index b9c901ce..e729e15 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -427,6 +427,17 @@
 	movq	%rbx, PER_CPU_VAR(irq_stack_union)+stack_canary_offset
 #endif
 
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * When switching from a shallower to a deeper call stack
+	 * the RSB may either underflow or use entries populated
+	 * with userspace addresses. On CPUs where those concerns
+	 * exist, overwrite the RSB with entries which capture
+	 * speculative execution to prevent attack.
+	 */
+	FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
+#endif
+
 	/* restore callee-saved registers */
 	popq	%r15
 	popq	%r14
@@ -1053,7 +1064,7 @@
 #endif
 
 #ifdef CONFIG_X86_MCE
-idtentry machine_check					has_error_code=0	paranoid=1 do_sym=*machine_check_vector(%rip)
+idtentry machine_check		do_mce			has_error_code=0	paranoid=1
 #endif
 
 /*
diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c
index 6bb7e92..0174290 100644
--- a/arch/x86/entry/vsyscall/vsyscall_64.c
+++ b/arch/x86/entry/vsyscall/vsyscall_64.c
@@ -46,6 +46,7 @@
 #else
 	EMULATE;
 #endif
+unsigned long vsyscall_pgprot = __PAGE_KERNEL_VSYSCALL;
 
 static int __init vsyscall_setup(char *str)
 {
@@ -336,11 +337,11 @@
 	extern char __vsyscall_page;
 	unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
 
+	if (vsyscall_mode != NATIVE)
+		vsyscall_pgprot = __PAGE_KERNEL_VVAR;
 	if (vsyscall_mode != NONE)
 		__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
-			     vsyscall_mode == NATIVE
-			     ? PAGE_KERNEL_VSYSCALL
-			     : PAGE_KERNEL_VVAR);
+			     __pgprot(vsyscall_pgprot));
 
 	BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
 		     (unsigned long)VSYSCALL_ADDR);
diff --git a/arch/x86/events/amd/power.c b/arch/x86/events/amd/power.c
index 9842270..21a4e41 100644
--- a/arch/x86/events/amd/power.c
+++ b/arch/x86/events/amd/power.c
@@ -277,7 +277,7 @@
 	int ret;
 
 	if (!x86_match_cpu(cpu_match))
-		return 0;
+		return -ENODEV;
 
 	if (!boot_cpu_has(X86_FEATURE_ACC_POWER))
 		return -ENODEV;
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 4467568..8537a21 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -197,9 +197,9 @@
 #define X86_FEATURE_RETPOLINE	( 7*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */
 #define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* AMD Retpoline mitigation for Spectre variant 2 */
 
-#define X86_FEATURE_INTEL_PT	( 7*32+15) /* Intel Processor Trace */
 #define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
 #define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
+#define X86_FEATURE_RSB_CTXSW		( 7*32+19) /* Fill RSB on context switches */
 
 /* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */
 #define X86_FEATURE_KAISER	( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */
@@ -235,6 +235,7 @@
 #define X86_FEATURE_SMAP	( 9*32+20) /* Supervisor Mode Access Prevention */
 #define X86_FEATURE_CLFLUSHOPT	( 9*32+23) /* CLFLUSHOPT instruction */
 #define X86_FEATURE_CLWB	( 9*32+24) /* CLWB instruction */
+#define X86_FEATURE_INTEL_PT	( 9*32+25) /* Intel Processor Trace */
 #define X86_FEATURE_AVX512PF	( 9*32+26) /* AVX-512 Prefetch */
 #define X86_FEATURE_AVX512ER	( 9*32+27) /* AVX-512 Exponential and Reciprocal */
 #define X86_FEATURE_AVX512CD	( 9*32+28) /* AVX-512 Conflict Detection */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index cbd1d44..20cfeeb 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1113,7 +1113,8 @@
 static inline int emulate_instruction(struct kvm_vcpu *vcpu,
 			int emulation_type)
 {
-	return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0);
+	return x86_emulate_instruction(vcpu, 0,
+			emulation_type | EMULTYPE_NO_REEXECUTE, NULL, 0);
 }
 
 void kvm_enable_efer_bits(u64);
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
index 402a11c..4ad4108 100644
--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -11,7 +11,7 @@
  * Fill the CPU return stack buffer.
  *
  * Each entry in the RSB, if used for a speculative 'ret', contains an
- * infinite 'pause; jmp' loop to capture speculative execution.
+ * infinite 'pause; lfence; jmp' loop to capture speculative execution.
  *
  * This is required in various cases for retpoline and IBRS-based
  * mitigations for the Spectre variant 2 vulnerability. Sometimes to
@@ -38,11 +38,13 @@
 	call	772f;				\
 773:	/* speculation trap */			\
 	pause;					\
+	lfence;					\
 	jmp	773b;				\
 772:						\
 	call	774f;				\
 775:	/* speculation trap */			\
 	pause;					\
+	lfence;					\
 	jmp	775b;				\
 774:						\
 	dec	reg;				\
@@ -73,6 +75,7 @@
 	call	.Ldo_rop_\@
 .Lspec_trap_\@:
 	pause
+	lfence
 	jmp	.Lspec_trap_\@
 .Ldo_rop_\@:
 	mov	\reg, (%_ASM_SP)
@@ -165,6 +168,7 @@
 	"       .align 16\n"					\
 	"901:	call   903f;\n"					\
 	"902:	pause;\n"					\
+	"    	lfence;\n"					\
 	"       jmp    902b;\n"					\
 	"       .align 16\n"					\
 	"903:	addl   $4, %%esp;\n"				\
@@ -190,6 +194,9 @@
 	SPECTRE_V2_IBRS,
 };
 
+extern char __indirect_thunk_start[];
+extern char __indirect_thunk_end[];
+
 /*
  * On VMEXIT we must ensure that no RSB predictions learned in the guest
  * can be followed in the host, by overwriting the RSB completely. Both
@@ -199,16 +206,17 @@
 static inline void vmexit_fill_RSB(void)
 {
 #ifdef CONFIG_RETPOLINE
-	unsigned long loops = RSB_CLEAR_LOOPS / 2;
+	unsigned long loops;
 
 	asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE
 		      ALTERNATIVE("jmp 910f",
 				  __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)),
 				  X86_FEATURE_RETPOLINE)
 		      "910:"
-		      : "=&r" (loops), ASM_CALL_CONSTRAINT
-		      : "r" (loops) : "memory" );
+		      : "=r" (loops), ASM_CALL_CONSTRAINT
+		      : : "memory" );
 #endif
 }
+
 #endif /* __ASSEMBLY__ */
 #endif /* __NOSPEC_BRANCH_H__ */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index e40b19c..353f038 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -596,7 +596,7 @@
 {
 	int tmp;
 
-#ifdef CONFIG_M486
+#ifdef CONFIG_X86_32
 	/*
 	 * Do a CPUID if available, otherwise do a jump.  The jump
 	 * can conveniently enough be the jump around CPUID.
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 01fd0a7..688315b 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -92,6 +92,7 @@
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *, long);
 #endif
+dotraplinkage void do_mce(struct pt_regs *, long);
 
 static inline int get_si_code(unsigned long condition)
 {
diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h
index 4865e10..9ee8506 100644
--- a/arch/x86/include/asm/vsyscall.h
+++ b/arch/x86/include/asm/vsyscall.h
@@ -13,6 +13,7 @@
  */
 extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
 extern bool vsyscall_enabled(void);
+extern unsigned long vsyscall_pgprot;
 #else
 static inline void map_vsyscall(void) {}
 static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index f3557a1..b5229ab 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -361,14 +361,17 @@
 		irq_data->chip_data = data;
 		irq_data->hwirq = virq + i;
 		err = assign_irq_vector_policy(virq + i, node, data, info);
-		if (err)
+		if (err) {
+			irq_data->chip_data = NULL;
+			free_apic_chip_data(data);
 			goto error;
+		}
 	}
 
 	return 0;
 
 error:
-	x86_vector_free_irqs(domain, virq, i + 1);
+	x86_vector_free_irqs(domain, virq, i);
 	return err;
 }
 
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 49d25dd..8cacf62 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -22,6 +22,7 @@
 #include <asm/alternative.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
+#include <asm/intel-family.h>
 
 static void __init spectre_v2_select_mitigation(void);
 
@@ -154,6 +155,23 @@
 	return SPECTRE_V2_CMD_NONE;
 }
 
+/* Check for Skylake-like CPUs (for RSB handling) */
+static bool __init is_skylake_era(void)
+{
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+	    boot_cpu_data.x86 == 6) {
+		switch (boot_cpu_data.x86_model) {
+		case INTEL_FAM6_SKYLAKE_MOBILE:
+		case INTEL_FAM6_SKYLAKE_DESKTOP:
+		case INTEL_FAM6_SKYLAKE_X:
+		case INTEL_FAM6_KABYLAKE_MOBILE:
+		case INTEL_FAM6_KABYLAKE_DESKTOP:
+			return true;
+		}
+	}
+	return false;
+}
+
 static void __init spectre_v2_select_mitigation(void)
 {
 	enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
@@ -212,6 +230,24 @@
 
 	spectre_v2_enabled = mode;
 	pr_info("%s\n", spectre_v2_strings[mode]);
+
+	/*
+	 * If neither SMEP or KPTI are available, there is a risk of
+	 * hitting userspace addresses in the RSB after a context switch
+	 * from a shallow call stack to a deeper one. To prevent this fill
+	 * the entire RSB, even when using IBRS.
+	 *
+	 * Skylake era CPUs have a separate issue with *underflow* of the
+	 * RSB, when they will predict 'ret' targets from the generic BTB.
+	 * The proper mitigation for this is IBRS. If IBRS is not supported
+	 * or deactivated in favour of retpolines the RSB fill on context
+	 * switch is required.
+	 */
+	if ((!boot_cpu_has(X86_FEATURE_KAISER) &&
+	     !boot_cpu_has(X86_FEATURE_SMEP)) || is_skylake_era()) {
+		setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
+		pr_info("Filling RSB on context switch\n");
+	}
 }
 
 #undef pr_fmt
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 7b9ae04..d198ae0 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -883,8 +883,8 @@
 
 	setup_force_cpu_cap(X86_FEATURE_ALWAYS);
 
-	/* Assume for now that ALL x86 CPUs are insecure */
-	setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
+	if (c->x86_vendor != X86_VENDOR_AMD)
+		setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
 
 	setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
 	setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index de6626c..be63371 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -934,6 +934,8 @@
 		ci_leaf_init(this_leaf++, &id4_regs);
 		__cache_cpumap_setup(cpu, idx, &id4_regs);
 	}
+	this_cpu_ci->cpu_map_populated = true;
+
 	return 0;
 }
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 8ca5f8a..fe5cd6e 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -1754,6 +1754,11 @@
 void (*machine_check_vector)(struct pt_regs *, long error_code) =
 						unexpected_machine_check;
 
+dotraplinkage void do_mce(struct pt_regs *regs, long error_code)
+{
+	machine_check_vector(regs, error_code);
+}
+
 /*
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off:
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index ac3e636..f90f176 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -40,6 +40,9 @@
 #include <asm/setup.h>
 #include <asm/msr.h>
 
+/* last level cache size per core */
+static int llc_size_per_core;
+
 /*
  * Temporary microcode blobs pointers storage. We note here during early load
  * the pointers to microcode blobs we've got from whatever storage (detached
@@ -1053,12 +1056,14 @@
 
 	/*
 	 * Late loading on model 79 with microcode revision less than 0x0b000021
-	 * may result in a system hang. This behavior is documented in item
-	 * BDF90, #334165 (Intel Xeon Processor E7-8800/4800 v4 Product Family).
+	 * and LLC size per core bigger than 2.5MB may result in a system hang.
+	 * This behavior is documented in item BDF90, #334165 (Intel Xeon
+	 * Processor E7-8800/4800 v4 Product Family).
 	 */
 	if (c->x86 == 6 &&
 	    c->x86_model == INTEL_FAM6_BROADWELL_X &&
 	    c->x86_mask == 0x01 &&
+	    llc_size_per_core > 2621440 &&
 	    c->microcode < 0x0b000021) {
 		pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode);
 		pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n");
@@ -1125,6 +1130,15 @@
 	.microcode_fini_cpu               = microcode_fini_cpu,
 };
 
+static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c)
+{
+	u64 llc_size = c->x86_cache_size * 1024;
+
+	do_div(llc_size, c->x86_max_cores);
+
+	return (int)llc_size;
+}
+
 struct microcode_ops * __init init_intel_microcode(void)
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
@@ -1135,6 +1149,8 @@
 		return NULL;
 	}
 
+	llc_size_per_core = calc_llc_size_per_core(c);
+
 	return &microcode_intel_ops;
 }
 
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 1db8dc4..b0dd9ae 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -31,7 +31,6 @@
 	const struct cpuid_bit *cb;
 
 	static const struct cpuid_bit cpuid_bits[] = {
-		{ X86_FEATURE_INTEL_PT,		CR_EBX,25, 0x00000007, 0 },
 		{ X86_FEATURE_AVX512_4VNNIW,	CR_EDX, 2, 0x00000007, 0 },
 		{ X86_FEATURE_AVX512_4FMAPS,	CR_EDX, 3, 0x00000007, 0 },
 		{ X86_FEATURE_APERFMPERF,	CR_ECX, 0, 0x00000006, 0 },
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c
index 4d74f73..dc20da1c 100644
--- a/arch/x86/kernel/kprobes/opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -37,6 +37,7 @@
 #include <asm/alternative.h>
 #include <asm/insn.h>
 #include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
 
 #include "common.h"
 
@@ -192,7 +193,7 @@
 }
 
 /* Check whether insn is indirect jump */
-static int insn_is_indirect_jump(struct insn *insn)
+static int __insn_is_indirect_jump(struct insn *insn)
 {
 	return ((insn->opcode.bytes[0] == 0xff &&
 		(X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
@@ -226,6 +227,26 @@
 	return (start <= target && target <= start + len);
 }
 
+static int insn_is_indirect_jump(struct insn *insn)
+{
+	int ret = __insn_is_indirect_jump(insn);
+
+#ifdef CONFIG_RETPOLINE
+	/*
+	 * Jump to x86_indirect_thunk_* is treated as an indirect jump.
+	 * Note that even with CONFIG_RETPOLINE=y, the kernel compiled with
+	 * older gcc may use indirect jump. So we add this check instead of
+	 * replace indirect-jump check.
+	 */
+	if (!ret)
+		ret = insn_jump_into_range(insn,
+				(unsigned long)__indirect_thunk_start,
+				(unsigned long)__indirect_thunk_end -
+				(unsigned long)__indirect_thunk_start);
+#endif
+	return ret;
+}
+
 /* Decode whole function to ensure any instructions don't jump into target */
 static int can_optimize(unsigned long paddr)
 {
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 44bf5cf..d07a9390 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -693,7 +693,6 @@
 		case INTEL_FAM6_KABYLAKE_DESKTOP:
 			crystal_khz = 24000;	/* 24.0 MHz */
 			break;
-		case INTEL_FAM6_SKYLAKE_X:
 		case INTEL_FAM6_ATOM_DENVERTON:
 			crystal_khz = 25000;	/* 25.0 MHz */
 			break;
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index dbf67f6..c7194e9 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -105,6 +105,13 @@
 		SOFTIRQENTRY_TEXT
 		*(.fixup)
 		*(.gnu.warning)
+
+#ifdef CONFIG_RETPOLINE
+		__indirect_thunk_start = .;
+		*(.text.__x86.indirect_thunk)
+		__indirect_thunk_end = .;
+#endif
+
 		/* End of text section */
 		_etext = .;
 	} :text = 0x9090
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index c8f8dd8..6f5a3b0 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -4990,6 +4990,8 @@
 	bool op_prefix = false;
 	bool has_seg_override = false;
 	struct opcode opcode;
+	u16 dummy;
+	struct desc_struct desc;
 
 	ctxt->memop.type = OP_NONE;
 	ctxt->memopp = NULL;
@@ -5008,6 +5010,11 @@
 	switch (mode) {
 	case X86EMUL_MODE_REAL:
 	case X86EMUL_MODE_VM86:
+		def_op_bytes = def_ad_bytes = 2;
+		ctxt->ops->get_segment(ctxt, &dummy, &desc, NULL, VCPU_SREG_CS);
+		if (desc.d)
+			def_op_bytes = def_ad_bytes = 4;
+		break;
 	case X86EMUL_MODE_PROT16:
 		def_op_bytes = def_ad_bytes = 2;
 		break;
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 6e219e5..5f810bb 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -257,8 +257,7 @@
 		    index == RTC_GSI) {
 			if (kvm_apic_match_dest(vcpu, NULL, 0,
 			             e->fields.dest_id, e->fields.dest_mode) ||
-			    (e->fields.trig_mode == IOAPIC_EDGE_TRIG &&
-			     kvm_apic_pending_eoi(vcpu, e->fields.vector)))
+			    kvm_apic_pending_eoi(vcpu, e->fields.vector))
 				__set_bit(e->fields.vector,
 					  ioapic_handled_vectors);
 		}
@@ -279,6 +278,7 @@
 {
 	unsigned index;
 	bool mask_before, mask_after;
+	int old_remote_irr, old_delivery_status;
 	union kvm_ioapic_redirect_entry *e;
 
 	switch (ioapic->ioregsel) {
@@ -301,14 +301,28 @@
 			return;
 		e = &ioapic->redirtbl[index];
 		mask_before = e->fields.mask;
+		/* Preserve read-only fields */
+		old_remote_irr = e->fields.remote_irr;
+		old_delivery_status = e->fields.delivery_status;
 		if (ioapic->ioregsel & 1) {
 			e->bits &= 0xffffffff;
 			e->bits |= (u64) val << 32;
 		} else {
 			e->bits &= ~0xffffffffULL;
 			e->bits |= (u32) val;
-			e->fields.remote_irr = 0;
 		}
+		e->fields.remote_irr = old_remote_irr;
+		e->fields.delivery_status = old_delivery_status;
+
+		/*
+		 * Some OSes (Linux, Xen) assume that Remote IRR bit will
+		 * be cleared by IOAPIC hardware when the entry is configured
+		 * as edge-triggered. This behavior is used to simulate an
+		 * explicit EOI on IOAPICs that don't have the EOI register.
+		 */
+		if (e->fields.trig_mode == IOAPIC_EDGE_TRIG)
+			e->fields.remote_irr = 0;
+
 		mask_after = e->fields.mask;
 		if (mask_before != mask_after)
 			kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 3ca6d15..178a344 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5194,7 +5194,7 @@
 		vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 	}
 
-	vmcs_writel(GUEST_RFLAGS, 0x02);
+	kvm_set_rflags(vcpu, X86_EFLAGS_FIXED);
 	kvm_rip_write(vcpu, 0xfff0);
 
 	vmcs_writel(GUEST_GDTR_BASE, 0);
@@ -6257,7 +6257,7 @@
 		if (test_bit(KVM_REQ_EVENT, &vcpu->requests))
 			return 1;
 
-		err = emulate_instruction(vcpu, EMULTYPE_NO_REEXECUTE);
+		err = emulate_instruction(vcpu, 0);
 
 		if (err == EMULATE_USER_EXIT) {
 			++vcpu->stat.mmio_exits;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d3f80cc..e023ef9 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1751,10 +1751,13 @@
 	/* both __this_cpu_read() and rdtsc() should be on the same cpu */
 	get_cpu();
 
-	kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL,
-			   &hv_clock.tsc_shift,
-			   &hv_clock.tsc_to_system_mul);
-	ret = __pvclock_read_cycles(&hv_clock, rdtsc());
+	if (__this_cpu_read(cpu_tsc_khz)) {
+		kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL,
+				   &hv_clock.tsc_shift,
+				   &hv_clock.tsc_to_system_mul);
+		ret = __pvclock_read_cycles(&hv_clock, rdtsc());
+	} else
+		ret = ktime_get_boot_ns() + ka->kvmclock_offset;
 
 	put_cpu();
 
@@ -5308,7 +5311,7 @@
 		vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
 		vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
 		vcpu->run->internal.ndata = 0;
-		r = EMULATE_FAIL;
+		r = EMULATE_USER_EXIT;
 	}
 	kvm_queue_exception(vcpu, UD_VECTOR);
 
diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c
index 073d1f1..9758524 100644
--- a/arch/x86/lib/delay.c
+++ b/arch/x86/lib/delay.c
@@ -93,6 +93,13 @@
 {
 	u64 start, end, delay, loops = __loops;
 
+	/*
+	 * Timer value of 0 causes MWAITX to wait indefinitely, unless there
+	 * is a store on the memory monitored by MONITORX.
+	 */
+	if (loops == 0)
+		return;
+
 	start = rdtsc_ordered();
 
 	for (;;) {
diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S
index cb45c6c..dfb2ba9 100644
--- a/arch/x86/lib/retpoline.S
+++ b/arch/x86/lib/retpoline.S
@@ -9,7 +9,7 @@
 #include <asm/nospec-branch.h>
 
 .macro THUNK reg
-	.section .text.__x86.indirect_thunk.\reg
+	.section .text.__x86.indirect_thunk
 
 ENTRY(__x86_indirect_thunk_\reg)
 	CFI_STARTPROC
@@ -25,7 +25,8 @@
  * than one per register with the correct names. So we do it
  * the simple and nasty way...
  */
-#define EXPORT_THUNK(reg) EXPORT_SYMBOL(__x86_indirect_thunk_ ## reg)
+#define __EXPORT_THUNK(sym) _ASM_NOKPROBE(sym); EXPORT_SYMBOL(sym)
+#define EXPORT_THUNK(reg) __EXPORT_THUNK(__x86_indirect_thunk_ ## reg)
 #define GENERATE_THUNK(reg) THUNK reg ; EXPORT_THUNK(reg)
 
 GENERATE_THUNK(_ASM_AX)
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 8b5ff88..74dea7f 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -191,14 +191,15 @@
  * 6. T1   : reaches here, sees vma_pkey(vma)=5, when we really
  *	     faulted on a pte with its pkey=4.
  */
-static void fill_sig_info_pkey(int si_code, siginfo_t *info, u32 *pkey)
+static void fill_sig_info_pkey(int si_signo, int si_code, siginfo_t *info,
+		u32 *pkey)
 {
 	/* This is effectively an #ifdef */
 	if (!boot_cpu_has(X86_FEATURE_OSPKE))
 		return;
 
 	/* Fault not from Protection Keys: nothing to do */
-	if (si_code != SEGV_PKUERR)
+	if ((si_code != SEGV_PKUERR) || (si_signo != SIGSEGV))
 		return;
 	/*
 	 * force_sig_info_fault() is called from a number of
@@ -237,7 +238,7 @@
 		lsb = PAGE_SHIFT;
 	info.si_addr_lsb = lsb;
 
-	fill_sig_info_pkey(si_code, &info, pkey);
+	fill_sig_info_pkey(si_signo, si_code, &info, pkey);
 
 	force_sig_info(si_signo, &info, tsk);
 }
diff --git a/arch/x86/mm/kaiser.c b/arch/x86/mm/kaiser.c
index a8ade08..ec678aa 100644
--- a/arch/x86/mm/kaiser.c
+++ b/arch/x86/mm/kaiser.c
@@ -344,7 +344,7 @@
 	if (vsyscall_enabled())
 		kaiser_add_user_map_early((void *)VSYSCALL_ADDR,
 					  PAGE_SIZE,
-					   __PAGE_KERNEL_VSYSCALL);
+					  vsyscall_pgprot);
 
 	for_each_possible_cpu(cpu) {
 		void *percpu_vaddr = __per_cpu_user_mapped_start +
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 15f7436..7840331 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -278,10 +278,10 @@
 	/* if (index >= array->map.max_entries)
 	 *   goto out;
 	 */
-	EMIT4(0x48, 0x8B, 0x46,                   /* mov rax, qword ptr [rsi + 16] */
+	EMIT2(0x89, 0xD2);                        /* mov edx, edx */
+	EMIT3(0x39, 0x56,                         /* cmp dword ptr [rsi + 16], edx */
 	      offsetof(struct bpf_array, map.max_entries));
-	EMIT3(0x48, 0x39, 0xD0);                  /* cmp rax, rdx */
-#define OFFSET1 47 /* number of bytes to jump */
+#define OFFSET1 43 /* number of bytes to jump */
 	EMIT2(X86_JBE, OFFSET1);                  /* jbe out */
 	label1 = cnt;
 
@@ -290,21 +290,20 @@
 	 */
 	EMIT2_off32(0x8B, 0x85, -STACKSIZE + 36); /* mov eax, dword ptr [rbp - 516] */
 	EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT);     /* cmp eax, MAX_TAIL_CALL_CNT */
-#define OFFSET2 36
+#define OFFSET2 32
 	EMIT2(X86_JA, OFFSET2);                   /* ja out */
 	label2 = cnt;
 	EMIT3(0x83, 0xC0, 0x01);                  /* add eax, 1 */
 	EMIT2_off32(0x89, 0x85, -STACKSIZE + 36); /* mov dword ptr [rbp - 516], eax */
 
 	/* prog = array->ptrs[index]; */
-	EMIT4_off32(0x48, 0x8D, 0x84, 0xD6,       /* lea rax, [rsi + rdx * 8 + offsetof(...)] */
+	EMIT4_off32(0x48, 0x8B, 0x84, 0xD6,       /* mov rax, [rsi + rdx * 8 + offsetof(...)] */
 		    offsetof(struct bpf_array, ptrs));
-	EMIT3(0x48, 0x8B, 0x00);                  /* mov rax, qword ptr [rax] */
 
 	/* if (prog == NULL)
 	 *   goto out;
 	 */
-	EMIT4(0x48, 0x83, 0xF8, 0x00);            /* cmp rax, 0 */
+	EMIT3(0x48, 0x85, 0xC0);		  /* test rax,rax */
 #define OFFSET3 10
 	EMIT2(X86_JE, OFFSET3);                   /* je out */
 	label3 = cnt;
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 84d7148..ab0d93a 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -120,7 +120,7 @@
 
 config CRYPTO_ECDH
 	tristate "ECDH algorithm"
-	select CRYTPO_KPP
+	select CRYPTO_KPP
 	help
 	  Generic implementation of the ECDH algorithm
 
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index f5e18c2..ca50eeb 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -149,7 +149,7 @@
 
 static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	const u32 forbidden = CRYPTO_ALG_INTERNAL;
+	const u32 allowed = CRYPTO_ALG_KERN_DRIVER_ONLY;
 	struct sock *sk = sock->sk;
 	struct alg_sock *ask = alg_sk(sk);
 	struct sockaddr_alg *sa = (void *)uaddr;
@@ -157,6 +157,10 @@
 	void *private;
 	int err;
 
+	/* If caller uses non-allowed flag, return error. */
+	if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
+		return -EINVAL;
+
 	if (sock->state == SS_CONNECTED)
 		return -EINVAL;
 
@@ -175,9 +179,7 @@
 	if (IS_ERR(type))
 		return PTR_ERR(type);
 
-	private = type->bind(sa->salg_name,
-			     sa->salg_feat & ~forbidden,
-			     sa->salg_mask & ~forbidden);
+	private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
 	if (IS_ERR(private)) {
 		module_put(type->owner);
 		return PTR_ERR(private);
diff --git a/crypto/sha3_generic.c b/crypto/sha3_generic.c
index 7e8ed96..a68be62 100644
--- a/crypto/sha3_generic.c
+++ b/crypto/sha3_generic.c
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <crypto/sha3.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #define KECCAK_ROUNDS 24
 
@@ -149,7 +150,7 @@
 			unsigned int i;
 
 			for (i = 0; i < sctx->rsizw; i++)
-				sctx->st[i] ^= ((u64 *) src)[i];
+				sctx->st[i] ^= get_unaligned_le64(src + 8 * i);
 			keccakf(sctx->st);
 
 			done += sctx->rsiz;
@@ -174,7 +175,7 @@
 	sctx->buf[sctx->rsiz - 1] |= 0x80;
 
 	for (i = 0; i < sctx->rsizw; i++)
-		sctx->st[i] ^= ((u64 *) sctx->buf)[i];
+		sctx->st[i] ^= get_unaligned_le64(sctx->buf + 8 * i);
 
 	keccakf(sctx->st);
 
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 691814d..943702d 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -594,25 +594,20 @@
 void acpi_ns_terminate(void)
 {
 	acpi_status status;
+	union acpi_operand_object *prev;
+	union acpi_operand_object *next;
 
 	ACPI_FUNCTION_TRACE(ns_terminate);
 
-#ifdef ACPI_EXEC_APP
-	{
-		union acpi_operand_object *prev;
-		union acpi_operand_object *next;
+	/* Delete any module-level code blocks */
 
-		/* Delete any module-level code blocks */
-
-		next = acpi_gbl_module_code_list;
-		while (next) {
-			prev = next;
-			next = next->method.mutex;
-			prev->method.mutex = NULL;	/* Clear the Mutex (cheated) field */
-			acpi_ut_remove_reference(prev);
-		}
+	next = acpi_gbl_module_code_list;
+	while (next) {
+		prev = next;
+		next = next->method.mutex;
+		prev->method.mutex = NULL;	/* Clear the Mutex (cheated) field */
+		acpi_ut_remove_reference(prev);
 	}
-#endif
 
 	/*
 	 * Free the entire namespace -- all nodes and all objects
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index 7b2c48f..201c7ce 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -146,6 +146,10 @@
 	int count;
 	struct acpi_hardware_id *id;
 
+	/* Avoid unnecessarily loading modules for non present devices. */
+	if (!acpi_device_is_present(acpi_dev))
+		return 0;
+
 	/*
 	 * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should
 	 * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 73c9c7f..f06317d 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -99,13 +99,13 @@
 		return -ENODEV;
 
 	/*
-	 * If the device has a _HID (or _CID) returning a valid ACPI/PNP
-	 * device ID, it is better to make it look less attractive here, so that
-	 * the other device with the same _ADR value (that may not have a valid
-	 * device ID) can be matched going forward.  [This means a second spec
-	 * violation in a row, so whatever we do here is best effort anyway.]
+	 * If the device has a _HID returning a valid ACPI/PNP device ID, it is
+	 * better to make it look less attractive here, so that the other device
+	 * with the same _ADR value (that may not have a valid device ID) can be
+	 * matched going forward.  [This means a second spec violation in a row,
+	 * so whatever we do here is best effort anyway.]
 	 */
-	return sta_present && list_empty(&adev->pnp.ids) ?
+	return sta_present && !adev->pnp.type.platform_id ?
 			FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
 }
 
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 33e363d..aee3952 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4322,6 +4322,7 @@
 	 * https://bugzilla.kernel.org/show_bug.cgi?id=121671
 	 */
 	{ "LITEON CX1-JB*-HP",	NULL,		ATA_HORKAGE_MAX_SEC_1024 },
+	{ "LITEON EP1-*",	NULL,		ATA_HORKAGE_MAX_SEC_1024 },
 
 	/* Devices we expect to fail diagnostics */
 
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index 10e1b9e..f03cf1d 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -121,6 +121,7 @@
 
 config IMG_ASCII_LCD
 	tristate "Imagination Technologies ASCII LCD Display"
+	depends on HAS_IOMEM
 	default y if MIPS_MALTA || MIPS_SEAD3
 	select SYSCON
 	help
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index e9fd32e..70e13cf 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -16,6 +16,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
+#include <linux/acpi.h>
 #include <linux/bitops.h>
 #include <linux/cacheinfo.h>
 #include <linux/compiler.h>
@@ -104,9 +105,16 @@
 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
 	struct cacheinfo *this_leaf, *sib_leaf;
 	unsigned int index;
-	int ret;
+	int ret = 0;
 
-	ret = cache_setup_of_node(cpu);
+	if (this_cpu_ci->cpu_map_populated)
+		return 0;
+
+	if (of_have_populated_dt())
+		ret = cache_setup_of_node(cpu);
+	else if (!acpi_disabled)
+		/* No cache property/hierarchy support yet in ACPI */
+		ret = -ENOTSUPP;
 	if (ret)
 		return ret;
 
@@ -203,8 +211,7 @@
 	 */
 	ret = cache_shared_cpu_map_setup(cpu);
 	if (ret) {
-		pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n",
-			cpu);
+		pr_warn("Unable to detect cache hierarchy for CPU %d\n", cpu);
 		goto free_ci;
 	}
 	return 0;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 24d6cef..402254d 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1558,9 +1558,8 @@
 	return err;
 }
 
-static void lo_release(struct gendisk *disk, fmode_t mode)
+static void __lo_release(struct loop_device *lo)
 {
-	struct loop_device *lo = disk->private_data;
 	int err;
 
 	if (atomic_dec_return(&lo->lo_refcnt))
@@ -1586,6 +1585,13 @@
 	mutex_unlock(&lo->lo_ctl_mutex);
 }
 
+static void lo_release(struct gendisk *disk, fmode_t mode)
+{
+	mutex_lock(&loop_index_mutex);
+	__lo_release(disk->private_data);
+	mutex_unlock(&loop_index_mutex);
+}
+
 static const struct block_device_operations lo_fops = {
 	.owner =	THIS_MODULE,
 	.open =		lo_open,
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 1ea2053..b0d0181 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -607,7 +607,7 @@
 
 config MSM_ADSPRPC
         tristate "QTI ADSP RPC driver"
-        depends on MSM_GLINK
+        depends on MSM_GLINK || MSM_SMD
         help
           Provides a communication mechanism that allows for clients to
           make remote method invocations across processor boundary to
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 3f35d54..e5ca5ab 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -26,6 +26,7 @@
 #include <linux/msm_ion.h>
 #include <soc/qcom/secure_buffer.h>
 #include <soc/qcom/glink.h>
+#include <soc/qcom/smd.h>
 #include <soc/qcom/subsystem_notif.h>
 #include <soc/qcom/subsystem_restart.h>
 #include <soc/qcom/service-notifier.h>
@@ -198,7 +199,6 @@
 	remote_arg_t *lpra;
 	remote_arg64_t *rpra;
 	int *fds;
-	unsigned int *attrs;
 	struct fastrpc_mmap **maps;
 	struct fastrpc_buf *buf;
 	size_t used;
@@ -207,8 +207,9 @@
 	struct overlap *overs;
 	struct overlap **overps;
 	struct smq_msg msg;
-	uint32_t *crc;
 	unsigned int magic;
+	unsigned int *attrs;
+	uint32_t *crc;
 };
 
 struct fastrpc_ctx_lst {
@@ -261,6 +262,7 @@
 	struct completion workport;
 	struct notifier_block nb;
 	struct kref kref;
+	int channel;
 	int sesscount;
 	int ssrcount;
 	void *handle;
@@ -288,6 +290,8 @@
 	struct ion_client *client;
 	struct device *dev;
 	unsigned int latency;
+	bool glink;
+	bool legacy;
 };
 
 struct fastrpc_mmap {
@@ -363,6 +367,7 @@
 	int qos_request;
 	struct mutex map_mutex;
 	struct mutex fl_map_mutex;
+	int refcount;
 };
 
 static struct fastrpc_apps gfa;
@@ -371,6 +376,7 @@
 	{
 		.name = "adsprpc-smd",
 		.subsys = "adsp",
+		.channel = SMD_APPS_QDSP,
 		.link.link_info.edge = "lpass",
 		.link.link_info.transport = "smem",
 		.spd = {
@@ -385,12 +391,14 @@
 	{
 		.name = "mdsprpc-smd",
 		.subsys = "modem",
+		.channel = SMD_APPS_MODEM,
 		.link.link_info.edge = "mpss",
 		.link.link_info.transport = "smem",
 	},
 	{
 		.name = "sdsprpc-smd",
 		.subsys = "slpi",
+		.channel = SMD_APPS_DSPS,
 		.link.link_info.edge = "dsps",
 		.link.link_info.transport = "smem",
 	},
@@ -807,13 +815,24 @@
 			goto bail;
 		}
 		map->phys = sg_dma_address(map->table->sgl);
+
 		if (sess->smmu.cb) {
 			map->phys += ((uint64_t)sess->smmu.cb << 32);
 			map->size = sg_dma_len(map->table->sgl);
 		} else {
 			map->size = buf_page_size(len);
 		}
+
 		vmid = fl->apps->channel[fl->cid].vmid;
+		if (!sess->smmu.enabled && !vmid) {
+			VERIFY(err, map->phys >= me->range.addr &&
+			map->phys + map->size <=
+			me->range.addr + me->range.size);
+			if (err) {
+				pr_err("adsprpc: mmap fail out of range\n");
+				goto bail;
+			}
+		}
 		if (vmid) {
 			int srcVM[1] = {VMID_HLOS};
 			int destVM[2] = {VMID_HLOS, vmid};
@@ -1018,6 +1037,7 @@
 			 struct fastrpc_ioctl_invoke_crc *invokefd,
 			 struct smq_invoke_ctx **po)
 {
+	struct fastrpc_apps *me = &gfa;
 	int err = 0, bufs, size = 0;
 	struct smq_invoke_ctx *ctx = NULL;
 	struct fastrpc_ctx_lst *clst = &fl->clst;
@@ -1040,9 +1060,14 @@
 	ctx->maps = (struct fastrpc_mmap **)(&ctx[1]);
 	ctx->lpra = (remote_arg_t *)(&ctx->maps[bufs]);
 	ctx->fds = (int *)(&ctx->lpra[bufs]);
-	ctx->attrs = (unsigned int *)(&ctx->fds[bufs]);
-	ctx->overs = (struct overlap *)(&ctx->attrs[bufs]);
-	ctx->overps = (struct overlap **)(&ctx->overs[bufs]);
+	if (me->legacy) {
+		ctx->overs = (struct overlap *)(&ctx->fds[bufs]);
+		ctx->overps = (struct overlap **)(&ctx->overs[bufs]);
+	} else {
+		ctx->attrs = (unsigned int *)(&ctx->fds[bufs]);
+		ctx->overs = (struct overlap *)(&ctx->attrs[bufs]);
+		ctx->overps = (struct overlap **)(&ctx->overs[bufs]);
+	}
 
 	K_COPY_FROM_USER(err, kernel, (void *)ctx->lpra, invoke->pra,
 					bufs * sizeof(*ctx->lpra));
@@ -1226,6 +1251,7 @@
 
 static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
 {
+	struct fastrpc_apps *me = &gfa;
 	remote_arg64_t *rpra;
 	remote_arg_t *lpra = ctx->lpra;
 	struct smq_invoke_buf *list;
@@ -1255,10 +1281,16 @@
 		size_t len = lpra[i].buf.len;
 
 		mutex_lock(&ctx->fl->fl_map_mutex);
-		if (ctx->fds[i] && (ctx->fds[i] != -1))
+		if (ctx->fds[i] && (ctx->fds[i] != -1)) {
+			unsigned int attrs = 0;
+
+			if (ctx->attrs)
+				attrs = ctx->attrs[i];
+
 			fastrpc_mmap_create(ctx->fl, ctx->fds[i],
-					ctx->attrs[i], buf, len,
+					attrs, buf, len,
 					mflags, &ctx->maps[i]);
+		}
 		mutex_unlock(&ctx->fl->fl_map_mutex);
 		ipage += 1;
 	}
@@ -1275,8 +1307,13 @@
 		ipage += 1;
 	}
 	mutex_unlock(&ctx->fl->fl_map_mutex);
-	metalen = copylen = (size_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) +
-				 (sizeof(uint32_t) * M_CRCLIST);
+	if (!me->legacy) {
+		metalen = copylen = (size_t)&ipage[0] +
+				(sizeof(uint64_t) * M_FDLIST) +
+				(sizeof(uint32_t) * M_CRCLIST);
+	} else {
+		metalen = copylen = (size_t)&ipage[0];
+	}
 
 	/* calculate len requreed for copying */
 	for (oix = 0; oix < inbufs + outbufs; ++oix) {
@@ -1372,16 +1409,18 @@
 		pages[i].addr = map->phys;
 		pages[i].size = map->size;
 	}
-	fdlist = (uint64_t *)&pages[bufs + handles];
-	for (i = 0; i < M_FDLIST; i++)
-		fdlist[i] = 0;
-	crclist = (uint32_t *)&fdlist[M_FDLIST];
-	memset(crclist, 0, sizeof(uint32_t)*M_CRCLIST);
+	if (!me->legacy) {
+		fdlist = (uint64_t *)&pages[bufs + handles];
+		for (i = 0; i < M_FDLIST; i++)
+			fdlist[i] = 0;
+		crclist = (uint32_t *)&fdlist[M_FDLIST];
+		memset(crclist, 0, sizeof(uint32_t)*M_CRCLIST);
+	}
 
 	/* copy non ion buffers */
 	PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY),
 	rlen = copylen - metalen;
-	for (oix = 0; oix < inbufs + outbufs; ++oix) {
+	for (oix = 0; rpra && oix < inbufs + outbufs; ++oix) {
 		int i = ctx->overps[oix]->raix;
 		struct fastrpc_mmap *map = ctx->maps[i];
 		size_t mlen;
@@ -1432,7 +1471,7 @@
 		if (map && (map->attr & FASTRPC_ATTR_COHERENT))
 			continue;
 
-		if (rpra[i].buf.len && ctx->overps[oix]->mstart)
+		if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart)
 			dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv),
 			uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len));
 	}
@@ -1455,11 +1494,12 @@
 static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
 		    remote_arg_t *upra)
 {
+	struct fastrpc_apps *me = &gfa;
 	uint32_t sc = ctx->sc;
 	struct smq_invoke_buf *list;
 	struct smq_phy_page *pages;
 	struct fastrpc_mmap *mmap;
-	uint64_t *fdlist;
+	uint64_t *fdlist = NULL;
 	uint32_t *crclist = NULL;
 
 	remote_arg64_t *rpra = ctx->rpra;
@@ -1471,8 +1511,10 @@
 	handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc);
 	list = smq_invoke_buf_start(ctx->rpra, sc);
 	pages = smq_phy_page_start(sc, list);
-	fdlist = (uint64_t *)(pages + inbufs + outbufs + handles);
-	crclist = (uint32_t *)(fdlist + M_FDLIST);
+	if (!me->legacy) {
+		fdlist = (uint64_t *)(pages + inbufs + outbufs + handles);
+		crclist = (uint32_t *)(fdlist + M_FDLIST);
+	}
 
 	for (i = inbufs; i < inbufs + outbufs; ++i) {
 		if (!ctx->maps[i]) {
@@ -1490,7 +1532,7 @@
 		}
 	}
 	mutex_lock(&ctx->fl->fl_map_mutex);
-	if (inbufs + outbufs + handles) {
+	if (fdlist && (inbufs + outbufs + handles)) {
 		for (i = 0; i < M_FDLIST; i++) {
 			if (!fdlist[i])
 				break;
@@ -1590,7 +1632,7 @@
 	struct smq_msg *msg = &ctx->msg;
 	struct fastrpc_file *fl = ctx->fl;
 	struct fastrpc_channel_ctx *channel_ctx = &fl->apps->channel[fl->cid];
-	int err = 0;
+	int err = 0, len;
 
 	VERIFY(err, NULL != channel_ctx->chan);
 	if (err)
@@ -1606,22 +1648,73 @@
 	msg->invoke.header.sc = ctx->sc;
 	msg->invoke.page.addr = ctx->buf ? ctx->buf->phys : 0;
 	msg->invoke.page.size = buf_page_size(ctx->used);
-
-	if (fl->ssrcount != channel_ctx->ssrcount) {
-		err = -ECONNRESET;
-		goto bail;
-	}
-	VERIFY(err, channel_ctx->link.port_state ==
+	if (fl->apps->glink) {
+		if (fl->ssrcount != channel_ctx->ssrcount) {
+			err = -ECONNRESET;
+			goto bail;
+		}
+		VERIFY(err, channel_ctx->link.port_state ==
 			FASTRPC_LINK_CONNECTED);
-	if (err)
-		goto bail;
-	err = glink_tx(channel_ctx->chan,
-		(void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg),
-		GLINK_TX_REQ_INTENT);
+		if (err)
+			goto bail;
+		err = glink_tx(channel_ctx->chan,
+			(void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg),
+			GLINK_TX_REQ_INTENT);
+	} else {
+		spin_lock(&fl->apps->hlock);
+		len = smd_write((smd_channel_t *)
+				channel_ctx->chan,
+				msg, sizeof(*msg));
+		spin_unlock(&fl->apps->hlock);
+		VERIFY(err, len == sizeof(*msg));
+	}
  bail:
 	return err;
 }
 
+static void fastrpc_smd_read_handler(int cid)
+{
+	struct fastrpc_apps *me = &gfa;
+	struct smq_invoke_rsp rsp = {0};
+	struct smq_invoke_ctx *ctx;
+	int ret = 0, err = 0;
+
+	do {
+		ret = smd_read_from_cb(me->channel[cid].chan, &rsp,
+					sizeof(rsp));
+		if (ret != sizeof(rsp))
+			break;
+		ctx = (struct smq_invoke_ctx *)(uint64_to_ptr(rsp.ctx & ~1));
+		VERIFY(err, (ctx && ctx->magic == FASTRPC_CTX_MAGIC));
+		if (err)
+			goto bail;
+		context_notify_user(uint64_to_ptr(rsp.ctx & ~1), rsp.retval);
+	} while (ret == sizeof(rsp));
+bail:
+	if (err)
+		pr_err("adsprpc: invalid response or context\n");
+
+}
+
+static void smd_event_handler(void *priv, unsigned int event)
+{
+	struct fastrpc_apps *me = &gfa;
+	int cid = (int)(uintptr_t)priv;
+
+	switch (event) {
+	case SMD_EVENT_OPEN:
+		complete(&me->channel[cid].workport);
+		break;
+	case SMD_EVENT_CLOSE:
+		fastrpc_notify_drivers(me, cid);
+		break;
+	case SMD_EVENT_DATA:
+		fastrpc_smd_read_handler(cid);
+		break;
+	}
+}
+
+
 static void fastrpc_init(struct fastrpc_apps *me)
 {
 	int i;
@@ -1914,6 +2007,8 @@
 		if (!strcmp(proc_name, "audiopd")) {
 			fl->spdname = AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME;
 			VERIFY(err, !fastrpc_mmap_remove_pdr(fl));
+			if (err)
+				goto bail;
 		}
 
 		if (!me->staticpd_flags) {
@@ -2355,10 +2450,11 @@
 
 	ctx = container_of(kref, struct fastrpc_channel_ctx, kref);
 	cid = ctx - &gcinfo[0];
-	fastrpc_glink_close(ctx->chan, cid);
+	if (!me->glink)
+		smd_close(ctx->chan);
+	else
+		fastrpc_glink_close(ctx->chan, cid);
 	ctx->chan = NULL;
-	glink_unregister_link_state_cb(ctx->link.link_notify_handle);
-	ctx->link.link_notify_handle = NULL;
 	mutex_unlock(&me->smd_mutex);
 	pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
 						MAJOR(me->dev_no), cid);
@@ -2512,7 +2608,7 @@
 		fastrpc_mmap_free(map, 1);
 	}
 	mutex_unlock(&fl->fl_map_mutex);
-	if (fl->ssrcount == fl->apps->channel[cid].ssrcount)
+	if (fl->refcount && (fl->ssrcount == fl->apps->channel[cid].ssrcount))
 		kref_put_mutex(&fl->apps->channel[cid].kref,
 				fastrpc_channel_close, &fl->apps->smd_mutex);
 	if (fl->sctx)
@@ -2805,15 +2901,21 @@
 		}
 	}
 	fl->ssrcount = me->channel[cid].ssrcount;
+	fl->refcount = 1;
 	if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) ||
 	    (me->channel[cid].chan == NULL)) {
-		VERIFY(err, 0 == fastrpc_glink_register(cid, me));
-		if (err)
-			goto bail;
-		VERIFY(err, 0 == fastrpc_glink_open(cid));
-		if (err)
-			goto bail;
-
+		if (me->glink) {
+			VERIFY(err, 0 == fastrpc_glink_register(cid, me));
+			if (err)
+				goto bail;
+			VERIFY(err, 0 == fastrpc_glink_open(cid));
+		} else {
+		VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID,
+				gcinfo[cid].channel,
+				(smd_channel_t **)&me->channel[cid].chan,
+				(void *)(uintptr_t)cid,
+				smd_event_handler));
+		}
 		VERIFY(err,
 			 wait_for_completion_timeout(&me->channel[cid].workport,
 						RPC_TIMEOUT));
@@ -2824,13 +2926,15 @@
 		kref_init(&me->channel[cid].kref);
 		pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name,
 						MAJOR(me->dev_no), cid);
-		err = glink_queue_rx_intent(me->channel[cid].chan, NULL,
-			FASTRPC_GLINK_INTENT_LEN);
-		err |= glink_queue_rx_intent(me->channel[cid].chan, NULL,
-			FASTRPC_GLINK_INTENT_LEN);
-		if (err)
-			pr_warn("adsprpc: initial intent fail for %d err %d\n",
-					 cid, err);
+		if (me->glink) {
+			err = glink_queue_rx_intent(me->channel[cid].chan, NULL,
+				FASTRPC_GLINK_INTENT_LEN);
+			err |= glink_queue_rx_intent(me->channel[cid].chan,
+				NULL, FASTRPC_GLINK_INTENT_LEN);
+			if (err)
+				pr_warn("adsprpc: initial intent fail for %d err %d\n",
+					cid, err);
+		}
 		if (cid == 0 && me->channel[cid].ssrcount !=
 				 me->channel[cid].prevssrcount) {
 			if (fastrpc_mmap_remove_ssr(fl))
@@ -2870,8 +2974,8 @@
 	fl->cid = -1;
 	if (debugfs_file != NULL)
 		fl->debugfs_file = debugfs_file;
-	memset(&fl->perf, 0, sizeof(fl->perf));
 	fl->qos_request = 0;
+	fl->refcount = 0;
 	filp->private_data = fl;
 	mutex_init(&fl->map_mutex);
 	mutex_init(&fl->fl_map_mutex);
@@ -3153,7 +3257,10 @@
 		ctx->ssrcount++;
 		ctx->issubsystemup = 0;
 		if (ctx->chan) {
-			fastrpc_glink_close(ctx->chan, cid);
+			if (me->glink)
+				fastrpc_glink_close(ctx->chan, cid);
+			else
+				smd_close(ctx->chan);
 			ctx->chan = NULL;
 			pr_info("'restart notifier: closed /dev/%s c %d %d'\n",
 				 gcinfo[cid].name, MAJOR(me->dev_no), cid);
@@ -3243,6 +3350,8 @@
 	{ .compatible = "qcom,msm-fastrpc-adsp", },
 	{ .compatible = "qcom,msm-fastrpc-compute", },
 	{ .compatible = "qcom,msm-fastrpc-compute-cb", },
+	{ .compatible = "qcom,msm-fastrpc-legacy-compute", },
+	{ .compatible = "qcom,msm-fastrpc-legacy-compute-cb", },
 	{ .compatible = "qcom,msm-adsprpc-mem-region", },
 	{}
 };
@@ -3311,6 +3420,85 @@
 	return err;
 }
 
+static int fastrpc_cb_legacy_probe(struct device *dev)
+{
+	struct fastrpc_apps *me = &gfa;
+	struct fastrpc_channel_ctx *chan;
+	struct fastrpc_session_ctx *first_sess = NULL, *sess = NULL;
+	const char *name;
+	unsigned int *sids = NULL, sids_size = 0;
+	int err = 0, ret = 0, i;
+
+	unsigned int start = 0x80000000;
+
+	VERIFY(err, NULL != (name = of_get_property(dev->of_node,
+					 "label", NULL)));
+	if (err)
+		goto bail;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (!gcinfo[i].name)
+			continue;
+		if (!strcmp(name, gcinfo[i].name))
+			break;
+	}
+	VERIFY(err, i < NUM_CHANNELS);
+	if (err)
+		goto bail;
+
+	chan = &gcinfo[i];
+	VERIFY(err, chan->sesscount < NUM_SESSIONS);
+	if (err)
+		goto bail;
+
+	first_sess  = &chan->session[chan->sesscount];
+
+	VERIFY(err, NULL != of_get_property(dev->of_node,
+				"sids", &sids_size));
+	if (err)
+		goto bail;
+
+	VERIFY(err, NULL != (sids = kzalloc(sids_size, GFP_KERNEL)));
+	if (err)
+		goto bail;
+	ret = of_property_read_u32_array(dev->of_node, "sids", sids,
+					sids_size/sizeof(unsigned int));
+	if (ret)
+		goto bail;
+
+	VERIFY(err, !IS_ERR_OR_NULL(first_sess->smmu.mapping =
+				arm_iommu_create_mapping(&platform_bus_type,
+						start, 0x78000000)));
+	if (err)
+		goto bail;
+
+	VERIFY(err, !arm_iommu_attach_device(dev, first_sess->smmu.mapping));
+	if (err)
+		goto bail;
+
+
+	for (i = 0; i < sids_size/sizeof(unsigned int); i++) {
+		VERIFY(err, chan->sesscount < NUM_SESSIONS);
+		if (err)
+			goto bail;
+		sess = &chan->session[chan->sesscount];
+		sess->smmu.cb = sids[i];
+		sess->smmu.dev = dev;
+		sess->smmu.mapping = first_sess->smmu.mapping;
+		sess->smmu.enabled = 1;
+		sess->used = 0;
+		sess->smmu.coherent = false;
+		sess->smmu.secure = false;
+		chan->sesscount++;
+	}
+	me->legacy = 1;
+bail:
+	kfree(sids);
+	return err;
+}
+
+
+
 static void init_secure_vmid_list(struct device *dev, char *prop_name,
 						struct secure_vm *destvm)
 {
@@ -3378,6 +3566,16 @@
 		return fastrpc_cb_probe(dev);
 
 	if (of_device_is_compatible(dev->of_node,
+					"qcom,msm-fastrpc-legacy-compute")) {
+		me->glink = false;
+	}
+
+	if (of_device_is_compatible(dev->of_node,
+					"qcom,msm-fastrpc-legacy-compute-cb")){
+		return fastrpc_cb_legacy_probe(dev);
+	}
+
+	if (of_device_is_compatible(dev->of_node,
 					"qcom,msm-adsprpc-mem-region")) {
 		me->dev = dev;
 		range.addr = 0;
@@ -3399,7 +3597,8 @@
 				break;
 			}
 		}
-		if (range.addr) {
+		if (range.addr && !of_property_read_bool(dev->of_node,
+							 "restrict-access")) {
 			int srcVM[1] = {VMID_HLOS};
 			int destVM[4] = {VMID_HLOS, VMID_MSS_MSA, VMID_SSC_Q6,
 						VMID_ADSP_Q6};
@@ -3413,6 +3612,8 @@
 					srcVM, 1, destVM, destVMperm, 4));
 			if (err)
 				goto bail;
+			me->range.addr = range.addr;
+			me->range.size = range.size;
 		}
 		return 0;
 	}
@@ -3492,6 +3693,7 @@
 
 	fastrpc_init(me);
 	me->dev = NULL;
+	me->glink = true;
 	VERIFY(err, 0 == platform_driver_register(&fastrpc_driver));
 	if (err)
 		goto register_bail;
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index e309241..93c164b 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -34,4 +34,11 @@
 	  become available, this bridge driver enables DIAG traffic over MHI
 	  and SMUX.
 
+config DIAG_USES_SMD
+	bool "Enable diag internal interface over SMD"
+	depends on DIAG_CHAR && MSM_SMD
+	help
+	  Diag over SMD enables exchanging diagnostic information between
+	  application processor and peripherals over SDM.
+
 endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index b61aae8..897375e 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -3,4 +3,5 @@
 obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_hsic.o
 obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_smux.o
 obj-$(CONFIG_MSM_MHI) += diagfwd_mhi.o
+obj-$(CONFIG_DIAG_USES_SMD) += diagfwd_smd.o
 diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagfwd_glink.o diagfwd_peripheral.o diagfwd_socket.o diag_mux.o diag_memorydevice.o diag_usb.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 0aad08a..23cf293 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -865,7 +865,7 @@
 	read_len += sizeof(struct diag_ctrl_dci_status);
 
 	for (i = 0; i < header->count; i++) {
-		if (read_len > len) {
+		if (read_len > (len - 2)) {
 			pr_err("diag: In %s, Invalid length len: %d\n",
 			       __func__, len);
 			return;
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index 0a3faba..a7f29e6 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -32,6 +32,7 @@
 #include "diag_dci.h"
 #include "diag_usb.h"
 #include "diagfwd_peripheral.h"
+#include "diagfwd_smd.h"
 #include "diagfwd_socket.h"
 #include "diagfwd_glink.h"
 #include "diag_debugfs.h"
@@ -42,6 +43,7 @@
 static int diag_dbgfs_table_index;
 static int diag_dbgfs_mempool_index;
 static int diag_dbgfs_usbinfo_index;
+static int diag_dbgfs_smdinfo_index;
 static int diag_dbgfs_socketinfo_index;
 static int diag_dbgfs_glinkinfo_index;
 static int diag_dbgfs_hsicinfo_index;
@@ -479,6 +481,112 @@
 	return ret;
 }
 
+#ifdef CONFIG_DIAG_USES_SMD
+static ssize_t diag_dbgfs_read_smdinfo(struct file *file, char __user *ubuf,
+				       size_t count, loff_t *ppos)
+{
+	char *buf = NULL;
+	int ret = 0;
+	int i = 0;
+	int j = 0;
+	unsigned int buf_size;
+	unsigned int bytes_remaining = 0;
+	unsigned int bytes_written = 0;
+	unsigned int bytes_in_buffer = 0;
+	struct diag_smd_info *smd_info = NULL;
+	struct diagfwd_info *fwd_ctxt = NULL;
+
+	if (diag_dbgfs_smdinfo_index >= NUM_PERIPHERALS) {
+		/* Done. Reset to prepare for future requests */
+		diag_dbgfs_smdinfo_index = 0;
+		return 0;
+	}
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf_size = DEBUG_BUF_SIZE;
+	bytes_remaining = buf_size;
+	for (i = 0; i < NUM_TYPES; i++) {
+		for (j = 0; j < NUM_PERIPHERALS; j++) {
+			switch (i) {
+			case TYPE_DATA:
+				smd_info = &smd_data[j];
+				break;
+			case TYPE_CNTL:
+				smd_info = &smd_cntl[j];
+				break;
+			case TYPE_DCI:
+				smd_info = &smd_dci[j];
+				break;
+			case TYPE_CMD:
+				smd_info = &smd_cmd[j];
+				break;
+			case TYPE_DCI_CMD:
+				smd_info = &smd_dci_cmd[j];
+				break;
+			default:
+				return -EINVAL;
+			}
+
+			fwd_ctxt = (struct diagfwd_info *)(smd_info->fwd_ctxt);
+
+			bytes_written = scnprintf(buf+bytes_in_buffer,
+				bytes_remaining,
+				"name\t\t:\t%s\n"
+				"hdl\t\t:\t%pK\n"
+				"inited\t\t:\t%d\n"
+				"opened\t\t:\t%d\n"
+				"diag_state\t:\t%d\n"
+				"fifo size\t:\t%d\n"
+				"open pending\t:\t%d\n"
+				"close pending\t:\t%d\n"
+				"read pending\t:\t%d\n"
+				"buf_1 busy\t:\t%d\n"
+				"buf_2 busy\t:\t%d\n"
+				"bytes read\t:\t%lu\n"
+				"bytes written\t:\t%lu\n"
+				"fwd inited\t:\t%d\n"
+				"fwd opened\t:\t%d\n"
+				"fwd ch_open\t:\t%d\n\n",
+				smd_info->name,
+				smd_info->hdl,
+				smd_info->inited,
+				atomic_read(&smd_info->opened),
+				atomic_read(&smd_info->diag_state),
+				smd_info->fifo_size,
+				work_pending(&smd_info->open_work),
+				work_pending(&smd_info->close_work),
+				work_pending(&smd_info->read_work),
+				(fwd_ctxt && fwd_ctxt->buf_1) ?
+				atomic_read(&fwd_ctxt->buf_1->in_busy) : -1,
+				(fwd_ctxt && fwd_ctxt->buf_2) ?
+				atomic_read(&fwd_ctxt->buf_2->in_busy) : -1,
+				(fwd_ctxt) ? fwd_ctxt->read_bytes : 0,
+				(fwd_ctxt) ? fwd_ctxt->write_bytes : 0,
+				(fwd_ctxt) ? fwd_ctxt->inited : -1,
+				(fwd_ctxt) ?
+				atomic_read(&fwd_ctxt->opened) : -1,
+				(fwd_ctxt) ? fwd_ctxt->ch_open : -1);
+			bytes_in_buffer += bytes_written;
+
+			/* Check if there is room to add another table entry */
+			bytes_remaining = buf_size - bytes_in_buffer;
+
+			if (bytes_remaining < bytes_written)
+				break;
+		}
+	}
+	diag_dbgfs_smdinfo_index = i+1;
+	*ppos = 0;
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
+
+	kfree(buf);
+	return ret;
+}
+#endif
+
 static ssize_t diag_dbgfs_read_socketinfo(struct file *file, char __user *ubuf,
 					  size_t count, loff_t *ppos)
 {
@@ -944,6 +1052,12 @@
 	.read = diag_dbgfs_read_status,
 };
 
+#ifdef CONFIG_DIAG_USES_SMD
+static const struct file_operations diag_dbgfs_smdinfo_ops = {
+	.read = diag_dbgfs_read_smdinfo,
+};
+#endif
+
 const struct file_operations diag_dbgfs_socketinfo_ops = {
 	.read = diag_dbgfs_read_socketinfo,
 };
@@ -989,6 +1103,13 @@
 	if (!entry)
 		goto err;
 
+#ifdef CONFIG_DIAG_USES_SMD
+	entry = debugfs_create_file("smdinfo", 0444, diag_dbgfs_dent, NULL,
+				    &diag_dbgfs_smdinfo_ops);
+	if (!entry)
+		goto err;
+#endif
+
 	entry = debugfs_create_file("socketinfo", 0444, diag_dbgfs_dent, 0,
 				    &diag_dbgfs_socketinfo_ops);
 	if (!entry)
@@ -1050,6 +1171,7 @@
 	diag_dbgfs_table_index = 0;
 	diag_dbgfs_mempool_index = 0;
 	diag_dbgfs_usbinfo_index = 0;
+	diag_dbgfs_smdinfo_index = 0;
 	diag_dbgfs_socketinfo_index = 0;
 	diag_dbgfs_hsicinfo_index = 0;
 	diag_dbgfs_bridgeinfo_index = 0;
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index f510c14..223bc03 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -536,8 +536,7 @@
 }
 
 static int diag_cmd_get_ssid_range(unsigned char *src_buf, int src_len,
-				   unsigned char *dest_buf, int dest_len,
-				   struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int write_len = 0;
@@ -545,23 +544,30 @@
 	struct diag_msg_ssid_query_t rsp;
 	struct diag_ssid_range_t ssid_range;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
 
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
 	    !mask_info) {
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
-	if (!diag_apps_responds())
+	if (!diag_apps_responds()) {
+		mutex_unlock(&driver->md_session_lock);
 		return 0;
+	}
 	mutex_lock(&driver->msg_mask_lock);
 	rsp.cmd_code = DIAG_CMD_MSG_CONFIG;
 	rsp.sub_cmd = DIAG_CMD_OP_GET_SSID_RANGE;
@@ -583,12 +589,12 @@
 		write_len += sizeof(ssid_range);
 	}
 	mutex_unlock(&driver->msg_mask_lock);
+	mutex_unlock(&driver->md_session_lock);
 	return write_len;
 }
 
 static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len,
-				   unsigned char *dest_buf, int dest_len,
-				   struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i = 0;
 	int write_len = 0;
@@ -641,8 +647,7 @@
 }
 
 static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len,
-				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int write_len = 0;
@@ -651,6 +656,10 @@
 	struct diag_build_mask_req_t *req = NULL;
 	struct diag_msg_build_mask_t rsp;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -658,15 +667,19 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
-	if (!diag_apps_responds())
+	if (!diag_apps_responds()) {
+		mutex_unlock(&driver->md_session_lock);
 		return 0;
+	}
 
 	mutex_lock(&driver->msg_mask_lock);
 	req = (struct diag_build_mask_req_t *)src_buf;
@@ -681,6 +694,7 @@
 		pr_err("diag: Invalid input in %s, mask->ptr: %pK\n",
 			__func__, mask->ptr);
 		mutex_unlock(&driver->msg_mask_lock);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
@@ -700,12 +714,12 @@
 	memcpy(dest_buf, &rsp, sizeof(rsp));
 	write_len += sizeof(rsp);
 	mutex_unlock(&driver->msg_mask_lock);
+	mutex_unlock(&driver->md_session_lock);
 	return write_len;
 }
 
 static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len,
-				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	uint32_t mask_size = 0, offset = 0;
 	uint32_t *temp = NULL;
@@ -716,6 +730,10 @@
 	struct diag_msg_build_mask_t rsp;
 	struct diag_mask_info *mask_info = NULL;
 	struct diag_msg_mask_t *mask_next = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -723,11 +741,13 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -740,6 +760,7 @@
 			__func__, mask->ptr);
 		mutex_unlock(&driver->msg_mask_lock);
 		mutex_unlock(&mask_info->lock);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) {
@@ -782,6 +803,7 @@
 				mutex_unlock(&mask->lock);
 				mutex_unlock(&driver->msg_mask_lock);
 				mutex_unlock(&mask_info->lock);
+				mutex_unlock(&driver->md_session_lock);
 				return -ENOMEM;
 			}
 			mask->ptr = temp;
@@ -802,6 +824,7 @@
 	}
 	mutex_unlock(&driver->msg_mask_lock);
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(MSG_MASKS_TYPE);
 
@@ -842,8 +865,7 @@
 }
 
 static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len,
-				     unsigned char *dest_buf, int dest_len,
-				     struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i, write_len = 0, peripheral;
 	int header_len = sizeof(struct diag_msg_config_rsp_t);
@@ -851,6 +873,10 @@
 	struct diag_msg_config_rsp_t *req = NULL;
 	struct diag_msg_mask_t *mask = NULL;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &msg_mask : info->msg_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -858,11 +884,13 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -877,6 +905,7 @@
 			__func__, mask->ptr);
 		mutex_unlock(&driver->msg_mask_lock);
 		mutex_unlock(&mask_info->lock);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	mask_info->status = (req->rt_mask) ? DIAG_CTRL_MASK_ALL_ENABLED :
@@ -889,7 +918,7 @@
 	}
 	mutex_unlock(&driver->msg_mask_lock);
 	mutex_unlock(&mask_info->lock);
-
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(MSG_MASKS_TYPE);
 
@@ -923,8 +952,7 @@
 }
 
 static int diag_cmd_get_event_mask(unsigned char *src_buf, int src_len,
-				   unsigned char *dest_buf, int dest_len,
-				   struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int write_len = 0;
 	uint32_t mask_size;
@@ -959,26 +987,30 @@
 }
 
 static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len,
-				      unsigned char *dest_buf, int dest_len,
-				      struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i, write_len = 0, mask_len = 0, peripheral;
 	int header_len = sizeof(struct diag_event_mask_config_t);
 	struct diag_event_mask_config_t rsp;
 	struct diag_event_mask_config_t *req;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
 
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	mask_info = (!info) ? &event_mask : info->event_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
 	    !mask_info) {
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	req = (struct diag_event_mask_config_t *)src_buf;
@@ -986,6 +1018,7 @@
 	if (mask_len <= 0 || mask_len > event_mask.mask_len) {
 		pr_err("diag: In %s, invalid event mask len: %d\n", __func__,
 		       mask_len);
+		mutex_unlock(&driver->md_session_lock);
 		return -EIO;
 	}
 
@@ -993,6 +1026,7 @@
 	memcpy(mask_info->ptr, src_buf + header_len, mask_len);
 	mask_info->status = DIAG_CTRL_MASK_VALID;
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 
@@ -1027,25 +1061,29 @@
 }
 
 static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len,
-				  unsigned char *dest_buf, int dest_len,
-				  struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int write_len = 0, i, peripheral;
 	uint8_t toggle = 0;
 	struct diag_event_report_t header;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
 
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	mask_info = (!info) ? &event_mask : info->event_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
 	    !mask_info) {
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -1059,6 +1097,7 @@
 		memset(mask_info->ptr, 0, mask_info->mask_len);
 	}
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(EVENT_MASKS_TYPE);
 
@@ -1088,8 +1127,7 @@
 }
 
 static int diag_cmd_get_log_mask(unsigned char *src_buf, int src_len,
-				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int status = LOG_STATUS_INVALID;
@@ -1102,6 +1140,10 @@
 	struct diag_log_config_req_t *req;
 	struct diag_log_config_rsp_t rsp;
 	struct diag_mask_info *mask_info = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &log_mask : info->log_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -1109,16 +1151,20 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
-	if (!diag_apps_responds())
+	if (!diag_apps_responds()) {
+		mutex_unlock(&driver->md_session_lock);
 		return 0;
+	}
 
 	req = (struct diag_log_config_req_t *)src_buf;
 	read_len += req_header_len;
@@ -1138,6 +1184,7 @@
 	if (!log_item->ptr) {
 		pr_err("diag: Invalid input in %s, mask: %pK\n",
 			__func__, log_item);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
@@ -1179,28 +1226,27 @@
 	rsp.status = status;
 	memcpy(dest_buf, &rsp, rsp_header_len);
 
+	mutex_unlock(&driver->md_session_lock);
 	return write_len;
 }
 
 static int diag_cmd_get_log_range(unsigned char *src_buf, int src_len,
-				  unsigned char *dest_buf, int dest_len,
-				  struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	int i;
 	int write_len = 0;
 	struct diag_log_config_rsp_t rsp;
-	struct diag_mask_info *mask_info = NULL;
 	struct diag_log_mask_t *mask = (struct diag_log_mask_t *)log_mask.ptr;
 
+	if (!mask)
+		return -EINVAL;
+
 	if (!diag_apps_responds())
 		return 0;
 
-	mask_info = (!info) ? &log_mask : info->log_mask;
-	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
-	    !mask_info) {
-		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
-		       __func__, src_buf, src_len, dest_buf, dest_len,
-		       mask_info);
+	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
+		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d\n",
+		       __func__, src_buf, src_len, dest_buf, dest_len);
 		return -EINVAL;
 	}
 
@@ -1223,7 +1269,7 @@
 
 static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len,
 				 unsigned char *dest_buf, int dest_len,
-				 struct diag_md_session_t *info)
+				 int pid)
 {
 	int i, peripheral, write_len = 0;
 	int status = LOG_STATUS_SUCCESS;
@@ -1236,6 +1282,10 @@
 	struct diag_log_mask_t *mask = NULL;
 	struct diag_mask_info *mask_info = NULL;
 	unsigned char *temp_buf = NULL;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &log_mask : info->log_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -1243,11 +1293,13 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 
@@ -1257,6 +1309,7 @@
 	if (!mask->ptr) {
 		pr_err("diag: Invalid input in %s, mask->ptr: %pK\n",
 			__func__, mask->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (req->equip_id >= MAX_EQUIP_ID) {
@@ -1319,6 +1372,7 @@
 		break;
 	}
 	mutex_unlock(&mask_info->lock);
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(LOG_MASKS_TYPE);
 
@@ -1365,13 +1419,16 @@
 }
 
 static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len,
-				     unsigned char *dest_buf, int dest_len,
-				     struct diag_md_session_t *info)
+			unsigned char *dest_buf, int dest_len, int pid)
 {
 	struct diag_mask_info *mask_info = NULL;
 	struct diag_log_mask_t *mask = NULL;
 	struct diag_log_config_rsp_t header;
 	int write_len = 0, i, peripheral;
+	struct diag_md_session_t *info = NULL;
+
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 
 	mask_info = (!info) ? &log_mask : info->log_mask;
 	if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0 ||
@@ -1379,17 +1436,20 @@
 		pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d, mask_info: %pK\n",
 		       __func__, src_buf, src_len, dest_buf, dest_len,
 		       mask_info);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	if (!mask_info->ptr) {
 		pr_err("diag: In %s, invalid input mask_info->ptr: %pK\n",
 			__func__, mask_info->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	mask = (struct diag_log_mask_t *)mask_info->ptr;
 	if (!mask->ptr) {
 		pr_err("diag: Invalid input in %s, mask->ptr: %pK\n",
 			__func__, mask->ptr);
+		mutex_unlock(&driver->md_session_lock);
 		return -EINVAL;
 	}
 	for (i = 0; i < MAX_EQUIP_ID; i++, mask++) {
@@ -1398,6 +1458,7 @@
 		mutex_unlock(&mask->lock);
 	}
 	mask_info->status = DIAG_CTRL_MASK_ALL_DISABLED;
+	mutex_unlock(&driver->md_session_lock);
 	if (diag_check_update(APPS_DATA))
 		diag_update_userspace_clients(LOG_MASKS_TYPE);
 
@@ -2144,13 +2205,11 @@
 	}
 }
 
-int diag_process_apps_masks(unsigned char *buf, int len,
-			    struct diag_md_session_t *info)
+int diag_process_apps_masks(unsigned char *buf, int len, int pid)
 {
 	int size = 0, sub_cmd = 0;
 	int (*hdlr)(unsigned char *src_buf, int src_len,
-		    unsigned char *dest_buf, int dest_len,
-		    struct diag_md_session_t *info) = NULL;
+		    unsigned char *dest_buf, int dest_len, int pid) = NULL;
 
 	if (!buf || len <= 0)
 		return -EINVAL;
@@ -2200,7 +2259,7 @@
 
 	if (hdlr)
 		size = hdlr(buf, len, driver->apps_rsp_buf,
-			    DIAG_MAX_RSP_SIZE, info);
+			    DIAG_MAX_RSP_SIZE, pid);
 
 	return (size > 0) ? size : 0;
 }
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index 1a52f94..6edeee9 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -167,8 +167,7 @@
 void diag_log_mask_free(struct diag_mask_info *mask_info);
 void diag_msg_mask_free(struct diag_mask_info *mask_info);
 void diag_event_mask_free(struct diag_mask_info *mask_info);
-int diag_process_apps_masks(unsigned char *buf, int len,
-			    struct diag_md_session_t *info);
+int diag_process_apps_masks(unsigned char *buf, int len, int pid);
 void diag_send_updates_peripheral(uint8_t peripheral);
 
 extern int diag_create_msg_mask_table_entry(struct diag_msg_mask_t *msg_mask,
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index 9cecb03..ce0c7bb 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -129,11 +129,10 @@
 
 int diag_md_write(int id, unsigned char *buf, int len, int ctx)
 {
-	int i;
+	int i, peripheral, pid = 0;
 	uint8_t found = 0;
 	unsigned long flags;
 	struct diag_md_info *ch = NULL;
-	int peripheral;
 	struct diag_md_session_t *session_info = NULL;
 
 	if (id < 0 || id >= NUM_DIAG_MD_DEV || id >= DIAG_NUM_PROC)
@@ -146,10 +145,14 @@
 	if (peripheral < 0)
 		return -EINVAL;
 
-	session_info =
-		diag_md_session_get_peripheral(peripheral);
-	if (!session_info)
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_peripheral(peripheral);
+	if (!session_info) {
+		mutex_unlock(&driver->md_session_lock);
 		return -EIO;
+	}
+	pid = session_info->pid;
+	mutex_unlock(&driver->md_session_lock);
 
 	ch = &diag_md[id];
 	if (!ch)
@@ -192,8 +195,7 @@
 
 	found = 0;
 	for (i = 0; i < driver->num_clients && !found; i++) {
-		if ((driver->client_map[i].pid !=
-		     session_info->pid) ||
+		if ((driver->client_map[i].pid != pid) ||
 		    (driver->client_map[i].pid == 0))
 			continue;
 
diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c
index 1cf7f52..060f03f 100644
--- a/drivers/char/diag/diag_usb.c
+++ b/drivers/char/diag/diag_usb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -221,7 +221,7 @@
 
 	if (!atomic_read(&ch->connected) &&
 		driver->usb_connected && diag_mask_param())
-		diag_clear_masks(NULL);
+		diag_clear_masks(0);
 
 	if (ch && ch->ops && ch->ops->close)
 		ch->ops->close(ch->ctxt, DIAG_USB_MODE);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9de40b0..badd12c 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -22,6 +22,7 @@
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/device.h>
+#include <soc/qcom/smd.h>
 #include <linux/atomic.h>
 #include "diagfwd_bridge.h"
 
@@ -714,7 +715,7 @@
 void diag_cmd_remove_reg_by_proc(int proc);
 int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
 int diag_mask_param(void);
-void diag_clear_masks(struct diag_md_session_t *info);
+void diag_clear_masks(int pid);
 uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask);
 int diag_query_pd(char *process_name);
 int diag_search_peripheral_by_pd(uint8_t pd_val);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0158549..6e1674b 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -167,7 +167,7 @@
 void *diag_ipc_log;
 #endif
 
-static void diag_md_session_close(struct diag_md_session_t *session_info);
+static void diag_md_session_close(int pid);
 
 /*
  * Returns the next delayed rsp id. If wrapping is enabled,
@@ -243,12 +243,13 @@
 
 	timer_in_progress = 0;
 	mutex_lock(&apps_data_mutex);
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (!hdlc_disabled)
 		diag_drain_apps_data(&hdlc_data);
 	else
@@ -374,8 +375,8 @@
 	return -ENOMEM;
 
 fail:
-	mutex_unlock(&driver->diagchar_mutex);
 	driver->num_clients--;
+	mutex_unlock(&driver->diagchar_mutex);
 	pr_err_ratelimited("diag: Insufficient memory for new client");
 	return -ENOMEM;
 }
@@ -422,7 +423,7 @@
 {
 	return diag_mask_clear_param;
 }
-void diag_clear_masks(struct diag_md_session_t *info)
+void diag_clear_masks(int pid)
 {
 	int ret;
 	char cmd_disable_log_mask[] = { 0x73, 0, 0, 0, 0, 0, 0, 0};
@@ -431,14 +432,14 @@
 
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
 	"diag: %s: masks clear request upon %s\n", __func__,
-	((info) ? "ODL exit" : "USB Disconnection"));
+	((pid) ? "ODL exit" : "USB Disconnection"));
 
 	ret = diag_process_apps_masks(cmd_disable_log_mask,
-			sizeof(cmd_disable_log_mask), info);
+			sizeof(cmd_disable_log_mask), pid);
 	ret = diag_process_apps_masks(cmd_disable_msg_mask,
-			sizeof(cmd_disable_msg_mask), info);
+			sizeof(cmd_disable_msg_mask), pid);
 	ret = diag_process_apps_masks(cmd_disable_event_mask,
-			sizeof(cmd_disable_event_mask), info);
+			sizeof(cmd_disable_event_mask), pid);
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
 	"diag:%s: masks cleared successfully\n", __func__);
 }
@@ -451,21 +452,23 @@
 	struct diag_md_session_t *session_info = NULL;
 	struct diag_logging_mode_param_t params;
 
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_pid(pid);
-	if (!session_info)
+	if (!session_info) {
+		mutex_unlock(&driver->md_session_lock);
 		return;
+	}
+	session_mask = session_info->peripheral_mask;
+	mutex_unlock(&driver->md_session_lock);
 
 	if (diag_mask_clear_param)
-		diag_clear_masks(session_info);
+		diag_clear_masks(pid);
 
 	mutex_lock(&driver->diag_maskclear_mutex);
 	driver->mask_clear = 1;
 	mutex_unlock(&driver->diag_maskclear_mutex);
 
 	mutex_lock(&driver->diagchar_mutex);
-	session_mask = session_info->peripheral_mask;
-	diag_md_session_close(session_info);
-
 	p_mask =
 	diag_translate_kernel_to_user_mask(session_mask);
 
@@ -489,7 +492,9 @@
 			}
 		}
 	}
-
+	mutex_lock(&driver->md_session_lock);
+	diag_md_session_close(pid);
+	mutex_unlock(&driver->md_session_lock);
 	diag_switch_logging(&params);
 	mutex_unlock(&driver->diagchar_mutex);
 }
@@ -1024,11 +1029,13 @@
 
 	if (driver->hdlc_encode_buf_len != 0)
 		return -EAGAIN;
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled) {
 		if (len < 4) {
 			pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
@@ -1386,15 +1393,16 @@
 	return err;
 }
 
-static void diag_md_session_close(struct diag_md_session_t *session_info)
+static void diag_md_session_close(int pid)
 {
 	int i;
 	uint8_t found = 0;
+	struct diag_md_session_t *session_info = NULL;
 
+	session_info = diag_md_session_get_pid(pid);
 	if (!session_info)
 		return;
 
-	mutex_lock(&driver->md_session_lock);
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		if (driver->md_session_map[i] != session_info)
 			continue;
@@ -1420,13 +1428,14 @@
 	driver->md_session_mode = (found) ? DIAG_MD_PERIPHERAL : DIAG_MD_NONE;
 	kfree(session_info);
 	session_info = NULL;
-	mutex_unlock(&driver->md_session_lock);
 	DIAG_LOG(DIAG_DEBUG_USERSPACE, "cleared up session\n");
 }
 
 struct diag_md_session_t *diag_md_session_get_pid(int pid)
 {
 	int i;
+	if (pid <= 0)
+		return NULL;
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		if (driver->md_session_map[i] &&
 		    driver->md_session_map[i]->pid == pid)
@@ -1442,10 +1451,12 @@
 	return driver->md_session_map[peripheral];
 }
 
-static int diag_md_peripheral_switch(struct diag_md_session_t *session_info,
+static int diag_md_peripheral_switch(int pid,
 				int peripheral_mask, int req_mode) {
 	int i, bit = 0;
+	struct diag_md_session_t *session_info = NULL;
 
+	session_info = diag_md_session_get_pid(pid);
 	if (!session_info)
 		return -EINVAL;
 	if (req_mode != DIAG_USB_MODE || req_mode != DIAG_MEMORY_DEVICE_MODE)
@@ -1455,25 +1466,20 @@
 	 * check that md_session_map for i == session_info,
 	 * if not then race condition occurred and bail
 	 */
-	mutex_lock(&driver->md_session_lock);
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		bit = MD_PERIPHERAL_MASK(i) & peripheral_mask;
 		if (!bit)
 			continue;
 		if (req_mode == DIAG_USB_MODE) {
-			if (driver->md_session_map[i] != session_info) {
-				mutex_unlock(&driver->md_session_lock);
+			if (driver->md_session_map[i] != session_info)
 				return -EINVAL;
-			}
 			driver->md_session_map[i] = NULL;
 			driver->md_session_mask &= ~bit;
 			session_info->peripheral_mask &= ~bit;
 
 		} else {
-			if (driver->md_session_map[i] != NULL) {
-				mutex_unlock(&driver->md_session_lock);
+			if (driver->md_session_map[i] != NULL)
 				return -EINVAL;
-			}
 			driver->md_session_map[i] = session_info;
 			driver->md_session_mask |= bit;
 			session_info->peripheral_mask |= bit;
@@ -1482,7 +1488,6 @@
 	}
 
 	driver->md_session_mode = DIAG_MD_PERIPHERAL;
-	mutex_unlock(&driver->md_session_lock);
 	DIAG_LOG(DIAG_DEBUG_USERSPACE, "Changed Peripherals:0x%x to mode:%d\n",
 		peripheral_mask, req_mode);
 }
@@ -1491,7 +1496,7 @@
 				 const struct diag_logging_mode_param_t *param,
 				 uint8_t *change_mode)
 {
-	int i, bit = 0, err = 0;
+	int i, bit = 0, err = 0, peripheral_mask = 0;
 	int change_mask = 0;
 	struct diag_md_session_t *session_info = NULL;
 
@@ -1515,12 +1520,13 @@
 	if (req_mode == DIAG_USB_MODE) {
 		if (curr_mode == DIAG_USB_MODE)
 			return 0;
+		mutex_lock(&driver->md_session_lock);
 		if (driver->md_session_mode == DIAG_MD_NONE
 		    && driver->md_session_mask == 0 && driver->logging_mask) {
 			*change_mode = 1;
+			mutex_unlock(&driver->md_session_lock);
 			return 0;
 		}
-
 		/*
 		 * curr_mode is either DIAG_MULTI_MODE or DIAG_MD_MODE
 		 * Check if requested peripherals are already in usb mode
@@ -1532,8 +1538,10 @@
 			if (bit & driver->logging_mask)
 				change_mask |= bit;
 		}
-		if (!change_mask)
+		if (!change_mask) {
+			mutex_unlock(&driver->md_session_lock);
 			return 0;
+		}
 
 		/*
 		 * Change is needed. Check if this md_session has set all the
@@ -1542,29 +1550,29 @@
 		 * If this session owns all the requested peripherals, then
 		 * call function to switch the modes/masks for the md_session
 		 */
-		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
-
 		if (!session_info) {
 			*change_mode = 1;
+			mutex_unlock(&driver->md_session_lock);
 			return 0;
 		}
-		if ((change_mask & session_info->peripheral_mask)
+		peripheral_mask = session_info->peripheral_mask;
+		if ((change_mask & peripheral_mask)
 							!= change_mask) {
 			DIAG_LOG(DIAG_DEBUG_USERSPACE,
 			    "Another MD Session owns a requested peripheral\n");
+			mutex_unlock(&driver->md_session_lock);
 			return -EINVAL;
 		}
 		*change_mode = 1;
 
 		/* If all peripherals are being set to USB Mode, call close */
-		if (~change_mask & session_info->peripheral_mask) {
-			err = diag_md_peripheral_switch(session_info,
+		if (~change_mask & peripheral_mask) {
+			err = diag_md_peripheral_switch(current->tgid,
 					change_mask, DIAG_USB_MODE);
 		} else
-			diag_md_session_close(session_info);
-
+			diag_md_session_close(current->tgid);
+		mutex_unlock(&driver->md_session_lock);
 		return err;
 
 	} else if (req_mode == DIAG_MEMORY_DEVICE_MODE) {
@@ -1573,21 +1581,23 @@
 		 * been set. Check that requested peripherals already set are
 		 * owned by this md session
 		 */
-		change_mask = driver->md_session_mask & param->peripheral_mask;
 		mutex_lock(&driver->md_session_lock);
+		change_mask = driver->md_session_mask & param->peripheral_mask;
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 
 		if (session_info) {
 			if ((session_info->peripheral_mask & change_mask)
 							!= change_mask) {
 				DIAG_LOG(DIAG_DEBUG_USERSPACE,
 				    "Another MD Session owns a requested peripheral\n");
+				mutex_unlock(&driver->md_session_lock);
 				return -EINVAL;
 			}
-			err = diag_md_peripheral_switch(session_info,
+			err = diag_md_peripheral_switch(current->tgid,
 					change_mask, DIAG_USB_MODE);
+			mutex_unlock(&driver->md_session_lock);
 		} else {
+			mutex_unlock(&driver->md_session_lock);
 			if (change_mask) {
 				DIAG_LOG(DIAG_DEBUG_USERSPACE,
 				    "Another MD Session owns a requested peripheral\n");
@@ -2047,19 +2057,17 @@
 {
 	uint8_t hdlc_support;
 	struct diag_md_session_t *session_info = NULL;
-	mutex_lock(&driver->md_session_lock);
-	session_info = diag_md_session_get_pid(current->tgid);
-	mutex_unlock(&driver->md_session_lock);
 	if (copy_from_user(&hdlc_support, (void __user *)ioarg,
 				sizeof(uint8_t)))
 		return -EFAULT;
 	mutex_lock(&driver->hdlc_disable_mutex);
-	if (session_info) {
-		mutex_lock(&driver->md_session_lock);
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_pid(current->tgid);
+	if (session_info)
 		session_info->hdlc_disabled = hdlc_support;
-		mutex_unlock(&driver->md_session_lock);
-	} else
+	else
 		driver->hdlc_disabled = hdlc_support;
+	mutex_unlock(&driver->md_session_lock);
 	mutex_unlock(&driver->hdlc_disable_mutex);
 	diag_update_md_clients(HDLC_SUPPORT_TYPE);
 
@@ -2885,7 +2893,6 @@
 	int remote_proc = 0;
 	const int mempool = POOL_TYPE_COPY;
 	unsigned char *user_space_data = NULL;
-	struct diag_md_session_t *info = NULL;
 
 	if (!buf || len <= 0 || len > CALLBACK_BUF_SIZE) {
 		pr_err_ratelimited("diag: In %s, invalid buf %pK len: %d\n",
@@ -2936,13 +2943,11 @@
 	} else {
 		wait_event_interruptible(driver->wait_q,
 					 (driver->in_busy_pktdata == 0));
-		mutex_lock(&driver->md_session_lock);
-		info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
-		ret = diag_process_apps_pkt(user_space_data, len, info);
+		ret = diag_process_apps_pkt(user_space_data, len,
+			current->tgid);
 		if (ret == 1)
 			diag_send_error_rsp((void *)(user_space_data), len,
-						info);
+						current->tgid);
 	}
 fail:
 	diagmem_free(driver, user_space_data, mempool);
@@ -3008,24 +3013,25 @@
 	if (!remote_proc) {
 		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 		if (!session_info) {
 			pr_err("diag:In %s request came from invalid md session pid:%d",
 				__func__, current->tgid);
+			mutex_unlock(&driver->md_session_lock);
 			return -EINVAL;
 		}
 		if (session_info)
 			hdlc_disabled = session_info->hdlc_disabled;
 		else
 			hdlc_disabled = driver->hdlc_disabled;
+		mutex_unlock(&driver->md_session_lock);
 		if (!hdlc_disabled)
 			diag_process_hdlc_pkt((void *)
 				(driver->user_space_data_buf),
-				len, session_info);
+				len, current->tgid);
 		else
 			diag_process_non_hdlc_pkt((char *)
 						(driver->user_space_data_buf),
-						len, session_info);
+						len, current->tgid);
 		return 0;
 	}
 
@@ -3102,11 +3108,13 @@
 
 	mutex_lock(&apps_data_mutex);
 	mutex_lock(&driver->hdlc_disable_mutex);
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled)
 		ret = diag_process_apps_data_non_hdlc(user_space_data, len,
 						      pkt_type);
@@ -3177,9 +3185,9 @@
 		ret += sizeof(int);
 		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 		exit_stat = diag_md_copy_to_user(buf, &ret, count,
 						 session_info);
+		mutex_unlock(&driver->md_session_lock);
 		goto exit;
 	} else if (driver->data_ready[index] & USER_SPACE_DATA_TYPE) {
 		/* In case, the thread wakes up and the logging mode is not
@@ -3199,14 +3207,16 @@
 
 		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_pid(current->tgid);
-		mutex_unlock(&driver->md_session_lock);
 		if (session_info) {
 			COPY_USER_SPACE_OR_ERR(buf+4,
 					session_info->hdlc_disabled,
 					sizeof(uint8_t));
-			if (ret == -EFAULT)
+			if (ret == -EFAULT) {
+				mutex_unlock(&driver->md_session_lock);
 				goto exit;
+			}
 		}
+		mutex_unlock(&driver->md_session_lock);
 		goto exit;
 	}
 
@@ -3226,12 +3236,16 @@
 	if (driver->data_ready[index] & MSG_MASKS_TYPE) {
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & MSG_MASKS_TYPE;
+		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_peripheral(APPS_DATA);
 		COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
-		if (ret == -EFAULT)
+		if (ret == -EFAULT) {
+			mutex_unlock(&driver->md_session_lock);
 			goto exit;
+		}
 		write_len = diag_copy_to_user_msg_mask(buf + ret, count,
 						       session_info);
+		mutex_unlock(&driver->md_session_lock);
 		if (write_len > 0)
 			ret += write_len;
 		driver->data_ready[index] ^= MSG_MASKS_TYPE;
@@ -3242,25 +3256,32 @@
 	if (driver->data_ready[index] & EVENT_MASKS_TYPE) {
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & EVENT_MASKS_TYPE;
+		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_peripheral(APPS_DATA);
 		COPY_USER_SPACE_OR_ERR(buf, data_type, 4);
-		if (ret == -EFAULT)
+		if (ret == -EFAULT) {
+			mutex_unlock(&driver->md_session_lock);
 			goto exit;
-
+		}
 		if (session_info && session_info->event_mask &&
 		    session_info->event_mask->ptr) {
 			COPY_USER_SPACE_OR_ERR(buf + sizeof(int),
 					*(session_info->event_mask->ptr),
 					session_info->event_mask->mask_len);
-			if (ret == -EFAULT)
+			if (ret == -EFAULT) {
+				mutex_unlock(&driver->md_session_lock);
 				goto exit;
+			}
 		} else {
 			COPY_USER_SPACE_OR_ERR(buf + sizeof(int),
 						*(event_mask.ptr),
 						event_mask.mask_len);
-			if (ret == -EFAULT)
+			if (ret == -EFAULT) {
+				mutex_unlock(&driver->md_session_lock);
 				goto exit;
+			}
 		}
+		mutex_unlock(&driver->md_session_lock);
 		driver->data_ready[index] ^= EVENT_MASKS_TYPE;
 		atomic_dec(&driver->data_ready_notif[index]);
 		goto exit;
@@ -3269,13 +3290,17 @@
 	if (driver->data_ready[index] & LOG_MASKS_TYPE) {
 		/*Copy the type of data being passed*/
 		data_type = driver->data_ready[index] & LOG_MASKS_TYPE;
+		mutex_lock(&driver->md_session_lock);
 		session_info = diag_md_session_get_peripheral(APPS_DATA);
 		COPY_USER_SPACE_OR_ERR(buf, data_type, sizeof(int));
-		if (ret == -EFAULT)
+		if (ret == -EFAULT) {
+			mutex_unlock(&driver->md_session_lock);
 			goto exit;
+		}
 
 		write_len = diag_copy_to_user_log_mask(buf + ret, count,
 						       session_info);
+		mutex_unlock(&driver->md_session_lock);
 		if (write_len > 0)
 			ret += write_len;
 		driver->data_ready[index] ^= LOG_MASKS_TYPE;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 1155087..33048e1 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -242,7 +242,7 @@
 }
 
 static void pack_rsp_and_send(unsigned char *buf, int len,
-				struct diag_md_session_t *info)
+				int pid)
 {
 	int err;
 	int retry_count = 0, i, rsp_ctxt;
@@ -250,6 +250,7 @@
 	unsigned long flags;
 	unsigned char *rsp_ptr = driver->encoded_rsp_buf;
 	struct diag_pkt_frame_t header;
+	struct diag_md_session_t *session_info = NULL, *info = NULL;
 
 	if (!rsp_ptr || !buf)
 		return;
@@ -260,6 +261,11 @@
 		return;
 	}
 
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_pid(pid);
+	info = (session_info) ? session_info :
+				diag_md_session_get_peripheral(APPS_DATA);
+
 	/*
 	 * Explicitly check for the Peripheral Modem here
 	 * is necessary till a way to identify a peripheral
@@ -279,6 +285,7 @@
 		}
 	} else
 		rsp_ctxt = driver->rsp_buf_ctxt;
+	mutex_unlock(&driver->md_session_lock);
 
 	/*
 	 * Keep trying till we get the buffer back. It should probably
@@ -302,8 +309,11 @@
 		 * draining responses when we are in Memory Device Mode.
 		 */
 		if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
-				driver->logging_mode == DIAG_MULTI_MODE)
+				driver->logging_mode == DIAG_MULTI_MODE) {
+			mutex_lock(&driver->md_session_lock);
 			chk_logging_wakeup();
+			mutex_unlock(&driver->md_session_lock);
+		}
 	}
 	if (driver->rsp_buf_busy) {
 		pr_err("diag: unable to get hold of response buffer\n");
@@ -332,13 +342,14 @@
 }
 
 static void encode_rsp_and_send(unsigned char *buf, int len,
-				struct diag_md_session_t *info)
+				int pid)
 {
 	struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 	struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
 	unsigned char *rsp_ptr = driver->encoded_rsp_buf;
 	int err, i, rsp_ctxt, retry_count = 0;
 	unsigned long flags;
+	struct diag_md_session_t *session_info = NULL, *info = NULL;
 
 	if (!rsp_ptr || !buf)
 		return;
@@ -349,6 +360,11 @@
 		return;
 	}
 
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_pid(pid);
+	info = (session_info) ? session_info :
+				diag_md_session_get_peripheral(APPS_DATA);
+
 	/*
 	 * Explicitly check for the Peripheral Modem here
 	 * is necessary till a way to identify a peripheral
@@ -368,7 +384,7 @@
 		}
 	} else
 		rsp_ctxt = driver->rsp_buf_ctxt;
-
+	mutex_unlock(&driver->md_session_lock);
 	/*
 	 * Keep trying till we get the buffer back. It should probably
 	 * take one or two iterations. When this loops till UINT_MAX, it
@@ -391,8 +407,11 @@
 		 * draining responses when we are in Memory Device Mode.
 		 */
 		if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
-				driver->logging_mode == DIAG_MULTI_MODE)
+				driver->logging_mode == DIAG_MULTI_MODE) {
+			mutex_lock(&driver->md_session_lock);
 			chk_logging_wakeup();
+			mutex_unlock(&driver->md_session_lock);
+		}
 	}
 
 	if (driver->rsp_buf_busy) {
@@ -424,22 +443,23 @@
 }
 
 static void diag_send_rsp(unsigned char *buf, int len,
-	struct diag_md_session_t *info)
+	int pid)
 {
-	struct diag_md_session_t *session_info = NULL;
+	struct diag_md_session_t *session_info = NULL, *info = NULL;
 	uint8_t hdlc_disabled;
-
+	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	session_info = (info) ? info :
 				diag_md_session_get_peripheral(APPS_DATA);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled)
-		pack_rsp_and_send(buf, len, session_info);
+		pack_rsp_and_send(buf, len, pid);
 	else
-		encode_rsp_and_send(buf, len, session_info);
+		encode_rsp_and_send(buf, len, pid);
 }
 
 void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type)
@@ -506,13 +526,14 @@
 	int i, j;
 
 	mutex_lock(&driver->diagchar_mutex);
+	mutex_lock(&driver->md_session_lock);
 	for (i = 0; i < NUM_MD_SESSIONS; i++) {
 		if (driver->md_session_map[i] != NULL)
 			for (j = 0; j < driver->num_clients; j++) {
 				if (driver->client_map[j].pid != 0 &&
 					driver->client_map[j].pid ==
 					driver->md_session_map[i]->pid) {
-					if (!(driver->data_ready[i] & type)) {
+					if (!(driver->data_ready[j] & type)) {
 						driver->data_ready[j] |= type;
 						atomic_inc(
 						&driver->data_ready_notif[j]);
@@ -521,6 +542,7 @@
 				}
 			}
 	}
+	mutex_unlock(&driver->md_session_lock);
 	wake_up_interruptible(&driver->wait_q);
 	mutex_unlock(&driver->diagchar_mutex);
 }
@@ -982,7 +1004,7 @@
 }
 
 void diag_send_error_rsp(unsigned char *buf, int len,
-			struct diag_md_session_t *info)
+			int pid)
 {
 	/* -1 to accommodate the first byte 0x13 */
 	if (len > (DIAG_MAX_RSP_SIZE - 1)) {
@@ -992,13 +1014,12 @@
 
 	*(uint8_t *)driver->apps_rsp_buf = DIAG_CMD_ERROR;
 	memcpy((driver->apps_rsp_buf + sizeof(uint8_t)), buf, len);
-	diag_send_rsp(driver->apps_rsp_buf, len + 1, info);
+	diag_send_rsp(driver->apps_rsp_buf, len + 1, pid);
 }
 
-int diag_process_apps_pkt(unsigned char *buf, int len,
-			struct diag_md_session_t *info)
+int diag_process_apps_pkt(unsigned char *buf, int len, int pid)
 {
-	int i;
+	int i, p_mask = 0;
 	int mask_ret;
 	int write_len = 0;
 	unsigned char *temp = NULL;
@@ -1007,14 +1028,15 @@
 	struct diag_cmd_reg_t *reg_item = NULL;
 	struct diagfwd_info *fwd_info = NULL;
 	uint32_t pd_mask = 0;
+	struct diag_md_session_t *info = NULL;
 
 	if (!buf)
 		return -EIO;
 
 	/* Check if the command is a supported mask command */
-	mask_ret = diag_process_apps_masks(buf, len, info);
+	mask_ret = diag_process_apps_masks(buf, len, pid);
 	if (mask_ret > 0) {
-		diag_send_rsp(driver->apps_rsp_buf, mask_ret, info);
+		diag_send_rsp(driver->apps_rsp_buf, mask_ret, pid);
 		return 0;
 	}
 
@@ -1036,7 +1058,7 @@
 						   driver->apps_rsp_buf,
 						   DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 
@@ -1045,18 +1067,22 @@
 	if (temp_entry) {
 		reg_item = container_of(temp_entry, struct diag_cmd_reg_t,
 					entry);
+		mutex_lock(&driver->md_session_lock);
+		info = diag_md_session_get_pid(pid);
 		if (info) {
+			p_mask = info->peripheral_mask;
+			mutex_unlock(&driver->md_session_lock);
 			MD_PERIPHERAL_PD_MASK(TYPE_CMD, reg_item->proc,
 				pd_mask);
 			if ((MD_PERIPHERAL_MASK(reg_item->proc) &
-				info->peripheral_mask) ||
-				(pd_mask & info->peripheral_mask))
+				p_mask) || (pd_mask & p_mask))
 				write_len = diag_send_data(reg_item, buf, len);
 		} else {
+			mutex_unlock(&driver->md_session_lock);
 			if (MD_PERIPHERAL_MASK(reg_item->proc) &
 				driver->logging_mask) {
 				mutex_unlock(&driver->cmd_reg_mutex);
-				diag_send_error_rsp(buf, len, info);
+				diag_send_error_rsp(buf, len, pid);
 				return write_len;
 			}
 			else
@@ -1074,13 +1100,13 @@
 		for (i = 0; i < 4; i++)
 			*(driver->apps_rsp_buf+i) = *(buf+i);
 		*(uint32_t *)(driver->apps_rsp_buf+4) = DIAG_MAX_REQ_SIZE;
-		diag_send_rsp(driver->apps_rsp_buf, 8, info);
+		diag_send_rsp(driver->apps_rsp_buf, 8, pid);
 		return 0;
 	} else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
 		(*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) {
 		len = diag_process_stm_cmd(buf, driver->apps_rsp_buf);
 		if (len > 0) {
-			diag_send_rsp(driver->apps_rsp_buf, len, info);
+			diag_send_rsp(driver->apps_rsp_buf, len, pid);
 			return 0;
 		}
 		return len;
@@ -1093,7 +1119,7 @@
 							driver->apps_rsp_buf,
 							DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	/* Check for time sync switch command */
@@ -1104,7 +1130,7 @@
 							driver->apps_rsp_buf,
 							DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	/* Check for diag id command */
@@ -1115,14 +1141,14 @@
 							driver->apps_rsp_buf,
 							DIAG_MAX_RSP_SIZE);
 		if (write_len > 0)
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	/* Check for download command */
 	else if ((chk_apps_master()) && (*buf == 0x3A)) {
 		/* send response back */
 		driver->apps_rsp_buf[0] = *buf;
-		diag_send_rsp(driver->apps_rsp_buf, 1, info);
+		diag_send_rsp(driver->apps_rsp_buf, 1, pid);
 		msleep(5000);
 		/* call download API */
 		msm_set_restart_mode(RESTART_DLOAD);
@@ -1142,7 +1168,7 @@
 			for (i = 0; i < 13; i++)
 				driver->apps_rsp_buf[i+3] = 0;
 
-			diag_send_rsp(driver->apps_rsp_buf, 16, info);
+			diag_send_rsp(driver->apps_rsp_buf, 16, pid);
 			return 0;
 		}
 	}
@@ -1151,7 +1177,7 @@
 		(*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
 		memcpy(driver->apps_rsp_buf, buf, 4);
 		driver->apps_rsp_buf[4] = wrap_enabled;
-		diag_send_rsp(driver->apps_rsp_buf, 5, info);
+		diag_send_rsp(driver->apps_rsp_buf, 5, pid);
 		return 0;
 	}
 	/* Wrap the Delayed Rsp ID */
@@ -1160,7 +1186,7 @@
 		wrap_enabled = true;
 		memcpy(driver->apps_rsp_buf, buf, 4);
 		driver->apps_rsp_buf[4] = wrap_count;
-		diag_send_rsp(driver->apps_rsp_buf, 6, info);
+		diag_send_rsp(driver->apps_rsp_buf, 6, pid);
 		return 0;
 	}
 	/* Mobile ID Rsp */
@@ -1171,7 +1197,7 @@
 						   driver->apps_rsp_buf,
 						   DIAG_MAX_RSP_SIZE);
 		if (write_len > 0) {
-			diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+			diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 			return 0;
 		}
 	}
@@ -1191,7 +1217,7 @@
 			for (i = 0; i < 55; i++)
 				driver->apps_rsp_buf[i] = 0;
 
-			diag_send_rsp(driver->apps_rsp_buf, 55, info);
+			diag_send_rsp(driver->apps_rsp_buf, 55, pid);
 			return 0;
 		}
 		/* respond to 0x7c command */
@@ -1204,14 +1230,14 @@
 							 chk_config_get_id();
 			*(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
 			*(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
-			diag_send_rsp(driver->apps_rsp_buf, 14, info);
+			diag_send_rsp(driver->apps_rsp_buf, 14, pid);
 			return 0;
 		}
 	}
 	write_len = diag_cmd_chk_stats(buf, len, driver->apps_rsp_buf,
 				       DIAG_MAX_RSP_SIZE);
 	if (write_len > 0) {
-		diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+		diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		return 0;
 	}
 	write_len = diag_cmd_disable_hdlc(buf, len, driver->apps_rsp_buf,
@@ -1223,7 +1249,7 @@
 		 * before disabling HDLC encoding on Apps processor.
 		 */
 		mutex_lock(&driver->hdlc_disable_mutex);
-		diag_send_rsp(driver->apps_rsp_buf, write_len, info);
+		diag_send_rsp(driver->apps_rsp_buf, write_len, pid);
 		/*
 		 * Set the value of hdlc_disabled after sending the response to
 		 * the tools. This is required since the tools is expecting a
@@ -1231,10 +1257,13 @@
 		 */
 		pr_debug("diag: In %s, disabling HDLC encoding\n",
 		       __func__);
+		mutex_lock(&driver->md_session_lock);
+		info = diag_md_session_get_pid(pid);
 		if (info)
 			info->hdlc_disabled = 1;
 		else
 			driver->hdlc_disabled = 1;
+		mutex_unlock(&driver->md_session_lock);
 		diag_update_md_clients(HDLC_SUPPORT_TYPE);
 		mutex_unlock(&driver->hdlc_disable_mutex);
 		return 0;
@@ -1243,13 +1272,12 @@
 
 	/* We have now come to the end of the function. */
 	if (chk_apps_only())
-		diag_send_error_rsp(buf, len, info);
+		diag_send_error_rsp(buf, len, pid);
 
 	return 0;
 }
 
-void diag_process_hdlc_pkt(void *data, unsigned int len,
-			   struct diag_md_session_t *info)
+void diag_process_hdlc_pkt(void *data, unsigned int len, int pid)
 {
 	int err = 0;
 	int ret = 0;
@@ -1309,7 +1337,7 @@
 		}
 
 		err = diag_process_apps_pkt(driver->hdlc_buf,
-					    driver->hdlc_buf_len, info);
+					    driver->hdlc_buf_len, pid);
 		if (err < 0)
 			goto fail;
 	} else {
@@ -1326,7 +1354,7 @@
 	 * recovery algorithm. Send an error response if the
 	 * packet is not in expected format.
 	 */
-	diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len, info);
+	diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len, pid);
 	driver->hdlc_buf_len = 0;
 end:
 	mutex_unlock(&driver->diag_hdlc_mutex);
@@ -1423,9 +1451,11 @@
 
 static uint8_t hdlc_reset;
 
-static void hdlc_reset_timer_start(struct diag_md_session_t *info)
+static void hdlc_reset_timer_start(int pid)
 {
+	struct diag_md_session_t *info = NULL;
 	mutex_lock(&driver->md_session_lock);
+	info = diag_md_session_get_pid(pid);
 	if (!hdlc_timer_in_progress) {
 		hdlc_timer_in_progress = 1;
 		if (info)
@@ -1467,15 +1497,16 @@
 }
 
 static void diag_hdlc_start_recovery(unsigned char *buf, int len,
-				     struct diag_md_session_t *info)
+				     int pid)
 {
 	int i;
 	static uint32_t bad_byte_counter;
 	unsigned char *start_ptr = NULL;
 	struct diag_pkt_frame_t *actual_pkt = NULL;
+	struct diag_md_session_t *info = NULL;
 
 	hdlc_reset = 1;
-	hdlc_reset_timer_start(info);
+	hdlc_reset_timer_start(pid);
 
 	actual_pkt = (struct diag_pkt_frame_t *)buf;
 	for (i = 0; i < len; i++) {
@@ -1495,10 +1526,13 @@
 			pr_err("diag: In %s, re-enabling HDLC encoding\n",
 					__func__);
 			mutex_lock(&driver->hdlc_disable_mutex);
+			mutex_lock(&driver->md_session_lock);
+			info = diag_md_session_get_pid(pid);
 			if (info)
 				info->hdlc_disabled = 0;
 			else
 				driver->hdlc_disabled = 0;
+			mutex_unlock(&driver->md_session_lock);
 			mutex_unlock(&driver->hdlc_disable_mutex);
 			diag_update_md_clients(HDLC_SUPPORT_TYPE);
 
@@ -1511,12 +1545,11 @@
 		mutex_lock(&driver->hdlc_recovery_mutex);
 		driver->incoming_pkt.processing = 0;
 		mutex_unlock(&driver->hdlc_recovery_mutex);
-		diag_process_non_hdlc_pkt(start_ptr, len - i, info);
+		diag_process_non_hdlc_pkt(start_ptr, len - i, pid);
 	}
 }
 
-void diag_process_non_hdlc_pkt(unsigned char *buf, int len,
-			       struct diag_md_session_t *info)
+void diag_process_non_hdlc_pkt(unsigned char *buf, int len, int pid)
 {
 	int err = 0;
 	uint16_t pkt_len = 0;
@@ -1572,11 +1605,11 @@
 		if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
 						CONTROL_CHAR) {
 			mutex_unlock(&driver->hdlc_recovery_mutex);
-			diag_hdlc_start_recovery(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
 			mutex_lock(&driver->hdlc_recovery_mutex);
 		}
 		err = diag_process_apps_pkt(data_ptr,
-					    actual_pkt->length, info);
+					    actual_pkt->length, pid);
 		if (err) {
 			pr_err("diag: In %s, unable to process incoming data packet, err: %d\n",
 			       __func__, err);
@@ -1598,8 +1631,8 @@
 		pkt_len = actual_pkt->length;
 
 		if (actual_pkt->start != CONTROL_CHAR) {
-			diag_hdlc_start_recovery(buf, len, info);
-			diag_send_error_rsp(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
+			diag_send_error_rsp(buf, len, pid);
 			goto end;
 		}
 		mutex_lock(&driver->hdlc_recovery_mutex);
@@ -1607,7 +1640,7 @@
 			pr_err("diag: In %s, incoming data is too large for the request buffer %d\n",
 			       __func__, pkt_len);
 			mutex_unlock(&driver->hdlc_recovery_mutex);
-			diag_hdlc_start_recovery(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
 			break;
 		}
 		if ((pkt_len + header_len) > (len - read_bytes)) {
@@ -1624,13 +1657,13 @@
 		if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
 						CONTROL_CHAR) {
 			mutex_unlock(&driver->hdlc_recovery_mutex);
-			diag_hdlc_start_recovery(buf, len, info);
+			diag_hdlc_start_recovery(buf, len, pid);
 			mutex_lock(&driver->hdlc_recovery_mutex);
 		}
 		else
 			hdlc_reset = 0;
 		err = diag_process_apps_pkt(data_ptr,
-					    actual_pkt->length, info);
+					    actual_pkt->length, pid);
 		if (err) {
 			mutex_unlock(&driver->hdlc_recovery_mutex);
 			break;
@@ -1649,9 +1682,9 @@
 		return -EINVAL;
 
 	if (!driver->hdlc_disabled)
-		diag_process_hdlc_pkt(buf, len, NULL);
+		diag_process_hdlc_pkt(buf, len, 0);
 	else
-		diag_process_non_hdlc_pkt(buf, len, NULL);
+		diag_process_non_hdlc_pkt(buf, len, 0);
 
 	diag_mux_queue_read(ctxt);
 	return 0;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 0e0bf2d..687aeb7 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -30,10 +30,8 @@
 
 int diagfwd_init(void);
 void diagfwd_exit(void);
-void diag_process_hdlc_pkt(void *data, unsigned int len,
-			   struct diag_md_session_t *info);
-void diag_process_non_hdlc_pkt(unsigned char *data, int len,
-			       struct diag_md_session_t *info);
+void diag_process_hdlc_pkt(void *data, unsigned int len, int pid);
+void diag_process_non_hdlc_pkt(unsigned char *data, int len, int pid);
 int chk_config_get_id(void);
 int chk_apps_only(void);
 int chk_apps_master(void);
@@ -45,10 +43,8 @@
 int diag_check_common_cmd(struct diag_pkt_header_t *header);
 void diag_update_userspace_clients(unsigned int type);
 void diag_update_sleeping_process(int process_id, int data_type);
-int diag_process_apps_pkt(unsigned char *buf, int len,
-			  struct diag_md_session_t *info);
-void diag_send_error_rsp(unsigned char *buf, int len,
-			 struct diag_md_session_t *info);
+int diag_process_apps_pkt(unsigned char *buf, int len, int pid);
+void diag_send_error_rsp(unsigned char *buf, int len, int pid);
 void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type);
 int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf);
 void diag_md_hdlc_reset_timer_func(unsigned long pid);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 162d53f..8d47ee38 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -333,8 +333,13 @@
 		if (!(driver->close_transport & PERIPHERAL_MASK(peripheral)))
 			continue;
 		driver->close_transport ^= PERIPHERAL_MASK(peripheral);
+#ifdef CONFIG_DIAG_USES_SMD
+		transport = driver->feature[peripheral].sockets_enabled ?
+					TRANSPORT_SMD : TRANSPORT_SOCKET;
+#else
 		transport = driver->feature[peripheral].sockets_enabled ?
 					TRANSPORT_GLINK : TRANSPORT_SOCKET;
+#endif
 		diagfwd_close_transport(transport, peripheral);
 	}
 	mutex_unlock(&driver->cntl_lock);
diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c
index f27f358..f8c3fde 100644
--- a/drivers/char/diag/diagfwd_mhi.c
+++ b/drivers/char/diag/diagfwd_mhi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -552,6 +552,8 @@
 	struct mhi_result *result = NULL;
 	struct diag_mhi_ch_t *ch = NULL;
 	void *buf = NULL;
+	struct diag_mhi_info *mhi_info = NULL;
+	unsigned long flags;
 
 	if (!cb_info)
 		return;
@@ -603,13 +605,6 @@
 		queue_work(diag_mhi[index].mhi_wq,
 			   &(diag_mhi[index].open_work));
 		break;
-	case MHI_CB_MHI_DISABLED:
-		DIAG_LOG(DIAG_DEBUG_BRIDGE,
-			 "received mhi disabled notifiation port: %d ch: %d\n",
-			 index, ch->type);
-		atomic_set(&(ch->opened), 0);
-		__mhi_close(&diag_mhi[index], CHANNELS_CLOSED);
-		break;
 	case MHI_CB_XFER:
 		/*
 		 * If the channel is a read channel, this is a read
@@ -636,6 +631,24 @@
 					   result->bytes_xferd,
 					   diag_mhi[index].id);
 		break;
+	case MHI_CB_MHI_DISABLED:
+	case MHI_CB_SYS_ERROR:
+	case MHI_CB_MHI_SHUTDOWN:
+		DIAG_LOG(DIAG_DEBUG_BRIDGE,
+			 "received mhi link down cb: %d port: %d ch: %d\n",
+			 cb_info->cb_reason, index, ch->type);
+		mhi_info = &diag_mhi[index];
+		if (!mhi_info->enabled)
+			return;
+		spin_lock_irqsave(&mhi_info->lock, flags);
+		mhi_info->enabled = 0;
+		spin_unlock_irqrestore(&mhi_info->lock, flags);
+		atomic_set(&(mhi_info->read_ch.opened), 0);
+		atomic_set(&(mhi_info->write_ch.opened), 0);
+		flush_workqueue(mhi_info->mhi_wq);
+		mhi_buf_tbl_clear(mhi_info);
+		diag_remote_dev_close(mhi_info->dev_id);
+		break;
 	default:
 		pr_err("diag: In %s, invalid cb reason 0x%x\n", __func__,
 		       cb_info->cb_reason);
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index c7bd2205..7908b82 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
 #include "diag_masks.h"
 #include "diag_dci.h"
 #include "diagfwd.h"
+#include "diagfwd_smd.h"
 #include "diagfwd_socket.h"
 #include "diag_mux.h"
 #include "diag_ipc_logging.h"
@@ -343,14 +344,13 @@
 		diag_ws_release();
 		return;
 	}
-
-	session_info =
-		diag_md_session_get_peripheral(peripheral);
+	mutex_lock(&driver->md_session_lock);
+	session_info = diag_md_session_get_peripheral(peripheral);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (hdlc_disabled) {
 		/* The data is raw and and on APPS side HDLC is disabled */
 		if (!buf) {
@@ -633,12 +633,13 @@
 
 	mutex_lock(&driver->hdlc_disable_mutex);
 	mutex_lock(&fwd_info->data_mutex);
+	mutex_lock(&driver->md_session_lock);
 	session_info = diag_md_session_get_peripheral(fwd_info->peripheral);
 	if (session_info)
 		hdlc_disabled = session_info->hdlc_disabled;
 	else
 		hdlc_disabled = driver->hdlc_disabled;
-
+	mutex_unlock(&driver->md_session_lock);
 	if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
 		if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) {
 			temp_buf = fwd_info->buf_1;
@@ -905,6 +906,8 @@
 			&peripheral_info[TYPE_DCI_CMD][peripheral];
 	}
 
+	_diag_smd_init();
+
 	if (driver->supports_sockets)
 		diag_socket_init();
 	diag_glink_init();
@@ -919,6 +922,8 @@
 	struct diagfwd_info *fwd_info = NULL;
 	int transport = 0;
 
+	_diag_smd_exit();
+
 	diag_socket_exit();
 
 	for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
@@ -1049,6 +1054,74 @@
 	}
 }
 
+#ifdef CONFIG_DIAG_USES_SMD
+void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
+{
+	struct diagfwd_info *fwd_info = NULL;
+	struct diagfwd_info *dest_info = NULL;
+	int (*init_fn)(uint8_t) = NULL;
+	void (*invalidate_fn)(void *, struct diagfwd_info *) = NULL;
+	int (*check_channel_state)(void *) = NULL;
+	uint8_t transport_open = 0;
+	int i = 0;
+
+	if (peripheral >= NUM_PERIPHERALS)
+		return;
+
+	switch (transport) {
+	case TRANSPORT_SMD:
+		transport_open = TRANSPORT_SOCKET;
+		init_fn = diag_socket_init_peripheral;
+		invalidate_fn = diag_socket_invalidate;
+		check_channel_state = diag_socket_check_state;
+		break;
+	case TRANSPORT_SOCKET:
+		if (peripheral == PERIPHERAL_WDSP) {
+		transport_open = TRANSPORT_GLINK;
+		init_fn = diag_glink_init_peripheral;
+		invalidate_fn = diag_glink_invalidate;
+		check_channel_state = diag_glink_check_state;
+		} else {
+			transport_open = TRANSPORT_SMD;
+			init_fn = diag_smd_init_peripheral;
+			invalidate_fn = diag_smd_invalidate;
+			check_channel_state = diag_smd_check_state;
+		}
+		break;
+	default:
+		return;
+
+	}
+
+	mutex_lock(&driver->diagfwd_channel_mutex[peripheral]);
+	fwd_info = &early_init_info[transport][peripheral];
+	if (fwd_info->p_ops && fwd_info->p_ops->close)
+		fwd_info->p_ops->close(fwd_info->ctxt);
+	fwd_info = &early_init_info[transport_open][peripheral];
+	dest_info = &peripheral_info[TYPE_CNTL][peripheral];
+	dest_info->inited = 1;
+	dest_info->ctxt = fwd_info->ctxt;
+	dest_info->p_ops = fwd_info->p_ops;
+	dest_info->c_ops = fwd_info->c_ops;
+	dest_info->ch_open = fwd_info->ch_open;
+	dest_info->read_bytes = fwd_info->read_bytes;
+	dest_info->write_bytes = fwd_info->write_bytes;
+	dest_info->inited = fwd_info->inited;
+	dest_info->buf_1 = fwd_info->buf_1;
+	dest_info->buf_2 = fwd_info->buf_2;
+	dest_info->transport = fwd_info->transport;
+	invalidate_fn(dest_info->ctxt, dest_info);
+	for (i = 0; i < NUM_WRITE_BUFFERS; i++)
+		dest_info->buf_ptr[i] = fwd_info->buf_ptr[i];
+	if (!check_channel_state(dest_info->ctxt))
+		diagfwd_late_open(dest_info);
+	diagfwd_cntl_open(dest_info);
+	init_fn(peripheral);
+	mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]);
+	diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
+	diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]);
+}
+#else
 void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
 {
 	struct diagfwd_info *fwd_info = NULL;
@@ -1108,6 +1181,7 @@
 	diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
 	diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]);
 }
+#endif
 
 void *diagfwd_request_write_buf(struct diagfwd_info *fwd_info)
 {
diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h
index 6ddce32..4124b17 100644
--- a/drivers/char/diag/diagfwd_peripheral.h
+++ b/drivers/char/diag/diagfwd_peripheral.h
@@ -18,9 +18,16 @@
 #define MAX_PERIPHERAL_HDLC_BUF_SZ	65539
 
 #define TRANSPORT_UNKNOWN		-1
+#ifdef CONFIG_DIAG_USES_SMD
+#define TRANSPORT_SMD			0
+#define TRANSPORT_SOCKET		1
+#define TRANSPORT_GLINK			2
+#define NUM_TRANSPORT			3
+#else
 #define TRANSPORT_SOCKET		0
 #define TRANSPORT_GLINK			1
 #define NUM_TRANSPORT			2
+#endif
 #define NUM_WRITE_BUFFERS		2
 #define PERIPHERAL_MASK(x)					\
 	((x == PERIPHERAL_MODEM) ? DIAG_CON_MPSS :		\
diff --git a/drivers/char/diag/diagfwd_smd.c b/drivers/char/diag/diagfwd_smd.c
new file mode 100644
index 0000000..27433a7
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smd.c
@@ -0,0 +1,923 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/ratelimit.h>
+#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/atomic.h>
+#include <linux/diagchar.h>
+#include <linux/of.h>
+#include <linux/kmemleak.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_peripheral.h"
+#include "diagfwd_smd.h"
+#include "diag_ipc_logging.h"
+
+struct diag_smd_info smd_data[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_DATA,
+		.name = "MODEM_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_DATA,
+		.name = "LPASS_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_DATA,
+		.name = "WCNSS_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_DATA,
+		.name = "SENSORS_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_DATA,
+		.name = "DIAG_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_DATA,
+		.name = "CDSP_DATA"
+	}
+};
+
+struct diag_smd_info smd_cntl[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_CNTL,
+		.name = "MODEM_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_CNTL,
+		.name = "LPASS_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_CNTL,
+		.name = "WCNSS_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_CNTL,
+		.name = "SENSORS_CNTL"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_CNTL,
+		.name = "DIAG_CTRL"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_CNTL,
+		.name = "CDSP_CNTL"
+	}
+};
+
+struct diag_smd_info smd_dci[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_DCI,
+		.name = "MODEM_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_DCI,
+		.name = "LPASS_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_DCI,
+		.name = "WCNSS_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_DCI,
+		.name = "SENSORS_DCI"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_DCI,
+		.name = "DIAG_DCI_DATA"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_DCI,
+		.name = "CDSP_DCI"
+	}
+};
+
+struct diag_smd_info smd_cmd[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_CMD,
+		.name = "MODEM_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_CMD,
+		.name = "LPASS_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_CMD,
+		.name = "WCNSS_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_CMD,
+		.name = "SENSORS_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_CMD,
+		.name = "DIAG_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_CMD,
+		.name = "CDSP_CMD"
+	}
+};
+
+struct diag_smd_info smd_dci_cmd[NUM_PERIPHERALS] = {
+	{
+		.peripheral = PERIPHERAL_MODEM,
+		.type = TYPE_DCI_CMD,
+		.name = "MODEM_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_LPASS,
+		.type = TYPE_DCI_CMD,
+		.name = "LPASS_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WCNSS,
+		.type = TYPE_DCI_CMD,
+		.name = "WCNSS_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_SENSORS,
+		.type = TYPE_DCI_CMD,
+		.name = "SENSORS_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_WDSP,
+		.type = TYPE_DCI_CMD,
+		.name = "DIAG_DCI_CMD"
+	},
+	{
+		.peripheral = PERIPHERAL_CDSP,
+		.type = TYPE_DCI_CMD,
+		.name = "CDSP_DCI_CMD"
+	}
+};
+
+static void diag_state_open_smd(void *ctxt);
+static void diag_state_close_smd(void *ctxt);
+static void smd_notify(void *ctxt, unsigned int event);
+static int diag_smd_write(void *ctxt, unsigned char *buf, int len);
+static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len);
+static void diag_smd_queue_read(void *ctxt);
+
+static struct diag_peripheral_ops smd_ops = {
+	.open = diag_state_open_smd,
+	.close = diag_state_close_smd,
+	.write = diag_smd_write,
+	.read = diag_smd_read,
+	.queue_read = diag_smd_queue_read
+};
+
+static void diag_state_open_smd(void *ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)(ctxt);
+	atomic_set(&smd_info->diag_state, 1);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		 "%s setting diag state to 1", smd_info->name);
+}
+
+static void diag_state_close_smd(void *ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)(ctxt);
+	atomic_set(&smd_info->diag_state, 0);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		 "%s setting diag state to 0", smd_info->name);
+	wake_up_interruptible(&smd_info->read_wait_q);
+	flush_workqueue(smd_info->wq);
+}
+
+static int smd_channel_probe(struct platform_device *pdev, uint8_t type)
+{
+	int r = 0;
+	int index = -1;
+	const char *channel_name = NULL;
+	struct diag_smd_info *smd_info = NULL;
+
+	switch (pdev->id) {
+	case SMD_APPS_MODEM:
+		index = PERIPHERAL_MODEM;
+		break;
+	case SMD_APPS_QDSP:
+		index = PERIPHERAL_LPASS;
+		break;
+	case SMD_APPS_WCNSS:
+		index = PERIPHERAL_WCNSS;
+		break;
+	case SMD_APPS_DSPS:
+		index = PERIPHERAL_SENSORS;
+		break;
+	default:
+		pr_debug("diag: In %s Received probe for invalid index %d",
+			__func__, pdev->id);
+		return -EINVAL;
+	}
+
+	switch (type) {
+	case TYPE_DATA:
+		smd_info = &smd_data[index];
+		channel_name = "DIAG";
+		break;
+	case TYPE_CNTL:
+		smd_info = &smd_cntl[index];
+		channel_name = "DIAG_CNTL";
+		break;
+	case TYPE_CMD:
+		smd_info = &smd_cmd[index];
+		channel_name = "DIAG_CMD";
+		break;
+	case TYPE_DCI:
+		smd_info = &smd_dci[index];
+		channel_name = "DIAG_2";
+		break;
+	case TYPE_DCI_CMD:
+		smd_info = &smd_dci_cmd[index];
+		channel_name = "DIAG_2_CMD";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (index == PERIPHERAL_WCNSS && type == TYPE_DATA)
+		channel_name = "APPS_RIVA_DATA";
+	else if (index == PERIPHERAL_WCNSS && type == TYPE_CNTL)
+		channel_name = "APPS_RIVA_CTRL";
+
+	if (!channel_name || !smd_info)
+		return -EIO;
+
+	r = smd_named_open_on_edge(channel_name, pdev->id, &smd_info->hdl,
+				   smd_info, smd_notify);
+
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pr_debug("diag: In %s, SMD port probed %s, id = %d, r = %d\n",
+		 __func__, smd_info->name, pdev->id, r);
+
+	return 0;
+}
+
+static int smd_data_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_DATA);
+}
+
+static int smd_cntl_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_CNTL);
+}
+
+static int smd_cmd_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_CMD);
+}
+
+static int smd_dci_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_DCI);
+}
+
+static int smd_dci_cmd_probe(struct platform_device *pdev)
+{
+	return smd_channel_probe(pdev, TYPE_DCI_CMD);
+}
+
+static int smd_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
+
+static int smd_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+
+static const struct dev_pm_ops smd_dev_pm_ops = {
+	.runtime_suspend = smd_runtime_suspend,
+	.runtime_resume = smd_runtime_resume,
+};
+
+static struct platform_driver diag_smd_ch_driver = {
+	.probe = smd_data_probe,
+	.driver = {
+		.name = "DIAG",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_lite_driver = {
+	.probe = smd_data_probe,
+	.driver = {
+		.name = "APPS_RIVA_DATA",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_cntl_driver = {
+	.probe = smd_cntl_probe,
+	.driver = {
+		.name = "DIAG_CNTL",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_lite_cntl_driver = {
+	.probe = smd_cntl_probe,
+	.driver = {
+		.name = "APPS_RIVA_CTRL",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_lite_cmd_driver = {
+	.probe = smd_cmd_probe,
+	.driver = {
+		.name = "DIAG_CMD",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	}
+};
+
+static struct platform_driver diag_smd_dci_driver = {
+	.probe = smd_dci_probe,
+	.driver = {
+		.name = "DIAG_2",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static struct platform_driver diag_smd_dci_cmd_driver = {
+	.probe = smd_dci_cmd_probe,
+	.driver = {
+		.name = "DIAG_2_CMD",
+		.owner = THIS_MODULE,
+		.pm   = &smd_dev_pm_ops,
+	},
+};
+
+static void smd_open_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+						      struct diag_smd_info,
+						      open_work);
+	if (!smd_info->inited)
+		return;
+
+	diagfwd_channel_open(smd_info->fwd_ctxt);
+	diagfwd_late_open(smd_info->fwd_ctxt);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+static void smd_close_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+						      struct diag_smd_info,
+						      close_work);
+	if (!smd_info->inited)
+		return;
+
+	diagfwd_channel_close(smd_info->fwd_ctxt);
+	wake_up_interruptible(&smd_info->read_wait_q);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+static void smd_read_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+						      struct diag_smd_info,
+						      read_work);
+	if (!smd_info->inited) {
+		diag_ws_release();
+		return;
+	}
+
+	diagfwd_channel_read(smd_info->fwd_ctxt);
+}
+
+static void diag_smd_late_init_work_fn(struct work_struct *work)
+{
+	struct diag_smd_info *smd_info = container_of(work,
+							struct diag_smd_info,
+							late_init_work);
+	if (!smd_info || !smd_info->hdl)
+		return;
+	diagfwd_channel_open(smd_info->fwd_ctxt);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "smd late init p: %d t: %d\n",
+			smd_info->peripheral, smd_info->type);
+}
+
+static void diag_smd_queue_read(void *ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (smd_info->inited && atomic_read(&smd_info->opened) &&
+	    smd_info->hdl) {
+		wake_up_interruptible(&smd_info->read_wait_q);
+		queue_work(smd_info->wq, &(smd_info->read_work));
+	}
+}
+int diag_smd_check_state(void *ctxt)
+{
+	struct diag_smd_info *info = NULL;
+
+	if (!ctxt)
+		return 0;
+
+	info = (struct diag_smd_info *)ctxt;
+	return (int)(atomic_read(&info->diag_state));
+}
+void diag_smd_invalidate(void *ctxt, struct diagfwd_info *fwd_ctxt)
+{
+	struct diag_smd_info *smd_info = NULL;
+	void *prev = NULL;
+
+	if (!ctxt || !fwd_ctxt)
+		return;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	prev = smd_info->fwd_ctxt;
+	smd_info->fwd_ctxt = fwd_ctxt;
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s prev: %pK fwd_ctxt: %pK\n",
+		 smd_info->name, prev, smd_info->fwd_ctxt);
+}
+
+static void __diag_smd_init(struct diag_smd_info *smd_info)
+{
+	char wq_name[DIAG_SMD_NAME_SZ + 10];
+
+	if (!smd_info)
+		return;
+
+	init_waitqueue_head(&smd_info->read_wait_q);
+	mutex_init(&smd_info->lock);
+	strlcpy(wq_name, "DIAG_SMD_", 10);
+	strlcat(wq_name, smd_info->name, sizeof(smd_info->name));
+	smd_info->wq = create_singlethread_workqueue(wq_name);
+	if (!smd_info->wq) {
+		pr_err("diag: In %s, unable to create workqueue for smd channel %s\n",
+		       __func__, smd_info->name);
+		return;
+	}
+	INIT_WORK(&(smd_info->open_work), smd_open_work_fn);
+	INIT_WORK(&(smd_info->close_work), smd_close_work_fn);
+	INIT_WORK(&(smd_info->read_work), smd_read_work_fn);
+	INIT_WORK(&(smd_info->late_init_work), diag_smd_late_init_work_fn);
+	smd_info->fifo_size = 0;
+	smd_info->hdl = NULL;
+	smd_info->fwd_ctxt = NULL;
+	atomic_set(&smd_info->opened, 0);
+	atomic_set(&smd_info->diag_state, 0);
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s initialized fwd_ctxt: %pK\n",
+		 smd_info->name, smd_info->fwd_ctxt);
+}
+
+int diag_smd_init(void)
+{
+	uint8_t peripheral;
+	struct diag_smd_info *smd_info = NULL;
+
+	for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
+		if (peripheral == PERIPHERAL_WDSP)
+			continue;
+		smd_info = &smd_cntl[peripheral];
+		__diag_smd_init(smd_info);
+		diagfwd_cntl_register(TRANSPORT_SMD, smd_info->peripheral,
+				      (void *)smd_info, &smd_ops,
+				      &smd_info->fwd_ctxt);
+		smd_info->inited = 1;
+		__diag_smd_init(&smd_data[peripheral]);
+		__diag_smd_init(&smd_cmd[peripheral]);
+		__diag_smd_init(&smd_dci[peripheral]);
+		__diag_smd_init(&smd_dci_cmd[peripheral]);
+	}
+
+	platform_driver_register(&diag_smd_cntl_driver);
+	platform_driver_register(&diag_smd_lite_cntl_driver);
+	platform_driver_register(&diag_smd_ch_driver);
+	platform_driver_register(&diag_smd_lite_driver);
+	platform_driver_register(&diag_smd_lite_cmd_driver);
+	platform_driver_register(&diag_smd_dci_driver);
+	platform_driver_register(&diag_smd_dci_cmd_driver);
+
+	return 0;
+}
+
+static void smd_late_init(struct diag_smd_info *smd_info)
+{
+	struct diagfwd_info *fwd_info = NULL;
+
+	if (!smd_info)
+		return;
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s entering\n",
+		 smd_info->name);
+
+	diagfwd_register(TRANSPORT_SMD, smd_info->peripheral, smd_info->type,
+			 (void *)smd_info, &smd_ops, &smd_info->fwd_ctxt);
+	fwd_info = smd_info->fwd_ctxt;
+	smd_info->inited = 1;
+	/*
+	 * The channel is already open by the probe call as a result of other
+	 * peripheral. Inform the diag fwd layer that the channel is open.
+	 */
+	if (atomic_read(&smd_info->opened))
+		queue_work(smd_info->wq, &(smd_info->late_init_work));
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+int diag_smd_init_peripheral(uint8_t peripheral)
+{
+	if (peripheral >= NUM_PERIPHERALS) {
+		pr_err("diag: In %s, invalid peripheral %d\n",
+		       __func__, peripheral);
+		return -EINVAL;
+	}
+
+	smd_late_init(&smd_data[peripheral]);
+	smd_late_init(&smd_dci[peripheral]);
+	smd_late_init(&smd_cmd[peripheral]);
+	smd_late_init(&smd_dci_cmd[peripheral]);
+
+	return 0;
+}
+
+static void __diag_smd_exit(struct diag_smd_info *smd_info)
+{
+	if (!smd_info)
+		return;
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s entering\n",
+		 smd_info->name);
+
+	diagfwd_deregister(smd_info->peripheral, smd_info->type,
+			   (void *)smd_info);
+	smd_info->fwd_ctxt = NULL;
+	smd_info->hdl = NULL;
+	if (smd_info->wq)
+		destroy_workqueue(smd_info->wq);
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n",
+		 smd_info->name);
+}
+
+void diag_smd_early_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < NUM_PERIPHERALS; i++) {
+		if (i == PERIPHERAL_WDSP)
+			continue;
+		__diag_smd_exit(&smd_cntl[i]);
+	}
+
+	platform_driver_unregister(&diag_smd_cntl_driver);
+	platform_driver_unregister(&diag_smd_lite_cntl_driver);
+}
+
+void diag_smd_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < NUM_PERIPHERALS; i++) {
+		if (i == PERIPHERAL_WDSP)
+			continue;
+		__diag_smd_exit(&smd_data[i]);
+		__diag_smd_exit(&smd_cmd[i]);
+		__diag_smd_exit(&smd_dci[i]);
+		__diag_smd_exit(&smd_dci_cmd[i]);
+	}
+
+	platform_driver_unregister(&diag_smd_ch_driver);
+	platform_driver_unregister(&diag_smd_lite_driver);
+	platform_driver_unregister(&diag_smd_lite_cmd_driver);
+	platform_driver_unregister(&diag_smd_dci_driver);
+	platform_driver_unregister(&diag_smd_dci_cmd_driver);
+}
+
+static int diag_smd_write_ext(struct diag_smd_info *smd_info,
+			      unsigned char *buf, int len)
+{
+	int err = 0;
+	int offset = 0;
+	int write_len = 0;
+	int retry_count = 0;
+	int max_retries = 3;
+	uint8_t avail = 0;
+
+	if (!smd_info || !buf || len <= 0) {
+		pr_err_ratelimited("diag: In %s, invalid params, smd_info: %pK, buf: %pK, len: %d\n",
+				   __func__, smd_info, buf, len);
+		return -EINVAL;
+	}
+
+	if (!smd_info->inited || !smd_info->hdl ||
+	    !atomic_read(&smd_info->opened))
+		return -ENODEV;
+
+	mutex_lock(&smd_info->lock);
+	err = smd_write_start(smd_info->hdl, len);
+	if (err) {
+		pr_err_ratelimited("diag: In %s, error calling smd_write_start, peripheral: %d, err: %d\n",
+				   __func__, smd_info->peripheral, err);
+		goto fail;
+	}
+
+	while (offset < len) {
+		retry_count = 0;
+		do {
+			if (smd_write_segment_avail(smd_info->hdl)) {
+				avail = 1;
+				break;
+			}
+			/*
+			 * The channel maybe busy - the FIFO can be full. Retry
+			 * after sometime. The value of 10000 was chosen
+			 * emprically as the optimal value for the peripherals
+			 * to read data from the SMD channel.
+			 */
+			usleep_range(10000, 10100);
+			retry_count++;
+		} while (retry_count < max_retries);
+
+		if (!avail) {
+			err = -EAGAIN;
+			goto fail;
+		}
+
+		write_len = smd_write_segment(smd_info->hdl, buf + offset,
+					      (len - offset));
+		offset += write_len;
+		write_len = 0;
+	}
+
+	err = smd_write_end(smd_info->hdl);
+	if (err) {
+		pr_err_ratelimited("diag: In %s, error calling smd_write_end, peripheral: %d, err: %d\n",
+				   __func__, smd_info->peripheral, err);
+		goto fail;
+	}
+
+fail:
+	mutex_unlock(&smd_info->lock);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		 "%s wrote to channel, write_len: %d, err: %d\n",
+		 smd_info->name, offset, err);
+	return err;
+}
+
+static int diag_smd_write(void *ctxt, unsigned char *buf, int len)
+{
+	int write_len = 0;
+	int retry_count = 0;
+	int max_retries = 3;
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt || !buf)
+		return -EIO;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (!smd_info || !buf || len <= 0) {
+		pr_err_ratelimited("diag: In %s, invalid params, smd_info: %pK, buf: %pK, len: %d\n",
+				   __func__, smd_info, buf, len);
+		return -EINVAL;
+	}
+
+	if (!smd_info->inited || !smd_info->hdl ||
+	    !atomic_read(&smd_info->opened))
+		return -ENODEV;
+
+	if (len > smd_info->fifo_size)
+		return diag_smd_write_ext(smd_info, buf, len);
+
+	do {
+		mutex_lock(&smd_info->lock);
+		write_len = smd_write(smd_info->hdl, buf, len);
+		mutex_unlock(&smd_info->lock);
+		if (write_len == len)
+			break;
+		/*
+		 * The channel maybe busy - the FIFO can be full. Retry after
+		 * sometime. The value of 10000 was chosen emprically as the
+		 * optimal value for the peripherals to read data from the SMD
+		 * channel.
+		 */
+		usleep_range(10000, 10100);
+		retry_count++;
+	} while (retry_count < max_retries);
+
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s wrote to channel, write_len: %d\n",
+		 smd_info->name, write_len);
+
+	if (write_len != len)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len)
+{
+	int pkt_len = 0;
+	int err = 0;
+	int total_recd_partial = 0;
+	int total_recd = 0;
+	uint8_t buf_full = 0;
+	unsigned char *temp_buf = NULL;
+	uint32_t read_len = 0;
+	struct diag_smd_info *smd_info = NULL;
+
+	if (!ctxt || !buf || buf_len <= 0)
+		return -EIO;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (!smd_info->hdl || !smd_info->inited ||
+	    !atomic_read(&smd_info->opened))
+		return -EIO;
+
+	/*
+	 * Always try to read the data if notification is received from smd
+	 * In case if packet size is 0 release the wake source hold earlier
+	 */
+	err = wait_event_interruptible(smd_info->read_wait_q,
+				       (smd_info->hdl != NULL) &&
+				       (atomic_read(&smd_info->opened) == 1));
+	if (err) {
+		diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
+		return -ERESTARTSYS;
+	}
+
+	/*
+	 * Reset the buffers. Also release the wake source hold earlier.
+	 */
+	if (atomic_read(&smd_info->diag_state) == 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			 "%s closing read thread. diag state is closed\n",
+			 smd_info->name);
+		diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
+		return 0;
+	}
+
+	if (!smd_info->hdl || !atomic_read(&smd_info->opened)) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+			 "%s stopping read, hdl: %pK, opened: %d\n",
+			 smd_info->name, smd_info->hdl,
+			 atomic_read(&smd_info->opened));
+		goto fail_return;
+	}
+
+	do {
+		total_recd_partial = 0;
+		temp_buf = buf + total_recd;
+		pkt_len = smd_cur_packet_size(smd_info->hdl);
+		if (pkt_len <= 0)
+			break;
+
+		if (total_recd + pkt_len > buf_len) {
+			buf_full = 1;
+			break;
+		}
+
+		while (total_recd_partial < pkt_len) {
+			read_len = smd_read_avail(smd_info->hdl);
+			if (!read_len) {
+				err = wait_event_interruptible(smd_info->
+					read_wait_q,
+					((atomic_read(&smd_info->opened)) &&
+					smd_read_avail(smd_info->hdl)));
+				if (err)
+					goto fail_return;
+
+				if (!smd_info->hdl ||
+				    !atomic_read(&smd_info->opened)) {
+					DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+						"%s exiting from wait",
+						smd_info->name);
+					goto fail_return;
+				}
+			}
+
+			if (pkt_len < read_len)
+				goto fail_return;
+
+			smd_read(smd_info->hdl, temp_buf, read_len);
+			total_recd_partial += read_len;
+			total_recd += read_len;
+			temp_buf += read_len;
+		}
+	} while (pkt_len > 0);
+
+	if ((smd_info->type == TYPE_DATA && pkt_len) || buf_full)
+		err = queue_work(smd_info->wq, &(smd_info->read_work));
+
+	if (total_recd > 0) {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s read total bytes: %d\n",
+			 smd_info->name, total_recd);
+		diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, total_recd);
+	} else {
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s error in read, err: %d\n",
+			 smd_info->name, total_recd);
+		goto fail_return;
+	}
+	return 0;
+
+fail_return:
+	diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
+	return -EINVAL;
+}
+
+static void smd_notify(void *ctxt, unsigned int event)
+{
+	struct diag_smd_info *smd_info = NULL;
+
+	smd_info = (struct diag_smd_info *)ctxt;
+	if (!smd_info)
+		return;
+
+	switch (event) {
+	case SMD_EVENT_OPEN:
+		atomic_set(&smd_info->opened, 1);
+		smd_info->fifo_size = smd_write_avail(smd_info->hdl);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s channel opened\n",
+			 smd_info->name);
+		queue_work(smd_info->wq, &(smd_info->open_work));
+		break;
+	case SMD_EVENT_CLOSE:
+		atomic_set(&smd_info->opened, 0);
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s channel closed\n",
+			 smd_info->name);
+		queue_work(smd_info->wq, &(smd_info->close_work));
+		break;
+	case SMD_EVENT_DATA:
+		diag_ws_on_notify();
+		queue_work(smd_info->wq, &(smd_info->read_work));
+		break;
+	}
+
+	wake_up_interruptible(&smd_info->read_wait_q);
+}
+
diff --git a/drivers/char/diag/diagfwd_smd.h b/drivers/char/diag/diagfwd_smd.h
new file mode 100644
index 0000000..388014e
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smd.h
@@ -0,0 +1,59 @@
+/* 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 DIAGFWD_SMD_H
+#define DIAGFWD_SMD_H
+
+#define DIAG_SMD_NAME_SZ	24
+#define SMD_DRAIN_BUF_SIZE	4096
+
+struct diag_smd_info {
+	uint8_t peripheral;
+	uint8_t type;
+	uint8_t inited;
+	atomic_t opened;
+	atomic_t diag_state;
+	uint32_t fifo_size;
+	smd_channel_t *hdl;
+	char name[DIAG_SMD_NAME_SZ];
+	struct mutex lock;
+	wait_queue_head_t read_wait_q;
+	struct workqueue_struct *wq;
+	struct work_struct open_work;
+	struct work_struct close_work;
+	struct work_struct read_work;
+	struct work_struct late_init_work;
+	struct diagfwd_info *fwd_ctxt;
+};
+
+extern struct diag_smd_info smd_data[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_cntl[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_dci[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_cmd[NUM_PERIPHERALS];
+extern struct diag_smd_info smd_dci_cmd[NUM_PERIPHERALS];
+
+int diag_smd_init_peripheral(uint8_t peripheral);
+void diag_smd_exit(void);
+int diag_smd_init(void);
+void diag_smd_early_exit(void);
+void diag_smd_invalidate(void *ctxt, struct diagfwd_info *fwd_ctxt);
+int diag_smd_check_state(void *ctxt);
+
+#ifndef CONFIG_DIAG_USES_SMD
+#define _diag_smd_exit(void)
+#define _diag_smd_init(void)
+#else
+#define _diag_smd_exit(void) diag_smd_exit(void)
+#define _diag_smd_init(void) diag_smd_init(void)
+#endif
+
+#endif
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 020e8ad..929aef0 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
  * Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1872,6 +1872,8 @@
 	if (core->flags & CLK_RECALC_NEW_RATES)
 		(void)clk_calc_new_rates(core, core->new_rate);
 
+	if (core->flags & CLK_CHILD_NO_RATE_PROP)
+		return rc;
 	/*
 	 * Use safe iteration, as change_rate can actually swap parents
 	 * for certain clock types.
diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig
index 16f8c32..d881a5d 100644
--- a/drivers/clk/msm/Kconfig
+++ b/drivers/clk/msm/Kconfig
@@ -16,3 +16,5 @@
 	   Generate clock data structures from definitions found in
 	   device tree.
 
+source "drivers/clk/msm/mdss/Kconfig"
+
diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile
index 4176553..d264e79 100644
--- a/drivers/clk/msm/Makefile
+++ b/drivers/clk/msm/Makefile
@@ -17,3 +17,6 @@
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-cpu-8953.o
 obj-$(CONFIG_ARCH_MSM8953)	+= clock-rcgwr.o
 endif
+
+obj-y               += mdss/
+
diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c
index b2dc3d26..fd80b56 100644
--- a/drivers/clk/msm/clock-gcc-8953.c
+++ b/drivers/clk/msm/clock-gcc-8953.c
@@ -3822,6 +3822,7 @@
 
 static const struct of_device_id msm_clock_gcc_match_table[] = {
 	{ .compatible = "qcom,gcc-8953" },
+	{ .compatible = "qcom,gcc-sdm632" },
 	{},
 };
 
@@ -3871,6 +3872,7 @@
 
 static const struct of_device_id msm_clock_debug_match_table[] = {
 	{ .compatible = "qcom,cc-debug-8953" },
+	{ .compatible = "qcom,cc-debug-sdm632" },
 	{}
 };
 
@@ -3983,6 +3985,7 @@
 
 static const struct of_device_id msm_clock_mdss_match_table[] = {
 	{ .compatible = "qcom,gcc-mdss-8953" },
+	{ .compatible = "qcom,gcc-mdss-sdm632" },
 	{}
 };
 
@@ -4131,6 +4134,7 @@
 static const struct of_device_id msm_clock_gfx_match_table[] = {
 	{ .compatible = "qcom,gcc-gfx-8953" },
 	{ .compatible = "qcom,gcc-gfx-sdm450" },
+	{ .compatible = "qcom,gcc-gfx-sdm632" },
 	{}
 };
 
diff --git a/drivers/clk/msm/mdss/Kconfig b/drivers/clk/msm/mdss/Kconfig
new file mode 100644
index 0000000..229780e
--- /dev/null
+++ b/drivers/clk/msm/mdss/Kconfig
@@ -0,0 +1,6 @@
+config MSM_MDSS_PLL
+	bool "MDSS pll programming"
+	---help---
+	It provides support for DSI, eDP and HDMI interface pll programming on MDSS
+	hardware. It also handles the pll specific resources and turn them on/off when
+	mdss pll client tries to enable/disable pll clocks.
diff --git a/drivers/clk/msm/mdss/Makefile b/drivers/clk/msm/mdss/Makefile
new file mode 100644
index 0000000..6285714
--- /dev/null
+++ b/drivers/clk/msm/mdss/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll-util.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-util.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-28lpm.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996-util.o
+obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-8996.o
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-28lpm.c b/drivers/clk/msm/mdss/mdss-dsi-pll-28lpm.c
new file mode 100644
index 0000000..17ff52e
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-28lpm.c
@@ -0,0 +1,522 @@
+/* Copyright (c) 2012-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <dt-bindings/clock/msm-clocks-8952.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+
+#define VCO_DELAY_USEC			1000
+
+static struct clk_div_ops fixed_2div_ops;
+static struct clk_ops byte_mux_clk_ops;
+static struct clk_ops pixel_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops analog_postdiv_clk_ops;
+static struct lpfr_cfg lpfr_lut_struct[] = {
+	{479500000, 8},
+	{480000000, 11},
+	{575500000, 8},
+	{576000000, 12},
+	{610500000, 8},
+	{659500000, 9},
+	{671500000, 10},
+	{672000000, 14},
+	{708500000, 10},
+	{750000000, 11},
+};
+
+static int vco_set_rate_lpm(struct clk *c, unsigned long rate)
+{
+	int rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/*
+	 * DSI PLL software reset. Add HW recommended delays after toggling
+	 * the software reset bit off and back on.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+	udelay(1000);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+	udelay(1000);
+
+	rc = vco_set_rate(vco, rate);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+static void dsi_pll_sw_reset_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	/*
+	 * DSI PLL software reset. Add HW recommended delays after toggling
+	 * the software reset bit off and back on.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+	ndelay(500);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+}
+
+static void dsi_pll_toggle_lock_detect_8916(
+				struct mdss_pll_resources *dsi_pll_res)
+{
+	/* DSI PLL toggle lock detect setting */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x04);
+	ndelay(500);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+	udelay(512);
+}
+
+static int dsi_pll_check_lock_status_8916(
+				struct mdss_pll_resources *dsi_pll_res)
+{
+	int rc = 0;
+
+	rc = dsi_pll_lock_status(dsi_pll_res);
+	if (rc)
+		pr_debug("PLL Locked\n");
+	else
+		pr_err("PLL failed to lock\n");
+
+	return rc;
+}
+
+
+static int gf_2_dsi_pll_enable_seq_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	int pll_locked = 0;
+
+	dsi_pll_sw_reset_8916(dsi_pll_res);
+
+	/*
+	 * GF PART 2 PLL power up sequence.
+	 * Add necessary delays recommended by hardware.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x04);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	udelay(3);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(500);
+
+	dsi_pll_toggle_lock_detect_8916(dsi_pll_res);
+
+	pll_locked = dsi_pll_check_lock_status_8916(dsi_pll_res);
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int gf_1_dsi_pll_enable_seq_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	int pll_locked = 0;
+
+	dsi_pll_sw_reset_8916(dsi_pll_res);
+	/*
+	 * GF PART 1 PLL power up sequence.
+	 * Add necessary delays recommended by hardware.
+	 */
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x14);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	udelay(3);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(500);
+
+	dsi_pll_toggle_lock_detect_8916(dsi_pll_res);
+
+	pll_locked = dsi_pll_check_lock_status_8916(dsi_pll_res);
+	return pll_locked ? 0 : -EINVAL;
+}
+
+static int tsmc_dsi_pll_enable_seq_8916(struct mdss_pll_resources *dsi_pll_res)
+{
+	int pll_locked = 0;
+
+	dsi_pll_sw_reset_8916(dsi_pll_res);
+	/*
+	 * TSMC PLL power up sequence.
+	 * Add necessary delays recommended by hardware.
+	 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+	udelay(500);
+
+	dsi_pll_toggle_lock_detect_8916(dsi_pll_res);
+
+	pll_locked = dsi_pll_check_lock_status_8916(dsi_pll_res);
+	return pll_locked ? 0 : -EINVAL;
+}
+
+/* Op structures */
+
+static const struct clk_ops clk_ops_dsi_vco = {
+	.set_rate = vco_set_rate_lpm,
+	.round_rate = vco_round_rate,
+	.handoff = vco_handoff,
+	.prepare = vco_prepare,
+	.unprepare = vco_unprepare,
+};
+
+
+static struct clk_div_ops fixed_4div_ops = {
+	.set_div = fixed_4div_set_div,
+	.get_div = fixed_4div_get_div,
+};
+
+static struct clk_div_ops analog_postdiv_ops = {
+	.set_div = analog_set_div,
+	.get_div = analog_get_div,
+};
+
+static struct clk_div_ops digital_postdiv_ops = {
+	.set_div = digital_set_div,
+	.get_div = digital_get_div,
+};
+
+static struct clk_mux_ops byte_mux_ops = {
+	.set_mux_sel = set_byte_mux_sel,
+	.get_mux_sel = get_byte_mux_sel,
+};
+
+/* DSI PLL0 clock structures */
+static struct dsi_pll_vco_clk dsi_pll0_vco_clk = {
+	.ref_clk_rate = 19200000,
+	.min_rate = 350000000,
+	.max_rate = 750000000,
+	.pll_en_seq_cnt = 9,
+	.pll_enable_seqs[0] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[1] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[2] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[3] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[4] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[5] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[6] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[7] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[8] = gf_2_dsi_pll_enable_seq_8916,
+	.lpfr_lut_size = 10,
+	.lpfr_lut = lpfr_lut_struct,
+	.c = {
+		.dbg_name = "dsi_pll0_vco_clk",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi_pll0_vco_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll0_analog_postdiv_clk = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &analog_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll0_vco_clk.c,
+		.dbg_name = "dsi_pll0_analog_postdiv_clk",
+		.ops = &analog_postdiv_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll0_analog_postdiv_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll0_indirect_path_div2_clk = {
+	.ops = &fixed_2div_ops,
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi_pll0_analog_postdiv_clk.c,
+		.dbg_name = "dsi_pll0_indirect_path_div2_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll0_indirect_path_div2_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll0_pixel_clk_src = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &digital_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll0_vco_clk.c,
+		.dbg_name = "dsi_pll0_pixel_clk_src",
+		.ops = &pixel_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll0_pixel_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi_pll0_byte_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]){
+		{&dsi_pll0_vco_clk.c, 0},
+		{&dsi_pll0_indirect_path_div2_clk.c, 1},
+	},
+	.ops = &byte_mux_ops,
+	.c = {
+		.parent = &dsi_pll0_vco_clk.c,
+		.dbg_name = "dsi_pll0_byte_mux",
+		.ops = &byte_mux_clk_ops,
+		CLK_INIT(dsi_pll0_byte_mux.c),
+	},
+};
+
+static struct div_clk dsi_pll0_byte_clk_src = {
+	.ops = &fixed_4div_ops,
+	.data = {
+		.min_div = 4,
+		.max_div = 4,
+	},
+	.c = {
+		.parent = &dsi_pll0_byte_mux.c,
+		.dbg_name = "dsi_pll0_byte_clk_src",
+		.ops = &byte_clk_src_ops,
+		CLK_INIT(dsi_pll0_byte_clk_src.c),
+	},
+};
+
+/* DSI PLL1 clock structures */
+static struct dsi_pll_vco_clk dsi_pll1_vco_clk = {
+	.ref_clk_rate = 19200000,
+	.min_rate = 350000000,
+	.max_rate = 750000000,
+	.pll_en_seq_cnt = 9,
+	.pll_enable_seqs[0] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[1] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[2] = tsmc_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[3] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[4] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[5] = gf_1_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[6] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[7] = gf_2_dsi_pll_enable_seq_8916,
+	.pll_enable_seqs[8] = gf_2_dsi_pll_enable_seq_8916,
+	.lpfr_lut_size = 10,
+	.lpfr_lut = lpfr_lut_struct,
+	.c = {
+		.dbg_name = "dsi_pll1_vco_clk",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi_pll1_vco_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll1_analog_postdiv_clk = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &analog_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll1_vco_clk.c,
+		.dbg_name = "dsi_pll1_analog_postdiv_clk",
+		.ops = &analog_postdiv_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll1_analog_postdiv_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll1_indirect_path_div2_clk = {
+	.ops = &fixed_2div_ops,
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi_pll1_analog_postdiv_clk.c,
+		.dbg_name = "dsi_pll1_indirect_path_div2_clk",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll1_indirect_path_div2_clk.c),
+	},
+};
+
+static struct div_clk dsi_pll1_pixel_clk_src = {
+	.data = {
+		.max_div = 255,
+		.min_div = 1,
+	},
+	.ops = &digital_postdiv_ops,
+	.c = {
+		.parent = &dsi_pll1_vco_clk.c,
+		.dbg_name = "dsi_pll1_pixel_clk_src",
+		.ops = &pixel_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi_pll1_pixel_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi_pll1_byte_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]){
+		{&dsi_pll1_vco_clk.c, 0},
+		{&dsi_pll1_indirect_path_div2_clk.c, 1},
+	},
+	.ops = &byte_mux_ops,
+	.c = {
+		.parent = &dsi_pll1_vco_clk.c,
+		.dbg_name = "dsi_pll1_byte_mux",
+		.ops = &byte_mux_clk_ops,
+		CLK_INIT(dsi_pll1_byte_mux.c),
+	},
+};
+
+static struct div_clk dsi_pll1_byte_clk_src = {
+	.ops = &fixed_4div_ops,
+	.data = {
+		.min_div = 4,
+		.max_div = 4,
+	},
+	.c = {
+		.parent = &dsi_pll1_byte_mux.c,
+		.dbg_name = "dsi_pll1_byte_clk_src",
+		.ops = &byte_clk_src_ops,
+		CLK_INIT(dsi_pll1_byte_clk_src.c),
+	},
+};
+
+static struct clk_lookup dsi_pll0_cc[] = {
+	CLK_LIST(dsi_pll0_pixel_clk_src),
+	CLK_LIST(dsi_pll0_byte_clk_src),
+};
+
+static struct clk_lookup dsi_pll1_cc[] = {
+	CLK_LIST(dsi_pll1_pixel_clk_src),
+	CLK_LIST(dsi_pll1_byte_clk_src),
+};
+
+int dsi_pll_clock_register_lpm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc;
+	int const ssc_freq_min = 30000; /* min. recommended freq. value */
+	int const ssc_freq_max = 33000; /* max. recommended freq. value */
+	int const ssc_ppm_max = 5000; /* max. recommended ppm */
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	if (!pll_res || !pll_res->pll_base) {
+		pr_err("Invalid PLL resources\n");
+		return -EPROBE_DEFER;
+	}
+
+	/* Set client data to mux, div and vco clocks */
+	if (!pll_res->index) {
+		dsi_pll0_byte_clk_src.priv = pll_res;
+		dsi_pll0_pixel_clk_src.priv = pll_res;
+		dsi_pll0_byte_mux.priv = pll_res;
+		dsi_pll0_indirect_path_div2_clk.priv = pll_res;
+		dsi_pll0_analog_postdiv_clk.priv = pll_res;
+		dsi_pll0_vco_clk.priv = pll_res;
+	} else {
+		dsi_pll1_byte_clk_src.priv = pll_res;
+		dsi_pll1_pixel_clk_src.priv = pll_res;
+		dsi_pll1_byte_mux.priv = pll_res;
+		dsi_pll1_indirect_path_div2_clk.priv = pll_res;
+		dsi_pll1_analog_postdiv_clk.priv = pll_res;
+		dsi_pll1_vco_clk.priv = pll_res;
+	}
+
+	pll_res->vco_delay = VCO_DELAY_USEC;
+
+	/* Set clock source operations */
+	pixel_clk_src_ops = clk_ops_slave_div;
+	pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	analog_postdiv_clk_ops = clk_ops_div;
+	analog_postdiv_clk_ops.prepare = dsi_pll_div_prepare;
+
+	byte_clk_src_ops = clk_ops_div;
+	byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	byte_mux_clk_ops = clk_ops_gen_mux;
+	byte_mux_clk_ops.prepare = dsi_pll_mux_prepare;
+
+	if (pll_res->ssc_en) {
+		if (!pll_res->ssc_freq || (pll_res->ssc_freq < ssc_freq_min) ||
+			(pll_res->ssc_freq > ssc_freq_max)) {
+			pll_res->ssc_freq = ssc_freq_min;
+			pr_debug("SSC frequency out of recommended range. Set to default=%d\n",
+				pll_res->ssc_freq);
+		}
+
+		if (!pll_res->ssc_ppm || (pll_res->ssc_ppm > ssc_ppm_max)) {
+			pll_res->ssc_ppm = ssc_ppm_max;
+			pr_debug("SSC PPM out of recommended range. Set to default=%d\n",
+				pll_res->ssc_ppm);
+		}
+	}
+
+	if ((pll_res->target_id == MDSS_PLL_TARGET_8952) ||
+		(pll_res->target_id == MDSS_PLL_TARGET_8937) ||
+		(pll_res->target_id == MDSS_PLL_TARGET_8909)) {
+		if (!pll_res->index)
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				dsi_pll0_cc, ARRAY_SIZE(dsi_pll0_cc));
+		else
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				dsi_pll1_cc, ARRAY_SIZE(dsi_pll1_cc));
+		if (rc) {
+			pr_err("Clock register failed\n");
+			rc = -EPROBE_DEFER;
+		}
+	} else {
+		pr_err("Invalid target ID\n");
+		rc = -EINVAL;
+	}
+
+	if (!rc)
+		pr_info("Registered DSI PLL:%d clocks successfully\n",
+				pll_res->index);
+
+	return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
new file mode 100644
index 0000000..c5d12e5
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996-util.c
@@ -0,0 +1,1239 @@
+/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clock-generic.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-dsi-pll-8996.h"
+
+#define DSI_PLL_POLL_MAX_READS                  15
+#define DSI_PLL_POLL_TIMEOUT_US                 1000
+#define MSM8996_DSI_PLL_REVISION_2		2
+
+#define DSI_PHY_SPARE_VAL	0x6a
+#define DSI_PLL_DEFAULT_POSTDIV	1
+
+#define CEIL(x, y)		(((x) + ((y)-1)) / (y))
+static void pll_db_commit_8996(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb);
+
+int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel)
+{
+	return 0;
+}
+
+int get_mdss_byte_mux_sel_8996(struct mux_clk *clk)
+{
+	return 0;
+}
+
+int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel)
+{
+	return 0;
+}
+
+int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk)
+{
+	return 0;
+}
+
+int post_n1_div_set_div(struct div_clk *clk, int div)
+{
+	struct mdss_pll_resources *pll = clk->priv;
+	struct dsi_pll_db *pdb;
+	struct dsi_pll_output *pout;
+	int rc;
+	u32 n1div = 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	pout = &pdb->out;
+
+	/*
+	 * vco rate = bit_clk * postdiv * n1div
+	 * vco range from 1300 to 2600 Mhz
+	 * postdiv = 1
+	 * n1div = 1 to 15
+	 * n1div = roundup(1300Mhz / bit_clk)
+	 * support bit_clk above 86.67Mhz
+	 */
+
+	/* this is for vco/bit clock */
+	pout->pll_postdiv = DSI_PLL_DEFAULT_POSTDIV;
+	pout->pll_n1div  = div;
+
+	n1div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	n1div &= ~0xf;
+	n1div |= (div & 0xf);
+	MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n1div);
+	/* ensure n1 divider is programed */
+	wmb();
+	pr_debug("ndx=%d div=%d postdiv=%x n1div=%x\n",
+			pll->index, div, pout->pll_postdiv, pout->pll_n1div);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return 0;
+}
+
+int post_n1_div_get_div(struct div_clk *clk)
+{
+	u32  div;
+	int rc;
+	struct mdss_pll_resources *pll = clk->priv;
+
+	if (is_gdsc_disabled(pll))
+		return 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/*
+	 * postdiv = 1/2/4/8
+	 * n1div = 1 - 15
+	 * fot the time being, assume postdiv = 1
+	 */
+
+	div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	div &= 0xF;
+	pr_debug("n1 div = %d\n", div);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return div;
+}
+
+int n2_div_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	u32 n2div;
+	struct mdss_pll_resources *pll = clk->priv;
+	struct dsi_pll_db *pdb;
+	struct dsi_pll_output *pout;
+	struct mdss_pll_resources *slave;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	pout = &pdb->out;
+
+	/* this is for pixel_clock */
+	n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	n2div &= ~0xf0;	/* bits 4 to 7 */
+	n2div |= (div << 4);
+	MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n2div);
+
+	/* commit slave if split display is enabled */
+	slave = pll->slave;
+	if (slave)
+		MDSS_PLL_REG_W(slave->pll_base, DSIPHY_CMN_CLK_CFG0, n2div);
+
+	pout->pll_n2div = div;
+
+	/* set dsiclk_sel=1 so that n2div *= 2 */
+	MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG1, 1);
+	pr_debug("ndx=%d div=%d n2div=%x\n", pll->index, div, n2div);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return rc;
+}
+
+int shadow_n2_div_set_div(struct div_clk *clk, int div)
+{
+	struct mdss_pll_resources *pll = clk->priv;
+	struct dsi_pll_db *pdb;
+	struct dsi_pll_output *pout;
+	u32 data;
+
+	pdb = pll->priv;
+	pout = &pdb->out;
+
+	pout->pll_n2div = div;
+
+	data = (pout->pll_n1div | (pout->pll_n2div << 4));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+			DSI_DYNAMIC_REFRESH_PLL_CTRL19,
+			DSIPHY_CMN_CLK_CFG0, DSIPHY_CMN_CLK_CFG1,
+			data, 1);
+	return 0;
+}
+
+int n2_div_get_div(struct div_clk *clk)
+{
+	int rc;
+	u32 n2div;
+	struct mdss_pll_resources *pll = clk->priv;
+
+	if (is_gdsc_disabled(pll))
+		return 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll=%d resources\n",
+						pll->index);
+		return rc;
+	}
+
+	n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0);
+	n2div >>= 4;
+	n2div &= 0x0f;
+
+	mdss_pll_resource_enable(pll, false);
+
+	pr_debug("ndx=%d div=%d\n", pll->index, n2div);
+
+	return n2div;
+}
+
+static bool pll_is_pll_locked_8996(struct mdss_pll_resources *pll)
+{
+	u32 status;
+	bool pll_locked;
+
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_atomic((pll->pll_base +
+			DSIPHY_PLL_RESET_SM_READY_STATUS),
+			status,
+			((status & BIT(5)) > 0),
+			DSI_PLL_POLL_MAX_READS,
+			DSI_PLL_POLL_TIMEOUT_US)) {
+		pr_err("DSI PLL ndx=%d status=%x failed to Lock\n",
+			pll->index, status);
+		pll_locked = false;
+	} else if (readl_poll_timeout_atomic((pll->pll_base +
+				DSIPHY_PLL_RESET_SM_READY_STATUS),
+				status,
+				((status & BIT(0)) > 0),
+				DSI_PLL_POLL_MAX_READS,
+				DSI_PLL_POLL_TIMEOUT_US)) {
+		pr_err("DSI PLL ndx=%d status=%x PLl not ready\n",
+			pll->index, status);
+		pll_locked = false;
+	} else {
+		pll_locked = true;
+	}
+
+	return pll_locked;
+}
+
+static void dsi_pll_start_8996(void __iomem *pll_base)
+{
+	pr_debug("start PLL at base=%pk\n", pll_base);
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VREF_CFG1, 0x10);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 1);
+	wmb();	/* make sure register committed */
+}
+
+static void dsi_pll_stop_8996(void __iomem *pll_base)
+{
+	pr_debug("stop PLL at base=%pk\n", pll_base);
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0);
+	wmb();	/* make sure register committed */
+}
+
+static inline bool pll_use_precal(struct mdss_pll_resources *pll)
+{
+	bool ret = true;
+	u32 spare = MDSS_PLL_REG_R(pll->pll_base,
+		DSIPHY_CMN_GLBL_DIGTOP_SPARE2);
+
+	if (!pll->cache_pll_trim_codes[0] || /* kvco code */
+	    !pll->cache_pll_trim_codes[1] || /* vco tune */
+	    !pll->cache_pll_trim_codes_rate ||
+	    (pll->cache_pll_trim_codes_rate != pll->vco_current_rate) ||
+	    (spare != DSI_PHY_SPARE_VAL)) /* phy reset */
+		ret = false;
+
+	pr_debug("ndx:%d kvco:%d vco_tune:%d spare:0x%x rate:%llu old:%llu ret:%d\n",
+		pll->index, pll->cache_pll_trim_codes[0],
+		pll->cache_pll_trim_codes[1], spare,
+		pll->cache_pll_trim_codes_rate,
+		pll->vco_current_rate, ret);
+
+	return ret;
+}
+
+int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll)
+{
+	int rc = 0;
+	struct dsi_pll_db *pdb;
+	struct mdss_pll_resources *slave;
+
+	if (!pll) {
+		pr_err("Invalid PLL resources\n");
+		return -EINVAL;
+	}
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	if (!pdb) {
+		pr_err("No priv found\n");
+		return -EINVAL;
+	}
+
+	dsi_pll_start_8996(pll->pll_base);
+
+	/*
+	 * both DSIPHY_PLL_CLKBUFLR_EN and DSIPHY_CMN_GLBL_TEST_CTRL
+	 * enabled at mdss_dsi_8996_phy_config()
+	 */
+
+	if (!pll_is_pll_locked_8996(pll)) {
+		pr_err("DSI PLL ndx=%d lock failed, retry full sequence!\n",
+			pll->index);
+		slave = pll->slave;
+
+		/* commit slave if split display is enabled */
+		if (slave)
+			pll_db_commit_8996(slave, pdb);
+
+		/* commit master itself */
+		pll_db_commit_8996(pll, pdb);
+
+		dsi_pll_start_8996(pll->pll_base);
+		if (!pll_is_pll_locked_8996(pll)) {
+			pr_err("DSI PLL ndx=%d lock failed!!!\n",
+				pll->index);
+			rc = -EINVAL;
+			goto init_lock_err;
+		}
+	}
+
+	if (!pll_use_precal(pll)) {
+		/* cache vco settings */
+		pll->cache_pll_trim_codes[0] = MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_CORE_KVCO_CODE_STATUS);
+		pll->cache_pll_trim_codes[1] = MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_CORE_VCO_TUNE_STATUS);
+		pll->cache_pll_trim_codes_rate = pll->vco_current_rate;
+
+		/* write spare */
+		MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_GLBL_DIGTOP_SPARE2,
+			DSI_PHY_SPARE_VAL);
+	}
+
+	pr_debug("DSI PLL ndx:%d Locked! kvco=0x%x vco_tune=0x%x rate=%llu\n",
+		pll->index, pll->cache_pll_trim_codes[0],
+		pll->cache_pll_trim_codes[1],
+		pll->cache_pll_trim_codes_rate);
+
+init_lock_err:
+	return rc;
+}
+
+static int dsi_pll_enable(struct clk *c)
+{
+	int i, rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	/* Try all enable sequences until one succeeds */
+	for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+		rc = vco->pll_enable_seqs[i](pll);
+		pr_debug("DSI PLL %s after sequence #%d\n",
+			rc ? "unlocked" : "locked", i + 1);
+		if (!rc)
+			break;
+	}
+
+	if (rc)
+		pr_err("ndx=%d DSI PLL failed to lock\n", pll->index);
+	else
+		pll->pll_on = true;
+
+	return rc;
+}
+
+static void dsi_pll_disable(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+	struct mdss_pll_resources *slave;
+
+	if (!pll->pll_on &&
+		mdss_pll_resource_enable(pll, true)) {
+		pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
+		return;
+	}
+
+	pll->handoff_resources = false;
+	slave = pll->slave;
+
+	dsi_pll_stop_8996(pll->pll_base);
+
+	mdss_pll_resource_enable(pll, false);
+
+	pll->pll_on = false;
+
+	pr_debug("DSI PLL ndx=%d Disabled\n", pll->index);
+}
+
+static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	pdb->in.fref = 19200000;	/* 19.2 Mhz*/
+	pdb->in.fdata = 0;		/* bit clock rate */
+	pdb->in.dsiclk_sel = 1;		/* 1, reg: 0x0014 */
+	pdb->in.ssc_en = pll->ssc_en;		/* 1, reg: 0x0494, bit 0 */
+	pdb->in.ldo_en = 0;		/* 0,  reg: 0x004c, bit 0 */
+
+	/* fixed  input */
+	pdb->in.refclk_dbler_en = 0;	/* 0, reg: 0x04c0, bit 1 */
+	pdb->in.vco_measure_time = 5;	/* 5, unknown */
+	pdb->in.kvco_measure_time = 5;	/* 5, unknown */
+	pdb->in.bandgap_timer = 4;	/* 4, reg: 0x0430, bit 3 - 5 */
+	pdb->in.pll_wakeup_timer = 5;	/* 5, reg: 0x043c, bit 0 - 2 */
+	pdb->in.plllock_cnt = 1;	/* 1, reg: 0x0488, bit 1 - 2 */
+	pdb->in.plllock_rng = 0;	/* 0, reg: 0x0488, bit 3 - 4 */
+	pdb->in.ssc_center = pll->ssc_center;/* 0, reg: 0x0494, bit 1 */
+	pdb->in.ssc_adj_period = 37;	/* 37, reg: 0x498, bit 0 - 9 */
+	pdb->in.ssc_spread = pll->ssc_ppm / 1000;
+	pdb->in.ssc_freq = pll->ssc_freq;
+
+	pdb->in.pll_ie_trim = 4;	/* 4, reg: 0x0400 */
+	pdb->in.pll_ip_trim = 4;	/* 4, reg: 0x0404 */
+	pdb->in.pll_cpcset_cur = 1;	/* 1, reg: 0x04f0, bit 0 - 2 */
+	pdb->in.pll_cpmset_cur = 1;	/* 1, reg: 0x04f0, bit 3 - 5 */
+	pdb->in.pll_icpmset = 4;	/* 4, reg: 0x04fc, bit 3 - 5 */
+	pdb->in.pll_icpcset = 4;	/* 4, reg: 0x04fc, bit 0 - 2 */
+	pdb->in.pll_icpmset_p = 0;	/* 0, reg: 0x04f4, bit 0 - 2 */
+	pdb->in.pll_icpmset_m = 0;	/* 0, reg: 0x04f4, bit 3 - 5 */
+	pdb->in.pll_icpcset_p = 0;	/* 0, reg: 0x04f8, bit 0 - 2 */
+	pdb->in.pll_icpcset_m = 0;	/* 0, reg: 0x04f8, bit 3 - 5 */
+	pdb->in.pll_lpf_res1 = 3;	/* 3, reg: 0x0504, bit 0 - 3 */
+	pdb->in.pll_lpf_cap1 = 11;	/* 11, reg: 0x0500, bit 0 - 3 */
+	pdb->in.pll_lpf_cap2 = 1;	/* 1, reg: 0x0500, bit 4 - 7 */
+	pdb->in.pll_iptat_trim = 7;
+	pdb->in.pll_c3ctrl = 2;		/* 2 */
+	pdb->in.pll_r3ctrl = 1;		/* 1 */
+}
+
+static void pll_8996_ssc_calc(struct mdss_pll_resources *pll,
+				struct dsi_pll_db *pdb)
+{
+	u32 period, ssc_period;
+	u32 ref, rem;
+	s64 step_size;
+
+	pr_debug("%s: vco=%lld ref=%lld\n", __func__,
+		pll->vco_current_rate, pll->vco_ref_clk_rate);
+
+	ssc_period = pdb->in.ssc_freq / 500;
+	period = (unsigned long)pll->vco_ref_clk_rate / 1000;
+	ssc_period  = CEIL(period, ssc_period);
+	ssc_period -= 1;
+	pdb->out.ssc_period = ssc_period;
+
+	pr_debug("%s: ssc, freq=%d spread=%d period=%d\n", __func__,
+	pdb->in.ssc_freq, pdb->in.ssc_spread, pdb->out.ssc_period);
+
+	step_size = (u32)pll->vco_current_rate;
+	ref = pll->vco_ref_clk_rate;
+	ref /= 1000;
+	step_size = div_s64(step_size, ref);
+	step_size <<= 20;
+	step_size = div_s64(step_size, 1000);
+	step_size *= pdb->in.ssc_spread;
+	step_size = div_s64(step_size, 1000);
+	step_size *= (pdb->in.ssc_adj_period + 1);
+
+	rem = 0;
+	step_size = div_s64_rem(step_size, ssc_period + 1, &rem);
+	if (rem)
+		step_size++;
+
+	pr_debug("%s: step_size=%lld\n", __func__, step_size);
+
+	step_size &= 0x0ffff;	/* take lower 16 bits */
+
+	pdb->out.ssc_step_size = step_size;
+}
+
+static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll,
+				struct dsi_pll_db *pdb)
+{
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	s64 multiplier = BIT(20);
+	s64 dec_start_multiple, dec_start, pll_comp_val;
+	s32 duration, div_frac_start;
+	s64 vco_clk_rate = pll->vco_current_rate;
+	s64 fref = pll->vco_ref_clk_rate;
+
+	pr_debug("vco_clk_rate=%lld ref_clk_rate=%lld\n",
+				vco_clk_rate, fref);
+
+	dec_start_multiple = div_s64(vco_clk_rate * multiplier, fref);
+	div_s64_rem(dec_start_multiple, multiplier, &div_frac_start);
+
+	dec_start = div_s64(dec_start_multiple, multiplier);
+
+	pout->dec_start = (u32)dec_start;
+	pout->div_frac_start = div_frac_start;
+
+	if (pin->plllock_cnt == 0)
+		duration = 1024;
+	else if (pin->plllock_cnt == 1)
+		duration = 256;
+	else if (pin->plllock_cnt == 2)
+		duration = 128;
+	else
+		duration = 32;
+
+	pll_comp_val =  duration * dec_start_multiple;
+	pll_comp_val =  div_s64(pll_comp_val, multiplier);
+	do_div(pll_comp_val, 10);
+
+	pout->plllock_cmp = (u32)pll_comp_val;
+
+	pout->pll_txclk_en = 1;
+	if (pll->revision == MSM8996_DSI_PLL_REVISION_2)
+		pout->cmn_ldo_cntrl = 0x3c;
+	else
+		pout->cmn_ldo_cntrl = 0x1c;
+}
+
+static u32 pll_8996_kvco_slop(u32 vrate)
+{
+	u32 slop = 0;
+
+	if (vrate > 1300000000UL && vrate <= 1800000000UL)
+		slop =  600;
+	else if (vrate > 1800000000UL && vrate < 2300000000UL)
+		slop = 400;
+	else if (vrate > 2300000000UL && vrate < 2600000000UL)
+		slop = 280;
+
+	return slop;
+}
+
+static inline u32 pll_8996_calc_kvco_code(s64 vco_clk_rate)
+{
+	u32 kvco_code;
+
+	if ((vco_clk_rate >= 2300000000ULL) &&
+	    (vco_clk_rate <= 2600000000ULL))
+		kvco_code = 0x2f;
+	else if ((vco_clk_rate >= 1800000000ULL) &&
+		 (vco_clk_rate < 2300000000ULL))
+		kvco_code = 0x2c;
+	else
+		kvco_code = 0x28;
+
+	pr_debug("rate: %llu kvco_code: 0x%x\n",
+		vco_clk_rate, kvco_code);
+	return kvco_code;
+}
+
+static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb,
+			 s64 vco_clk_rate, s64 fref)
+{
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	s64 data;
+	u32 cnt;
+
+	data = fref * pin->vco_measure_time;
+	do_div(data, 1000000);
+	data &= 0x03ff;	/* 10 bits */
+	data -= 2;
+	pout->pll_vco_div_ref = data;
+
+	data = (unsigned long)vco_clk_rate / 1000000;	/* unit is Mhz */
+	data *= pin->vco_measure_time;
+	do_div(data, 10);
+	pout->pll_vco_count = data; /* reg: 0x0474, 0x0478 */
+
+	data = fref * pin->kvco_measure_time;
+	do_div(data, 1000000);
+	data &= 0x03ff;	/* 10 bits */
+	data -= 1;
+	pout->pll_kvco_div_ref = data;
+
+	cnt = pll_8996_kvco_slop(vco_clk_rate);
+	cnt *= 2;
+	do_div(cnt, 100);
+	cnt *= pin->kvco_measure_time;
+	pout->pll_kvco_count = cnt;
+
+	pout->pll_misc1 = 16;
+	pout->pll_resetsm_cntrl = 48;
+	pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3;
+	pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer;
+	pout->pll_kvco_code = pll_8996_calc_kvco_code(vco_clk_rate);
+}
+
+static void pll_db_commit_ssc(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	data = pin->ssc_adj_period;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER1, data);
+	data = (pin->ssc_adj_period >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER2, data);
+
+	data = pout->ssc_period;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER1, data);
+	data = (pout->ssc_period >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER2, data);
+
+	data = pout->ssc_step_size;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE1, data);
+	data = (pout->ssc_step_size >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE2, data);
+
+	data = (pin->ssc_center & 0x01);
+	data <<= 1;
+	data |= 0x01; /* enable */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_EN_CENTER, data);
+
+	wmb();	/* make sure register committed */
+}
+
+static int pll_precal_commit_8996(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	/*
+	 * if pre-calibrated values cannot be used, return
+	 * error, so we use full sequence.
+	 */
+	if (!pll_use_precal(pll)) {
+		pr_debug("cannot use precal sequence ndx:%d\n", pll->index);
+		return -EINVAL;
+	}
+
+	data = pout->cmn_ldo_cntrl;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data);
+
+	/* stop pll */
+	data = 0;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, data);
+
+	data = 0x7f;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data);
+
+	data = 0x20;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, data);
+
+	data = 0x38;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL, data);
+
+	data = BIT(7);
+	data |= pll->cache_pll_trim_codes[1]; /* vco tune */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_VCO_TUNE, data);
+
+	data = BIT(5);
+	data |= pll->cache_pll_trim_codes[0]; /* kvco code */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_CODE, data);
+
+	data = 0xff; /* data, clk, pll normal operation */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data);
+
+	data = 0x0;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, data);
+	wmb();	/* make sure register committed */
+
+	return 0;
+}
+
+static void pll_db_commit_common(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	/* confgiure the non frequency dependent pll registers */
+	data = 0;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SYSCLK_EN_RESET, data);
+
+	/* DSIPHY_PLL_CLKBUFLR_EN updated at dsi phy */
+
+	data = pout->pll_txclk_en;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_TXCLK_EN, data);
+
+	data = pout->pll_resetsm_cntrl;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL, data);
+	data = pout->pll_resetsm_cntrl2;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL2, data);
+	data = pout->pll_resetsm_cntrl5;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL5, data);
+
+	data = pout->pll_vco_div_ref;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF1, data);
+	data = (pout->pll_vco_div_ref >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF2, data);
+
+	data = pout->pll_kvco_div_ref;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF1, data);
+	data = (pout->pll_kvco_div_ref >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF2, data);
+
+	data = pout->pll_misc1;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_MISC1, data);
+
+	data = pin->pll_ie_trim;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IE_TRIM, data);
+
+	data = pin->pll_ip_trim;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IP_TRIM, data);
+
+	data = ((pin->pll_cpmset_cur << 3) | pin->pll_cpcset_cur);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CP_SET_CUR, data);
+
+	data = ((pin->pll_icpcset_p << 3) | pin->pll_icpcset_m);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPCSET, data);
+
+	data = ((pin->pll_icpmset_p << 3) | pin->pll_icpcset_m);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPMSET, data);
+
+	data = ((pin->pll_icpmset << 3) | pin->pll_icpcset);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICP_SET, data);
+
+	data = ((pdb->in.pll_lpf_cap2 << 4) | pdb->in.pll_lpf_cap1);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF1, data);
+
+	data = pin->pll_iptat_trim;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IPTAT_TRIM, data);
+
+	data = (pdb->in.pll_c3ctrl | (pdb->in.pll_r3ctrl << 4));
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data);
+}
+
+static void pll_db_commit_8996(struct mdss_pll_resources *pll,
+					struct dsi_pll_db *pdb)
+{
+	void __iomem *pll_base = pll->pll_base;
+	struct dsi_pll_input *pin = &pdb->in;
+	struct dsi_pll_output *pout = &pdb->out;
+	char data;
+
+	data = pout->cmn_ldo_cntrl;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data);
+
+	pll_db_commit_common(pll, pdb);
+
+	/* de assert pll start and apply pll sw reset */
+	/* stop pll */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0);
+
+	/* pll sw reset */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0x20);
+	wmb();	/* make sure register committed */
+	udelay(10);
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0);
+	wmb();	/* make sure register committed */
+
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_VCO_TUNE, 0);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_CODE, 0);
+	wmb(); /* make sure register committed */
+
+	data = pdb->in.dsiclk_sel; /* set dsiclk_sel = 1  */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG1, data);
+
+	data = 0xff; /* data, clk, pll normal operation */
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data);
+
+	/* configure the frequency dependent pll registers */
+	data = pout->dec_start;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DEC_START, data);
+
+	data = pout->div_frac_start;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START1, data);
+	data = (pout->div_frac_start >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START2, data);
+	data = (pout->div_frac_start >> 16);
+	data &= 0x0f;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START3, data);
+
+	data = pout->plllock_cmp;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP1, data);
+	data = (pout->plllock_cmp >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP2, data);
+	data = (pout->plllock_cmp >> 16);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP3, data);
+
+	data = ((pin->plllock_cnt << 1) | (pin->plllock_rng << 3));
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP_EN, data);
+
+	data = pout->pll_vco_count;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT1, data);
+	data = (pout->pll_vco_count >> 8);
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT2, data);
+
+	data = pout->pll_kvco_count;
+	data &= 0x0ff;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT1, data);
+	data = (pout->pll_kvco_count >> 8);
+	data &= 0x03;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT2, data);
+
+	data = (((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1);
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF2_POSTDIV, data);
+
+	data = pout->pll_kvco_code;
+	MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_CODE, data);
+	pr_debug("kvco_code:0x%x\n", data);
+
+	data = (pout->pll_n1div | (pout->pll_n2div << 4));
+	MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG0, data);
+
+	if (pll->ssc_en)
+		pll_db_commit_ssc(pll, pdb);
+
+	pr_debug("pll:%d\n", pll->index);
+	wmb();	/* make sure register committed */
+}
+
+/*
+ * pll_source_finding:
+ * Both GLBL_TEST_CTRL and CLKBUFLR_EN are configured
+ * at mdss_dsi_8996_phy_config()
+ */
+static int pll_source_finding(struct mdss_pll_resources *pll)
+{
+	u32 clk_buf_en;
+	u32 glbl_test_ctrl;
+
+	glbl_test_ctrl = MDSS_PLL_REG_R(pll->pll_base,
+				DSIPHY_CMN_GLBL_TEST_CTRL);
+	clk_buf_en = MDSS_PLL_REG_R(pll->pll_base,
+				DSIPHY_PLL_CLKBUFLR_EN);
+
+	glbl_test_ctrl &= BIT(2);
+	glbl_test_ctrl >>= 2;
+
+	pr_debug("%s: pll=%d clk_buf_en=%x glbl_test_ctrl=%x\n",
+		__func__, pll->index, clk_buf_en, glbl_test_ctrl);
+
+	clk_buf_en &= (PLL_OUTPUT_RIGHT | PLL_OUTPUT_LEFT);
+
+	if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) &&
+			(clk_buf_en == PLL_OUTPUT_BOTH))
+		return PLL_MASTER;
+
+	if ((glbl_test_ctrl == PLL_SOURCE_FROM_RIGHT) &&
+			(clk_buf_en == PLL_OUTPUT_NONE))
+		return PLL_SLAVE;
+
+	if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) &&
+			(clk_buf_en == PLL_OUTPUT_RIGHT))
+		return PLL_STANDALONE;
+
+	pr_debug("%s: Error pll setup, clk_buf_en=%x glbl_test_ctrl=%x\n",
+			__func__, clk_buf_en, glbl_test_ctrl);
+
+	return PLL_UNKNOWN;
+}
+
+static void pll_source_setup(struct mdss_pll_resources *pll)
+{
+	int status;
+	struct dsi_pll_db *pdb = (struct dsi_pll_db *)pll->priv;
+	struct mdss_pll_resources *other;
+
+	if (pdb->source_setup_done)
+		return;
+
+	pdb->source_setup_done++;
+
+	status = pll_source_finding(pll);
+
+	if (status == PLL_STANDALONE || status == PLL_UNKNOWN)
+		return;
+
+	other = pdb->next->pll;
+	if (!other)
+		return;
+
+	pr_debug("%s: status=%d pll=%d other=%d\n", __func__,
+			status, pll->index, other->index);
+
+	if (status == PLL_MASTER)
+		pll->slave = other;
+	else
+		other->slave = pll;
+}
+
+int pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
+{
+	int rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+	struct mdss_pll_resources *slave;
+	struct dsi_pll_db *pdb;
+
+	pdb = (struct dsi_pll_db *)pll->priv;
+	if (!pdb) {
+		pr_err("No prov found\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi plla=%d\n", pll->index);
+		return rc;
+	}
+
+	pll_source_setup(pll);
+
+	pr_debug("%s: ndx=%d base=%pk rate=%lu slave=%pk\n", __func__,
+				pll->index, pll->pll_base, rate, pll->slave);
+
+	pll->vco_current_rate = rate;
+	pll->vco_ref_clk_rate = vco->ref_clk_rate;
+
+	mdss_dsi_pll_8996_input_init(pll, pdb);
+	/*
+	 * tx_band = pll_postdiv
+	 * 0: divided by 1 <== for now
+	 * 1: divided by 2
+	 * 2: divided by 4
+	 * 3: divided by 8
+	 */
+	pdb->out.pll_postdiv = DSI_PLL_DEFAULT_POSTDIV;
+
+	pll_8996_dec_frac_calc(pll, pdb);
+
+	if (pll->ssc_en)
+		pll_8996_ssc_calc(pll, pdb);
+
+	pll_8996_calc_vco_count(pdb, pll->vco_current_rate,
+					pll->vco_ref_clk_rate);
+
+	/* precal sequence, only for the master */
+	if (pll_precal_commit_8996(pll, pdb)) {
+		pr_debug("retry full sequence\n");
+		slave = pll->slave;
+
+		/* commit slave if split display is enabled */
+		if (slave)
+			pll_db_commit_8996(slave, pdb);
+
+		/* commit master itself */
+		pll_db_commit_8996(pll, pdb);
+	}
+
+	mdss_pll_resource_enable(pll, false);
+
+	return rc;
+}
+
+static void shadow_pll_dynamic_refresh_8996(struct mdss_pll_resources *pll,
+				struct dsi_pll_db *pdb, int *pll_trim_codes)
+{
+	struct dsi_pll_output *pout = &pdb->out;
+
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL20,
+		DSIPHY_CMN_CTRL_0, DSIPHY_PLL_SYSCLK_EN_RESET,
+		0xFF, 0x0);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL21,
+		DSIPHY_PLL_DEC_START, DSIPHY_PLL_DIV_FRAC_START1,
+		pout->dec_start, (pout->div_frac_start & 0x0FF));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL22,
+		DSIPHY_PLL_DIV_FRAC_START2, DSIPHY_PLL_DIV_FRAC_START3,
+		((pout->div_frac_start >> 8) & 0x0FF),
+		((pout->div_frac_start >> 16) & 0x0F));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL23,
+		DSIPHY_PLL_PLLLOCK_CMP1, DSIPHY_PLL_PLLLOCK_CMP2,
+		(pout->plllock_cmp & 0x0FF),
+		((pout->plllock_cmp >> 8) & 0x0FF));
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL24,
+		DSIPHY_PLL_PLLLOCK_CMP3, DSIPHY_PLL_PLL_VCO_TUNE,
+		((pout->plllock_cmp >> 16) & 0x03),
+		(pll_trim_codes[1] | BIT(7))); /* VCO tune*/
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL25,
+		DSIPHY_PLL_KVCO_CODE, DSIPHY_PLL_RESETSM_CNTRL,
+		(pll_trim_codes[0] | BIT(5)), 0x38);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL26,
+		DSIPHY_PLL_PLL_LPF2_POSTDIV, DSIPHY_CMN_PLL_CNTRL,
+		(((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1), 0x01);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL27,
+		DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL,
+		0x01, 0x01);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL28,
+		DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL,
+		0x01, 0x01);
+	MDSS_DYN_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_CTRL29,
+		DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL,
+		0x01, 0x01);
+	MDSS_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, 0x0000001E);
+	MDSS_PLL_REG_W(pll->dyn_pll_base,
+		DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0x001FFE00);
+
+	pr_debug("core_kvco_code=0x%x core_vco_tune=0x%x\n",
+			pll_trim_codes[0], pll_trim_codes[1]);
+
+	/*
+	 * Ensure all the dynamic refresh registers are written before
+	 * dynamic refresh to change the fps is triggered
+	 */
+	wmb();
+}
+
+int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate)
+{
+	int rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+	struct dsi_pll_db *pdb;
+	int pll_trim_codes[2] = {0, 0};
+
+	if (!pll) {
+		pr_err("PLL data not found\n");
+		return -EINVAL;
+	}
+
+	pdb = pll->priv;
+	if (!pdb) {
+		pr_err("No priv data found\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi plla=%d\n", pll->index);
+		return rc;
+	}
+
+	pr_debug("%s: ndx=%d base=%pk rate=%lu\n", __func__,
+			pll->index, pll->pll_base, rate);
+
+	pll->vco_current_rate = rate;
+	pll->vco_ref_clk_rate = vco->ref_clk_rate;
+
+	mdss_dsi_pll_8996_input_init(pll, pdb);
+
+	pll_8996_dec_frac_calc(pll, pdb);
+
+	pll_8996_calc_vco_count(pdb, pll->vco_current_rate,
+			pll->vco_ref_clk_rate);
+
+	shadow_pll_dynamic_refresh_8996(pll, pdb, pll_trim_codes);
+
+	rc = mdss_pll_resource_enable(pll, false);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi plla=%d\n", pll->index);
+		return rc;
+	}
+
+	return rc;
+}
+
+static unsigned long pll_vco_get_rate_8996(struct clk *c)
+{
+	u64 vco_rate, multiplier = BIT(20);
+	s32 div_frac_start;
+	u32 dec_start;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	u64 ref_clk = vco->ref_clk_rate;
+	int rc;
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (is_gdsc_disabled(pll))
+		return 0;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
+		return rc;
+	}
+
+	dec_start = MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DEC_START);
+	dec_start &= 0x0ff;
+	pr_debug("dec_start = 0x%x\n", dec_start);
+
+	div_frac_start = (MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DIV_FRAC_START3) & 0x0f) << 16;
+	div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8;
+	div_frac_start |= MDSS_PLL_REG_R(pll->pll_base,
+			DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff;
+	pr_debug("div_frac_start = 0x%x\n", div_frac_start);
+
+	vco_rate = ref_clk * dec_start;
+	vco_rate += ((ref_clk * div_frac_start) / multiplier);
+
+	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+	mdss_pll_resource_enable(pll, false);
+
+	return (unsigned long)vco_rate;
+}
+
+long pll_vco_round_rate_8996(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+	u32 div;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+	div = vco->min_rate / rate;
+	if (div > 15) {
+		/* rate < 86.67 Mhz */
+		pr_err("rate=%lu NOT supportted\n", rate);
+		return -EINVAL;
+	}
+
+	if (rate < vco->min_rate)
+		rrate = vco->min_rate;
+	if (rate > vco->max_rate)
+		rrate = vco->max_rate;
+
+	return rrate;
+}
+
+enum handoff pll_vco_handoff_8996(struct clk *c)
+{
+	int rc;
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (is_gdsc_disabled(pll))
+		return HANDOFF_DISABLED_CLK;
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll=%d\n", pll->index);
+		return ret;
+	}
+
+	if (pll_is_pll_locked_8996(pll)) {
+		pll->handoff_resources = true;
+		pll->pll_on = true;
+		c->rate = pll_vco_get_rate_8996(c);
+		ret = HANDOFF_ENABLED_CLK;
+	} else {
+		mdss_pll_resource_enable(pll, false);
+	}
+
+	return ret;
+}
+
+enum handoff shadow_pll_vco_handoff_8996(struct clk *c)
+{
+	return HANDOFF_DISABLED_CLK;
+}
+
+int pll_vco_prepare_8996(struct clk *c)
+{
+	int rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (!pll) {
+		pr_err("Dsi pll resources are not available\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_resource_enable(pll, true);
+	if (rc) {
+		pr_err("ndx=%d Failed to enable mdss dsi pll resources\n",
+							pll->index);
+		return rc;
+	}
+
+	if ((pll->vco_cached_rate != 0)
+	    && (pll->vco_cached_rate == c->rate)) {
+		rc = c->ops->set_rate(c, pll->vco_cached_rate);
+		if (rc) {
+			pr_err("index=%d vco_set_rate failed. rc=%d\n",
+					rc, pll->index);
+			mdss_pll_resource_enable(pll, false);
+			goto error;
+		}
+	}
+
+	rc = dsi_pll_enable(c);
+
+	if (rc) {
+		mdss_pll_resource_enable(pll, false);
+		pr_err("ndx=%d failed to enable dsi pll\n", pll->index);
+	}
+
+error:
+	return rc;
+}
+
+void pll_vco_unprepare_8996(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll = vco->priv;
+
+	if (!pll) {
+		pr_err("Dsi pll resources are not available\n");
+		return;
+	}
+
+	pll->vco_cached_rate = c->rate;
+	dsi_pll_disable(c);
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996.c b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.c
new file mode 100644
index 0000000..6423342
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.c
@@ -0,0 +1,572 @@
+/* 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.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/workqueue.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/msm-clocks-8996.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-dsi-pll-8996.h"
+
+#define VCO_DELAY_USEC		1
+
+static struct dsi_pll_db pll_db[DSI_PLL_NUM];
+
+static struct clk_ops n2_clk_src_ops;
+static struct clk_ops shadow_n2_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops post_n1_div_clk_src_ops;
+static struct clk_ops shadow_post_n1_div_clk_src_ops;
+
+static struct clk_ops clk_ops_gen_mux_dsi;
+
+/* Op structures */
+static const struct clk_ops clk_ops_dsi_vco = {
+	.set_rate = pll_vco_set_rate_8996,
+	.round_rate = pll_vco_round_rate_8996,
+	.handoff = pll_vco_handoff_8996,
+	.prepare = pll_vco_prepare_8996,
+	.unprepare = pll_vco_unprepare_8996,
+};
+
+static struct clk_div_ops post_n1_div_ops = {
+	.set_div = post_n1_div_set_div,
+	.get_div = post_n1_div_get_div,
+};
+
+static struct clk_div_ops n2_div_ops = {	/* hr_oclk3 */
+	.set_div = n2_div_set_div,
+	.get_div = n2_div_get_div,
+};
+
+static struct clk_mux_ops mdss_byte_mux_ops = {
+	.set_mux_sel = set_mdss_byte_mux_sel_8996,
+	.get_mux_sel = get_mdss_byte_mux_sel_8996,
+};
+
+static struct clk_mux_ops mdss_pixel_mux_ops = {
+	.set_mux_sel = set_mdss_pixel_mux_sel_8996,
+	.get_mux_sel = get_mdss_pixel_mux_sel_8996,
+};
+
+/* Shadow ops for dynamic refresh */
+static const struct clk_ops clk_ops_shadow_dsi_vco = {
+	.set_rate = shadow_pll_vco_set_rate_8996,
+	.round_rate = pll_vco_round_rate_8996,
+	.handoff = shadow_pll_vco_handoff_8996,
+};
+
+static struct clk_div_ops shadow_post_n1_div_ops = {
+	.set_div = post_n1_div_set_div,
+};
+
+static struct clk_div_ops shadow_n2_div_ops = {
+	.set_div = shadow_n2_div_set_div,
+};
+
+static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
+	.ref_clk_rate = 19200000UL,
+	.min_rate = 1300000000UL,
+	.max_rate = 2600000000UL,
+	.pll_en_seq_cnt = 1,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
+	.c = {
+		.dbg_name = "dsi0pll_vco_clk_8996",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi0pll_vco_clk.c),
+	},
+};
+
+static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = {
+	.ref_clk_rate = 19200000u,
+	.min_rate = 1300000000u,
+	.max_rate = 2600000000u,
+	.c = {
+		.dbg_name = "dsi0pll_shadow_vco_clk",
+		.ops = &clk_ops_shadow_dsi_vco,
+		CLK_INIT(dsi0pll_shadow_vco_clk.c),
+	},
+};
+
+static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
+	.ref_clk_rate = 19200000UL,
+	.min_rate = 1300000000UL,
+	.max_rate = 2600000000UL,
+	.pll_en_seq_cnt = 1,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
+	.c = {
+		.dbg_name = "dsi1pll_vco_clk_8996",
+		.ops = &clk_ops_dsi_vco,
+		CLK_INIT(dsi1pll_vco_clk.c),
+	},
+};
+
+static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = {
+	.ref_clk_rate = 19200000u,
+	.min_rate = 1300000000u,
+	.max_rate = 2600000000u,
+	.pll_en_seq_cnt = 1,
+	.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
+	.c = {
+		.dbg_name = "dsi1pll_shadow_vco_clk",
+		.ops = &clk_ops_shadow_dsi_vco,
+		CLK_INIT(dsi1pll_shadow_vco_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &post_n1_div_ops,
+	.c = {
+		.parent = &dsi0pll_vco_clk.c,
+		.dbg_name = "dsi0pll_post_n1_div_clk",
+		.ops = &post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_post_n1_div_ops,
+	.c = {
+		.parent = &dsi0pll_shadow_vco_clk.c,
+		.dbg_name = "dsi0pll_shadow_post_n1_div_clk",
+		.ops = &shadow_post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_shadow_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &post_n1_div_ops,
+	.c = {
+		.parent = &dsi1pll_vco_clk.c,
+		.dbg_name = "dsi1pll_post_n1_div_clk",
+		.ops = &post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_post_n1_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_post_n1_div_ops,
+	.c = {
+		.parent = &dsi1pll_shadow_vco_clk.c,
+		.dbg_name = "dsi1pll_shadow_post_n1_div_clk",
+		.ops = &shadow_post_n1_div_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_shadow_post_n1_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &n2_div_ops,
+	.c = {
+		.parent = &dsi0pll_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_n2_div_clk",
+		.ops = &n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_n2_div_ops,
+	.c = {
+		.parent = &dsi0pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_shadow_n2_div_clk",
+		.ops = &shadow_n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_shadow_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &n2_div_ops,
+	.c = {
+		.parent = &dsi1pll_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_n2_div_clk",
+		.ops = &n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_n2_div_clk = {
+	.data = {
+		.max_div = 15,
+		.min_div = 1,
+	},
+	.ops = &shadow_n2_div_ops,
+	.c = {
+		.parent = &dsi1pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_shadow_n2_div_clk",
+		.ops = &shadow_n2_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_shadow_n2_div_clk.c),
+	},
+};
+
+static struct div_clk dsi0pll_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi0pll_n2_div_clk.c,
+		.dbg_name = "dsi0pll_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_pixel_clk_src.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi0pll_shadow_n2_div_clk.c,
+		.dbg_name = "dsi0pll_shadow_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_shadow_pixel_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi1pll_n2_div_clk.c,
+		.dbg_name = "dsi1pll_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_pixel_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_pixel_clk_src = {
+	.data = {
+		.div = 2,
+		.min_div = 2,
+		.max_div = 2,
+	},
+	.c = {
+		.parent = &dsi1pll_shadow_n2_div_clk.c,
+		.dbg_name = "dsi1pll_shadow_pixel_clk_src",
+		.ops = &clk_ops_div,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_shadow_pixel_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi0pll_pixel_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi0pll_pixel_clk_src.c, 0},
+		{&dsi0pll_shadow_pixel_clk_src.c, 1},
+	},
+	.ops = &mdss_pixel_mux_ops,
+	.c = {
+		.parent = &dsi0pll_pixel_clk_src.c,
+		.dbg_name = "dsi0pll_pixel_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_pixel_clk_mux.c),
+	}
+};
+
+static struct mux_clk dsi1pll_pixel_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi1pll_pixel_clk_src.c, 0},
+		{&dsi1pll_shadow_pixel_clk_src.c, 1},
+	},
+	.ops = &mdss_pixel_mux_ops,
+	.c = {
+		.parent = &dsi1pll_pixel_clk_src.c,
+		.dbg_name = "dsi1pll_pixel_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_pixel_clk_mux.c),
+	}
+};
+
+static struct div_clk dsi0pll_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi0pll_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi0pll_byte_clk_src.c),
+	},
+};
+
+static struct div_clk dsi0pll_shadow_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi0pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi0pll_shadow_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi0pll_shadow_byte_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi1pll_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi1pll_byte_clk_src.c),
+	},
+};
+
+static struct div_clk dsi1pll_shadow_byte_clk_src = {
+	.data = {
+		.div = 8,
+		.min_div = 8,
+		.max_div = 8,
+	},
+	.c = {
+		.parent = &dsi1pll_shadow_post_n1_div_clk.c,
+		.dbg_name = "dsi1pll_shadow_byte_clk_src",
+		.ops = &clk_ops_div,
+		CLK_INIT(dsi1pll_shadow_byte_clk_src.c),
+	},
+};
+
+static struct mux_clk dsi0pll_byte_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi0pll_byte_clk_src.c, 0},
+		{&dsi0pll_shadow_byte_clk_src.c, 1},
+	},
+	.ops = &mdss_byte_mux_ops,
+	.c = {
+		.parent = &dsi0pll_byte_clk_src.c,
+		.dbg_name = "dsi0pll_byte_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi0pll_byte_clk_mux.c),
+	}
+};
+static struct mux_clk dsi1pll_byte_clk_mux = {
+	.num_parents = 2,
+	.parents = (struct clk_src[]) {
+		{&dsi1pll_byte_clk_src.c, 0},
+		{&dsi1pll_shadow_byte_clk_src.c, 1},
+	},
+	.ops = &mdss_byte_mux_ops,
+	.c = {
+		.parent = &dsi1pll_byte_clk_src.c,
+		.dbg_name = "dsi1pll_byte_clk_mux",
+		.ops = &clk_ops_gen_mux_dsi,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(dsi1pll_byte_clk_mux.c),
+	}
+};
+
+static struct clk_lookup mdss_dsi_pllcc_8996[] = {
+	CLK_LIST(dsi0pll_byte_clk_mux),
+	CLK_LIST(dsi0pll_byte_clk_src),
+	CLK_LIST(dsi0pll_pixel_clk_mux),
+	CLK_LIST(dsi0pll_pixel_clk_src),
+	CLK_LIST(dsi0pll_n2_div_clk),
+	CLK_LIST(dsi0pll_post_n1_div_clk),
+	CLK_LIST(dsi0pll_vco_clk),
+	CLK_LIST(dsi0pll_shadow_byte_clk_src),
+	CLK_LIST(dsi0pll_shadow_pixel_clk_src),
+	CLK_LIST(dsi0pll_shadow_n2_div_clk),
+	CLK_LIST(dsi0pll_shadow_post_n1_div_clk),
+	CLK_LIST(dsi0pll_shadow_vco_clk),
+};
+
+static struct clk_lookup mdss_dsi_pllcc_8996_1[] = {
+	CLK_LIST(dsi1pll_byte_clk_mux),
+	CLK_LIST(dsi1pll_byte_clk_src),
+	CLK_LIST(dsi1pll_pixel_clk_mux),
+	CLK_LIST(dsi1pll_pixel_clk_src),
+	CLK_LIST(dsi1pll_n2_div_clk),
+	CLK_LIST(dsi1pll_post_n1_div_clk),
+	CLK_LIST(dsi1pll_vco_clk),
+	CLK_LIST(dsi1pll_shadow_byte_clk_src),
+	CLK_LIST(dsi1pll_shadow_pixel_clk_src),
+	CLK_LIST(dsi1pll_shadow_n2_div_clk),
+	CLK_LIST(dsi1pll_shadow_post_n1_div_clk),
+	CLK_LIST(dsi1pll_shadow_vco_clk),
+};
+
+int dsi_pll_clock_register_8996(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc = 0, ndx;
+	int const ssc_freq_default = 31500; /* default h/w recommended value */
+	int const ssc_ppm_default = 5000; /* default h/w recommended value */
+	struct dsi_pll_db *pdb;
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	if (!pll_res || !pll_res->pll_base) {
+		pr_err("Invalid PLL resources\n");
+		return -EPROBE_DEFER;
+	}
+
+	if (pll_res->index >= DSI_PLL_NUM) {
+		pr_err("pll ndx=%d is NOT supported\n", pll_res->index);
+		return -EINVAL;
+	}
+
+	ndx = pll_res->index;
+	pdb = &pll_db[ndx];
+	pll_res->priv = pdb;
+	pdb->pll = pll_res;
+	ndx++;
+	ndx %= DSI_PLL_NUM;
+	pdb->next = &pll_db[ndx];
+
+	/* Set clock source operations */
+
+	/* hr_oclk3, pixel_clock */
+	n2_clk_src_ops = clk_ops_slave_div;
+	n2_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	shadow_n2_clk_src_ops = clk_ops_slave_div;
+
+	/* hr_ockl2, byte, vco pll */
+	post_n1_div_clk_src_ops = clk_ops_div;
+	post_n1_div_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	shadow_post_n1_div_clk_src_ops = clk_ops_div;
+
+	byte_clk_src_ops = clk_ops_div;
+	byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+
+	clk_ops_gen_mux_dsi = clk_ops_gen_mux;
+	clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
+	clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
+
+	if (pll_res->ssc_en) {
+		if (!pll_res->ssc_freq)
+			pll_res->ssc_freq = ssc_freq_default;
+		if (!pll_res->ssc_ppm)
+			pll_res->ssc_ppm = ssc_ppm_default;
+	}
+
+	/* Set client data to mux, div and vco clocks.  */
+	if (pll_res->index == DSI_PLL_1) {
+		dsi1pll_byte_clk_src.priv = pll_res;
+		dsi1pll_pixel_clk_src.priv = pll_res;
+		dsi1pll_post_n1_div_clk.priv = pll_res;
+		dsi1pll_n2_div_clk.priv = pll_res;
+		dsi1pll_vco_clk.priv = pll_res;
+
+		dsi1pll_shadow_byte_clk_src.priv = pll_res;
+		dsi1pll_shadow_pixel_clk_src.priv = pll_res;
+		dsi1pll_shadow_post_n1_div_clk.priv = pll_res;
+		dsi1pll_shadow_n2_div_clk.priv = pll_res;
+		dsi1pll_shadow_vco_clk.priv = pll_res;
+
+		pll_res->vco_delay = VCO_DELAY_USEC;
+		if ((pll_res->target_id == MDSS_PLL_TARGET_8996) ||
+			(pll_res->target_id == MDSS_PLL_TARGET_8953)) {
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				mdss_dsi_pllcc_8996_1,
+				ARRAY_SIZE(mdss_dsi_pllcc_8996_1));
+		}
+	} else {
+		dsi0pll_byte_clk_src.priv = pll_res;
+		dsi0pll_pixel_clk_src.priv = pll_res;
+		dsi0pll_post_n1_div_clk.priv = pll_res;
+		dsi0pll_n2_div_clk.priv = pll_res;
+		dsi0pll_vco_clk.priv = pll_res;
+
+		dsi0pll_shadow_byte_clk_src.priv = pll_res;
+		dsi0pll_shadow_pixel_clk_src.priv = pll_res;
+		dsi0pll_shadow_post_n1_div_clk.priv = pll_res;
+		dsi0pll_shadow_n2_div_clk.priv = pll_res;
+		dsi0pll_shadow_vco_clk.priv = pll_res;
+
+		pll_res->vco_delay = VCO_DELAY_USEC;
+		if ((pll_res->target_id == MDSS_PLL_TARGET_8996) ||
+			(pll_res->target_id == MDSS_PLL_TARGET_8953)) {
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				mdss_dsi_pllcc_8996,
+				ARRAY_SIZE(mdss_dsi_pllcc_8996));
+		}
+	}
+
+	if (!rc) {
+		pr_info("Registered DSI PLL ndx=%d clocks successfully\n",
+						pll_res->index);
+	}
+
+	return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h
new file mode 100644
index 0000000..57700e8
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-8996.h
@@ -0,0 +1,224 @@
+/* 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.
+ */
+
+#ifndef MDSS_DSI_PLL_8996_H
+#define MDSS_DSI_PLL_8996_H
+
+#define DSIPHY_CMN_CLK_CFG0		0x0010
+#define DSIPHY_CMN_CLK_CFG1		0x0014
+#define DSIPHY_CMN_GLBL_TEST_CTRL	0x0018
+
+#define DSIPHY_CMN_PLL_CNTRL		0x0048
+#define DSIPHY_CMN_CTRL_0		0x001c
+#define DSIPHY_CMN_CTRL_1		0x0020
+
+#define DSIPHY_CMN_LDO_CNTRL		0x004c
+#define DSIPHY_CMN_GLBL_DIGTOP_SPARE2	0x005c
+
+#define DSIPHY_PLL_IE_TRIM		0x0400
+#define DSIPHY_PLL_IP_TRIM		0x0404
+
+#define DSIPHY_PLL_IPTAT_TRIM		0x0410
+
+#define DSIPHY_PLL_CLKBUFLR_EN		0x041c
+
+#define DSIPHY_PLL_SYSCLK_EN_RESET	0x0428
+#define DSIPHY_PLL_RESETSM_CNTRL	0x042c
+#define DSIPHY_PLL_RESETSM_CNTRL2	0x0430
+#define DSIPHY_PLL_RESETSM_CNTRL3	0x0434
+#define DSIPHY_PLL_RESETSM_CNTRL4	0x0438
+#define DSIPHY_PLL_RESETSM_CNTRL5	0x043c
+#define DSIPHY_PLL_KVCO_DIV_REF1	0x0440
+#define DSIPHY_PLL_KVCO_DIV_REF2	0x0444
+#define DSIPHY_PLL_KVCO_COUNT1		0x0448
+#define DSIPHY_PLL_KVCO_COUNT2		0x044c
+#define DSIPHY_PLL_VREF_CFG1		0x045c
+
+#define DSIPHY_PLL_KVCO_CODE		0x0458
+#define DSIPHY_PLL_CORE_VCO_TUNE_STATUS	0x4D0
+#define DSIPHY_PLL_CORE_KVCO_CODE_STATUS	0x4D4
+
+#define DSIPHY_PLL_VCO_DIV_REF1		0x046c
+#define DSIPHY_PLL_VCO_DIV_REF2		0x0470
+#define DSIPHY_PLL_VCO_COUNT1		0x0474
+#define DSIPHY_PLL_VCO_COUNT2		0x0478
+#define DSIPHY_PLL_PLLLOCK_CMP1		0x047c
+#define DSIPHY_PLL_PLLLOCK_CMP2		0x0480
+#define DSIPHY_PLL_PLLLOCK_CMP3		0x0484
+#define DSIPHY_PLL_PLLLOCK_CMP_EN	0x0488
+#define DSIPHY_PLL_PLL_VCO_TUNE		0x048C
+#define DSIPHY_PLL_DEC_START		0x0490
+#define DSIPHY_PLL_SSC_EN_CENTER	0x0494
+#define DSIPHY_PLL_SSC_ADJ_PER1		0x0498
+#define DSIPHY_PLL_SSC_ADJ_PER2		0x049c
+#define DSIPHY_PLL_SSC_PER1		0x04a0
+#define DSIPHY_PLL_SSC_PER2		0x04a4
+#define DSIPHY_PLL_SSC_STEP_SIZE1	0x04a8
+#define DSIPHY_PLL_SSC_STEP_SIZE2	0x04ac
+#define DSIPHY_PLL_DIV_FRAC_START1	0x04b4
+#define DSIPHY_PLL_DIV_FRAC_START2	0x04b8
+#define DSIPHY_PLL_DIV_FRAC_START3	0x04bc
+#define DSIPHY_PLL_TXCLK_EN		0x04c0
+#define DSIPHY_PLL_PLL_CRCTRL		0x04c4
+
+#define DSIPHY_PLL_RESET_SM_READY_STATUS 0x04cc
+
+#define DSIPHY_PLL_PLL_MISC1		0x04e8
+
+#define DSIPHY_PLL_CP_SET_CUR		0x04f0
+#define DSIPHY_PLL_PLL_ICPMSET		0x04f4
+#define DSIPHY_PLL_PLL_ICPCSET		0x04f8
+#define DSIPHY_PLL_PLL_ICP_SET		0x04fc
+#define DSIPHY_PLL_PLL_LPF1		0x0500
+#define DSIPHY_PLL_PLL_LPF2_POSTDIV	0x0504
+#define DSIPHY_PLL_PLL_BANDGAP	0x0508
+
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL15		0x050
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL19		0x060
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL20		0x064
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL21		0x068
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL22		0x06C
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL23		0x070
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL24		0x074
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL25		0x078
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL26		0x07C
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL27		0x080
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL28		0x084
+#define DSI_DYNAMIC_REFRESH_PLL_CTRL29		0x088
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR	0x094
+#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2	0x098
+
+struct dsi_pll_input {
+	u32 fref;	/* 19.2 Mhz, reference clk */
+	u32 fdata;	/* bit clock rate */
+	u32 dsiclk_sel; /* 1, reg: 0x0014 */
+	u32 n2div;	/* 1, reg: 0x0010, bit 4-7 */
+	u32 ssc_en;	/* 1, reg: 0x0494, bit 0 */
+	u32 ldo_en;	/* 0,  reg: 0x004c, bit 0 */
+
+	/* fixed  */
+	u32 refclk_dbler_en;	/* 0, reg: 0x04c0, bit 1 */
+	u32 vco_measure_time;	/* 5, unknown */
+	u32 kvco_measure_time;	/* 5, unknown */
+	u32 bandgap_timer;	/* 4, reg: 0x0430, bit 3 - 5 */
+	u32 pll_wakeup_timer;	/* 5, reg: 0x043c, bit 0 - 2 */
+	u32 plllock_cnt;	/* 1, reg: 0x0488, bit 1 - 2 */
+	u32 plllock_rng;	/* 1, reg: 0x0488, bit 3 - 4 */
+	u32 ssc_center;		/* 0, reg: 0x0494, bit 1 */
+	u32 ssc_adj_period;	/* 37, reg: 0x498, bit 0 - 9 */
+	u32 ssc_spread;		/* 0.005  */
+	u32 ssc_freq;		/* unknown */
+	u32 pll_ie_trim;	/* 4, reg: 0x0400 */
+	u32 pll_ip_trim;	/* 4, reg: 0x0404 */
+	u32 pll_iptat_trim;	/* reg: 0x0410 */
+	u32 pll_cpcset_cur;	/* 1, reg: 0x04f0, bit 0 - 2 */
+	u32 pll_cpmset_cur;	/* 1, reg: 0x04f0, bit 3 - 5 */
+
+	u32 pll_icpmset;	/* 4, reg: 0x04fc, bit 3 - 5 */
+	u32 pll_icpcset;	/* 4, reg: 0x04fc, bit 0 - 2 */
+
+	u32 pll_icpmset_p;	/* 0, reg: 0x04f4, bit 0 - 2 */
+	u32 pll_icpmset_m;	/* 0, reg: 0x04f4, bit 3 - 5 */
+
+	u32 pll_icpcset_p;	/* 0, reg: 0x04f8, bit 0 - 2 */
+	u32 pll_icpcset_m;	/* 0, reg: 0x04f8, bit 3 - 5 */
+
+	u32 pll_lpf_res1;	/* 3, reg: 0x0504, bit 0 - 3 */
+	u32 pll_lpf_cap1;	/* 11, reg: 0x0500, bit 0 - 3 */
+	u32 pll_lpf_cap2;	/* 1, reg: 0x0500, bit 4 - 7 */
+	u32 pll_c3ctrl;		/* 2, reg: 0x04c4 */
+	u32 pll_r3ctrl;		/* 1, reg: 0x04c4 */
+};
+
+struct dsi_pll_output {
+	u32 pll_txclk_en;	/* reg: 0x04c0 */
+	u32 dec_start;		/* reg: 0x0490 */
+	u32 div_frac_start;	/* reg: 0x04b4, 0x4b8, 0x04bc */
+	u32 ssc_period;		/* reg: 0x04a0, 0x04a4 */
+	u32 ssc_step_size;	/* reg: 0x04a8, 0x04ac */
+	u32 plllock_cmp;	/* reg: 0x047c, 0x0480, 0x0484 */
+	u32 pll_vco_div_ref;	/* reg: 0x046c, 0x0470 */
+	u32 pll_vco_count;	/* reg: 0x0474, 0x0478 */
+	u32 pll_kvco_div_ref;	/* reg: 0x0440, 0x0444 */
+	u32 pll_kvco_count;	/* reg: 0x0448, 0x044c */
+	u32 pll_misc1;		/* reg: 0x04e8 */
+	u32 pll_lpf2_postdiv;	/* reg: 0x0504 */
+	u32 pll_resetsm_cntrl;	/* reg: 0x042c */
+	u32 pll_resetsm_cntrl2;	/* reg: 0x0430 */
+	u32 pll_resetsm_cntrl5;	/* reg: 0x043c */
+	u32 pll_kvco_code;		/* reg: 0x0458 */
+
+	u32 cmn_clk_cfg0;	/* reg: 0x0010 */
+	u32 cmn_clk_cfg1;	/* reg: 0x0014 */
+	u32 cmn_ldo_cntrl;	/* reg: 0x004c */
+
+	u32 pll_postdiv;	/* vco */
+	u32 pll_n1div;		/* vco */
+	u32 pll_n2div;		/* hr_oclk3, pixel_clock */
+	u32 fcvo;
+};
+
+enum {
+	DSI_PLL_0,
+	DSI_PLL_1,
+	DSI_PLL_NUM
+};
+
+struct dsi_pll_db {
+	struct dsi_pll_db *next;
+	struct mdss_pll_resources *pll;
+	struct dsi_pll_input in;
+	struct dsi_pll_output out;
+	int source_setup_done;
+};
+
+enum {
+	PLL_OUTPUT_NONE,
+	PLL_OUTPUT_RIGHT,
+	PLL_OUTPUT_LEFT,
+	PLL_OUTPUT_BOTH
+};
+
+enum {
+	PLL_SOURCE_FROM_LEFT,
+	PLL_SOURCE_FROM_RIGHT
+};
+
+enum {
+	PLL_UNKNOWN,
+	PLL_STANDALONE,
+	PLL_SLAVE,
+	PLL_MASTER
+};
+
+int pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
+long pll_vco_round_rate_8996(struct clk *c, unsigned long rate);
+enum handoff pll_vco_handoff_8996(struct clk *c);
+enum handoff shadow_pll_vco_handoff_8996(struct clk *c);
+int shadow_post_n1_div_set_div(struct div_clk *clk, int div);
+int shadow_post_n1_div_get_div(struct div_clk *clk);
+int shadow_n2_div_set_div(struct div_clk *clk, int div);
+int shadow_n2_div_get_div(struct div_clk *clk);
+int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
+int pll_vco_prepare_8996(struct clk *c);
+void pll_vco_unprepare_8996(struct clk *c);
+int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel);
+int get_mdss_byte_mux_sel_8996(struct mux_clk *clk);
+int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel);
+int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk);
+int post_n1_div_set_div(struct div_clk *clk, int div);
+int post_n1_div_get_div(struct div_clk *clk);
+int n2_div_set_div(struct div_clk *clk, int div);
+int n2_div_get_div(struct div_clk *clk);
+int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll);
+
+#endif  /* MDSS_DSI_PLL_8996_H */
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-util.c
new file mode 100644
index 0000000..3bc7564
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-util.c
@@ -0,0 +1,654 @@
+/* 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/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/clk/msm-clock-generic.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+
+#define DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG	(0x0)
+#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG	(0x0004)
+#define DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG	(0x0008)
+#define DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG	(0x000C)
+#define DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG		(0x0010)
+#define DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG	(0x0014)
+#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG	(0x0024)
+#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG	(0x0028)
+#define DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG		(0x002C)
+#define DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG	(0x0030)
+#define DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG	(0x0034)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0		(0x0038)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1		(0x003C)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2		(0x0040)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3		(0x0044)
+#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4		(0x0048)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG0		(0x004C)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG1		(0x0050)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG2		(0x0054)
+#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG3		(0x0058)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0		(0x006C)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG2		(0x0074)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3		(0x0078)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4		(0x007C)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG5		(0x0080)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6		(0x0084)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7		(0x0088)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8		(0x008C)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9		(0x0090)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10	(0x0094)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11	(0x0098)
+#define DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG	(0x009C)
+#define DSI_PHY_PLL_UNIPHY_PLL_STATUS		(0x00C0)
+
+#define DSI_PLL_POLL_DELAY_US			50
+#define DSI_PLL_POLL_TIMEOUT_US			500
+
+int set_byte_mux_sel(struct mux_clk *clk, int sel)
+{
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	pr_debug("byte mux set to %s mode\n", sel ? "indirect" : "direct");
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG, (sel << 1));
+
+	return 0;
+}
+
+int get_byte_mux_sel(struct mux_clk *clk)
+{
+	int mux_mode, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	mux_mode = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG) & BIT(1);
+
+	pr_debug("byte mux mode = %s", mux_mode ? "indirect" : "direct");
+	mdss_pll_resource_enable(dsi_pll_res, false);
+
+	return !!mux_mode;
+}
+
+int dsi_pll_div_prepare(struct clk *c)
+{
+	struct div_clk *div = to_div_clk(c);
+	/* Restore the divider's value */
+	return div->ops->set_div(div, div->data.div);
+}
+
+int dsi_pll_mux_prepare(struct clk *c)
+{
+	struct mux_clk *mux = to_mux_clk(c);
+	int i, rc, sel = 0;
+	struct mdss_pll_resources *dsi_pll_res = mux->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	for (i = 0; i < mux->num_parents; i++)
+		if (mux->parents[i].src == c->parent) {
+			sel = mux->parents[i].sel;
+			break;
+		}
+
+	if (i == mux->num_parents) {
+		pr_err("Failed to select the parent clock\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* Restore the mux source select value */
+	rc = mux->ops->set_mux_sel(mux, sel);
+
+error:
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int fixed_4div_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG, (div - 1));
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int fixed_4div_get_div(struct div_clk *clk)
+{
+	int div = 0, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return div + 1;
+}
+
+int digital_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, (div - 1));
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int digital_get_div(struct div_clk *clk)
+{
+	int div = 0, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+					DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return div + 1;
+}
+
+int analog_set_div(struct div_clk *clk, int div)
+{
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, div - 1);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	return rc;
+}
+
+int analog_get_div(struct div_clk *clk)
+{
+	int div = 0, rc;
+	struct mdss_pll_resources *dsi_pll_res = clk->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(clk->priv, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	div = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+		DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG) + 1;
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+
+	return div;
+}
+
+int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res)
+{
+	u32 status;
+	int pll_locked;
+
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_atomic((dsi_pll_res->pll_base +
+			DSI_PHY_PLL_UNIPHY_PLL_STATUS),
+			status,
+			((status & BIT(0)) == 1),
+			DSI_PLL_POLL_DELAY_US,
+			DSI_PLL_POLL_TIMEOUT_US)) {
+		pr_debug("DSI PLL status=%x failed to Lock\n", status);
+		pll_locked = 0;
+	} else {
+		pll_locked = 1;
+	}
+
+	return pll_locked;
+}
+
+static int pll_28nm_vco_rate_calc(struct dsi_pll_vco_clk *vco,
+		struct mdss_dsi_vco_calc *vco_calc, unsigned long vco_clk_rate)
+{
+	s32 rem;
+	s64 frac_n_mode, ref_doubler_en_b;
+	s64 ref_clk_to_pll, div_fb, frac_n_value;
+	int i;
+
+	/* Configure the Loop filter resistance */
+	for (i = 0; i < vco->lpfr_lut_size; i++)
+		if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate)
+			break;
+	if (i == vco->lpfr_lut_size) {
+		pr_err("unable to get loop filter resistance. vco=%ld\n",
+			vco_clk_rate);
+		return -EINVAL;
+	}
+	vco_calc->lpfr_lut_res = vco->lpfr_lut[i].r;
+
+	div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem);
+	if (rem) {
+		vco_calc->refclk_cfg = 0x1;
+		frac_n_mode = 1;
+		ref_doubler_en_b = 0;
+	} else {
+		vco_calc->refclk_cfg = 0x0;
+		frac_n_mode = 0;
+		ref_doubler_en_b = 1;
+	}
+
+	pr_debug("refclk_cfg = %lld\n", vco_calc->refclk_cfg);
+
+	ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (vco_calc->refclk_cfg))
+			  + (ref_doubler_en_b * vco->ref_clk_rate));
+
+	div_fb = div_s64_rem(vco_clk_rate, ref_clk_to_pll, &rem);
+	frac_n_value = div_s64(((s64)rem * (1 << 16)), ref_clk_to_pll);
+	vco_calc->gen_vco_clk = vco_clk_rate;
+
+	pr_debug("ref_clk_to_pll = %lld\n", ref_clk_to_pll);
+	pr_debug("div_fb = %lld\n", div_fb);
+	pr_debug("frac_n_value = %lld\n", frac_n_value);
+
+	pr_debug("Generated VCO Clock: %lld\n", vco_calc->gen_vco_clk);
+	rem = 0;
+	if (frac_n_mode) {
+		vco_calc->sdm_cfg0 = 0;
+		vco_calc->sdm_cfg1 = (div_fb & 0x3f) - 1;
+		vco_calc->sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem);
+		vco_calc->sdm_cfg2 = rem;
+	} else {
+		vco_calc->sdm_cfg0 = (0x1 << 5);
+		vco_calc->sdm_cfg0 |= (div_fb & 0x3f) - 1;
+		vco_calc->sdm_cfg1 = 0;
+		vco_calc->sdm_cfg2 = 0;
+		vco_calc->sdm_cfg3 = 0;
+	}
+
+	pr_debug("sdm_cfg0=%lld\n", vco_calc->sdm_cfg0);
+	pr_debug("sdm_cfg1=%lld\n", vco_calc->sdm_cfg1);
+	pr_debug("sdm_cfg2=%lld\n", vco_calc->sdm_cfg2);
+	pr_debug("sdm_cfg3=%lld\n", vco_calc->sdm_cfg3);
+
+	vco_calc->cal_cfg11 = div_s64_rem(vco_calc->gen_vco_clk,
+			256 * 1000000, &rem);
+	vco_calc->cal_cfg10 = rem / 1000000;
+	pr_debug("cal_cfg10=%lld, cal_cfg11=%lld\n",
+		vco_calc->cal_cfg10, vco_calc->cal_cfg11);
+
+	return 0;
+}
+
+static void pll_28nm_ssc_param_calc(struct dsi_pll_vco_clk *vco,
+		struct mdss_dsi_vco_calc *vco_calc)
+{
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+	s64 ppm_freq, incr, spread_freq, div_rf, frac_n_value;
+	s32 rem;
+
+	if (!dsi_pll_res->ssc_en) {
+		pr_debug("DSI PLL SSC not enabled\n");
+		return;
+	}
+
+	vco_calc->ssc.kdiv = DIV_ROUND_CLOSEST(vco->ref_clk_rate,
+			1000000) - 1;
+	vco_calc->ssc.triang_steps = DIV_ROUND_CLOSEST(vco->ref_clk_rate,
+			dsi_pll_res->ssc_freq * (vco_calc->ssc.kdiv + 1));
+	ppm_freq = div_s64(vco_calc->gen_vco_clk * dsi_pll_res->ssc_ppm,
+			1000000);
+	incr = div64_s64(ppm_freq * 65536, vco->ref_clk_rate * 2 *
+			vco_calc->ssc.triang_steps);
+
+	vco_calc->ssc.triang_inc_7_0 = incr & 0xff;
+	vco_calc->ssc.triang_inc_9_8 = (incr >> 8) & 0x3;
+
+	if (!dsi_pll_res->ssc_center)
+		spread_freq = vco_calc->gen_vco_clk - ppm_freq;
+	else
+		spread_freq = vco_calc->gen_vco_clk - (ppm_freq / 2);
+
+	div_rf = div_s64(spread_freq, 2 * vco->ref_clk_rate);
+	vco_calc->ssc.dc_offset = (div_rf - 1);
+
+	div_s64_rem(spread_freq, 2 * vco->ref_clk_rate, &rem);
+	frac_n_value = div_s64((s64)rem * 65536, 2 * vco->ref_clk_rate);
+
+	vco_calc->ssc.freq_seed_7_0 = frac_n_value & 0xff;
+	vco_calc->ssc.freq_seed_15_8 = (frac_n_value >> 8) & 0xff;
+}
+
+static void pll_28nm_vco_config(void __iomem *pll_base,
+		struct mdss_dsi_vco_calc *vco_calc,
+		u32 vco_delay_us, bool ssc_en)
+{
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG,
+		vco_calc->lpfr_lut_res);
+
+	/* Loop filter capacitance values : c1 and c2 */
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15);
+
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d);
+
+	if (!ssc_en) {
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
+			(u32)(vco_calc->sdm_cfg1 & 0xff));
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+			(u32)(vco_calc->sdm_cfg2 & 0xff));
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+			(u32)(vco_calc->sdm_cfg3 & 0xff));
+	} else {
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
+			(u32)vco_calc->ssc.dc_offset);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+			(u32)vco_calc->ssc.freq_seed_7_0);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+			(u32)vco_calc->ssc.freq_seed_15_8);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG0,
+			(u32)vco_calc->ssc.kdiv);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG1,
+			(u32)vco_calc->ssc.triang_inc_7_0);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG2,
+			(u32)vco_calc->ssc.triang_inc_9_8);
+		MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG3,
+			(u32)vco_calc->ssc.triang_steps);
+	}
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00);
+
+	/* Add hardware recommended delay for correct PLL configuration */
+	if (vco_delay_us)
+		udelay(vco_delay_us);
+
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG,
+		(u32)vco_calc->refclk_cfg);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
+		(u32)vco_calc->sdm_cfg0);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00);
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10,
+		(u32)(vco_calc->cal_cfg10 & 0xff));
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11,
+		(u32)(vco_calc->cal_cfg11 & 0xff));
+	MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20);
+}
+
+int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
+{
+	struct mdss_dsi_vco_calc vco_calc = {0};
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+	int rc = 0;
+
+	rc = pll_28nm_vco_rate_calc(vco, &vco_calc, rate);
+	if (rc) {
+		pr_err("vco rate calculation failed\n");
+		return rc;
+	}
+
+	pll_28nm_ssc_param_calc(vco, &vco_calc);
+	pll_28nm_vco_config(dsi_pll_res->pll_base, &vco_calc,
+		dsi_pll_res->vco_delay, dsi_pll_res->ssc_en);
+
+	return 0;
+}
+
+unsigned long vco_get_rate(struct clk *c)
+{
+	u32 sdm0, doubler, sdm_byp_div;
+	u64 vco_rate;
+	u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	u64 ref_clk = vco->ref_clk_rate;
+	int rc;
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/* Check to see if the ref clk doubler is enabled */
+	doubler = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+				 DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG) & BIT(0);
+	ref_clk += (doubler * vco->ref_clk_rate);
+
+	/* see if it is integer mode or sdm mode */
+	sdm0 = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+					DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0);
+	if (sdm0 & BIT(6)) {
+		/* integer mode */
+		sdm_byp_div = (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1;
+		vco_rate = ref_clk * sdm_byp_div;
+	} else {
+		/* sdm mode */
+		sdm_dc_off = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF;
+		pr_debug("sdm_dc_off = %d\n", sdm_dc_off);
+		sdm2 = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF;
+		sdm3 = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF;
+		sdm_freq_seed = (sdm3 << 8) | sdm2;
+		pr_debug("sdm_freq_seed = %d\n", sdm_freq_seed);
+
+		vco_rate = (ref_clk * (sdm_dc_off + 1)) +
+			mult_frac(ref_clk, sdm_freq_seed, BIT(16));
+		pr_debug("vco rate = %lld", vco_rate);
+	}
+
+	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+
+	return (unsigned long)vco_rate;
+}
+
+static int dsi_pll_enable(struct clk *c)
+{
+	int i, rc;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return rc;
+	}
+
+	/* Try all enable sequences until one succeeds */
+	for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+		rc = vco->pll_enable_seqs[i](dsi_pll_res);
+		pr_debug("DSI PLL %s after sequence #%d\n",
+			rc ? "unlocked" : "locked", i + 1);
+		if (!rc)
+			break;
+	}
+
+	if (rc) {
+		mdss_pll_resource_enable(dsi_pll_res, false);
+		pr_err("DSI PLL failed to lock\n");
+	}
+	dsi_pll_res->pll_on = true;
+
+	return rc;
+}
+
+static void dsi_pll_disable(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (!dsi_pll_res->pll_on &&
+		mdss_pll_resource_enable(dsi_pll_res, true)) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return;
+	}
+
+	dsi_pll_res->handoff_resources = false;
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00);
+
+	mdss_pll_resource_enable(dsi_pll_res, false);
+	dsi_pll_res->pll_on = false;
+
+	pr_debug("DSI PLL Disabled\n");
+}
+
+long vco_round_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+	if (rate < vco->min_rate)
+		rrate = vco->min_rate;
+	if (rate > vco->max_rate)
+		rrate = vco->max_rate;
+
+	return rrate;
+}
+
+enum handoff vco_handoff(struct clk *c)
+{
+	int rc;
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (is_gdsc_disabled(dsi_pll_res))
+		return HANDOFF_DISABLED_CLK;
+
+	rc = mdss_pll_resource_enable(dsi_pll_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss dsi pll resources\n");
+		return ret;
+	}
+
+	if (dsi_pll_lock_status(dsi_pll_res)) {
+		dsi_pll_res->handoff_resources = true;
+		dsi_pll_res->pll_on = true;
+		c->rate = vco_get_rate(c);
+		ret = HANDOFF_ENABLED_CLK;
+	} else {
+		mdss_pll_resource_enable(dsi_pll_res, false);
+	}
+
+	return ret;
+}
+
+int vco_prepare(struct clk *c)
+{
+	int rc = 0;
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (!dsi_pll_res) {
+		pr_err("Dsi pll resources are not available\n");
+		return -EINVAL;
+	}
+
+	if ((dsi_pll_res->vco_cached_rate != 0)
+	    && (dsi_pll_res->vco_cached_rate == c->rate)) {
+		rc = c->ops->set_rate(c, dsi_pll_res->vco_cached_rate);
+		if (rc) {
+			pr_err("vco_set_rate failed. rc=%d\n", rc);
+			goto error;
+		}
+	}
+
+	rc = dsi_pll_enable(c);
+
+error:
+	return rc;
+}
+
+void vco_unprepare(struct clk *c)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	if (!dsi_pll_res) {
+		pr_err("Dsi pll resources are not available\n");
+		return;
+	}
+
+	dsi_pll_res->vco_cached_rate = c->rate;
+	dsi_pll_disable(c);
+}
+
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll.h b/drivers/clk/msm/mdss/mdss-dsi-pll.h
new file mode 100644
index 0000000..4a9bb64
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll.h
@@ -0,0 +1,132 @@
+/* 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.
+ */
+
+#ifndef __MDSS_DSI_PLL_H
+#define __MDSS_DSI_PLL_H
+
+#define MAX_DSI_PLL_EN_SEQS	10
+
+#define DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG		(0x0020)
+#define DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2	(0x0064)
+#define DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG		(0x0068)
+#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1		(0x0070)
+
+/* Register offsets for 20nm PHY PLL */
+#define MMSS_DSI_PHY_PLL_PLL_CNTRL		(0x0014)
+#define MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN	(0x002C)
+#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN		(0x009C)
+
+struct lpfr_cfg {
+	unsigned long vco_rate;
+	u32 r;
+};
+
+struct dsi_pll_vco_clk {
+	unsigned long	ref_clk_rate;
+	unsigned long	min_rate;
+	unsigned long	max_rate;
+	u32		pll_en_seq_cnt;
+	struct lpfr_cfg *lpfr_lut;
+	u32		lpfr_lut_size;
+	void		*priv;
+
+	struct clk	c;
+
+	int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])
+			(struct mdss_pll_resources *dsi_pll_Res);
+};
+
+struct ssc_params {
+	s32 kdiv;
+	s64 triang_inc_7_0;
+	s64 triang_inc_9_8;
+	s64 triang_steps;
+	s64 dc_offset;
+	s64 freq_seed_7_0;
+	s64 freq_seed_15_8;
+};
+
+struct mdss_dsi_vco_calc {
+	s64 sdm_cfg0;
+	s64 sdm_cfg1;
+	s64 sdm_cfg2;
+	s64 sdm_cfg3;
+	s64 cal_cfg10;
+	s64 cal_cfg11;
+	s64 refclk_cfg;
+	s64 gen_vco_clk;
+	u32 lpfr_lut_res;
+	struct ssc_params ssc;
+};
+
+static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
+{
+	return container_of(clk, struct dsi_pll_vco_clk, c);
+}
+
+int dsi_pll_clock_register_hpm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+int dsi_pll_clock_register_20nm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+int dsi_pll_clock_register_lpm(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+int dsi_pll_clock_register_8996(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+
+int set_byte_mux_sel(struct mux_clk *clk, int sel);
+int get_byte_mux_sel(struct mux_clk *clk);
+int dsi_pll_div_prepare(struct clk *c);
+int dsi_pll_mux_prepare(struct clk *c);
+int fixed_4div_set_div(struct div_clk *clk, int div);
+int fixed_4div_get_div(struct div_clk *clk);
+int digital_set_div(struct div_clk *clk, int div);
+int digital_get_div(struct div_clk *clk);
+int analog_set_div(struct div_clk *clk, int div);
+int analog_get_div(struct div_clk *clk);
+int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);
+int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
+unsigned long vco_get_rate(struct clk *c);
+long vco_round_rate(struct clk *c, unsigned long rate);
+enum handoff vco_handoff(struct clk *c);
+int vco_prepare(struct clk *c);
+void vco_unprepare(struct clk *c);
+
+/* APIs for 20nm PHY PLL */
+int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
+int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco,
+				unsigned long rate);
+long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate);
+enum handoff pll_20nm_vco_handoff(struct clk *c);
+int pll_20nm_vco_prepare(struct clk *c);
+void pll_20nm_vco_unprepare(struct clk *c);
+int pll_20nm_vco_enable_seq(struct mdss_pll_resources *dsi_pll_res);
+
+int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
+int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
+int get_bypass_lp_div_mux_sel(struct mux_clk *clk);
+int fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
+int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
+int fixed_hr_oclk2_get_div(struct div_clk *clk);
+int hr_oclk3_set_div(struct div_clk *clk, int div);
+int shadow_hr_oclk3_set_div(struct div_clk *clk, int div);
+int hr_oclk3_get_div(struct div_clk *clk);
+int ndiv_set_div(struct div_clk *clk, int div);
+int shadow_ndiv_set_div(struct div_clk *clk, int div);
+int ndiv_get_div(struct div_clk *clk);
+void __dsi_pll_disable(void __iomem *pll_base);
+
+int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel);
+int get_mdss_pixel_mux_sel(struct mux_clk *clk);
+int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel);
+int get_mdss_byte_mux_sel(struct mux_clk *clk);
+
+#endif
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c
new file mode 100644
index 0000000..0f2d61e
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-8996.c
@@ -0,0 +1,2689 @@
+/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <dt-bindings/clock/msm-clocks-8996.h>
+
+#include "mdss-pll.h"
+#include "mdss-hdmi-pll.h"
+
+/* CONSTANTS */
+#define HDMI_BIT_CLK_TO_PIX_CLK_RATIO            10
+#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD         3400000000UL
+#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD          1500000000UL
+#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD          750000000
+#define HDMI_CLKS_PLL_DIVSEL                     0
+#define HDMI_CORECLK_DIV                         5
+#define HDMI_REF_CLOCK                           19200000
+#define HDMI_64B_ERR_VAL                         0xFFFFFFFFFFFFFFFFULL
+#define HDMI_VERSION_8996_V1                     1
+#define HDMI_VERSION_8996_V2                     2
+#define HDMI_VERSION_8996_V3                     3
+#define HDMI_VERSION_8996_V3_1_8                 4
+
+#define HDMI_VCO_MAX_FREQ                        12000000000UL
+#define HDMI_VCO_MIN_FREQ                        8000000000UL
+#define HDMI_2400MHZ_BIT_CLK_HZ                  2400000000UL
+#define HDMI_2250MHZ_BIT_CLK_HZ                  2250000000UL
+#define HDMI_2000MHZ_BIT_CLK_HZ                  2000000000UL
+#define HDMI_1700MHZ_BIT_CLK_HZ                  1700000000UL
+#define HDMI_1200MHZ_BIT_CLK_HZ                  1200000000UL
+#define HDMI_1334MHZ_BIT_CLK_HZ                  1334000000UL
+#define HDMI_1000MHZ_BIT_CLK_HZ                  1000000000UL
+#define HDMI_850MHZ_BIT_CLK_HZ                   850000000
+#define HDMI_667MHZ_BIT_CLK_HZ                   667000000
+#define HDMI_600MHZ_BIT_CLK_HZ                   600000000
+#define HDMI_500MHZ_BIT_CLK_HZ                   500000000
+#define HDMI_450MHZ_BIT_CLK_HZ                   450000000
+#define HDMI_334MHZ_BIT_CLK_HZ                   334000000
+#define HDMI_300MHZ_BIT_CLK_HZ                   300000000
+#define HDMI_282MHZ_BIT_CLK_HZ                   282000000
+#define HDMI_250MHZ_BIT_CLK_HZ                   250000000
+#define HDMI_KHZ_TO_HZ                           1000
+
+/* PLL REGISTERS */
+#define QSERDES_COM_ATB_SEL1                     (0x000)
+#define QSERDES_COM_ATB_SEL2                     (0x004)
+#define QSERDES_COM_FREQ_UPDATE                  (0x008)
+#define QSERDES_COM_BG_TIMER                     (0x00C)
+#define QSERDES_COM_SSC_EN_CENTER                (0x010)
+#define QSERDES_COM_SSC_ADJ_PER1                 (0x014)
+#define QSERDES_COM_SSC_ADJ_PER2                 (0x018)
+#define QSERDES_COM_SSC_PER1                     (0x01C)
+#define QSERDES_COM_SSC_PER2                     (0x020)
+#define QSERDES_COM_SSC_STEP_SIZE1               (0x024)
+#define QSERDES_COM_SSC_STEP_SIZE2               (0x028)
+#define QSERDES_COM_POST_DIV                     (0x02C)
+#define QSERDES_COM_POST_DIV_MUX                 (0x030)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN          (0x034)
+#define QSERDES_COM_CLK_ENABLE1                  (0x038)
+#define QSERDES_COM_SYS_CLK_CTRL                 (0x03C)
+#define QSERDES_COM_SYSCLK_BUF_ENABLE            (0x040)
+#define QSERDES_COM_PLL_EN                       (0x044)
+#define QSERDES_COM_PLL_IVCO                     (0x048)
+#define QSERDES_COM_LOCK_CMP1_MODE0              (0x04C)
+#define QSERDES_COM_LOCK_CMP2_MODE0              (0x050)
+#define QSERDES_COM_LOCK_CMP3_MODE0              (0x054)
+#define QSERDES_COM_LOCK_CMP1_MODE1              (0x058)
+#define QSERDES_COM_LOCK_CMP2_MODE1              (0x05C)
+#define QSERDES_COM_LOCK_CMP3_MODE1              (0x060)
+#define QSERDES_COM_LOCK_CMP1_MODE2              (0x064)
+#define QSERDES_COM_CMN_RSVD0                    (0x064)
+#define QSERDES_COM_LOCK_CMP2_MODE2              (0x068)
+#define QSERDES_COM_EP_CLOCK_DETECT_CTRL         (0x068)
+#define QSERDES_COM_LOCK_CMP3_MODE2              (0x06C)
+#define QSERDES_COM_SYSCLK_DET_COMP_STATUS       (0x06C)
+#define QSERDES_COM_BG_TRIM                      (0x070)
+#define QSERDES_COM_CLK_EP_DIV                   (0x074)
+#define QSERDES_COM_CP_CTRL_MODE0                (0x078)
+#define QSERDES_COM_CP_CTRL_MODE1                (0x07C)
+#define QSERDES_COM_CP_CTRL_MODE2                (0x080)
+#define QSERDES_COM_CMN_RSVD1                    (0x080)
+#define QSERDES_COM_PLL_RCTRL_MODE0              (0x084)
+#define QSERDES_COM_PLL_RCTRL_MODE1              (0x088)
+#define QSERDES_COM_PLL_RCTRL_MODE2              (0x08C)
+#define QSERDES_COM_CMN_RSVD2                    (0x08C)
+#define QSERDES_COM_PLL_CCTRL_MODE0              (0x090)
+#define QSERDES_COM_PLL_CCTRL_MODE1              (0x094)
+#define QSERDES_COM_PLL_CCTRL_MODE2              (0x098)
+#define QSERDES_COM_CMN_RSVD3                    (0x098)
+#define QSERDES_COM_PLL_CNTRL                    (0x09C)
+#define QSERDES_COM_PHASE_SEL_CTRL               (0x0A0)
+#define QSERDES_COM_PHASE_SEL_DC                 (0x0A4)
+#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL         (0x0A8)
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM          (0x0A8)
+#define QSERDES_COM_SYSCLK_EN_SEL                (0x0AC)
+#define QSERDES_COM_CML_SYSCLK_SEL               (0x0B0)
+#define QSERDES_COM_RESETSM_CNTRL                (0x0B4)
+#define QSERDES_COM_RESETSM_CNTRL2               (0x0B8)
+#define QSERDES_COM_RESTRIM_CTRL                 (0x0BC)
+#define QSERDES_COM_RESTRIM_CTRL2                (0x0C0)
+#define QSERDES_COM_RESCODE_DIV_NUM              (0x0C4)
+#define QSERDES_COM_LOCK_CMP_EN                  (0x0C8)
+#define QSERDES_COM_LOCK_CMP_CFG                 (0x0CC)
+#define QSERDES_COM_DEC_START_MODE0              (0x0D0)
+#define QSERDES_COM_DEC_START_MODE1              (0x0D4)
+#define QSERDES_COM_DEC_START_MODE2              (0x0D8)
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL          (0x0D8)
+#define QSERDES_COM_DIV_FRAC_START1_MODE0        (0x0DC)
+#define QSERDES_COM_DIV_FRAC_START2_MODE0        (0x0E0)
+#define QSERDES_COM_DIV_FRAC_START3_MODE0        (0x0E4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE1        (0x0E8)
+#define QSERDES_COM_DIV_FRAC_START2_MODE1        (0x0EC)
+#define QSERDES_COM_DIV_FRAC_START3_MODE1        (0x0F0)
+#define QSERDES_COM_DIV_FRAC_START1_MODE2        (0x0F4)
+#define QSERDES_COM_VCO_TUNE_MINVAL1             (0x0F4)
+#define QSERDES_COM_DIV_FRAC_START2_MODE2        (0x0F8)
+#define QSERDES_COM_VCO_TUNE_MINVAL2             (0x0F8)
+#define QSERDES_COM_DIV_FRAC_START3_MODE2        (0x0FC)
+#define QSERDES_COM_CMN_RSVD4                    (0x0FC)
+#define QSERDES_COM_INTEGLOOP_INITVAL            (0x100)
+#define QSERDES_COM_INTEGLOOP_EN                 (0x104)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0        (0x108)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0        (0x10C)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1        (0x110)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1        (0x114)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE2        (0x118)
+#define QSERDES_COM_VCO_TUNE_MAXVAL1             (0x118)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE2        (0x11C)
+#define QSERDES_COM_VCO_TUNE_MAXVAL2             (0x11C)
+#define QSERDES_COM_RES_TRIM_CONTROL2            (0x120)
+#define QSERDES_COM_VCO_TUNE_CTRL                (0x124)
+#define QSERDES_COM_VCO_TUNE_MAP                 (0x128)
+#define QSERDES_COM_VCO_TUNE1_MODE0              (0x12C)
+#define QSERDES_COM_VCO_TUNE2_MODE0              (0x130)
+#define QSERDES_COM_VCO_TUNE1_MODE1              (0x134)
+#define QSERDES_COM_VCO_TUNE2_MODE1              (0x138)
+#define QSERDES_COM_VCO_TUNE1_MODE2              (0x13C)
+#define QSERDES_COM_VCO_TUNE_INITVAL1            (0x13C)
+#define QSERDES_COM_VCO_TUNE2_MODE2              (0x140)
+#define QSERDES_COM_VCO_TUNE_INITVAL2            (0x140)
+#define QSERDES_COM_VCO_TUNE_TIMER1              (0x144)
+#define QSERDES_COM_VCO_TUNE_TIMER2              (0x148)
+#define QSERDES_COM_SAR                          (0x14C)
+#define QSERDES_COM_SAR_CLK                      (0x150)
+#define QSERDES_COM_SAR_CODE_OUT_STATUS          (0x154)
+#define QSERDES_COM_SAR_CODE_READY_STATUS        (0x158)
+#define QSERDES_COM_CMN_STATUS                   (0x15C)
+#define QSERDES_COM_RESET_SM_STATUS              (0x160)
+#define QSERDES_COM_RESTRIM_CODE_STATUS          (0x164)
+#define QSERDES_COM_PLLCAL_CODE1_STATUS          (0x168)
+#define QSERDES_COM_PLLCAL_CODE2_STATUS          (0x16C)
+#define QSERDES_COM_BG_CTRL                      (0x170)
+#define QSERDES_COM_CLK_SELECT                   (0x174)
+#define QSERDES_COM_HSCLK_SEL                    (0x178)
+#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS     (0x17C)
+#define QSERDES_COM_PLL_ANALOG                   (0x180)
+#define QSERDES_COM_CORECLK_DIV                  (0x184)
+#define QSERDES_COM_SW_RESET                     (0x188)
+#define QSERDES_COM_CORE_CLK_EN                  (0x18C)
+#define QSERDES_COM_C_READY_STATUS               (0x190)
+#define QSERDES_COM_CMN_CONFIG                   (0x194)
+#define QSERDES_COM_CMN_RATE_OVERRIDE            (0x198)
+#define QSERDES_COM_SVS_MODE_CLK_SEL             (0x19C)
+#define QSERDES_COM_DEBUG_BUS0                   (0x1A0)
+#define QSERDES_COM_DEBUG_BUS1                   (0x1A4)
+#define QSERDES_COM_DEBUG_BUS2                   (0x1A8)
+#define QSERDES_COM_DEBUG_BUS3                   (0x1AC)
+#define QSERDES_COM_DEBUG_BUS_SEL                (0x1B0)
+#define QSERDES_COM_CMN_MISC1                    (0x1B4)
+#define QSERDES_COM_CMN_MISC2                    (0x1B8)
+#define QSERDES_COM_CORECLK_DIV_MODE1            (0x1BC)
+#define QSERDES_COM_CORECLK_DIV_MODE2            (0x1C0)
+#define QSERDES_COM_CMN_RSVD5                    (0x1C0)
+
+/* Tx Channel base addresses */
+#define HDMI_TX_L0_BASE_OFFSET                   (0x400)
+#define HDMI_TX_L1_BASE_OFFSET                   (0x600)
+#define HDMI_TX_L2_BASE_OFFSET                   (0x800)
+#define HDMI_TX_L3_BASE_OFFSET                   (0xA00)
+
+/* Tx Channel PHY registers */
+#define QSERDES_TX_L0_BIST_MODE_LANENO                    (0x000)
+#define QSERDES_TX_L0_BIST_INVERT                         (0x004)
+#define QSERDES_TX_L0_CLKBUF_ENABLE                       (0x008)
+#define QSERDES_TX_L0_CMN_CONTROL_ONE                     (0x00C)
+#define QSERDES_TX_L0_CMN_CONTROL_TWO                     (0x010)
+#define QSERDES_TX_L0_CMN_CONTROL_THREE                   (0x014)
+#define QSERDES_TX_L0_TX_EMP_POST1_LVL                    (0x018)
+#define QSERDES_TX_L0_TX_POST2_EMPH                       (0x01C)
+#define QSERDES_TX_L0_TX_BOOST_LVL_UP_DN                  (0x020)
+#define QSERDES_TX_L0_HP_PD_ENABLES                       (0x024)
+#define QSERDES_TX_L0_TX_IDLE_LVL_LARGE_AMP               (0x028)
+#define QSERDES_TX_L0_TX_DRV_LVL                          (0x02C)
+#define QSERDES_TX_L0_TX_DRV_LVL_OFFSET                   (0x030)
+#define QSERDES_TX_L0_RESET_TSYNC_EN                      (0x034)
+#define QSERDES_TX_L0_PRE_STALL_LDO_BOOST_EN              (0x038)
+#define QSERDES_TX_L0_TX_BAND                             (0x03C)
+#define QSERDES_TX_L0_SLEW_CNTL                           (0x040)
+#define QSERDES_TX_L0_INTERFACE_SELECT                    (0x044)
+#define QSERDES_TX_L0_LPB_EN                              (0x048)
+#define QSERDES_TX_L0_RES_CODE_LANE_TX                    (0x04C)
+#define QSERDES_TX_L0_RES_CODE_LANE_RX                    (0x050)
+#define QSERDES_TX_L0_RES_CODE_LANE_OFFSET                (0x054)
+#define QSERDES_TX_L0_PERL_LENGTH1                        (0x058)
+#define QSERDES_TX_L0_PERL_LENGTH2                        (0x05C)
+#define QSERDES_TX_L0_SERDES_BYP_EN_OUT                   (0x060)
+#define QSERDES_TX_L0_DEBUG_BUS_SEL                       (0x064)
+#define QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN    (0x068)
+#define QSERDES_TX_L0_TX_POL_INV                          (0x06C)
+#define QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN          (0x070)
+#define QSERDES_TX_L0_BIST_PATTERN1                       (0x074)
+#define QSERDES_TX_L0_BIST_PATTERN2                       (0x078)
+#define QSERDES_TX_L0_BIST_PATTERN3                       (0x07C)
+#define QSERDES_TX_L0_BIST_PATTERN4                       (0x080)
+#define QSERDES_TX_L0_BIST_PATTERN5                       (0x084)
+#define QSERDES_TX_L0_BIST_PATTERN6                       (0x088)
+#define QSERDES_TX_L0_BIST_PATTERN7                       (0x08C)
+#define QSERDES_TX_L0_BIST_PATTERN8                       (0x090)
+#define QSERDES_TX_L0_LANE_MODE                           (0x094)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE                  (0x098)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE_CONFIGURATION    (0x09C)
+#define QSERDES_TX_L0_ATB_SEL1                            (0x0A0)
+#define QSERDES_TX_L0_ATB_SEL2                            (0x0A4)
+#define QSERDES_TX_L0_RCV_DETECT_LVL                      (0x0A8)
+#define QSERDES_TX_L0_RCV_DETECT_LVL_2                    (0x0AC)
+#define QSERDES_TX_L0_PRBS_SEED1                          (0x0B0)
+#define QSERDES_TX_L0_PRBS_SEED2                          (0x0B4)
+#define QSERDES_TX_L0_PRBS_SEED3                          (0x0B8)
+#define QSERDES_TX_L0_PRBS_SEED4                          (0x0BC)
+#define QSERDES_TX_L0_RESET_GEN                           (0x0C0)
+#define QSERDES_TX_L0_RESET_GEN_MUXES                     (0x0C4)
+#define QSERDES_TX_L0_TRAN_DRVR_EMP_EN                    (0x0C8)
+#define QSERDES_TX_L0_TX_INTERFACE_MODE                   (0x0CC)
+#define QSERDES_TX_L0_PWM_CTRL                            (0x0D0)
+#define QSERDES_TX_L0_PWM_ENCODED_OR_DATA                 (0x0D4)
+#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND2            (0x0D8)
+#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND2            (0x0DC)
+#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND2            (0x0E0)
+#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND2            (0x0E4)
+#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND0_1          (0x0E8)
+#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND0_1          (0x0EC)
+#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND0_1          (0x0F0)
+#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND0_1          (0x0F4)
+#define QSERDES_TX_L0_VMODE_CTRL1                         (0x0F8)
+#define QSERDES_TX_L0_VMODE_CTRL2                         (0x0FC)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV_CNTL              (0x100)
+#define QSERDES_TX_L0_BIST_STATUS                         (0x104)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT1                   (0x108)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT2                   (0x10C)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV                   (0x110)
+
+/* HDMI PHY REGISTERS */
+#define HDMI_PHY_BASE_OFFSET                  (0xC00)
+
+#define HDMI_PHY_CFG                          (0x00)
+#define HDMI_PHY_PD_CTL                       (0x04)
+#define HDMI_PHY_MODE                         (0x08)
+#define HDMI_PHY_MISR_CLEAR                   (0x0C)
+#define HDMI_PHY_TX0_TX1_BIST_CFG0            (0x10)
+#define HDMI_PHY_TX0_TX1_BIST_CFG1            (0x14)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0      (0x18)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1      (0x1C)
+#define HDMI_PHY_TX0_TX1_BIST_PATTERN0        (0x20)
+#define HDMI_PHY_TX0_TX1_BIST_PATTERN1        (0x24)
+#define HDMI_PHY_TX2_TX3_BIST_CFG0            (0x28)
+#define HDMI_PHY_TX2_TX3_BIST_CFG1            (0x2C)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0      (0x30)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1      (0x34)
+#define HDMI_PHY_TX2_TX3_BIST_PATTERN0        (0x38)
+#define HDMI_PHY_TX2_TX3_BIST_PATTERN1        (0x3C)
+#define HDMI_PHY_DEBUG_BUS_SEL                (0x40)
+#define HDMI_PHY_TXCAL_CFG0                   (0x44)
+#define HDMI_PHY_TXCAL_CFG1                   (0x48)
+#define HDMI_PHY_TX0_TX1_LANE_CTL             (0x4C)
+#define HDMI_PHY_TX2_TX3_LANE_CTL             (0x50)
+#define HDMI_PHY_LANE_BIST_CONFIG             (0x54)
+#define HDMI_PHY_CLOCK                        (0x58)
+#define HDMI_PHY_MISC1                        (0x5C)
+#define HDMI_PHY_MISC2                        (0x60)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS0         (0x64)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS1         (0x68)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS2         (0x6C)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS0         (0x70)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS1         (0x74)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS2         (0x78)
+#define HDMI_PHY_PRE_MISR_STATUS0             (0x7C)
+#define HDMI_PHY_PRE_MISR_STATUS1             (0x80)
+#define HDMI_PHY_PRE_MISR_STATUS2             (0x84)
+#define HDMI_PHY_PRE_MISR_STATUS3             (0x88)
+#define HDMI_PHY_POST_MISR_STATUS0            (0x8C)
+#define HDMI_PHY_POST_MISR_STATUS1            (0x90)
+#define HDMI_PHY_POST_MISR_STATUS2            (0x94)
+#define HDMI_PHY_POST_MISR_STATUS3            (0x98)
+#define HDMI_PHY_STATUS                       (0x9C)
+#define HDMI_PHY_MISC3_STATUS                 (0xA0)
+#define HDMI_PHY_MISC4_STATUS                 (0xA4)
+#define HDMI_PHY_DEBUG_BUS0                   (0xA8)
+#define HDMI_PHY_DEBUG_BUS1                   (0xAC)
+#define HDMI_PHY_DEBUG_BUS2                   (0xB0)
+#define HDMI_PHY_DEBUG_BUS3                   (0xB4)
+#define HDMI_PHY_PHY_REVISION_ID0             (0xB8)
+#define HDMI_PHY_PHY_REVISION_ID1             (0xBC)
+#define HDMI_PHY_PHY_REVISION_ID2             (0xC0)
+#define HDMI_PHY_PHY_REVISION_ID3             (0xC4)
+
+#define HDMI_PLL_POLL_MAX_READS                100
+#define HDMI_PLL_POLL_TIMEOUT_US               1500
+
+enum hdmi_pll_freqs {
+	HDMI_PCLK_25200_KHZ,
+	HDMI_PCLK_27027_KHZ,
+	HDMI_PCLK_27000_KHZ,
+	HDMI_PCLK_74250_KHZ,
+	HDMI_PCLK_148500_KHZ,
+	HDMI_PCLK_154000_KHZ,
+	HDMI_PCLK_268500_KHZ,
+	HDMI_PCLK_297000_KHZ,
+	HDMI_PCLK_594000_KHZ,
+	HDMI_PCLK_MAX
+};
+
+struct hdmi_8996_phy_pll_reg_cfg {
+	u32 tx_l0_lane_mode;
+	u32 tx_l2_lane_mode;
+	u32 tx_l0_tx_band;
+	u32 tx_l1_tx_band;
+	u32 tx_l2_tx_band;
+	u32 tx_l3_tx_band;
+	u32 com_svs_mode_clk_sel;
+	u32 com_hsclk_sel;
+	u32 com_pll_cctrl_mode0;
+	u32 com_pll_rctrl_mode0;
+	u32 com_cp_ctrl_mode0;
+	u32 com_dec_start_mode0;
+	u32 com_div_frac_start1_mode0;
+	u32 com_div_frac_start2_mode0;
+	u32 com_div_frac_start3_mode0;
+	u32 com_integloop_gain0_mode0;
+	u32 com_integloop_gain1_mode0;
+	u32 com_lock_cmp_en;
+	u32 com_lock_cmp1_mode0;
+	u32 com_lock_cmp2_mode0;
+	u32 com_lock_cmp3_mode0;
+	u32 com_core_clk_en;
+	u32 com_coreclk_div;
+	u32 com_restrim_ctrl;
+	u32 com_vco_tune_ctrl;
+
+	u32 tx_l0_tx_drv_lvl;
+	u32 tx_l0_tx_emp_post1_lvl;
+	u32 tx_l1_tx_drv_lvl;
+	u32 tx_l1_tx_emp_post1_lvl;
+	u32 tx_l2_tx_drv_lvl;
+	u32 tx_l2_tx_emp_post1_lvl;
+	u32 tx_l3_tx_drv_lvl;
+	u32 tx_l3_tx_emp_post1_lvl;
+	u32 tx_l0_vmode_ctrl1;
+	u32 tx_l0_vmode_ctrl2;
+	u32 tx_l1_vmode_ctrl1;
+	u32 tx_l1_vmode_ctrl2;
+	u32 tx_l2_vmode_ctrl1;
+	u32 tx_l2_vmode_ctrl2;
+	u32 tx_l3_vmode_ctrl1;
+	u32 tx_l3_vmode_ctrl2;
+	u32 tx_l0_res_code_lane_tx;
+	u32 tx_l1_res_code_lane_tx;
+	u32 tx_l2_res_code_lane_tx;
+	u32 tx_l3_res_code_lane_tx;
+
+	u32 phy_mode;
+};
+
+struct hdmi_8996_v3_post_divider {
+	u64 vco_freq;
+	u64 hsclk_divsel;
+	u64 vco_ratio;
+	u64 tx_band_sel;
+	u64 half_rate_mode;
+};
+
+static inline struct hdmi_pll_vco_clk *to_hdmi_8996_vco_clk(struct clk *clk)
+{
+	return container_of(clk, struct hdmi_pll_vco_clk, c);
+}
+
+static inline u64 hdmi_8996_v1_get_post_div_lt_2g(u64 bclk)
+{
+	if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ)
+		return 2;
+	else if (bclk >= HDMI_1700MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_1200MHZ_BIT_CLK_HZ)
+		return 4;
+	else if (bclk >= HDMI_850MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_600MHZ_BIT_CLK_HZ)
+		return 4;
+	else if (bclk >= HDMI_450MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_300MHZ_BIT_CLK_HZ)
+		return 4;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_post_div_lt_2g(u64 bclk, u64 vco_range)
+{
+	u64 hdmi_8ghz = vco_range;
+	u64 tmp_calc;
+
+	hdmi_8ghz <<= 2;
+	tmp_calc = hdmi_8ghz;
+	do_div(tmp_calc, 6U);
+
+	if (bclk >= vco_range)
+		return 2;
+	else if (bclk >= tmp_calc)
+		return 3;
+	else if (bclk >= vco_range >> 1)
+		return 4;
+
+	tmp_calc = hdmi_8ghz;
+	do_div(tmp_calc, 12U);
+	if (bclk >= tmp_calc)
+		return 3;
+	else if (bclk >= vco_range >> 2)
+		return 4;
+
+	tmp_calc = hdmi_8ghz;
+	do_div(tmp_calc, 24U);
+	if (bclk >= tmp_calc)
+		return 3;
+	else if (bclk >= vco_range >> 3)
+		return 4;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_post_div_gt_2g(u64 hsclk)
+{
+	if (hsclk >= 0 && hsclk <= 3)
+		return hsclk + 1;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_get_coreclk_div_lt_2g(u64 bclk)
+{
+	if (bclk >= HDMI_1334MHZ_BIT_CLK_HZ)
+		return 1;
+	else if (bclk >= HDMI_1000MHZ_BIT_CLK_HZ)
+		return 1;
+	else if (bclk >= HDMI_667MHZ_BIT_CLK_HZ)
+		return 2;
+	else if (bclk >= HDMI_500MHZ_BIT_CLK_HZ)
+		return 2;
+	else if (bclk >= HDMI_334MHZ_BIT_CLK_HZ)
+		return 3;
+	else if (bclk >= HDMI_250MHZ_BIT_CLK_HZ)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_get_coreclk_div_ratio(u64 clks_pll_divsel,
+						  u64 coreclk_div)
+{
+	if (clks_pll_divsel == 0)
+		return coreclk_div*2;
+	else if (clks_pll_divsel == 1)
+		return coreclk_div*4;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v1_get_tx_band(u64 bclk)
+{
+	if (bclk >= 2400000000UL)
+		return 0;
+	if (bclk >= 1200000000UL)
+		return 1;
+	if (bclk >= 600000000UL)
+		return 2;
+	if (bclk >= 300000000UL)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_tx_band(u64 bclk, u64 vco_range)
+{
+	if (bclk >= vco_range)
+		return 0;
+	else if (bclk >= vco_range >> 1)
+		return 1;
+	else if (bclk >= vco_range >> 2)
+		return 2;
+	else if (bclk >= vco_range >> 3)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v1_get_hsclk(u64 fdata)
+{
+	if (fdata >= 9600000000UL)
+		return 0;
+	else if (fdata >= 4800000000UL)
+		return 1;
+	else if (fdata >= 3200000000UL)
+		return 2;
+	else if (fdata >= 2400000000UL)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+}
+
+static inline u64 hdmi_8996_v2_get_hsclk(u64 fdata, u64 vco_range)
+{
+	u64 tmp_calc = vco_range;
+
+	tmp_calc <<= 2;
+	do_div(tmp_calc, 3U);
+	if (fdata >= (vco_range << 2))
+		return 0;
+	else if (fdata >= (vco_range << 1))
+		return 1;
+	else if (fdata >= tmp_calc)
+		return 2;
+	else if (fdata >= vco_range)
+		return 3;
+
+	return HDMI_64B_ERR_VAL;
+
+}
+
+static inline u64 hdmi_8996_v2_get_vco_freq(u64 bclk, u64 vco_range)
+{
+	u64 tx_band_div_ratio = 1U << hdmi_8996_v2_get_tx_band(bclk, vco_range);
+	u64 pll_post_div_ratio;
+
+	if (bclk >= vco_range) {
+		u64 hsclk = hdmi_8996_v2_get_hsclk(bclk, vco_range);
+
+		pll_post_div_ratio = hdmi_8996_v2_get_post_div_gt_2g(hsclk);
+	} else {
+		pll_post_div_ratio = hdmi_8996_v2_get_post_div_lt_2g(bclk,
+								vco_range);
+	}
+
+	return bclk * (pll_post_div_ratio * tx_band_div_ratio);
+}
+
+static inline u64 hdmi_8996_v2_get_fdata(u64 bclk, u64 vco_range)
+{
+	if (bclk >= vco_range)
+		return bclk;
+
+	{
+		u64 tmp_calc = hdmi_8996_v2_get_vco_freq(bclk, vco_range);
+		u64 pll_post_div_ratio_lt_2g = hdmi_8996_v2_get_post_div_lt_2g(
+							bclk, vco_range);
+		if (pll_post_div_ratio_lt_2g == HDMI_64B_ERR_VAL)
+			return HDMI_64B_ERR_VAL;
+
+		do_div(tmp_calc, pll_post_div_ratio_lt_2g);
+		return tmp_calc;
+	}
+}
+
+static inline u64 hdmi_8996_get_cpctrl(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) ||
+	    (gen_ssc == true))
+		/*
+		 * This should be ROUND(11/(19.2/20))).
+		 * Since ref clock does not change, hardcoding to 11
+		 */
+		return 0xB;
+
+	return 0x23;
+}
+
+static inline u64 hdmi_8996_get_rctrl(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) || (gen_ssc == true))
+		return 0x16;
+
+	return 0x10;
+}
+
+static inline u64 hdmi_8996_get_cctrl(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) || (gen_ssc == true))
+		return 0x28;
+
+	return 0x1;
+}
+
+static inline u64 hdmi_8996_get_integloop_gain(u64 frac_start, bool gen_ssc)
+{
+	if ((frac_start != 0) || (gen_ssc == true))
+		return 0x80;
+
+	return 0xC4;
+}
+
+static inline u64 hdmi_8996_v3_get_integloop_gain(u64 frac_start, u64 bclk,
+							bool gen_ssc)
+{
+	u64 digclk_divsel = bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2;
+	u64 base = ((frac_start != 0) || (gen_ssc == true)) ? 0x40 : 0xC4;
+
+	base <<= digclk_divsel;
+
+	return (base <= 2046 ? base : 0x7FE);
+}
+
+static inline u64 hdmi_8996_get_vco_tune(u64 fdata, u64 div)
+{
+	u64 vco_tune;
+
+	vco_tune = fdata * div;
+	do_div(vco_tune, 1000000);
+	vco_tune = 13000 - vco_tune - 256;
+	do_div(vco_tune, 5);
+
+	return vco_tune;
+}
+
+static inline u64 hdmi_8996_get_pll_cmp(u64 pll_cmp_cnt, u64 core_clk)
+{
+	u64 pll_cmp;
+	u64 rem;
+
+	pll_cmp = pll_cmp_cnt * core_clk;
+	rem = do_div(pll_cmp, HDMI_REF_CLOCK);
+	if (rem > (HDMI_REF_CLOCK >> 1))
+		pll_cmp++;
+	pll_cmp -= 1;
+
+	return pll_cmp;
+}
+
+static inline u64 hdmi_8996_v3_get_pll_cmp(u64 pll_cmp_cnt, u64 fdata)
+{
+	u64 dividend = pll_cmp_cnt * fdata;
+	u64 divisor = HDMI_REF_CLOCK * 10;
+	u64 rem;
+
+	rem = do_div(dividend, divisor);
+	if (rem > (divisor >> 1))
+		dividend++;
+
+	return dividend - 1;
+}
+
+static int hdmi_8996_v3_get_post_div(struct hdmi_8996_v3_post_divider *pd,
+						u64 bclk)
+{
+	u32 ratio[] = {2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35};
+	u32 tx_band_sel[] = {0, 1, 2, 3};
+	u64 vco_freq[60];
+	u64 vco, vco_optimal, half_rate_mode = 0;
+	int vco_optimal_index, vco_freq_index;
+	int i, j, k, x;
+
+	for (i = 0; i <= 1; i++) {
+		vco_optimal = HDMI_VCO_MAX_FREQ;
+		vco_optimal_index = -1;
+		vco_freq_index = 0;
+		for (j = 0; j < 15; j++) {
+			for (k = 0; k < 4; k++) {
+				u64 ratio_mult = ratio[j] << tx_band_sel[k];
+
+				vco = bclk >> half_rate_mode;
+				vco *= ratio_mult;
+				vco_freq[vco_freq_index++] = vco;
+			}
+		}
+
+		for (x = 0; x < 60; x++) {
+			u64 vco_tmp = vco_freq[x];
+
+			if ((vco_tmp >= HDMI_VCO_MIN_FREQ) &&
+					(vco_tmp <= vco_optimal)) {
+				vco_optimal = vco_tmp;
+				vco_optimal_index = x;
+			}
+		}
+
+		if (vco_optimal_index == -1) {
+			if (!half_rate_mode)
+				half_rate_mode++;
+			else
+				return -EINVAL;
+		} else {
+			pd->vco_freq = vco_optimal;
+			pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4];
+			pd->vco_ratio = ratio[vco_optimal_index / 4];
+			break;
+		}
+	}
+
+	switch (pd->vco_ratio) {
+	case 2:
+		pd->hsclk_divsel = 0;
+		break;
+	case 3:
+		pd->hsclk_divsel = 4;
+		break;
+	case 4:
+		pd->hsclk_divsel = 8;
+		break;
+	case 5:
+		pd->hsclk_divsel = 12;
+		break;
+	case 6:
+		pd->hsclk_divsel = 1;
+		break;
+	case 9:
+		pd->hsclk_divsel = 5;
+		break;
+	case 10:
+		pd->hsclk_divsel = 2;
+		break;
+	case 12:
+		pd->hsclk_divsel = 9;
+		break;
+	case 14:
+		pd->hsclk_divsel = 3;
+		break;
+	case 15:
+		pd->hsclk_divsel = 13;
+		break;
+	case 20:
+		pd->hsclk_divsel = 10;
+		break;
+	case 21:
+		pd->hsclk_divsel = 7;
+		break;
+	case 25:
+		pd->hsclk_divsel = 14;
+		break;
+	case 28:
+		pd->hsclk_divsel = 11;
+		break;
+	case 35:
+		pd->hsclk_divsel = 15;
+		break;
+	};
+
+	return 0;
+}
+
+static int hdmi_8996_v1_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg)
+{
+	int rc = -EINVAL;
+	u64 fdata, clk_divtx, tmds_clk;
+	u64 bclk;
+	u64 post_div_gt_2g;
+	u64 post_div_lt_2g;
+	u64 coreclk_div1_lt_2g;
+	u64 core_clk_div_ratio;
+	u64 core_clk;
+	u64 pll_cmp;
+	u64 tx_band;
+	u64 tx_band_div_ratio;
+	u64 hsclk;
+	u64 dec_start;
+	u64 frac_start;
+	u64 pll_divisor = 4 * HDMI_REF_CLOCK;
+	u64 cpctrl;
+	u64 rctrl;
+	u64 cctrl;
+	u64 integloop_gain;
+	u64 vco_tune;
+	u64 vco_freq;
+	u64 rem;
+
+	/* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */
+	bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+		tmds_clk = bclk/4;
+	else
+		tmds_clk = bclk;
+
+	post_div_lt_2g = hdmi_8996_v1_get_post_div_lt_2g(bclk);
+	if (post_div_lt_2g == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	coreclk_div1_lt_2g = hdmi_8996_get_coreclk_div_lt_2g(bclk);
+
+	core_clk_div_ratio = hdmi_8996_get_coreclk_div_ratio(
+				HDMI_CLKS_PLL_DIVSEL, HDMI_CORECLK_DIV);
+
+	tx_band = hdmi_8996_v1_get_tx_band(bclk);
+	if (tx_band == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	tx_band_div_ratio = 1 << tx_band;
+
+	if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ) {
+		fdata = bclk;
+		hsclk = hdmi_8996_v1_get_hsclk(fdata);
+		if (hsclk == HDMI_64B_ERR_VAL)
+			goto fail;
+
+		post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL;
+		if (post_div_gt_2g == HDMI_64B_ERR_VAL)
+			goto fail;
+
+		vco_freq = bclk * (post_div_gt_2g * tx_band_div_ratio);
+		clk_divtx = vco_freq;
+		do_div(clk_divtx, post_div_gt_2g);
+	} else {
+		vco_freq = bclk * (post_div_lt_2g * tx_band_div_ratio);
+		fdata = vco_freq;
+		do_div(fdata, post_div_lt_2g);
+		hsclk = hdmi_8996_v1_get_hsclk(fdata);
+		if (hsclk == HDMI_64B_ERR_VAL)
+			goto fail;
+
+		clk_divtx = vco_freq;
+		do_div(clk_divtx, post_div_lt_2g);
+		post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL;
+		if (post_div_gt_2g == HDMI_64B_ERR_VAL)
+			goto fail;
+	}
+
+	/* Decimal and fraction values */
+	dec_start = fdata * post_div_gt_2g;
+	do_div(dec_start, pll_divisor);
+	frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) -
+			(fdata * post_div_gt_2g))) * (1 << 20));
+	rem = do_div(frac_start, pll_divisor);
+	/* Round off frac_start to closest integer */
+	if (rem >= (pll_divisor >> 1))
+		frac_start++;
+
+	cpctrl = hdmi_8996_get_cpctrl(frac_start, false);
+	rctrl = hdmi_8996_get_rctrl(frac_start, false);
+	cctrl = hdmi_8996_get_cctrl(frac_start, false);
+	integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false);
+	vco_tune = hdmi_8996_get_vco_tune(fdata, post_div_gt_2g);
+
+	core_clk = clk_divtx;
+	do_div(core_clk, core_clk_div_ratio);
+	pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk);
+
+	/* Debug dump */
+	DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq);
+	DEV_DBG("%s: fdata: %llu\n", __func__, fdata);
+	DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx);
+	DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk);
+	DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk);
+	DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk);
+	DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start);
+	DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start);
+	DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl);
+	DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl);
+	DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl);
+	DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain);
+	DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune);
+	DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band);
+	DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp);
+
+	/* Convert these values to register specific values */
+	cfg->tx_l0_lane_mode = 0x3;
+	cfg->tx_l2_lane_mode = 0x3;
+	cfg->tx_l0_tx_band = tx_band + 4;
+	cfg->tx_l1_tx_band = tx_band + 4;
+	cfg->tx_l2_tx_band = tx_band + 4;
+	cfg->tx_l3_tx_band = tx_band + 4;
+	cfg->tx_l0_res_code_lane_tx = 0x33;
+	cfg->tx_l1_res_code_lane_tx = 0x33;
+	cfg->tx_l2_res_code_lane_tx = 0x33;
+	cfg->tx_l3_res_code_lane_tx = 0x33;
+	cfg->com_restrim_ctrl = 0x0;
+	cfg->com_vco_tune_ctrl = 0x1C;
+
+	cfg->com_svs_mode_clk_sel =
+			(bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2);
+	cfg->com_hsclk_sel = (0x28 | hsclk);
+	cfg->com_pll_cctrl_mode0 = cctrl;
+	cfg->com_pll_rctrl_mode0 = rctrl;
+	cfg->com_cp_ctrl_mode0 = cpctrl;
+	cfg->com_dec_start_mode0 = dec_start;
+	cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF);
+	cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8);
+	cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16);
+	cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF);
+	cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8);
+	cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF);
+	cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8);
+	cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
+	cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4));
+	cfg->com_coreclk_div = HDMI_CORECLK_DIV;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x22;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->com_restrim_ctrl = 0x0;
+	} else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x25;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->com_restrim_ctrl = 0x0;
+	} else {
+		cfg->tx_l0_tx_drv_lvl = 0x20;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l1_tx_drv_lvl = 0x20;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l2_tx_drv_lvl = 0x20;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l3_tx_drv_lvl = 0x20;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0E;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0E;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0E;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x0E;
+		cfg->com_restrim_ctrl = 0xD8;
+	}
+
+	cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;
+	DEV_DBG("HDMI 8996 PLL: PLL Settings\n");
+	DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band);
+	DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band);
+	DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band);
+	DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band);
+	DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n",
+						cfg->com_svs_mode_clk_sel);
+	DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel);
+	DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n",
+						cfg->com_pll_cctrl_mode0);
+	DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n",
+						cfg->com_pll_rctrl_mode0);
+	DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n",
+						cfg->com_cp_ctrl_mode0);
+	DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n",
+						cfg->com_dec_start_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n",
+						cfg->com_div_frac_start1_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n",
+						cfg->com_div_frac_start2_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n",
+						cfg->com_div_frac_start3_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n",
+						cfg->com_integloop_gain0_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n",
+						cfg->com_integloop_gain1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n",
+						cfg->com_lock_cmp1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n",
+						cfg->com_lock_cmp2_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n",
+						cfg->com_lock_cmp3_mode0);
+	DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en);
+	DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div);
+	DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n",	cfg->com_restrim_ctrl);
+
+	DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l0_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l1_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l2_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l3_tx_emp_post1_lvl);
+
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l0_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l1_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l2_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l3_res_code_lane_tx);
+
+	DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode);
+	rc = 0;
+fail:
+	return rc;
+}
+
+static int hdmi_8996_v2_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg)
+{
+	int rc = -EINVAL;
+	u64 fdata, clk_divtx, tmds_clk;
+	u64 bclk;
+	u64 post_div;
+	u64 core_clk_div;
+	u64 core_clk_div_ratio;
+	u64 core_clk;
+	u64 pll_cmp;
+	u64 tx_band;
+	u64 tx_band_div_ratio;
+	u64 hsclk;
+	u64 dec_start;
+	u64 frac_start;
+	u64 pll_divisor = 4 * HDMI_REF_CLOCK;
+	u64 cpctrl;
+	u64 rctrl;
+	u64 cctrl;
+	u64 integloop_gain;
+	u64 vco_tune;
+	u64 vco_freq;
+	u64 vco_range;
+	u64 rem;
+
+	/* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */
+	bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+		tmds_clk = pix_clk >> 2;
+	else
+		tmds_clk = pix_clk;
+
+	vco_range = bclk < HDMI_282MHZ_BIT_CLK_HZ ? HDMI_2000MHZ_BIT_CLK_HZ :
+				HDMI_2250MHZ_BIT_CLK_HZ;
+
+	fdata = hdmi_8996_v2_get_fdata(bclk, vco_range);
+	if (fdata == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	hsclk = hdmi_8996_v2_get_hsclk(fdata, vco_range);
+	if (hsclk == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	if (bclk >= vco_range)
+		post_div = hdmi_8996_v2_get_post_div_gt_2g(hsclk);
+	else
+		post_div = hdmi_8996_v2_get_post_div_lt_2g(bclk, vco_range);
+
+	if (post_div == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	core_clk_div = 5;
+	core_clk_div_ratio = core_clk_div * 2;
+
+	tx_band = hdmi_8996_v2_get_tx_band(bclk, vco_range);
+	if (tx_band == HDMI_64B_ERR_VAL)
+		goto fail;
+
+	tx_band_div_ratio = 1 << tx_band;
+
+	vco_freq = hdmi_8996_v2_get_vco_freq(bclk, vco_range);
+	clk_divtx = vco_freq;
+	do_div(clk_divtx, post_div);
+
+	/* Decimal and fraction values */
+	dec_start = fdata * post_div;
+	do_div(dec_start, pll_divisor);
+	frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) -
+			(fdata * post_div))) * (1 << 20));
+	rem = do_div(frac_start, pll_divisor);
+	/* Round off frac_start to closest integer */
+	if (rem >= (pll_divisor >> 1))
+		frac_start++;
+
+	cpctrl = hdmi_8996_get_cpctrl(frac_start, false);
+	rctrl = hdmi_8996_get_rctrl(frac_start, false);
+	cctrl = hdmi_8996_get_cctrl(frac_start, false);
+	integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false);
+	vco_tune = hdmi_8996_get_vco_tune(fdata, post_div);
+
+	core_clk = clk_divtx;
+	do_div(core_clk, core_clk_div_ratio);
+	pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk);
+
+	/* Debug dump */
+	DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq);
+	DEV_DBG("%s: fdata: %llu\n", __func__, fdata);
+	DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx);
+	DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk);
+	DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk);
+	DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk);
+	DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start);
+	DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start);
+	DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl);
+	DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl);
+	DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl);
+	DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain);
+	DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune);
+	DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band);
+	DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp);
+
+	/* Convert these values to register specific values */
+	cfg->tx_l0_lane_mode = 0x3;
+	cfg->tx_l2_lane_mode = 0x3;
+	cfg->tx_l0_tx_band = tx_band + 4;
+	cfg->tx_l1_tx_band = tx_band + 4;
+	cfg->tx_l2_tx_band = tx_band + 4;
+	cfg->tx_l3_tx_band = tx_band + 4;
+
+	if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD)
+		cfg->com_svs_mode_clk_sel = 1;
+	else
+		cfg->com_svs_mode_clk_sel = 2;
+
+	cfg->com_hsclk_sel = (0x28 | hsclk);
+	cfg->com_pll_cctrl_mode0 = cctrl;
+	cfg->com_pll_rctrl_mode0 = rctrl;
+	cfg->com_cp_ctrl_mode0 = cpctrl;
+	cfg->com_dec_start_mode0 = dec_start;
+	cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF);
+	cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8);
+	cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16);
+	cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF);
+	cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8);
+	cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF);
+	cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8);
+	cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
+	cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4));
+	cfg->com_coreclk_div = HDMI_CORECLK_DIV;
+	cfg->com_vco_tune_ctrl = 0x0;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x22;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->tx_l0_res_code_lane_tx = 0x3F;
+		cfg->tx_l1_res_code_lane_tx = 0x3F;
+		cfg->tx_l2_res_code_lane_tx = 0x3F;
+		cfg->tx_l3_res_code_lane_tx = 0x3F;
+		cfg->com_restrim_ctrl = 0x0;
+	} else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x25;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+		cfg->tx_l0_res_code_lane_tx = 0x39;
+		cfg->tx_l1_res_code_lane_tx = 0x39;
+		cfg->tx_l2_res_code_lane_tx = 0x39;
+		cfg->tx_l3_res_code_lane_tx = 0x39;
+		cfg->com_restrim_ctrl = 0x0;
+	} else {
+		cfg->tx_l0_tx_drv_lvl = 0x20;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l1_tx_drv_lvl = 0x20;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l2_tx_drv_lvl = 0x20;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l3_tx_drv_lvl = 0x20;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0E;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0E;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0E;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x0E;
+		cfg->tx_l0_res_code_lane_tx = 0x3F;
+		cfg->tx_l1_res_code_lane_tx = 0x3F;
+		cfg->tx_l2_res_code_lane_tx = 0x3F;
+		cfg->tx_l3_res_code_lane_tx = 0x3F;
+		cfg->com_restrim_ctrl = 0xD8;
+	}
+
+	cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;
+	DEV_DBG("HDMI 8996 PLL: PLL Settings\n");
+	DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band);
+	DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band);
+	DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band);
+	DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band);
+	DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n",
+						cfg->com_svs_mode_clk_sel);
+	DEV_DBG("PLL PARAM: com_vco_tune_ctrl = 0x%x\n",
+						cfg->com_vco_tune_ctrl);
+	DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel);
+	DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en);
+	DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n",
+						cfg->com_pll_cctrl_mode0);
+	DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n",
+						cfg->com_pll_rctrl_mode0);
+	DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n",
+						cfg->com_cp_ctrl_mode0);
+	DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n",
+						cfg->com_dec_start_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n",
+						cfg->com_div_frac_start1_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n",
+						cfg->com_div_frac_start2_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n",
+						cfg->com_div_frac_start3_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n",
+						cfg->com_integloop_gain0_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n",
+						cfg->com_integloop_gain1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n",
+						cfg->com_lock_cmp1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n",
+						cfg->com_lock_cmp2_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n",
+						cfg->com_lock_cmp3_mode0);
+	DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en);
+	DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div);
+
+	DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l0_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l1_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l2_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l3_tx_emp_post1_lvl);
+
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l0_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l1_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l2_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n",
+					cfg->tx_l3_res_code_lane_tx);
+	DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n",	cfg->com_restrim_ctrl);
+
+	DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode);
+	rc = 0;
+fail:
+	return rc;
+}
+
+static int hdmi_8996_v3_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg)
+{
+	int rc = -EINVAL;
+	struct hdmi_8996_v3_post_divider pd;
+	u64 fdata, tmds_clk;
+	u64 bclk;
+	u64 pll_cmp;
+	u64 tx_band;
+	u64 hsclk;
+	u64 dec_start;
+	u64 frac_start;
+	u64 pll_divisor = 4 * HDMI_REF_CLOCK;
+	u64 cpctrl;
+	u64 rctrl;
+	u64 cctrl;
+	u64 integloop_gain;
+	u64 vco_freq;
+	u64 rem;
+
+	/* FDATA, HSCLK, PIXEL_CLK, TMDS_CLK */
+	bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)
+		tmds_clk = pix_clk >> 2;
+	else
+		tmds_clk = pix_clk;
+
+	if (hdmi_8996_v3_get_post_div(&pd, bclk) || pd.vco_ratio <= 0 ||
+			pd.vco_freq <= 0)
+		goto fail;
+
+	vco_freq = pd.vco_freq;
+	fdata = pd.vco_freq;
+	do_div(fdata, pd.vco_ratio);
+
+	hsclk = pd.hsclk_divsel;
+	dec_start = vco_freq;
+	do_div(dec_start, pll_divisor);
+
+	frac_start = vco_freq * (1 << 20);
+	rem = do_div(frac_start, pll_divisor);
+	frac_start -= dec_start * (1 << 20);
+	if (rem > (pll_divisor >> 1))
+		frac_start++;
+
+	cpctrl = hdmi_8996_get_cpctrl(frac_start, false);
+	rctrl = hdmi_8996_get_rctrl(frac_start, false);
+	cctrl = hdmi_8996_get_cctrl(frac_start, false);
+	integloop_gain = hdmi_8996_v3_get_integloop_gain(frac_start, bclk,
+									false);
+	pll_cmp = hdmi_8996_v3_get_pll_cmp(1024, fdata);
+	tx_band = pd.tx_band_sel;
+
+	/* Debug dump */
+	DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq);
+	DEV_DBG("%s: fdata: %llu\n", __func__, fdata);
+	DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk);
+	DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk);
+	DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk);
+	DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start);
+	DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start);
+	DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl);
+	DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl);
+	DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl);
+	DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain);
+	DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band);
+	DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp);
+
+	/* Convert these values to register specific values */
+	cfg->tx_l0_tx_band = tx_band + 4;
+	cfg->tx_l1_tx_band = tx_band + 4;
+	cfg->tx_l2_tx_band = tx_band + 4;
+	cfg->tx_l3_tx_band = tx_band + 4;
+
+	if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD)
+		cfg->com_svs_mode_clk_sel = 1;
+	else
+		cfg->com_svs_mode_clk_sel = 2;
+
+	cfg->com_hsclk_sel = (0x20 | hsclk);
+	cfg->com_pll_cctrl_mode0 = cctrl;
+	cfg->com_pll_rctrl_mode0 = rctrl;
+	cfg->com_cp_ctrl_mode0 = cpctrl;
+	cfg->com_dec_start_mode0 = dec_start;
+	cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF);
+	cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8);
+	cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16);
+	cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF);
+	cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8);
+	cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF);
+	cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8);
+	cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);
+	cfg->com_lock_cmp_en = 0x04;
+	cfg->com_core_clk_en = 0x2C;
+	cfg->com_coreclk_div = HDMI_CORECLK_DIV;
+	cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;
+	cfg->com_vco_tune_ctrl = 0x0;
+
+	cfg->tx_l0_lane_mode = 0x43;
+	cfg->tx_l2_lane_mode = 0x43;
+
+	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x22;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+	} else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x25;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0D;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0D;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0D;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x00;
+	} else {
+		cfg->tx_l0_tx_drv_lvl = 0x20;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l1_tx_drv_lvl = 0x20;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l2_tx_drv_lvl = 0x20;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l3_tx_drv_lvl = 0x20;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x20;
+		cfg->tx_l0_vmode_ctrl1 = 0x00;
+		cfg->tx_l0_vmode_ctrl2 = 0x0E;
+		cfg->tx_l1_vmode_ctrl1 = 0x00;
+		cfg->tx_l1_vmode_ctrl2 = 0x0E;
+		cfg->tx_l2_vmode_ctrl1 = 0x00;
+		cfg->tx_l2_vmode_ctrl2 = 0x0E;
+		cfg->tx_l3_vmode_ctrl1 = 0x00;
+		cfg->tx_l3_vmode_ctrl2 = 0x0E;
+	}
+
+	DEV_DBG("HDMI 8996 PLL: PLL Settings\n");
+	DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band);
+	DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band);
+	DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band);
+	DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band);
+	DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n",
+						cfg->com_svs_mode_clk_sel);
+	DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel);
+	DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en);
+	DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n",
+						cfg->com_pll_cctrl_mode0);
+	DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n",
+						cfg->com_pll_rctrl_mode0);
+	DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n",
+						cfg->com_cp_ctrl_mode0);
+	DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n",
+						cfg->com_dec_start_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n",
+						cfg->com_div_frac_start1_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n",
+						cfg->com_div_frac_start2_mode0);
+	DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n",
+						cfg->com_div_frac_start3_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n",
+						cfg->com_integloop_gain0_mode0);
+	DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n",
+						cfg->com_integloop_gain1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n",
+						cfg->com_lock_cmp1_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n",
+						cfg->com_lock_cmp2_mode0);
+	DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n",
+						cfg->com_lock_cmp3_mode0);
+	DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en);
+	DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div);
+	DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode);
+
+	DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode);
+	DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode);
+	DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l0_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l1_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l2_tx_emp_post1_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl);
+	DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n",
+						cfg->tx_l3_tx_emp_post1_lvl);
+
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1);
+	DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2);
+	rc = 0;
+fail:
+	return rc;
+}
+
+static int hdmi_8996_calculate(u32 pix_clk,
+			       struct hdmi_8996_phy_pll_reg_cfg *cfg, u32 ver)
+{
+	switch (ver) {
+	case HDMI_VERSION_8996_V3:
+	case HDMI_VERSION_8996_V3_1_8:
+		return hdmi_8996_v3_calculate(pix_clk, cfg);
+	case HDMI_VERSION_8996_V2:
+		return hdmi_8996_v2_calculate(pix_clk, cfg);
+	default:
+		return hdmi_8996_v1_calculate(pix_clk, cfg);
+	}
+}
+
+static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	struct hdmi_8996_phy_pll_reg_cfg cfg = {0};
+
+	rc = hdmi_8996_calculate(tmds_clk, &cfg, ver);
+	if (rc) {
+		DEV_ERR("%s: PLL calculation failed\n", __func__);
+		return rc;
+	}
+
+	/* Initially shut down PHY */
+	DEV_DBG("%s: Disabling PHY\n", __func__);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x0);
+	udelay(500);
+
+	/* Power up sequence */
+	switch (ver) {
+	case HDMI_VERSION_8996_V2:
+	case HDMI_VERSION_8996_V3:
+	case HDMI_VERSION_8996_V3_1_8:
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x04);
+		break;
+	};
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX0_TX1_LANE_CTL, 0x0F);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX2_TX3_LANE_CTL, 0x0F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				     QSERDES_TX_L0_CLKBUF_ENABLE, 0x03);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		     QSERDES_TX_L0_LANE_MODE, cfg.tx_l0_lane_mode);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		     QSERDES_TX_L0_LANE_MODE, cfg.tx_l2_lane_mode);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l0_tx_band);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l1_tx_band);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l2_tx_band);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		     QSERDES_TX_L0_TX_BAND, cfg.tx_l3_tx_band);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			       QSERDES_TX_L0_RESET_TSYNC_EN, 0x03);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1E);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0E);
+	if (ver == HDMI_VERSION_8996_V1)
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06);
+
+	/* Bypass VCO calibration */
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL,
+					cfg.com_svs_mode_clk_sel);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_TRIM, 0x0F);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_IVCO, 0x0F);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_CTRL,
+			cfg.com_vco_tune_ctrl);
+
+	switch (ver) {
+	case HDMI_VERSION_8996_V1:
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL,
+					cfg.com_svs_mode_clk_sel);
+		break;
+	default:
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06);
+	}
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_SELECT, 0x30);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_HSCLK_SEL,
+		       cfg.com_hsclk_sel);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_EN,
+		       cfg.com_lock_cmp_en);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CCTRL_MODE0,
+		       cfg.com_pll_cctrl_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_RCTRL_MODE0,
+		       cfg.com_pll_rctrl_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CP_CTRL_MODE0,
+		       cfg.com_cp_ctrl_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEC_START_MODE0,
+		       cfg.com_dec_start_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START1_MODE0,
+		       cfg.com_div_frac_start1_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START2_MODE0,
+		       cfg.com_div_frac_start2_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START3_MODE0,
+		       cfg.com_div_frac_start3_mode0);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN0_MODE0,
+			cfg.com_integloop_gain0_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN1_MODE0,
+			cfg.com_integloop_gain1_mode0);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0,
+			cfg.com_lock_cmp1_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0,
+			cfg.com_lock_cmp2_mode0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0,
+			cfg.com_lock_cmp3_mode0);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_MAP, 0x00);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORE_CLK_EN,
+		       cfg.com_core_clk_en);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORECLK_DIV,
+		       cfg.com_coreclk_div);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_CONFIG, 0x02);
+
+	if (ver == HDMI_VERSION_8996_V3 || ver == HDMI_VERSION_8996_V3_1_8)
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESCODE_DIV_NUM, 0x15);
+
+	/* TX lanes setup (TX 0/1/2/3) */
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000023);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l0_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l0_tx_emp_post1_lvl);
+
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000023);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l1_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l1_tx_emp_post1_lvl);
+
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000023);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l2_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l2_tx_emp_post1_lvl);
+
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				0x00000020);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_TX_DRV_LVL,
+				cfg.tx_l3_tx_drv_lvl);
+	}
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_EMP_POST1_LVL,
+		       cfg.tx_l3_tx_emp_post1_lvl);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l0_vmode_ctrl1);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL2,
+		       cfg.tx_l0_vmode_ctrl2);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l1_vmode_ctrl1);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL2,
+		       cfg.tx_l1_vmode_ctrl2);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l2_vmode_ctrl1);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			QSERDES_TX_L0_VMODE_CTRL2,
+			cfg.tx_l2_vmode_ctrl2);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_VMODE_CTRL1,
+		       cfg.tx_l3_vmode_ctrl1);
+	if (ver == HDMI_VERSION_8996_V3_1_8) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_VMODE_CTRL2,
+				0x0000000D);
+	} else {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+				QSERDES_TX_L0_VMODE_CTRL2,
+				cfg.tx_l3_vmode_ctrl2);
+	}
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00);
+
+	if (ver < HDMI_VERSION_8996_V3) {
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l0_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l1_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l2_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			       QSERDES_TX_L0_RES_CODE_LANE_TX,
+			       cfg.tx_l3_res_code_lane_tx);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESTRIM_CTRL,
+			       cfg.com_restrim_ctrl);
+
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG0, 0x00);
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG1, 0x05);
+	}
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_MODE, cfg.phy_mode);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1F);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+			QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40);
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x0C);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x0C);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x0C);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_HP_PD_ENABLES, 0x03);
+
+	if (ver == HDMI_VERSION_8996_V2) {
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x01);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x01);
+	}
+	/*
+	 * Ensure that vco configuration gets flushed to hardware before
+	 * enabling the PLL
+	 */
+	wmb();
+	return 0;
+}
+
+static int hdmi_8996_phy_ready_status(struct mdss_pll_resources *io)
+{
+	u32 status = 0;
+	int phy_ready = 0;
+	int rc;
+	u32 read_count = 0;
+
+	rc = mdss_pll_resource_enable(io, true);
+	if (rc) {
+		DEV_ERR("%s: pll resource can't be enabled\n", __func__);
+		return rc;
+	}
+
+	DEV_DBG("%s: Waiting for PHY Ready\n", __func__);
+
+	/* Poll for PHY read status */
+	while (read_count < HDMI_PLL_POLL_MAX_READS) {
+		status = MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS);
+		if ((status & BIT(0)) == 1) {
+			phy_ready = 1;
+			DEV_DBG("%s: PHY READY\n", __func__);
+			break;
+		}
+		udelay(HDMI_PLL_POLL_TIMEOUT_US);
+		read_count++;
+	}
+
+	if (read_count == HDMI_PLL_POLL_MAX_READS) {
+		phy_ready = 0;
+		DEV_DBG("%s: PHY READY TIMEOUT\n", __func__);
+	}
+
+	mdss_pll_resource_enable(io, false);
+
+	return phy_ready;
+}
+
+static int hdmi_8996_pll_lock_status(struct mdss_pll_resources *io)
+{
+	u32 status;
+	int pll_locked = 0;
+	int rc;
+	u32 read_count = 0;
+
+	rc = mdss_pll_resource_enable(io, true);
+	if (rc) {
+		DEV_ERR("%s: pll resource can't be enabled\n", __func__);
+		return rc;
+	}
+
+	DEV_DBG("%s: Waiting for PLL lock\n", __func__);
+
+	while (read_count < HDMI_PLL_POLL_MAX_READS) {
+		status = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_C_READY_STATUS);
+		if ((status & BIT(0)) == 1) {
+			pll_locked = 1;
+			DEV_DBG("%s: C READY\n", __func__);
+			break;
+		}
+		udelay(HDMI_PLL_POLL_TIMEOUT_US);
+		read_count++;
+	}
+
+	if (read_count == HDMI_PLL_POLL_MAX_READS) {
+		pll_locked = 0;
+		DEV_DBG("%s: C READY TIMEOUT\n", __func__);
+	}
+
+	mdss_pll_resource_enable(io, false);
+
+	return pll_locked;
+}
+
+static int hdmi_8996_v1_perform_sw_calibration(struct clk *c)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	u32 max_code = 0x190;
+	u32 min_code = 0x0;
+	u32 max_cnt = 0;
+	u32 min_cnt = 0;
+	u32 expected_counter_value = 0;
+	u32 step = 0;
+	u32 dbus_all = 0;
+	u32 dbus_sel = 0;
+	u32 vco_code = 0;
+	u32 val = 0;
+
+	vco_code = 0xC8;
+
+	DEV_DBG("%s: Starting SW calibration with vco_code = %d\n", __func__,
+		 vco_code);
+
+	expected_counter_value =
+	   (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0) << 16) |
+	   (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0) << 8) |
+	   (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0));
+
+	DEV_DBG("%s: expected_counter_value = %d\n", __func__,
+		 expected_counter_value);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val |= BIT(4);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val |= BIT(3);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x4);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+	val |= BIT(1);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+	udelay(60);
+
+	while (1) {
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0,
+			       vco_code & 0xFF);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0,
+			       (vco_code >> 8) & 0x3);
+
+		udelay(20);
+
+		val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+		val &= ~BIT(1);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+		udelay(60);
+
+		val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+		val |= BIT(1);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+		udelay(60);
+
+		dbus_all =
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS3) << 24) |
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS2) << 16) |
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS1) << 8) |
+		  (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS0));
+
+		dbus_sel = (dbus_all >> 9) & 0x3FFFF;
+		DEV_DBG("%s: loop[%d], dbus_all = 0x%x, dbus_sel = 0x%x\n",
+			__func__, step, dbus_all, dbus_sel);
+		if (dbus_sel == 0)
+			DEV_ERR("%s: CHECK HDMI REF CLK\n", __func__);
+
+		if (dbus_sel == expected_counter_value) {
+			max_code = vco_code;
+			max_cnt = dbus_sel;
+			min_code = vco_code;
+			min_cnt = dbus_sel;
+		} else if (dbus_sel == 0) {
+			max_code = vco_code;
+			max_cnt = dbus_sel;
+			vco_code = (max_code + min_code)/2;
+		} else if (dbus_sel > expected_counter_value) {
+			min_code = vco_code;
+			min_cnt = dbus_sel;
+			vco_code = (max_code + min_code)/2;
+		} else if (dbus_sel < expected_counter_value) {
+			max_code = vco_code;
+			max_cnt = dbus_sel;
+			vco_code = (max_code + min_code)/2;
+		}
+
+		step++;
+
+		if ((vco_code == 0) || (vco_code == 0x3FF) || (step > 0x3FF)) {
+			DEV_ERR("%s: VCO tune code search failed\n", __func__);
+			rc = -ENOTSUPP;
+			break;
+		}
+		if ((max_code - min_code) <= 1) {
+			if ((max_code - min_code) == 1) {
+				if (abs((int)(max_cnt - expected_counter_value))
+				    < abs((int)(min_cnt - expected_counter_value
+					))) {
+					vco_code = max_code;
+				} else {
+					vco_code = min_code;
+				}
+			}
+			break;
+		}
+		DEV_DBG("%s: loop[%d], new vco_code = %d\n", __func__, step,
+			 vco_code);
+	}
+
+	DEV_DBG("%s: CALIB done. vco_code = %d\n", __func__, vco_code);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0,
+		       vco_code & 0xFF);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0,
+		       (vco_code >> 8) & 0x3);
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG);
+	val &= ~BIT(1);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val |= BIT(4);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1);
+	val &= ~BIT(3);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val);
+
+	return rc;
+}
+
+static int hdmi_8996_v2_perform_sw_calibration(struct clk *c)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	u32 vco_code1, vco_code2, integral_loop, ready_poll;
+	u32 read_count = 0;
+
+	while (read_count < (HDMI_PLL_POLL_MAX_READS << 1)) {
+		ready_poll = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_C_READY_STATUS);
+		if ((ready_poll & BIT(0)) == 1) {
+			ready_poll = 1;
+			DEV_DBG("%s: C READY\n", __func__);
+			break;
+		}
+		udelay(HDMI_PLL_POLL_TIMEOUT_US);
+		read_count++;
+	}
+
+	if (read_count == (HDMI_PLL_POLL_MAX_READS << 1)) {
+		ready_poll = 0;
+		DEV_DBG("%s: C READY TIMEOUT, TRYING SW CALIBRATION\n",
+								__func__);
+	}
+
+	vco_code1 = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_PLLCAL_CODE1_STATUS);
+	vco_code2 = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_PLLCAL_CODE2_STATUS);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x5);
+	integral_loop = MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DEBUG_BUS0);
+
+	if (((ready_poll & 0x1) == 0) || (((ready_poll & 1) == 1) &&
+			(vco_code1 == 0xFF) && ((vco_code2 & 0x3) == 0x1) &&
+			(integral_loop > 0xC0))) {
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x04);
+		MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x00);
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x17);
+		udelay(100);
+
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x11);
+		udelay(100);
+
+		MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19);
+	}
+	return rc;
+}
+
+static int hdmi_8996_perform_sw_calibration(struct clk *c, u32 ver)
+{
+	switch (ver) {
+	case HDMI_VERSION_8996_V1:
+		return hdmi_8996_v1_perform_sw_calibration(c);
+	case HDMI_VERSION_8996_V2:
+		return hdmi_8996_v2_perform_sw_calibration(c);
+	}
+	return 0;
+}
+
+static int hdmi_8996_vco_enable(struct clk *c, u32 ver)
+{
+	int rc = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x1);
+	udelay(100);
+
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19);
+	udelay(100);
+
+	rc = hdmi_8996_perform_sw_calibration(c, ver);
+	if (rc) {
+		DEV_ERR("%s: software calibration failed\n", __func__);
+		return rc;
+	}
+
+	rc = hdmi_8996_pll_lock_status(io);
+	if (!rc) {
+		DEV_ERR("%s: PLL not locked\n", __func__);
+		return rc;
+	}
+
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+	MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET,
+		       QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,
+		       0x6F);
+
+	/* Disable SSC */
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER1, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER2, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE1, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE2, 0x0);
+	MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_EN_CENTER, 0x2);
+
+	rc = hdmi_8996_phy_ready_status(io);
+	if (!rc) {
+		DEV_ERR("%s: PHY not READY\n", __func__);
+		return rc;
+	}
+
+	/* Restart the retiming buffer */
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x18);
+	udelay(1);
+	MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19);
+
+	io->pll_on = true;
+	return 0;
+}
+
+static int hdmi_8996_v1_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V1);
+}
+
+static int hdmi_8996_v2_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V2);
+}
+
+static int hdmi_8996_v3_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3);
+}
+
+static int hdmi_8996_v3_1p8_vco_enable(struct clk *c)
+{
+	return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3_1_8);
+}
+
+static int hdmi_8996_vco_get_lock_range(struct clk *c, unsigned long pixel_clk)
+{
+	u32 rng = 64, cmp_cnt = 1024;
+	u32 coreclk_div = 5, clks_pll_divsel = 2;
+	u32 vco_freq, vco_ratio, ppm_range;
+	u64 bclk;
+	struct hdmi_8996_v3_post_divider pd;
+
+	bclk = ((u64)pixel_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+
+	DEV_DBG("%s: rate=%ld\n", __func__, pixel_clk);
+
+	if (hdmi_8996_v3_get_post_div(&pd, bclk) ||
+		pd.vco_ratio <= 0 || pd.vco_freq <= 0) {
+		DEV_ERR("%s: couldn't get post div\n", __func__);
+		return -EINVAL;
+	}
+
+	do_div(pd.vco_freq, HDMI_KHZ_TO_HZ * HDMI_KHZ_TO_HZ);
+
+	vco_freq  = (u32) pd.vco_freq;
+	vco_ratio = (u32) pd.vco_ratio;
+
+	DEV_DBG("%s: freq %d, ratio %d\n", __func__,
+		vco_freq, vco_ratio);
+
+	ppm_range = (rng * HDMI_REF_CLOCK) / cmp_cnt;
+	ppm_range /= vco_freq / vco_ratio;
+	ppm_range *= coreclk_div * clks_pll_divsel;
+
+	DEV_DBG("%s: ppm range: %d\n", __func__, ppm_range);
+
+	return ppm_range;
+}
+
+static int hdmi_8996_vco_rate_atomic_update(struct clk *c,
+	unsigned long rate, u32 ver)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	void __iomem *pll;
+	struct hdmi_8996_phy_pll_reg_cfg cfg = {0};
+	int rc = 0;
+
+	rc = hdmi_8996_calculate(rate, &cfg, ver);
+	if (rc) {
+		DEV_ERR("%s: PLL calculation failed\n", __func__);
+		goto end;
+	}
+
+	pll = io->pll_base;
+
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DEC_START_MODE0,
+		       cfg.com_dec_start_mode0);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START1_MODE0,
+		       cfg.com_div_frac_start1_mode0);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START2_MODE0,
+		       cfg.com_div_frac_start2_mode0);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START3_MODE0,
+		       cfg.com_div_frac_start3_mode0);
+
+	MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x01);
+	MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x00);
+
+	DEV_DBG("%s: updated to rate %ld\n", __func__, rate);
+end:
+	return rc;
+}
+
+static int hdmi_8996_vco_set_rate(struct clk *c, unsigned long rate, u32 ver)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	unsigned int set_power_dwn = 0;
+	bool atomic_update = false;
+	int rc, pll_lock_range;
+
+	rc = mdss_pll_resource_enable(io, true);
+	if (rc) {
+		DEV_ERR("pll resource can't be enabled\n");
+		return rc;
+	}
+
+	DEV_DBG("%s: rate %ld\n", __func__, rate);
+
+	if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0) &&
+		MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) {
+		pll_lock_range = hdmi_8996_vco_get_lock_range(c, vco->rate);
+
+		if (pll_lock_range > 0 && vco->rate) {
+			u32 range_limit;
+
+			range_limit  = vco->rate *
+				(pll_lock_range / HDMI_KHZ_TO_HZ);
+			range_limit /= HDMI_KHZ_TO_HZ;
+
+			DEV_DBG("%s: range limit %d\n", __func__, range_limit);
+
+			if (abs(rate - vco->rate) < range_limit)
+				atomic_update = true;
+		}
+	}
+
+	if (io->pll_on && !atomic_update)
+		set_power_dwn = 1;
+
+	if (atomic_update) {
+		hdmi_8996_vco_rate_atomic_update(c, rate, ver);
+	} else {
+		rc = hdmi_8996_phy_pll_set_clk_rate(c, rate, ver);
+		if (rc)
+			DEV_ERR("%s: Failed to set clk rate\n", __func__);
+	}
+
+	mdss_pll_resource_enable(io, false);
+
+	if (set_power_dwn)
+		hdmi_8996_vco_enable(c, ver);
+
+	vco->rate = rate;
+	vco->rate_set = true;
+
+	return 0;
+}
+
+static int hdmi_8996_v1_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V1);
+}
+
+static int hdmi_8996_v2_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V2);
+}
+
+static int hdmi_8996_v3_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3);
+}
+
+static int hdmi_8996_v3_1p8_vco_set_rate(struct clk *c, unsigned long rate)
+{
+	return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3_1_8);
+}
+
+static unsigned long hdmi_get_hsclk_sel_divisor(unsigned long hsclk_sel)
+{
+	unsigned long divisor;
+
+	switch (hsclk_sel) {
+	case 0:
+		divisor = 2;
+		break;
+	case 1:
+		divisor = 6;
+		break;
+	case 2:
+		divisor = 10;
+		break;
+	case 3:
+		divisor = 14;
+		break;
+	case 4:
+		divisor = 3;
+		break;
+	case 5:
+		divisor = 9;
+		break;
+	case 6:
+	case 13:
+		divisor = 15;
+		break;
+	case 7:
+		divisor = 21;
+		break;
+	case 8:
+		divisor = 4;
+		break;
+	case 9:
+		divisor = 12;
+		break;
+	case 10:
+		divisor = 20;
+		break;
+	case 11:
+		divisor = 28;
+		break;
+	case 12:
+		divisor = 5;
+		break;
+	case 14:
+		divisor = 25;
+		break;
+	case 15:
+		divisor = 35;
+		break;
+	default:
+		divisor = 1;
+		DEV_ERR("%s: invalid hsclk_sel value = %lu",
+				__func__, hsclk_sel);
+		break;
+	}
+
+	return divisor;
+}
+
+static unsigned long hdmi_8996_vco_get_rate(struct clk *c)
+{
+	unsigned long freq = 0, hsclk_sel = 0, tx_band = 0, dec_start = 0,
+		      div_frac_start = 0, vco_clock_freq = 0;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	if (mdss_pll_resource_enable(io, true)) {
+		DEV_ERR("%s: pll resource can't be enabled\n", __func__);
+		return freq;
+	}
+
+	dec_start = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEC_START_MODE0);
+
+	div_frac_start =
+		MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DIV_FRAC_START1_MODE0) |
+		MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DIV_FRAC_START2_MODE0) << 8 |
+		MDSS_PLL_REG_R(io->pll_base,
+				QSERDES_COM_DIV_FRAC_START3_MODE0) << 16;
+
+	vco_clock_freq = (dec_start + (div_frac_start / (1 << 20)))
+		* 4 * (HDMI_REF_CLOCK);
+
+	hsclk_sel = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_HSCLK_SEL) & 0x15;
+	hsclk_sel = hdmi_get_hsclk_sel_divisor(hsclk_sel);
+	tx_band = MDSS_PLL_REG_R(io->pll_base + HDMI_TX_L0_BASE_OFFSET,
+			QSERDES_TX_L0_TX_BAND) & 0x3;
+
+	freq = vco_clock_freq / (10 * hsclk_sel * (1 << tx_band));
+
+	mdss_pll_resource_enable(io, false);
+
+	DEV_DBG("%s: freq = %lu\n", __func__, freq);
+
+	return freq;
+}
+
+static long hdmi_8996_vco_round_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long rrate = rate;
+
+	DEV_DBG("rrate=%ld\n", rrate);
+
+	return rrate;
+}
+
+static int hdmi_8996_vco_prepare(struct clk *c, u32 ver)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+	int ret = 0;
+
+	DEV_DBG("rate=%ld\n", vco->rate);
+
+	if (!vco->rate_set && vco->rate)
+		ret = hdmi_8996_vco_set_rate(c, vco->rate, ver);
+
+	if (!ret) {
+		ret = mdss_pll_resource_enable(io, true);
+		if (ret)
+			DEV_ERR("pll resource can't be enabled\n");
+	}
+
+	return ret;
+}
+
+static int hdmi_8996_v1_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V1);
+}
+
+static int hdmi_8996_v2_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V2);
+}
+
+static int hdmi_8996_v3_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3);
+}
+
+static int hdmi_8996_v3_1p8_vco_prepare(struct clk *c)
+{
+	return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3_1_8);
+}
+
+static void hdmi_8996_vco_unprepare(struct clk *c)
+{
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	vco->rate_set = false;
+
+	if (!io) {
+		DEV_ERR("Invalid input parameter\n");
+		return;
+	}
+
+	if (!io->pll_on &&
+		mdss_pll_resource_enable(io, true)) {
+		DEV_ERR("pll resource can't be enabled\n");
+		return;
+	}
+
+	io->handoff_resources = false;
+	mdss_pll_resource_enable(io, false);
+	io->pll_on = false;
+}
+
+static enum handoff hdmi_8996_vco_handoff(struct clk *c)
+{
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+	struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c);
+	struct mdss_pll_resources *io = vco->priv;
+
+	if (is_gdsc_disabled(io))
+		return HANDOFF_DISABLED_CLK;
+
+	if (mdss_pll_resource_enable(io, true)) {
+		DEV_ERR("pll resource can't be enabled\n");
+		return ret;
+	}
+
+	io->handoff_resources = true;
+
+	if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0)) {
+		if (MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) {
+			io->pll_on = true;
+			c->rate = hdmi_8996_vco_get_rate(c);
+			vco->rate = c->rate;
+			ret = HANDOFF_ENABLED_CLK;
+		} else {
+			io->handoff_resources = false;
+			mdss_pll_resource_enable(io, false);
+			DEV_DBG("%s: PHY not ready\n", __func__);
+		}
+	} else {
+		io->handoff_resources = false;
+		mdss_pll_resource_enable(io, false);
+		DEV_DBG("%s: PLL not locked\n", __func__);
+	}
+
+	DEV_DBG("done, ret=%d\n", ret);
+	return ret;
+}
+
+static const struct clk_ops hdmi_8996_v1_vco_clk_ops = {
+	.enable = hdmi_8996_v1_vco_enable,
+	.set_rate = hdmi_8996_v1_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v1_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+static const struct clk_ops hdmi_8996_v2_vco_clk_ops = {
+	.enable = hdmi_8996_v2_vco_enable,
+	.set_rate = hdmi_8996_v2_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v2_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+static const struct clk_ops hdmi_8996_v3_vco_clk_ops = {
+	.enable = hdmi_8996_v3_vco_enable,
+	.set_rate = hdmi_8996_v3_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v3_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+static const struct clk_ops hdmi_8996_v3_1p8_vco_clk_ops = {
+	.enable = hdmi_8996_v3_1p8_vco_enable,
+	.set_rate = hdmi_8996_v3_1p8_vco_set_rate,
+	.get_rate = hdmi_8996_vco_get_rate,
+	.round_rate = hdmi_8996_vco_round_rate,
+	.prepare = hdmi_8996_v3_1p8_vco_prepare,
+	.unprepare = hdmi_8996_vco_unprepare,
+	.handoff = hdmi_8996_vco_handoff,
+};
+
+
+static struct hdmi_pll_vco_clk hdmi_vco_clk = {
+	.c = {
+		.dbg_name = "hdmi_8996_vco_clk",
+		.ops = &hdmi_8996_v1_vco_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(hdmi_vco_clk.c),
+	},
+};
+
+static struct clk_lookup hdmipllcc_8996[] = {
+	CLK_LIST(hdmi_vco_clk),
+};
+
+int hdmi_8996_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res, u32 ver)
+{
+	int rc = -ENOTSUPP;
+
+	if (!pll_res || !pll_res->phy_base || !pll_res->pll_base) {
+		DEV_ERR("%s: Invalid input parameters\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
+	/* Set client data for vco, mux and div clocks */
+	hdmi_vco_clk.priv = pll_res;
+
+	switch (ver) {
+	case HDMI_VERSION_8996_V2:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v2_vco_clk_ops;
+		break;
+	case HDMI_VERSION_8996_V3:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v3_vco_clk_ops;
+		break;
+	case HDMI_VERSION_8996_V3_1_8:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v3_1p8_vco_clk_ops;
+		break;
+	default:
+		hdmi_vco_clk.c.ops = &hdmi_8996_v1_vco_clk_ops;
+		break;
+	};
+
+	rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8996,
+					ARRAY_SIZE(hdmipllcc_8996));
+	if (rc) {
+		DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc);
+		rc = -EPROBE_DEFER;
+	} else {
+		DEV_DBG("%s SUCCESS\n", __func__);
+	}
+
+	return rc;
+}
+
+int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V1);
+}
+
+int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V2);
+}
+
+int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V3);
+}
+
+int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	return hdmi_8996_pll_clock_register(pdev, pll_res,
+						HDMI_VERSION_8996_V3_1_8);
+}
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll.h b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
new file mode 100644
index 0000000..1f21d79
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
@@ -0,0 +1,53 @@
+/* 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.
+ */
+
+#ifndef __MDSS_HDMI_PLL_H
+#define __MDSS_HDMI_PLL_H
+
+struct hdmi_pll_cfg {
+	unsigned long vco_rate;
+	u32 reg;
+};
+
+struct hdmi_pll_vco_clk {
+	unsigned long	rate;	/* current vco rate */
+	unsigned long	min_rate;	/* min vco rate */
+	unsigned long	max_rate;	/* max vco rate */
+	bool		rate_set;
+	struct hdmi_pll_cfg *ip_seti;
+	struct hdmi_pll_cfg *cp_seti;
+	struct hdmi_pll_cfg *ip_setp;
+	struct hdmi_pll_cfg *cp_setp;
+	struct hdmi_pll_cfg *crctrl;
+	void		*priv;
+
+	struct clk	c;
+};
+
+int hdmi_pll_clock_register(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+
+int hdmi_20nm_pll_clock_register(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+
+int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res);
+#endif
diff --git a/drivers/clk/msm/mdss/mdss-pll-util.c b/drivers/clk/msm/mdss/mdss-pll-util.c
new file mode 100644
index 0000000..7f7da9b
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-pll-util.c
@@ -0,0 +1,364 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/vmalloc.h>
+#include <linux/memblock.h>
+
+#include "mdss-pll.h"
+
+int mdss_pll_util_resource_init(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	int rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	rc = msm_mdss_config_vreg(&pdev->dev,
+				mp->vreg_config, mp->num_vreg, 1);
+	if (rc) {
+		pr_err("Vreg config failed rc=%d\n", rc);
+		goto vreg_err;
+	}
+
+	rc = msm_mdss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk);
+	if (rc) {
+		pr_err("Clock get failed rc=%d\n", rc);
+		goto clk_err;
+	}
+
+	return rc;
+
+clk_err:
+	msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
+vreg_err:
+	return rc;
+}
+
+/**
+ * mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name
+ *@pll_res: Pointer to the PLL resource
+ *@name: Regulator name as specified in the pll dtsi
+ *
+ * This is a helper function to retrieve the regulator information
+ * for each pll resource.
+ */
+struct mdss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
+		, char *name)
+{
+
+	struct mdss_vreg *regulator = NULL;
+	int i;
+
+	if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) {
+		pr_err("%s Invalid PLL resource\n", __func__);
+		goto error;
+	}
+
+	regulator = pll_res->mp.vreg_config;
+
+	for (i = 0; i < pll_res->mp.num_vreg; i++) {
+		if (!strcmp(name, regulator->vreg_name)) {
+			pr_debug("Found regulator match for %s\n", name);
+			break;
+		}
+		regulator++;
+	}
+
+error:
+	return regulator;
+}
+
+void mdss_pll_util_resource_deinit(struct platform_device *pdev,
+					 struct mdss_pll_resources *pll_res)
+{
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	msm_mdss_put_clk(mp->clk_config, mp->num_clk);
+
+	msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
+}
+
+void mdss_pll_util_resource_release(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	devm_kfree(&pdev->dev, mp->clk_config);
+	devm_kfree(&pdev->dev, mp->vreg_config);
+	mp->num_vreg = 0;
+	mp->num_clk = 0;
+}
+
+int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res,
+								bool enable)
+{
+	int rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	if (enable) {
+		rc = msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg,
+					  enable);
+		if (rc) {
+			pr_err("Failed to enable vregs rc=%d\n", rc);
+			goto vreg_err;
+		}
+
+		rc = msm_mdss_clk_set_rate(mp->clk_config, mp->num_clk);
+		if (rc) {
+			pr_err("Failed to set clock rate rc=%d\n", rc);
+			goto clk_err;
+		}
+
+		rc = msm_mdss_enable_clk(mp->clk_config, mp->num_clk, enable);
+		if (rc) {
+			pr_err("clock enable failed rc:%d\n", rc);
+			goto clk_err;
+		}
+	} else {
+		msm_mdss_enable_clk(mp->clk_config, mp->num_clk, enable);
+
+		msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
+	}
+
+	return rc;
+
+clk_err:
+	msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
+vreg_err:
+	return rc;
+}
+
+static int mdss_pll_util_parse_dt_supply(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int i = 0, rc = 0;
+	u32 tmp = 0;
+	struct device_node *of_node = NULL, *supply_root_node = NULL;
+	struct device_node *supply_node = NULL;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	of_node = pdev->dev.of_node;
+
+	mp->num_vreg = 0;
+	supply_root_node = of_get_child_by_name(of_node,
+						"qcom,platform-supply-entries");
+	if (!supply_root_node) {
+		pr_err("no supply entry present\n");
+		return rc;
+	}
+
+	for_each_child_of_node(supply_root_node, supply_node) {
+		mp->num_vreg++;
+	}
+
+	if (mp->num_vreg == 0) {
+		pr_debug("no vreg\n");
+		return rc;
+	}
+	pr_debug("vreg found. count=%d\n", mp->num_vreg);
+
+	mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct mdss_vreg) *
+						mp->num_vreg, GFP_KERNEL);
+	if (!mp->vreg_config) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	for_each_child_of_node(supply_root_node, supply_node) {
+
+		const char *st = NULL;
+
+		rc = of_property_read_string(supply_node,
+						"qcom,supply-name", &st);
+		if (rc) {
+			pr_err(":error reading name. rc=%d\n", rc);
+			goto error;
+		}
+
+		strlcpy(mp->vreg_config[i].vreg_name, st,
+					sizeof(mp->vreg_config[i].vreg_name));
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-min-voltage", &tmp);
+		if (rc) {
+			pr_err(": error reading min volt. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].min_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-max-voltage", &tmp);
+		if (rc) {
+			pr_err(": error reading max volt. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].max_voltage = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-enable-load", &tmp);
+		if (rc) {
+			pr_err(": error reading enable load. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-disable-load", &tmp);
+		if (rc) {
+			pr_err(": error reading disable load. rc=%d\n", rc);
+			goto error;
+		}
+		mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] = tmp;
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-ulp-load", &tmp);
+		if (rc)
+			pr_warn(": error reading ulp load. rc=%d\n", rc);
+
+		mp->vreg_config[i].load[DSS_REG_MODE_ULP] = (!rc ? tmp :
+			mp->vreg_config[i].load[DSS_REG_MODE_ENABLE]);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-pre-on-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply pre sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-pre-off-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply pre sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-post-on-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply post sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+		rc = of_property_read_u32(supply_node,
+					"qcom,supply-post-off-sleep", &tmp);
+		if (rc)
+			pr_debug("error reading supply post sleep value. rc=%d\n",
+							rc);
+
+		mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+		pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, ulp=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+			mp->vreg_config[i].vreg_name,
+			mp->vreg_config[i].min_voltage,
+			mp->vreg_config[i].max_voltage,
+			mp->vreg_config[i].load[DSS_REG_MODE_ENABLE],
+			mp->vreg_config[i].load[DSS_REG_MODE_DISABLE],
+			mp->vreg_config[i].load[DSS_REG_MODE_ULP],
+			mp->vreg_config[i].pre_on_sleep,
+			mp->vreg_config[i].post_on_sleep,
+			mp->vreg_config[i].pre_off_sleep,
+			mp->vreg_config[i].post_off_sleep);
+		++i;
+
+		rc = 0;
+	}
+
+	return rc;
+
+error:
+	if (mp->vreg_config) {
+		devm_kfree(&pdev->dev, mp->vreg_config);
+		mp->vreg_config = NULL;
+		mp->num_vreg = 0;
+	}
+
+	return rc;
+}
+
+static int mdss_pll_util_parse_dt_clock(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	u32 i = 0, rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+	const char *clock_name;
+	u32 clock_rate;
+
+	mp->num_clk = of_property_count_strings(pdev->dev.of_node,
+							"clock-names");
+	if (mp->num_clk <= 0) {
+		pr_err("clocks are not defined\n");
+		goto clk_err;
+	}
+
+	mp->clk_config = devm_kzalloc(&pdev->dev,
+			sizeof(struct mdss_clk) * mp->num_clk, GFP_KERNEL);
+	if (!mp->clk_config) {
+		rc = -ENOMEM;
+		mp->num_clk = 0;
+		goto clk_err;
+	}
+
+	for (i = 0; i < mp->num_clk; i++) {
+		of_property_read_string_index(pdev->dev.of_node, "clock-names",
+							i, &clock_name);
+		strlcpy(mp->clk_config[i].clk_name, clock_name,
+				sizeof(mp->clk_config[i].clk_name));
+
+		of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
+							i, &clock_rate);
+		mp->clk_config[i].rate = clock_rate;
+
+		if (!clock_rate)
+			mp->clk_config[i].type = DSS_CLK_AHB;
+		else
+			mp->clk_config[i].type = DSS_CLK_PCLK;
+	}
+
+clk_err:
+	return rc;
+}
+
+int mdss_pll_util_resource_parse(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc = 0;
+	struct mdss_module_power *mp = &pll_res->mp;
+
+	rc = mdss_pll_util_parse_dt_supply(pdev, pll_res);
+	if (rc) {
+		pr_err("vreg parsing failed rc=%d\n", rc);
+		goto end;
+	}
+
+	rc = mdss_pll_util_parse_dt_clock(pdev, pll_res);
+	if (rc) {
+		pr_err("clock name parsing failed rc=%d", rc);
+		goto clk_err;
+	}
+
+	return rc;
+
+clk_err:
+	devm_kfree(&pdev->dev, mp->vreg_config);
+	mp->num_vreg = 0;
+end:
+	return rc;
+}
diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c
new file mode 100644
index 0000000..49f3d7b
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-pll.c
@@ -0,0 +1,439 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/of_device.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/clk/msm-clock-generic.h>
+
+#include "mdss-pll.h"
+#include "mdss-dsi-pll.h"
+#include "mdss-hdmi-pll.h"
+
+int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable)
+{
+	int rc = 0;
+	int changed = 0;
+
+	if (!pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Don't turn off resources during handoff or add more than
+	 * 1 refcount.
+	 */
+	if (pll_res->handoff_resources &&
+		(!enable || (enable & pll_res->resource_enable))) {
+		pr_debug("Do not turn on/off pll resources during handoff case\n");
+		return rc;
+	}
+
+	if (enable) {
+		if (pll_res->resource_ref_cnt == 0)
+			changed++;
+		pll_res->resource_ref_cnt++;
+	} else {
+		if (pll_res->resource_ref_cnt) {
+			pll_res->resource_ref_cnt--;
+			if (pll_res->resource_ref_cnt == 0)
+				changed++;
+		} else {
+			pr_err("PLL Resources already OFF\n");
+		}
+	}
+
+	if (changed) {
+		rc = mdss_pll_util_resource_enable(pll_res, enable);
+		if (rc)
+			pr_err("Resource update failed rc=%d\n", rc);
+		else
+			pll_res->resource_enable = enable;
+	}
+
+	return rc;
+}
+
+static int mdss_pll_resource_init(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	return mdss_pll_util_resource_init(pdev, pll_res);
+}
+
+static void mdss_pll_resource_deinit(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return;
+	}
+
+	mdss_pll_util_resource_deinit(pdev, pll_res);
+}
+
+static void mdss_pll_resource_release(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res)
+{
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return;
+	}
+
+	mdss_pll_util_resource_release(pdev, pll_res);
+}
+
+static int mdss_pll_resource_parse(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc = 0;
+	const char *compatible_stream;
+
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	rc = mdss_pll_util_resource_parse(pdev, pll_res);
+	if (rc) {
+		pr_err("Failed to parse the resources rc=%d\n", rc);
+		goto end;
+	}
+
+	compatible_stream = of_get_property(pdev->dev.of_node,
+				"compatible", NULL);
+	if (!compatible_stream) {
+		pr_err("Failed to parse the compatible stream\n");
+		goto err;
+	}
+
+	if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8952")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
+		pll_res->target_id = MDSS_PLL_TARGET_8952;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8937")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
+		pll_res->target_id = MDSS_PLL_TARGET_8937;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8909")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_LPM;
+		pll_res->target_id = MDSS_PLL_TARGET_8909;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8996")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+		pll_res->target_id = MDSS_PLL_TARGET_8996;
+		pll_res->revision = 1;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8996_v2")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+		pll_res->target_id = MDSS_PLL_TARGET_8996;
+		pll_res->revision = 2;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8953")) {
+		pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+		pll_res->target_id = MDSS_PLL_TARGET_8953;
+		pll_res->revision = 2;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v2")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V2;
+	} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v3")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3;
+	} else if (!strcmp(compatible_stream,
+				"qcom,mdss_hdmi_pll_8996_v3_1p8")) {
+		pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3_1_8;
+	} else {
+		goto err;
+	}
+
+	return rc;
+
+err:
+	mdss_pll_resource_release(pdev, pll_res);
+end:
+	return rc;
+}
+
+static int mdss_pll_clock_register(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res)
+{
+	int rc;
+
+	if (!pdev || !pll_res) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	switch (pll_res->pll_interface_type) {
+	case MDSS_DSI_PLL_LPM:
+		rc = dsi_pll_clock_register_lpm(pdev, pll_res);
+		break;
+	case MDSS_DSI_PLL_8996:
+		rc = dsi_pll_clock_register_8996(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996:
+		rc = hdmi_8996_v1_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996_V2:
+		rc = hdmi_8996_v2_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996_V3:
+		rc = hdmi_8996_v3_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_HDMI_PLL_8996_V3_1_8:
+		rc = hdmi_8996_v3_1p8_pll_clock_register(pdev, pll_res);
+		break;
+	case MDSS_UNKNOWN_PLL:
+	default:
+		rc = -EINVAL;
+		break;
+	}
+
+	if (rc) {
+		pr_err("Pll ndx=%d clock register failed rc=%d\n",
+				pll_res->index, rc);
+	}
+
+	return rc;
+}
+
+static int mdss_pll_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	const char *label;
+	struct resource *pll_base_reg;
+	struct resource *phy_base_reg;
+	struct resource *dynamic_pll_base_reg;
+	struct resource *gdsc_base_reg;
+	struct mdss_pll_resources *pll_res;
+
+	if (!pdev->dev.of_node) {
+		pr_err("MDSS pll driver only supports device tree probe\n");
+		rc = -ENOTSUPP;
+		goto error;
+	}
+
+	label = of_get_property(pdev->dev.of_node, "label", NULL);
+	if (!label)
+		pr_info("%d: MDSS pll label not specified\n", __LINE__);
+	else
+		pr_info("MDSS pll label = %s\n", label);
+
+	pll_res = devm_kzalloc(&pdev->dev, sizeof(struct mdss_pll_resources),
+								GFP_KERNEL);
+	if (!pll_res) {
+		rc = -ENOMEM;
+		goto error;
+	}
+	platform_set_drvdata(pdev, pll_res);
+
+	rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
+			&pll_res->index);
+	if (rc) {
+		pr_err("Unable to get the cell-index rc=%d\n", rc);
+		pll_res->index = 0;
+	}
+
+	pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node,
+						"qcom,dsi-pll-ssc-en");
+
+	if (pll_res->ssc_en) {
+		pr_info("%s: label=%s PLL SSC enabled\n", __func__, label);
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+			"qcom,ssc-frequency-hz", &pll_res->ssc_freq);
+
+		rc = of_property_read_u32(pdev->dev.of_node,
+			"qcom,ssc-ppm", &pll_res->ssc_ppm);
+
+		pll_res->ssc_center = false;
+
+		label = of_get_property(pdev->dev.of_node,
+			"qcom,dsi-pll-ssc-mode", NULL);
+
+		if (label && !strcmp(label, "center-spread"))
+			pll_res->ssc_center = true;
+	}
+
+	pll_base_reg = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, "pll_base");
+	if (!pll_base_reg) {
+		pr_err("Unable to get the pll base resources\n");
+		rc = -ENOMEM;
+		goto io_error;
+	}
+
+	pll_res->pll_base = ioremap(pll_base_reg->start,
+						resource_size(pll_base_reg));
+	if (!pll_res->pll_base) {
+		pr_err("Unable to remap pll base resources\n");
+		rc = -ENOMEM;
+		goto io_error;
+	}
+
+	pr_debug("%s: ndx=%d base=%p\n", __func__,
+			pll_res->index, pll_res->pll_base);
+
+	rc = mdss_pll_resource_parse(pdev, pll_res);
+	if (rc) {
+		pr_err("Pll resource parsing from dt failed rc=%d\n", rc);
+		goto res_parse_error;
+	}
+
+	phy_base_reg = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, "phy_base");
+	if (phy_base_reg) {
+		pll_res->phy_base = ioremap(phy_base_reg->start,
+						resource_size(phy_base_reg));
+		if (!pll_res->phy_base) {
+			pr_err("Unable to remap pll phy base resources\n");
+			rc = -ENOMEM;
+			goto phy_io_error;
+		}
+	}
+
+	dynamic_pll_base_reg = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "dynamic_pll_base");
+	if (dynamic_pll_base_reg) {
+		pll_res->dyn_pll_base = ioremap(dynamic_pll_base_reg->start,
+				resource_size(dynamic_pll_base_reg));
+		if (!pll_res->dyn_pll_base) {
+			pr_err("Unable to remap dynamic pll base resources\n");
+			rc = -ENOMEM;
+			goto dyn_pll_io_error;
+		}
+	}
+
+	gdsc_base_reg = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "gdsc_base");
+	if (!gdsc_base_reg) {
+		pr_err("Unable to get the gdsc base resource\n");
+		rc = -ENOMEM;
+		goto gdsc_io_error;
+	}
+	pll_res->gdsc_base = ioremap(gdsc_base_reg->start,
+			resource_size(gdsc_base_reg));
+	if (!pll_res->gdsc_base) {
+		pr_err("Unable to remap gdsc base resources\n");
+		rc = -ENOMEM;
+		goto gdsc_io_error;
+	}
+
+	rc = mdss_pll_resource_init(pdev, pll_res);
+	if (rc) {
+		pr_err("Pll ndx=%d resource init failed rc=%d\n",
+				pll_res->index, rc);
+		goto res_init_error;
+	}
+
+	rc = mdss_pll_clock_register(pdev, pll_res);
+	if (rc) {
+		pr_err("Pll ndx=%d clock register failed rc=%d\n",
+			pll_res->index, rc);
+		goto clock_register_error;
+	}
+
+	return rc;
+
+clock_register_error:
+	mdss_pll_resource_deinit(pdev, pll_res);
+res_init_error:
+	if (pll_res->gdsc_base)
+		iounmap(pll_res->gdsc_base);
+gdsc_io_error:
+	if (pll_res->dyn_pll_base)
+		iounmap(pll_res->dyn_pll_base);
+dyn_pll_io_error:
+	if (pll_res->phy_base)
+		iounmap(pll_res->phy_base);
+phy_io_error:
+	mdss_pll_resource_release(pdev, pll_res);
+res_parse_error:
+	iounmap(pll_res->pll_base);
+io_error:
+	devm_kfree(&pdev->dev, pll_res);
+error:
+	return rc;
+}
+
+static int mdss_pll_remove(struct platform_device *pdev)
+{
+	struct mdss_pll_resources *pll_res;
+
+	pll_res = platform_get_drvdata(pdev);
+	if (!pll_res) {
+		pr_err("Invalid PLL resource data");
+		return 0;
+	}
+
+	mdss_pll_resource_deinit(pdev, pll_res);
+	if (pll_res->phy_base)
+		iounmap(pll_res->phy_base);
+	if (pll_res->gdsc_base)
+		iounmap(pll_res->gdsc_base);
+	mdss_pll_resource_release(pdev, pll_res);
+	iounmap(pll_res->pll_base);
+	devm_kfree(&pdev->dev, pll_res);
+	return 0;
+}
+
+static const struct of_device_id mdss_pll_dt_match[] = {
+	{.compatible = "qcom,mdss_dsi_pll_8996"},
+	{.compatible = "qcom,mdss_dsi_pll_8996_v2"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996_v2"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996_v3"},
+	{.compatible = "qcom,mdss_hdmi_pll_8996_v3_1p8"},
+	{.compatible = "qcom,mdss_dsi_pll_8952"},
+	{.compatible = "qcom,mdss_dsi_pll_8937"},
+	{.compatible = "qcom,mdss_dsi_pll_8909"},
+	{.compatible = "qcom,mdss_dsi_pll_8953"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mdss_clock_dt_match);
+
+static struct platform_driver mdss_pll_driver = {
+	.probe = mdss_pll_probe,
+	.remove = mdss_pll_remove,
+	.driver = {
+		.name = "mdss_pll",
+		.of_match_table = mdss_pll_dt_match,
+	},
+};
+
+static int __init mdss_pll_driver_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&mdss_pll_driver);
+	if (rc)
+		pr_err("mdss_register_pll_driver() failed!\n");
+
+	return rc;
+}
+subsys_initcall(mdss_pll_driver_init);
+
+static void __exit mdss_pll_driver_deinit(void)
+{
+	platform_driver_unregister(&mdss_pll_driver);
+}
+module_exit(mdss_pll_driver_deinit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("mdss pll driver");
diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h
new file mode 100644
index 0000000..1fa5cff
--- /dev/null
+++ b/drivers/clk/msm/mdss/mdss-pll.h
@@ -0,0 +1,197 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __MDSS_PLL_H
+#define __MDSS_PLL_H
+
+#include <linux/mdss_io_util.h>
+#include <linux/io.h>
+
+#define MDSS_PLL_REG_W(base, offset, data)	\
+				writel_relaxed((data), (base) + (offset))
+#define MDSS_PLL_REG_R(base, offset)	readl_relaxed((base) + (offset))
+
+#define PLL_CALC_DATA(addr0, addr1, data0, data1)      \
+	(((data1) << 24) | ((((addr1) / 4) & 0xFF) << 16) | \
+	 ((data0) << 8) | (((addr0) / 4) & 0xFF))
+
+#define MDSS_DYN_PLL_REG_W(base, offset, addr0, addr1, data0, data1)   \
+		writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \
+			(base) + (offset))
+
+enum {
+	MDSS_DSI_PLL_LPM,
+	MDSS_DSI_PLL_8996,
+	MDSS_HDMI_PLL_8996,
+	MDSS_HDMI_PLL_8996_V2,
+	MDSS_HDMI_PLL_8996_V3,
+	MDSS_HDMI_PLL_8996_V3_1_8,
+	MDSS_UNKNOWN_PLL,
+};
+
+enum {
+	MDSS_PLL_TARGET_8996,
+	MDSS_PLL_TARGET_8952,
+	MDSS_PLL_TARGET_8937,
+	MDSS_PLL_TARGET_8953,
+	MDSS_PLL_TARGET_8909,
+};
+
+struct mdss_pll_resources {
+
+	/* Pll specific resources like GPIO, power supply, clocks, etc*/
+	struct mdss_module_power mp;
+
+	/*
+	 * dsi/edp/hmdi plls' base register, phy, gdsc and dynamic refresh
+	 * register mapping
+	 */
+	void __iomem	*pll_base;
+	void __iomem	*phy_base;
+	void __iomem	*gdsc_base;
+	void __iomem	*dyn_pll_base;
+
+	bool	is_init_locked;
+	s64	vco_current_rate;
+	s64	vco_locking_rate;
+	s64	vco_ref_clk_rate;
+
+	/*
+	 * Certain pll's needs to update the same vco rate after resume in
+	 * suspend/resume scenario. Cached the vco rate for such plls.
+	 */
+	unsigned long	vco_cached_rate;
+
+	/* dsi/edp/hmdi pll interface type */
+	u32		pll_interface_type;
+
+	/*
+	 * Target ID. Used in pll_register API for valid target check before
+	 * registering the PLL clocks.
+	 */
+	u32		target_id;
+
+	/* HW recommended delay during configuration of vco clock rate */
+	u32		vco_delay;
+
+	/* Ref-count of the PLL resources */
+	u32		resource_ref_cnt;
+
+	/*
+	 * Keep track to resource status to avoid updating same status for the
+	 * pll from different paths
+	 */
+	bool		resource_enable;
+
+	/*
+	 * Certain plls' do not allow vco rate update if it is on. Keep track of
+	 * status for them to turn on/off after set rate success.
+	 */
+	bool		pll_on;
+
+	/*
+	 * handoff_status is true of pll is already enabled by bootloader with
+	 * continuous splash enable case. Clock API will call the handoff API
+	 * to enable the status. It is disabled if continuous splash
+	 * feature is disabled.
+	 */
+	bool		handoff_resources;
+
+	/*
+	 * caching the pll trim codes in the case of dynamic refresh
+	 * or cmd mode idle screen.
+	 */
+	int		cache_pll_trim_codes[2];
+
+	/*
+	 * caching the pll trim codes rate
+	 */
+	s64		cache_pll_trim_codes_rate;
+
+	/*
+	 * for maintaining the status of saving trim codes
+	 */
+	bool		reg_upd;
+
+	/*
+	 * Notifier callback for MDSS gdsc regulator events
+	 */
+	struct notifier_block gdsc_cb;
+
+	/*
+	 * Worker function to call PLL off event
+	 */
+	struct work_struct pll_off;
+
+	/*
+	 * PLL index if multiple index are available. Eg. in case of
+	 * DSI we have 2 plls.
+	 */
+	uint32_t index;
+
+	bool ssc_en;	/* share pll with master */
+	bool ssc_center;	/* default is down spread */
+	u32 ssc_freq;
+	u32 ssc_ppm;
+
+	struct mdss_pll_resources *slave;
+
+	/*
+	 * target pll revision information
+	 */
+	int		revision;
+
+	void *priv;
+
+	/*
+	 * dynamic refresh pll codes stored in this structure
+	 */
+	struct dfps_info *dfps;
+
+};
+
+struct mdss_pll_vco_calc {
+	s32 div_frac_start1;
+	s32 div_frac_start2;
+	s32 div_frac_start3;
+	s64 dec_start1;
+	s64 dec_start2;
+	s64 pll_plllock_cmp1;
+	s64 pll_plllock_cmp2;
+	s64 pll_plllock_cmp3;
+};
+
+static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res)
+{
+	if (!pll_res->gdsc_base) {
+		WARN(1, "gdsc_base register is not defined\n");
+		return true;
+	}
+
+	return ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) &&
+		(!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true;
+}
+
+int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable);
+int mdss_pll_util_resource_init(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res);
+void mdss_pll_util_resource_deinit(struct platform_device *pdev,
+					 struct mdss_pll_resources *pll_res);
+void mdss_pll_util_resource_release(struct platform_device *pdev,
+					struct mdss_pll_resources *pll_res);
+int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res,
+								bool enable);
+int mdss_pll_util_resource_parse(struct platform_device *pdev,
+				struct mdss_pll_resources *pll_res);
+struct mdss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
+		, char *name);
+#endif
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index b6204cb..bf4df55 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -31,6 +31,7 @@
 #include <linux/sched.h>
 #include <linux/cpufreq.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 #include <dt-bindings/clock/qcom,cpucc-sdm845.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
@@ -47,6 +48,7 @@
 #define MAX_CLUSTER_CNT			3
 #define MAX_MEM_ACC_VAL_PER_LEVEL	3
 #define CORE_COUNT_VAL(val)		((val & GENMASK(18, 16)) >> 16)
+#define CURRENT_LVAL(val)		((val & GENMASK(23, 16)) >> 16)
 
 #define OSM_REG_SIZE			32
 
@@ -54,6 +56,7 @@
 #define FREQ_REG			0x110
 #define VOLT_REG			0x114
 #define CORE_DCVS_CTRL			0xbc
+#define PSTATE_STATUS			0x700
 
 #define DCVS_PERF_STATE_DESIRED_REG_0_V1	0x780
 #define DCVS_PERF_STATE_DESIRED_REG_0_V2	0x920
@@ -74,6 +77,7 @@
 	u16 virtual_corner;
 	u16 open_loop_volt;
 	long frequency;
+	u32 lval;
 	u16 ccount;
 };
 
@@ -205,7 +209,7 @@
 	struct clk_osm *c = to_clk_osm(hw);
 	struct clk_hw *p_hw = clk_hw_get_parent(hw);
 	struct clk_osm *parent = to_clk_osm(p_hw);
-	int index = 0;
+	int core_num, index = 0;
 
 	if (!c || !parent)
 		return -EINVAL;
@@ -217,8 +221,9 @@
 		return -EINVAL;
 	}
 
+	core_num = parent->per_core_dcvs ? c->core_num : 0;
 	clk_osm_write_reg(parent, index,
-				DCVS_PERF_STATE_DESIRED_REG(c->core_num,
+				DCVS_PERF_STATE_DESIRED_REG(core_num,
 							is_sdm845v1));
 
 	/* Make sure the write goes through before proceeding */
@@ -227,19 +232,52 @@
 	return 0;
 }
 
+static int clk_pwrcl_set_rate(struct clk_hw *hw, unsigned long rate,
+						unsigned long parent_rate)
+{
+	struct clk_hw *p_hw = clk_hw_get_parent(hw);
+	struct clk_osm *parent = to_clk_osm(p_hw);
+	int ret, index = 0, count = 40;
+	u32 curr_lval;
+
+	ret = clk_cpu_set_rate(hw, rate, parent_rate);
+	if (ret)
+		return ret;
+
+	index = clk_osm_search_table(parent->osm_table,
+					parent->num_entries, rate);
+	if (index < 0)
+		return -EINVAL;
+
+	/*
+	 * Poll the CURRENT_FREQUENCY value of the PSTATE_STATUS register to
+	 * check if the L_VAL has been updated.
+	 */
+	while (count-- > 0) {
+		curr_lval = CURRENT_LVAL(clk_osm_read_reg(parent,
+								PSTATE_STATUS));
+		if (curr_lval <= parent->osm_table[index].lval)
+			return 0;
+		udelay(50);
+	}
+	pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate);
+	return -ETIMEDOUT;
+}
+
 static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
 					unsigned long parent_rate)
 {
 	struct clk_osm *c = to_clk_osm(hw);
 	struct clk_hw *p_hw = clk_hw_get_parent(hw);
 	struct clk_osm *parent = to_clk_osm(p_hw);
-	int index = 0;
+	int core_num, index = 0;
 
 	if (!c || !parent)
 		return -EINVAL;
 
+	core_num = parent->per_core_dcvs ? c->core_num : 0;
 	index = clk_osm_read_reg(parent,
-				DCVS_PERF_STATE_DESIRED_REG(c->core_num,
+				DCVS_PERF_STATE_DESIRED_REG(core_num,
 							is_sdm845v1));
 	return parent->osm_table[index].frequency;
 }
@@ -262,6 +300,8 @@
 	struct clk_osm *cpuclk = to_clk_osm(hw);
 	int index = 0;
 	unsigned long r_rate;
+	int count = 40;
+	u32 curr_lval;
 
 	if (!cpuclk)
 		return -EINVAL;
@@ -288,6 +328,25 @@
 	/* Make sure the write goes through before proceeding */
 	clk_osm_mb(cpuclk);
 
+	/*
+	 * Poll the CURRENT_FREQUENCY value of the PSTATE_STATUS register to
+	 * check if the L_VAL has been updated.
+	 */
+	if (cpuclk->rate >= cpuclk->mx_turbo_freq &&
+					rate < cpuclk->mx_turbo_freq) {
+		while (count-- > 0) {
+			curr_lval = CURRENT_LVAL(clk_osm_read_reg(cpuclk,
+								PSTATE_STATUS));
+			if (curr_lval <= cpuclk->osm_table[index].lval) {
+				cpuclk->rate = rate;
+				return 0;
+			}
+			udelay(50);
+		}
+		pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate);
+		return -ETIMEDOUT;
+	}
+	cpuclk->rate = rate;
 	return 0;
 }
 
@@ -318,7 +377,14 @@
 	.debug_init = clk_debug_measure_add,
 };
 
-static const struct clk_ops clk_ops_core = {
+static const struct clk_ops clk_ops_pwrcl_core = {
+	.set_rate = clk_pwrcl_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_perfcl_core = {
 	.set_rate = clk_cpu_set_rate,
 	.round_rate = clk_cpu_round_rate,
 	.recalc_rate = clk_cpu_recalc_rate,
@@ -338,6 +404,7 @@
 		.name = "l3_clk",
 		.parent_names = (const char *[]){ "bi_tcxo_ao" },
 		.num_parents = 1,
+		.flags = CLK_CHILD_NO_RATE_PROP,
 		.ops = &clk_ops_l3_osm,
 		.vdd_class = &vdd_l3_mx_ao,
 	},
@@ -381,7 +448,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -394,7 +461,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -407,7 +474,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -420,7 +487,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -433,7 +500,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -446,7 +513,7 @@
 		.parent_names = (const char *[]){ "pwrcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_pwrcl_core,
 	},
 };
 
@@ -466,7 +533,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -479,7 +546,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -492,7 +559,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -505,7 +572,7 @@
 		.parent_names = (const char *[]){ "perfcl_clk" },
 		.num_parents = 1,
 		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_ops_core,
+		.ops = &clk_ops_perfcl_core,
 	},
 };
 
@@ -974,6 +1041,7 @@
 		src = ((data & GENMASK(31, 30)) >> 30);
 		lval = (data & GENMASK(7, 0));
 		c->osm_table[i].ccount = CORE_COUNT_VAL(data);
+		c->osm_table[i].lval = lval;
 
 		if (!src)
 			c->osm_table[i].frequency = OSM_INIT_RATE;
diff --git a/drivers/clk/qcom/gcc-sdxpoorwills.c b/drivers/clk/qcom/gcc-sdxpoorwills.c
index 696d7fb..c6e8faa 100644
--- a/drivers/clk/qcom/gcc-sdxpoorwills.c
+++ b/drivers/clk/qcom/gcc-sdxpoorwills.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1316,33 +1316,6 @@
 	},
 };
 
-static struct clk_branch gcc_mss_cfg_ahb_clk = {
-	.halt_reg = 0x40000,
-	.halt_check = BRANCH_HALT,
-	.hwcg_reg = 0x40000,
-	.hwcg_bit = 1,
-	.clkr = {
-		.enable_reg = 0x40000,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_mss_cfg_ahb_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
-static struct clk_gate2 gcc_mss_gpll0_div_clk_src = {
-	.udelay = 500,
-	.clkr = {
-		.enable_reg = 0x6d004,
-		.enable_mask = BIT(17),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_mss_gpll0_div_clk_src",
-			.ops = &clk_gate2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_pcie_0_clkref_clk = {
 	.halt_reg = 0x88004,
 	.halt_check = BRANCH_HALT,
@@ -1794,8 +1767,6 @@
 	[GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
 	[GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
 	[GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
-	[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_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,
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 3f9fcd9..7290205 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,8 @@
 #include "mdss-dsi-pll.h"
 #include "mdss-pll.h"
 #include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+#define CREATE_TRACE_POINTS
+#include "mdss_pll_trace.h"
 
 #define VCO_DELAY_USEC 1
 
@@ -890,8 +892,13 @@
 		MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE,
 					pll->cached_outdiv);
 	}
-
+	MDSS_PLL_ATRACE_BEGIN("pll_lock");
+	trace_mdss_pll_lock_start((u64)pll->vco_cached_rate,
+			pll->vco_current_rate,
+			pll->cached_cfg0, pll->cached_cfg1,
+			pll->cached_outdiv, pll->resource_ref_cnt);
 	rc = dsi_pll_enable(vco);
+	MDSS_PLL_ATRACE_END("pll_lock");
 	if (rc) {
 		mdss_pll_resource_enable(pll, false);
 		pr_err("pll(%d) enable failed, rc=%d\n", pll->index, rc);
diff --git a/drivers/clk/qcom/mdss/mdss_pll_trace.h b/drivers/clk/qcom/mdss/mdss_pll_trace.h
new file mode 100644
index 0000000..cd4fda6
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss_pll_trace.h
@@ -0,0 +1,116 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#if !defined(_MDSS_PLL_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _MDSS_PLL_TRACE_H_
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mdss_pll
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE mdss_pll_trace
+
+
+TRACE_EVENT(mdss_pll_lock_start,
+	TP_PROTO(
+			u64 vco_cached_rate,
+			s64 vco_current_rate,
+			u32 cached_cfg0,
+			u32 cached_cfg1,
+			u32 cached_outdiv,
+			u32 resource_ref_cnt),
+	TP_ARGS(
+			vco_cached_rate,
+			vco_current_rate,
+			cached_cfg0,
+			cached_cfg1,
+			cached_outdiv,
+			resource_ref_cnt),
+	TP_STRUCT__entry(
+			__field(u64, vco_cached_rate)
+			__field(s64, vco_current_rate)
+			__field(u32, cached_cfg0)
+			__field(u32, cached_cfg1)
+			__field(u32, cached_outdiv)
+			__field(u32, resource_ref_cnt)
+
+	),
+	TP_fast_assign(
+			__entry->vco_cached_rate = vco_cached_rate;
+			__entry->vco_current_rate = vco_current_rate;
+			__entry->cached_cfg0 = cached_cfg0;
+			__entry->cached_cfg1 = cached_cfg1;
+			__entry->cached_outdiv = cached_outdiv;
+			__entry->resource_ref_cnt = resource_ref_cnt;
+	),
+	 TP_printk(
+		"vco_cached_rate=%llu vco_current_rate=%lld cached_cfg0=%d cached_cfg1=%d cached_outdiv=%d resource_ref_cnt=%d",
+			__entry->vco_cached_rate,
+			__entry->vco_current_rate,
+			__entry->cached_cfg0,
+			__entry->cached_cfg1,
+			__entry->cached_outdiv,
+			__entry->resource_ref_cnt)
+);
+
+TRACE_EVENT(pll_tracing_mark_write,
+	TP_PROTO(int pid, const char *name, bool trace_begin),
+	TP_ARGS(pid, name, trace_begin),
+	TP_STRUCT__entry(
+			__field(int, pid)
+			__string(trace_name, name)
+			__field(bool, trace_begin)
+	),
+	TP_fast_assign(
+			__entry->pid = pid;
+			__assign_str(trace_name, name);
+			__entry->trace_begin = trace_begin;
+	),
+	TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E",
+		__entry->pid, __get_str(trace_name))
+)
+
+TRACE_EVENT(mdss_pll_trace_counter,
+	TP_PROTO(int pid, char *name, int value),
+	TP_ARGS(pid, name, value),
+	TP_STRUCT__entry(
+			__field(int, pid)
+			__string(counter_name, name)
+			__field(int, value)
+	),
+	TP_fast_assign(
+			__entry->pid = current->tgid;
+			__assign_str(counter_name, name);
+			__entry->value = value;
+	),
+	TP_printk("%d|%s|%d", __entry->pid,
+			__get_str(counter_name), __entry->value)
+)
+
+#define MDSS_PLL_ATRACE_END(name) trace_pll_tracing_mark_write(current->tgid,\
+		name, 0)
+#define MDSS_PLL_ATRACE_BEGIN(name) trace_pll_tracing_mark_write(current->tgid,\
+		name, 1)
+#define MDSS_PLL_ATRACE_FUNC() MDSS_PLL_ATRACE_BEGIN(__func__)
+#define MDSS_PLL_ATRACE_INT(name, value) \
+	trace_mdss_pll_trace_counter(current->tgid, name, value)
+
+
+#endif /* _MDSS_PLL_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index f18dccf..bb540a5 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -331,6 +331,7 @@
 if MIPS
 config LOONGSON2_CPUFREQ
 	tristate "Loongson2 CPUFreq Driver"
+	depends on LEMOTE_MACH2F
 	help
 	  This option adds a CPUFreq driver for loongson processors which
 	  support software configurable cpu frequency.
@@ -343,6 +344,7 @@
 
 config LOONGSON1_CPUFREQ
 	tristate "Loongson1 CPUFreq Driver"
+	depends on LOONGSON1_LS1B
 	help
 	  This option adds a CPUFreq driver for loongson1 processors which
 	  support software configurable cpu frequency.
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1d5dba9..ff72d8a 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -730,6 +730,9 @@
 									\
 	memcpy(&new_policy, policy, sizeof(*policy));			\
 									\
+	new_policy.min = new_policy.user_policy.min;			\
+	new_policy.max = new_policy.user_policy.max;			\
+									\
 	ret = sscanf(buf, "%u", &new_policy.object);			\
 	if (ret != 1)							\
 		return -EINVAL;						\
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 19fe223..6c66b7f 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1251,7 +1251,6 @@
 
 		state_id |= (level->psci_id & cluster->psci_mode_mask)
 					<< cluster->psci_mode_shift;
-		(*aff_lvl)++;
 
 		/*
 		 * We may have updated the broadcast timers, update
@@ -1259,6 +1258,8 @@
 		 */
 		if (level->notify_rpm)
 			system_sleep_update_wakeup();
+		if (level->psci_id)
+			(*aff_lvl)++;
 	}
 unlock_and_return:
 	spin_unlock(&cluster->sync_lock);
@@ -1731,6 +1732,18 @@
 {
 	int rc;
 
+#ifdef CONFIG_ARM
+	int cpu;
+
+	for_each_possible_cpu(cpu) {
+		rc = arm_cpuidle_init(smp_processor_id());
+		if (rc) {
+			pr_err("CPU%d ARM CPUidle init failed (%d)\n", cpu, rc);
+			return rc;
+		}
+	}
+#endif
+
 	rc = platform_driver_register(&lpm_driver);
 	if (rc) {
 		pr_info("Error registering %s\n", lpm_driver.driver.name);
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 2b6b112..3d50bae 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -249,8 +249,9 @@
 }
 
 #ifdef CONFIG_CPU_IDLE
-static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
+static __maybe_unused DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
 
+#ifdef CONFIG_DT_IDLE_STATES
 static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
 {
 	int i, ret, count = 0;
@@ -303,6 +304,10 @@
 	kfree(psci_states);
 	return ret;
 }
+#else
+static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
+{ return 0; }
+#endif
 
 #ifdef CONFIG_ACPI
 #include <acpi/processor.h>
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index dc37dbe..a83e97e 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -323,3 +323,6 @@
 };
 
 module_platform_driver(ath79_gpio_driver);
+
+MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X GPIO API support");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index 98c7ff2..8d62db4 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -58,3 +58,7 @@
 	return platform_driver_register(&iop3xx_gpio_driver);
 }
 arch_initcall(iop3xx_gpio_init);
+
+MODULE_DESCRIPTION("GPIO handling for Intel IOP3xx processors");
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index adba614..abb5a27 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -190,6 +190,16 @@
 	};
 	int i, j;
 
+	/*
+	 * STMPE1600: to be able to get IRQ from pins,
+	 * a read must be done on GPMR register, or a write in
+	 * GPSR or GPCR registers
+	 */
+	if (stmpe->partnum == STMPE1600) {
+		stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_LSB]);
+		stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_GPMR_CSB]);
+	}
+
 	for (i = 0; i < CACHE_NR_REGS; i++) {
 		/* STMPE801 and STMPE1600 don't have RE and FE registers */
 		if ((stmpe->partnum == STMPE801 ||
@@ -227,21 +237,11 @@
 {
 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
-	struct stmpe *stmpe = stmpe_gpio->stmpe;
 	int offset = d->hwirq;
 	int regoffset = offset / 8;
 	int mask = BIT(offset % 8);
 
 	stmpe_gpio->regs[REG_IE][regoffset] |= mask;
-
-	/*
-	 * STMPE1600 workaround: to be able to get IRQ from pins,
-	 * a read must be done on GPMR register, or a write in
-	 * GPSR or GPCR registers
-	 */
-	if (stmpe->partnum == STMPE1600)
-		stmpe_reg_read(stmpe,
-			       stmpe->regs[STMPE_IDX_GPMR_LSB + regoffset]);
 }
 
 static void stmpe_dbg_show_one(struct seq_file *s,
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 063d176..f3c3680 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -705,6 +705,9 @@
 	struct gpioevent_data ge;
 	int ret, level;
 
+	/* Do not leak kernel stack to userspace */
+	memset(&ge, 0, sizeof(ge));
+
 	ge.timestamp = ktime_get_real_ns();
 	level = gpiod_get_value_cansleep(le->desc);
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
index 1a0a5f7..47951f4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
@@ -367,29 +367,50 @@
 {
 	struct amdgpu_device *adev = get_amdgpu_device(kgd);
 	struct cik_sdma_rlc_registers *m;
+	unsigned long end_jiffies;
 	uint32_t sdma_base_addr;
+	uint32_t data;
 
 	m = get_sdma_mqd(mqd);
 	sdma_base_addr = get_sdma_base_addr(m);
 
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR,
-			m->sdma_rlc_virtual_addr);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
+		m->sdma_rlc_rb_cntl & (~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK));
 
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE,
-			m->sdma_rlc_rb_base);
-
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI,
-			m->sdma_rlc_rb_base_hi);
-
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO,
-			m->sdma_rlc_rb_rptr_addr_lo);
-
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI,
-			m->sdma_rlc_rb_rptr_addr_hi);
+	end_jiffies = msecs_to_jiffies(2000) + jiffies;
+	while (true) {
+		data = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS);
+		if (data & SDMA0_RLC0_CONTEXT_STATUS__IDLE_MASK)
+			break;
+		if (time_after(jiffies, end_jiffies))
+			return -ETIME;
+		usleep_range(500, 1000);
+	}
+	if (m->sdma_engine_id) {
+		data = RREG32(mmSDMA1_GFX_CONTEXT_CNTL);
+		data = REG_SET_FIELD(data, SDMA1_GFX_CONTEXT_CNTL,
+				RESUME_CTX, 0);
+		WREG32(mmSDMA1_GFX_CONTEXT_CNTL, data);
+	} else {
+		data = RREG32(mmSDMA0_GFX_CONTEXT_CNTL);
+		data = REG_SET_FIELD(data, SDMA0_GFX_CONTEXT_CNTL,
+				RESUME_CTX, 0);
+		WREG32(mmSDMA0_GFX_CONTEXT_CNTL, data);
+	}
 
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL,
-			m->sdma_rlc_doorbell);
-
+				m->sdma_rlc_doorbell);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR,
+				m->sdma_rlc_virtual_addr);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, m->sdma_rlc_rb_base);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI,
+			m->sdma_rlc_rb_base_hi);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO,
+			m->sdma_rlc_rb_rptr_addr_lo);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI,
+			m->sdma_rlc_rb_rptr_addr_hi);
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
 			m->sdma_rlc_rb_cntl);
 
@@ -493,9 +514,9 @@
 	}
 
 	WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0);
-	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0);
+	WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL,
+		RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL) |
+		SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index f26d1fd..cb505f6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -416,6 +416,10 @@
 		if (candidate == lobj)
 			break;
 
+		/* We can't move pinned BOs here */
+		if (bo->pin_count)
+			continue;
+
 		other = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type);
 
 		/* Check if this BO is in one of the domains we need space for */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
index d83de98..8577a56 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
@@ -215,8 +215,8 @@
 	BUG_ON(!mm || !mqd || !q);
 
 	m = get_sdma_mqd(mqd);
-	m->sdma_rlc_rb_cntl = ffs(q->queue_size / sizeof(unsigned int)) <<
-			SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT |
+	m->sdma_rlc_rb_cntl = (ffs(q->queue_size / sizeof(unsigned int)) - 1)
+			<< SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT |
 			q->vmid << SDMA0_RLC0_RB_CNTL__RB_VMID__SHIFT |
 			1 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT |
 			6 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index e1fb40b..5425c68 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -205,6 +205,24 @@
 
 	switch (type) {
 	case KFD_QUEUE_TYPE_SDMA:
+		if (dev->dqm->queue_count >=
+			CIK_SDMA_QUEUES_PER_ENGINE * CIK_SDMA_ENGINE_NUM) {
+			pr_err("Over-subscription is not allowed for SDMA.\n");
+			retval = -EPERM;
+			goto err_create_queue;
+		}
+
+		retval = create_cp_queue(pqm, dev, &q, properties, f, *qid);
+		if (retval != 0)
+			goto err_create_queue;
+		pqn->q = q;
+		pqn->kq = NULL;
+		retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd,
+						&q->properties.vmid);
+		pr_debug("DQM returned %d for create_queue\n", retval);
+		print_queue(q);
+		break;
+
 	case KFD_QUEUE_TYPE_COMPUTE:
 		/* check if there is over subscription */
 		if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 44d476e..f64f35c 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -97,7 +97,7 @@
 #define DP0_ACTIVEVAL		0x0650
 #define DP0_SYNCVAL		0x0654
 #define DP0_MISC		0x0658
-#define TU_SIZE_RECOMMENDED		(0x3f << 16) /* LSCLK cycles per TU */
+#define TU_SIZE_RECOMMENDED		(63) /* LSCLK cycles per TU */
 #define BPC_6				(0 << 5)
 #define BPC_8				(1 << 5)
 
@@ -318,7 +318,7 @@
 				tmp = (tmp << 8) | buf[i];
 			i++;
 			if (((i % 4) == 0) || (i == size)) {
-				tc_write(DP0_AUXWDATA(i >> 2), tmp);
+				tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp);
 				tmp = 0;
 			}
 		}
@@ -603,8 +603,15 @@
 	ret = drm_dp_link_probe(&tc->aux, &tc->link.base);
 	if (ret < 0)
 		goto err_dpcd_read;
-	if ((tc->link.base.rate != 162000) && (tc->link.base.rate != 270000))
-		goto err_dpcd_inval;
+	if (tc->link.base.rate != 162000 && tc->link.base.rate != 270000) {
+		dev_dbg(tc->dev, "Falling to 2.7 Gbps rate\n");
+		tc->link.base.rate = 270000;
+	}
+
+	if (tc->link.base.num_lanes > 2) {
+		dev_dbg(tc->dev, "Falling to 2 lanes\n");
+		tc->link.base.num_lanes = 2;
+	}
 
 	ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp);
 	if (ret < 0)
@@ -637,9 +644,6 @@
 err_dpcd_read:
 	dev_err(tc->dev, "failed to read DPCD: %d\n", ret);
 	return ret;
-err_dpcd_inval:
-	dev_err(tc->dev, "invalid DPCD\n");
-	return -EINVAL;
 }
 
 static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode)
@@ -655,6 +659,14 @@
 	int lower_margin = mode->vsync_start - mode->vdisplay;
 	int vsync_len = mode->vsync_end - mode->vsync_start;
 
+	/*
+	 * Recommended maximum number of symbols transferred in a transfer unit:
+	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
+	 *              (output active video bandwidth in bytes))
+	 * Must be less than tu_size.
+	 */
+	max_tu_symbol = TU_SIZE_RECOMMENDED - 1;
+
 	dev_dbg(tc->dev, "set mode %dx%d\n",
 		mode->hdisplay, mode->vdisplay);
 	dev_dbg(tc->dev, "H margin %d,%d sync %d\n",
@@ -664,13 +676,18 @@
 	dev_dbg(tc->dev, "total: %dx%d\n", mode->htotal, mode->vtotal);
 
 
-	/* LCD Ctl Frame Size */
-	tc_write(VPCTRL0, (0x40 << 20) /* VSDELAY */ |
+	/*
+	 * LCD Ctl Frame Size
+	 * datasheet is not clear of vsdelay in case of DPI
+	 * assume we do not need any delay when DPI is a source of
+	 * sync signals
+	 */
+	tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ |
 		 OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED);
-	tc_write(HTIM01, (left_margin << 16) |		/* H back porch */
-			 (hsync_len << 0));		/* Hsync */
-	tc_write(HTIM02, (right_margin << 16) |		/* H front porch */
-			 (mode->hdisplay << 0));	/* width */
+	tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */
+			 (ALIGN(hsync_len, 2) << 0));	 /* Hsync */
+	tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) |  /* H front porch */
+			 (ALIGN(mode->hdisplay, 2) << 0)); /* width */
 	tc_write(VTIM01, (upper_margin << 16) |		/* V back porch */
 			 (vsync_len << 0));		/* Vsync */
 	tc_write(VTIM02, (lower_margin << 16) |		/* V front porch */
@@ -689,7 +706,7 @@
 	/* DP Main Stream Attributes */
 	vid_sync_dly = hsync_len + left_margin + mode->hdisplay;
 	tc_write(DP0_VIDSYNCDELAY,
-		 (0x003e << 16) |	/* thresh_dly */
+		 (max_tu_symbol << 16) |	/* thresh_dly */
 		 (vid_sync_dly << 0));
 
 	tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal));
@@ -705,14 +722,8 @@
 	tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
 		 DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888);
 
-	/*
-	 * Recommended maximum number of symbols transferred in a transfer unit:
-	 * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size,
-	 *              (output active video bandwidth in bytes))
-	 * Must be less than tu_size.
-	 */
-	max_tu_symbol = TU_SIZE_RECOMMENDED - 1;
-	tc_write(DP0_MISC, (max_tu_symbol << 23) | TU_SIZE_RECOMMENDED | BPC_8);
+	tc_write(DP0_MISC, (max_tu_symbol << 23) | (TU_SIZE_RECOMMENDED << 16) |
+			   BPC_8);
 
 	return 0;
 err:
@@ -808,8 +819,6 @@
 	unsigned int rate;
 	u32 dp_phy_ctrl;
 	int timeout;
-	bool aligned;
-	bool ready;
 	u32 value;
 	int ret;
 	u8 tmp[8];
@@ -954,16 +963,15 @@
 		ret = drm_dp_dpcd_read_link_status(aux, tmp + 2);
 		if (ret < 0)
 			goto err_dpcd_read;
-		ready = (tmp[2] == ((DP_CHANNEL_EQ_BITS << 4) | /* Lane1 */
-				     DP_CHANNEL_EQ_BITS));      /* Lane0 */
-		aligned = tmp[4] & DP_INTERLANE_ALIGN_DONE;
-	} while ((--timeout) && !(ready && aligned));
+	} while ((--timeout) &&
+		 !(drm_dp_channel_eq_ok(tmp + 2,  tc->link.base.num_lanes)));
 
 	if (timeout == 0) {
 		/* Read DPCD 0x200-0x201 */
 		ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT, tmp, 2);
 		if (ret < 0)
 			goto err_dpcd_read;
+		dev_err(dev, "channel(s) EQ not ok\n");
 		dev_info(dev, "0x0200 SINK_COUNT: 0x%02x\n", tmp[0]);
 		dev_info(dev, "0x0201 DEVICE_SERVICE_IRQ_VECTOR: 0x%02x\n",
 			 tmp[1]);
@@ -974,10 +982,6 @@
 		dev_info(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n",
 			 tmp[6]);
 
-		if (!ready)
-			dev_err(dev, "Lane0/1 not ready\n");
-		if (!aligned)
-			dev_err(dev, "Lane0/1 not aligned\n");
 		return -EAGAIN;
 	}
 
@@ -1105,7 +1109,10 @@
 static int tc_connector_mode_valid(struct drm_connector *connector,
 				   struct drm_display_mode *mode)
 {
-	/* Accept any mode */
+	/* DPI interface clock limitation: upto 154 MHz */
+	if (mode->clock > 154000)
+		return MODE_CLOCK_HIGH;
+
 	return MODE_OK;
 }
 
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0ee052b..70e8414 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -149,6 +149,32 @@
 EXPORT_SYMBOL(drm_bridge_detach);
 
 /**
+ * drm_bridge_connector_init - call bridge's connector_init callback to allow
+ *                     the bridge to update connector's behavior.
+ * @bridge: bridge control structure
+ * @connector: connector control structure
+ *
+ * Calls ->connector_init() &drm_bridge_funcs op for the bridge.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector)
+{
+	int ret = 0;
+
+	if (!bridge || !connector)
+		return -EINVAL;
+
+	if (bridge->funcs->connector_init)
+		ret = bridge->funcs->connector_init(bridge, connector);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_bridge_connector_init);
+
+/**
  * DOC: bridge callbacks
  *
  * The &drm_bridge_funcs ops are populated by the bridge driver. The DRM
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 79f2ec9..630b5fb 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -29,24 +29,54 @@
 	struct dp_aux dp_aux;
 	struct dp_catalog_aux *catalog;
 	struct dp_aux_cfg *cfg;
-
 	struct mutex mutex;
 	struct completion comp;
+	struct drm_dp_aux drm_aux;
 
-	u32 aux_error_num;
-	u32 retry_cnt;
 	bool cmd_busy;
 	bool native;
 	bool read;
 	bool no_send_addr;
 	bool no_send_stop;
+
 	u32 offset;
 	u32 segment;
+	u32 aux_error_num;
+	u32 retry_cnt;
+
 	atomic_t aborted;
 
-	struct drm_dp_aux drm_aux;
+	u8 *dpcd;
+	u8 *edid;
 };
 
+#ifdef CONFIG_DYNAMIC_DEBUG
+static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+	DEFINE_DYNAMIC_DEBUG_METADATA(ddm, "dp aux tracker");
+
+	if (unlikely(ddm.flags & _DPRINTK_FLAGS_PRINT)) {
+		u8 buf[SZ_64];
+		struct dp_aux_private *aux = container_of(drm_aux,
+			struct dp_aux_private, drm_aux);
+
+		snprintf(buf, SZ_64, "[drm-dp] %5s %5s %5xh(%2zu): ",
+			aux->native ? "NATIVE" : "I2C",
+			aux->read ? "READ" : "WRITE",
+			msg->address, msg->size);
+
+		print_hex_dump(KERN_DEBUG, buf, DUMP_PREFIX_NONE,
+			8, 1, msg->buffer, msg->size, false);
+	}
+}
+#else
+static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+}
+#endif
+
 static char *dp_aux_get_error(u32 aux_error)
 {
 	switch (aux_error) {
@@ -320,6 +350,7 @@
  *
  * @aux: DP AUX private structure
  * @input_msg: input message from DRM upstream APIs
+ * @send_seg: send the seg to sink
  *
  * return: void
  *
@@ -327,7 +358,7 @@
  * sinks that do not handle the i2c middle-of-transaction flag correctly.
  */
 static void dp_aux_transfer_helper(struct dp_aux_private *aux,
-		struct drm_dp_aux_msg *input_msg)
+		struct drm_dp_aux_msg *input_msg, bool send_seg)
 {
 	struct drm_dp_aux_msg helper_msg;
 	u32 const message_size = 0x10;
@@ -346,7 +377,7 @@
 	 * duplicate AUX transactions related to this while reading the
 	 * first 16 bytes of each block.
 	 */
-	if (!(aux->offset % edid_block_length))
+	if (!(aux->offset % edid_block_length) || !send_seg)
 		goto end;
 
 	aux->read = false;
@@ -388,6 +419,110 @@
 		aux->segment = 0x0; /* reset segment at end of block */
 }
 
+static int dp_aux_transfer_ready(struct dp_aux_private *aux,
+		struct drm_dp_aux_msg *msg, bool send_seg)
+{
+	int ret = 0;
+	int const aux_cmd_native_max = 16;
+	int const aux_cmd_i2c_max = 128;
+
+	if (atomic_read(&aux->aborted)) {
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+
+	/* Ignore address only message */
+	if ((msg->size == 0) || (msg->buffer == NULL)) {
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+		goto error;
+	}
+
+	/* msg sanity check */
+	if ((aux->native && (msg->size > aux_cmd_native_max)) ||
+		(msg->size > aux_cmd_i2c_max)) {
+		pr_err("%s: invalid msg: size(%zu), request(%x)\n",
+			__func__, msg->size, msg->request);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	dp_aux_update_offset_and_segment(aux, msg);
+
+	dp_aux_transfer_helper(aux, msg, send_seg);
+
+	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+
+	if (aux->read) {
+		aux->no_send_addr = true;
+		aux->no_send_stop = false;
+	} else {
+		aux->no_send_addr = true;
+		aux->no_send_stop = true;
+	}
+
+	aux->cmd_busy = true;
+error:
+	return ret;
+}
+
+static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+	u32 timeout;
+	ssize_t ret;
+	struct dp_aux_private *aux = container_of(drm_aux,
+		struct dp_aux_private, drm_aux);
+
+	ret = dp_aux_transfer_ready(aux, msg, false);
+	if (ret)
+		goto end;
+
+	aux->aux_error_num = DP_AUX_ERR_NONE;
+
+	if (aux->native) {
+		if (aux->read && ((msg->address + msg->size) < SZ_1K)) {
+			aux->dp_aux.reg = msg->address;
+
+			reinit_completion(&aux->comp);
+			timeout = wait_for_completion_timeout(&aux->comp, HZ);
+			if (!timeout)
+				pr_err("aux timeout for 0x%x\n", msg->address);
+
+			aux->dp_aux.reg = 0xFFFF;
+
+			memcpy(msg->buffer, aux->dpcd + msg->address,
+				msg->size);
+			aux->aux_error_num = DP_AUX_ERR_NONE;
+		} else {
+			memset(msg->buffer, 0, msg->size);
+		}
+	} else {
+		if (aux->read && msg->address == 0x50) {
+			memcpy(msg->buffer,
+				aux->edid + aux->offset - 16,
+				msg->size);
+		}
+	}
+
+	if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+		dp_aux_hex_dump(drm_aux, msg);
+
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	} else {
+		/* Reply defer to retry */
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+	}
+
+	ret = msg->size;
+end:
+	return ret;
+}
+
 /*
  * This function does the real job to process an AUX transaction.
  * It will call aux_reset() function to reset the AUX channel,
@@ -397,52 +532,21 @@
 		struct drm_dp_aux_msg *msg)
 {
 	ssize_t ret;
-	int const aux_cmd_native_max = 16;
-	int const aux_cmd_i2c_max = 128;
 	int const retry_count = 5;
 	struct dp_aux_private *aux = container_of(drm_aux,
 		struct dp_aux_private, drm_aux);
 
 	mutex_lock(&aux->mutex);
 
-	if (atomic_read(&aux->aborted)) {
-		ret = -ETIMEDOUT;
+	ret = dp_aux_transfer_ready(aux, msg, true);
+	if (ret)
 		goto unlock_exit;
-	}
 
-	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
-
-	/* Ignore address only message */
-	if ((msg->size == 0) || (msg->buffer == NULL)) {
-		msg->reply = aux->native ?
-			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	if (!aux->cmd_busy) {
 		ret = msg->size;
 		goto unlock_exit;
 	}
 
-	/* msg sanity check */
-	if ((aux->native && (msg->size > aux_cmd_native_max)) ||
-		(msg->size > aux_cmd_i2c_max)) {
-		pr_err("%s: invalid msg: size(%zu), request(%x)\n",
-			__func__, msg->size, msg->request);
-		ret = -EINVAL;
-		goto unlock_exit;
-	}
-
-	dp_aux_update_offset_and_segment(aux, msg);
-	dp_aux_transfer_helper(aux, msg);
-
-	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
-	aux->cmd_busy = true;
-
-	if (aux->read) {
-		aux->no_send_addr = true;
-		aux->no_send_stop = false;
-	} else {
-		aux->no_send_addr = true;
-		aux->no_send_stop = true;
-	}
-
 	ret = dp_aux_cmd_fifo_tx(aux, msg);
 	if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) {
 		aux->retry_cnt++;
@@ -459,6 +563,8 @@
 		if (aux->read)
 			dp_aux_cmd_fifo_rx(aux, msg);
 
+		dp_aux_hex_dump(drm_aux, msg);
+
 		msg->reply = aux->native ?
 			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
 	} else {
@@ -558,6 +664,41 @@
 	drm_dp_aux_unregister(&aux->drm_aux);
 }
 
+static void dp_aux_dpcd_updated(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	complete(&aux->comp);
+}
+
+static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en,
+		u8 *edid, u8 *dpcd)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	aux->edid = edid;
+	aux->dpcd = dpcd;
+
+	if (en)
+		aux->drm_aux.transfer = dp_aux_transfer_debug;
+	else
+		aux->drm_aux.transfer = dp_aux_transfer;
+}
+
 struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
 		struct dp_aux_cfg *aux_cfg)
 {
@@ -586,6 +727,7 @@
 	aux->cfg = aux_cfg;
 	dp_aux = &aux->dp_aux;
 	aux->retry_cnt = 0;
+	aux->dp_aux.reg = 0xFFFF;
 
 	dp_aux->isr     = dp_aux_isr;
 	dp_aux->init    = dp_aux_init;
@@ -594,6 +736,8 @@
 	dp_aux->drm_aux_deregister = dp_aux_deregister;
 	dp_aux->reconfig = dp_aux_reconfig;
 	dp_aux->abort = dp_aux_abort_transaction;
+	dp_aux->dpcd_updated = dp_aux_dpcd_updated;
+	dp_aux->set_sim_mode = dp_aux_set_sim_mode;
 
 	return dp_aux;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index e8cb1cc..bf52d57 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,19 @@
 #include "dp_catalog.h"
 #include "drm_dp_helper.h"
 
+#define DP_STATE_NOTIFICATION_SENT          BIT(0)
+#define DP_STATE_TRAIN_1_STARTED            BIT(1)
+#define DP_STATE_TRAIN_1_SUCCEEDED          BIT(2)
+#define DP_STATE_TRAIN_1_FAILED             BIT(3)
+#define DP_STATE_TRAIN_2_STARTED            BIT(4)
+#define DP_STATE_TRAIN_2_SUCCEEDED          BIT(5)
+#define DP_STATE_TRAIN_2_FAILED             BIT(6)
+#define DP_STATE_CTRL_POWERED_ON            BIT(7)
+#define DP_STATE_CTRL_POWERED_OFF           BIT(8)
+#define DP_STATE_LINK_MAINTENANCE_STARTED   BIT(9)
+#define DP_STATE_LINK_MAINTENANCE_COMPLETED BIT(10)
+#define DP_STATE_LINK_MAINTENANCE_FAILED    BIT(11)
+
 enum dp_aux_error {
 	DP_AUX_ERR_NONE	= 0,
 	DP_AUX_ERR_ADDR	= -1,
@@ -29,6 +42,9 @@
 };
 
 struct dp_aux {
+	u32 reg;
+	u32 state;
+
 	struct drm_dp_aux *drm_aux;
 	int (*drm_aux_register)(struct dp_aux *aux);
 	void (*drm_aux_deregister)(struct dp_aux *aux);
@@ -37,6 +53,8 @@
 	void (*deinit)(struct dp_aux *aux);
 	void (*reconfig)(struct dp_aux *aux);
 	void (*abort)(struct dp_aux *aux);
+	void (*dpcd_updated)(struct dp_aux *aux);
+	void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd);
 };
 
 struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index cfb4436..56a41b5 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,15 +23,12 @@
 #define DP_GET_MSB(x)	(x >> 8)
 #define DP_GET_LSB(x)	(x & 0xff)
 
-#define dp_read(offset) readl_relaxed((offset))
-#define dp_write(offset, data) writel_relaxed((data), (offset))
-
-#define dp_catalog_get_priv(x) { \
+#define dp_catalog_get_priv(x) ({ \
 	struct dp_catalog *dp_catalog; \
 	dp_catalog = container_of(x, struct dp_catalog, x); \
-	catalog = container_of(dp_catalog, struct dp_catalog_private, \
+	container_of(dp_catalog, struct dp_catalog_private, \
 				dp_catalog); \
-}
+})
 
 #define DP_INTERRUPT_STATUS1 \
 	(DP_INTR_AUX_I2C_DONE| \
@@ -48,6 +45,14 @@
 
 #define DP_INTR_MASK2		(DP_INTERRUPT_STATUS2 << 2)
 
+#define dp_catalog_fill_io(x) { \
+	catalog->io.x = parser->get_io(parser, #x); \
+}
+
+#define dp_catalog_fill_io_buf(x) { \
+	parser->get_io_buf(parser, #x); \
+}
+
 static u8 const vm_pre_emphasis[4][4] = {
 	{0x00, 0x0B, 0x12, 0xFF},       /* pe0, 0 db */
 	{0x00, 0x0A, 0x12, 0xFF},       /* pe1, 3.5 db */
@@ -63,30 +68,77 @@
 	{0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
 };
 
+struct dp_catalog_io {
+	struct dp_io_data *dp_ahb;
+	struct dp_io_data *dp_aux;
+	struct dp_io_data *dp_link;
+	struct dp_io_data *dp_p0;
+	struct dp_io_data *dp_phy;
+	struct dp_io_data *dp_ln_tx0;
+	struct dp_io_data *dp_ln_tx1;
+	struct dp_io_data *dp_mmss_cc;
+	struct dp_io_data *dp_pll;
+	struct dp_io_data *usb3_dp_com;
+	struct dp_io_data *hdcp_physical;
+};
+
 /* audio related catalog functions */
 struct dp_catalog_private {
 	struct device *dev;
-	struct dp_io *io;
+	struct dp_catalog_io io;
+	struct dp_parser *parser;
 
 	u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
 	struct dp_catalog dp_catalog;
+
+	char exe_mode[SZ_4];
 };
 
+static u32 dp_read(struct dp_catalog_private *catalog,
+		struct dp_io_data *io_data, u32 offset)
+{
+	u32 data = 0;
+
+	if (!strcmp(catalog->exe_mode, "hw") ||
+	    !strcmp(catalog->exe_mode, "all")) {
+		data = readl_relaxed(io_data->io.base + offset);
+	} else if (!strcmp(catalog->exe_mode, "sw")) {
+		if (io_data->buf)
+			memcpy(&data, io_data->buf + offset, sizeof(offset));
+	}
+
+	return data;
+}
+
+static void dp_write(struct dp_catalog_private *catalog,
+		struct dp_io_data *io_data, u32 offset, u32 data)
+{
+	if (!strcmp(catalog->exe_mode, "hw") ||
+	    !strcmp(catalog->exe_mode, "all"))
+		writel_relaxed(data, io_data->io.base + offset);
+
+	if (!strcmp(catalog->exe_mode, "sw") ||
+	    !strcmp(catalog->exe_mode, "all")) {
+		if (io_data->buf)
+			memcpy(io_data->buf + offset, &data, sizeof(data));
+	}
+}
+
 /* aux related catalog functions */
 static u32 dp_catalog_aux_read_data(struct dp_catalog_aux *aux)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	return dp_read(base + DP_AUX_DATA);
+	return dp_read(catalog, io_data, DP_AUX_DATA);
 end:
 	return 0;
 }
@@ -95,7 +147,7 @@
 {
 	int rc = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
@@ -103,10 +155,10 @@
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	dp_write(base + DP_AUX_DATA, aux->data);
+	dp_write(catalog, io_data, DP_AUX_DATA, aux->data);
 end:
 	return rc;
 }
@@ -115,7 +167,7 @@
 {
 	int rc = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
@@ -123,10 +175,10 @@
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	dp_write(base + DP_AUX_TRANS_CTRL, aux->data);
+	dp_write(catalog, io_data, DP_AUX_TRANS_CTRL, aux->data);
 end:
 	return rc;
 }
@@ -136,7 +188,7 @@
 	int rc = 0;
 	u32 data = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
@@ -144,15 +196,15 @@
 		goto end;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
 	if (read) {
-		data = dp_read(base + DP_AUX_TRANS_CTRL);
+		data = dp_read(catalog, io_data, DP_AUX_TRANS_CTRL);
 		data &= ~BIT(9);
-		dp_write(base + DP_AUX_TRANS_CTRL, data);
+		dp_write(catalog, io_data, DP_AUX_TRANS_CTRL, data);
 	} else {
-		dp_write(base + DP_AUX_TRANS_CTRL, 0);
+		dp_write(catalog, io_data, DP_AUX_TRANS_CTRL, 0);
 	}
 end:
 	return rc;
@@ -161,7 +213,7 @@
 static void dp_catalog_aux_clear_hw_interrupts(struct dp_catalog_aux *aux)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *phy_base;
+	struct dp_io_data *io_data;
 	u32 data = 0;
 
 	if (!aux) {
@@ -169,17 +221,16 @@
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	phy_base = catalog->io->phy_io.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_phy;
 
-	data = dp_read(phy_base + DP_PHY_AUX_INTERRUPT_STATUS);
-	pr_debug("PHY_AUX_INTERRUPT_STATUS=0x%08x\n", data);
+	data = dp_read(catalog, io_data, DP_PHY_AUX_INTERRUPT_STATUS);
 
-	dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
 	wmb(); /* make sure 0x1f is written before next write */
-	dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f);
 	wmb(); /* make sure 0x9f is written before next write */
-	dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_CLEAR, 0);
 	wmb(); /* make sure register is cleared */
 }
 
@@ -187,24 +238,25 @@
 {
 	u32 aux_ctrl;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	aux_ctrl = dp_read(base + DP_AUX_CTRL);
+	aux_ctrl = dp_read(catalog, io_data, DP_AUX_CTRL);
 
 	aux_ctrl |= BIT(1);
-	dp_write(base + DP_AUX_CTRL, aux_ctrl);
+	dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 	usleep_range(1000, 1010); /* h/w recommended delay */
 
 	aux_ctrl &= ~BIT(1);
-	dp_write(base + DP_AUX_CTRL, aux_ctrl);
+
+	dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 	wmb(); /* make sure AUX reset is done here */
 }
 
@@ -212,27 +264,27 @@
 {
 	u32 aux_ctrl;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
-
+	struct dp_io_data *io_data;
 	if (!aux) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_aux;
 
-	aux_ctrl = dp_read(base + DP_AUX_CTRL);
+	aux_ctrl = dp_read(catalog, io_data, DP_AUX_CTRL);
 
 	if (enable) {
 		aux_ctrl |= BIT(0);
-		dp_write(base + DP_AUX_CTRL, aux_ctrl);
+		dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 		wmb(); /* make sure AUX module is enabled */
-		dp_write(base + DP_TIMEOUT_COUNT, 0xffff);
-		dp_write(base + DP_AUX_LIMITS, 0xffff);
+
+		dp_write(catalog, io_data, DP_TIMEOUT_COUNT, 0xffff);
+		dp_write(catalog, io_data, DP_AUX_LIMITS, 0xffff);
 	} else {
 		aux_ctrl &= ~BIT(0);
-		dp_write(base + DP_AUX_CTRL, aux_ctrl);
+		dp_write(catalog, io_data, DP_AUX_CTRL, aux_ctrl);
 	}
 }
 
@@ -241,13 +293,16 @@
 {
 	struct dp_catalog_private *catalog;
 	u32 new_index = 0, current_index = 0;
+	struct dp_io_data *io_data;
 
 	if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
+	catalog = dp_catalog_get_priv(aux);
+
+	io_data = catalog->io.dp_phy;
 
 	current_index = cfg[type].current_index;
 	new_index = (current_index + 1) % cfg[type].cfg_cnt;
@@ -255,8 +310,7 @@
 		dp_phy_aux_config_type_to_string(type),
 	cfg[type].lut[current_index], cfg[type].lut[new_index]);
 
-	dp_write(catalog->io->phy_io.base + cfg[type].offset,
-			cfg[type].lut[new_index]);
+	dp_write(catalog, io_data, cfg[type].offset, cfg[type].lut[new_index]);
 	cfg[type].current_index = new_index;
 }
 
@@ -264,6 +318,7 @@
 		struct dp_aux_cfg *cfg)
 {
 	struct dp_catalog_private *catalog;
+	struct dp_io_data *io_data;
 	int i = 0;
 
 	if (!aux || !cfg) {
@@ -271,25 +326,32 @@
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
+	catalog = dp_catalog_get_priv(aux);
 
-	dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x65);
+	io_data = catalog->io.dp_phy;
+	dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x65);
 	wmb(); /* make sure PD programming happened */
 
 	/* Turn on BIAS current for PHY/PLL */
-	dp_write(catalog->io->dp_pll_io.base +
-		QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b);
+	io_data = catalog->io.dp_pll;
+	dp_write(catalog, io_data, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b);
+
+	io_data = catalog->io.dp_phy;
+	dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x02);
+	wmb(); /* make sure PD programming happened */
+	dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x7d);
+
+	/* Turn on BIAS current for PHY/PLL */
+	io_data = catalog->io.dp_pll;
+	dp_write(catalog, io_data, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f);
 
 	/* DP AUX CFG register programming */
-	for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
-		pr_debug("%s: offset=0x%08x, value=0x%08x\n",
-			dp_phy_aux_config_type_to_string(i),
-			cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
-		dp_write(catalog->io->phy_io.base + cfg[i].offset,
-			cfg[i].lut[cfg[i].current_index]);
-	}
+	io_data = catalog->io.dp_phy;
+	for (i = 0; i < PHY_AUX_CFG_MAX; i++)
+		dp_write(catalog, io_data, cfg[i].offset,
+				cfg[i].lut[cfg[i].current_index]);
 
-	dp_write(catalog->io->phy_io.base + DP_PHY_AUX_INTERRUPT_MASK, 0x1F);
+	dp_write(catalog, io_data, DP_PHY_AUX_INTERRUPT_MASK, 0x1F);
 	wmb(); /* make sure AUX configuration is done before enabling it */
 }
 
@@ -297,46 +359,46 @@
 {
 	u32 ack;
 	struct dp_catalog_private *catalog;
-	void __iomem *ahb_base;
+	struct dp_io_data *io_data;
 
 	if (!aux) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(aux);
-	ahb_base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(aux);
+	io_data = catalog->io.dp_ahb;
 
-	aux->isr = dp_read(ahb_base + DP_INTR_STATUS);
+	aux->isr = dp_read(catalog, io_data, DP_INTR_STATUS);
 	aux->isr &= ~DP_INTR_MASK1;
 	ack = aux->isr & DP_INTERRUPT_STATUS1;
 	ack <<= 1;
 	ack |= DP_INTR_MASK1;
-	dp_write(ahb_base + DP_INTR_STATUS, ack);
+	dp_write(catalog, io_data, DP_INTR_STATUS, ack);
 }
 
 /* controller related catalog functions */
 static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return -EINVAL;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	return dp_read(base + DP_HDCP_STATUS);
+	return dp_read(catalog, io_data, DP_HDCP_STATUS);
 }
 
 static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
 	struct drm_msm_ext_hdr_metadata *hdr;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 header, parity, data;
 	u8 buf[SZ_128], off = 0;
 
@@ -345,16 +407,16 @@
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
+	catalog = dp_catalog_get_priv(panel);
 	hdr = &panel->hdr_data.hdr_meta;
-	base = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 
 	/* HEADER BYTE 1 */
 	header = panel->hdr_data.vscext_header_byte1;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_1_BIT)
 			| (parity << PARITY_BYTE_1_BIT));
-	dp_write(base + MMSS_DP_VSCEXT_0, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_0, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -363,22 +425,22 @@
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_2_BIT)
 			| (parity << PARITY_BYTE_2_BIT));
-	dp_write(base + MMSS_DP_VSCEXT_1, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_1, data);
 
 	/* HEADER BYTE 3 */
 	header = panel->hdr_data.vscext_header_byte3;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_3_BIT)
 			| (parity << PARITY_BYTE_3_BIT));
-	data |= dp_read(base + MMSS_DP_VSCEXT_1);
-	dp_write(base + MMSS_DP_VSCEXT_1, data);
+	data |= dp_read(catalog, io_data, MMSS_DP_VSCEXT_1);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_1, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = panel->hdr_data.version;
 	data |= panel->hdr_data.length << 8;
 	data |= hdr->eotf << 16;
-	dp_write(base + MMSS_DP_VSCEXT_2, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_2, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -386,7 +448,7 @@
 		(DP_GET_MSB(hdr->display_primaries_x[0]) << 8) |
 		(DP_GET_LSB(hdr->display_primaries_y[0]) << 16) |
 		(DP_GET_MSB(hdr->display_primaries_y[0]) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_3, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_3, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -394,7 +456,7 @@
 		(DP_GET_MSB(hdr->display_primaries_x[1]) << 8) |
 		(DP_GET_LSB(hdr->display_primaries_y[1]) << 16) |
 		(DP_GET_MSB(hdr->display_primaries_y[1]) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_4, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_4, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -402,7 +464,7 @@
 		(DP_GET_MSB(hdr->display_primaries_x[2]) << 8) |
 		(DP_GET_LSB(hdr->display_primaries_y[2]) << 16) |
 		(DP_GET_MSB(hdr->display_primaries_y[2]) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_5, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_5, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -410,7 +472,7 @@
 		(DP_GET_MSB(hdr->white_point_x) << 8) |
 		(DP_GET_LSB(hdr->white_point_y) << 16) |
 		(DP_GET_MSB(hdr->white_point_y) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_6, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_6, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -418,7 +480,7 @@
 		(DP_GET_MSB(hdr->max_luminance) << 8) |
 		(DP_GET_LSB(hdr->min_luminance) << 16) |
 		(DP_GET_MSB(hdr->min_luminance) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_7, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_7, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -426,12 +488,12 @@
 		(DP_GET_MSB(hdr->max_content_light_level) << 8) |
 		(DP_GET_LSB(hdr->max_average_light_level) << 16) |
 		(DP_GET_MSB(hdr->max_average_light_level) << 24));
-	dp_write(base + MMSS_DP_VSCEXT_8, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_8, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = 0;
-	dp_write(base + MMSS_DP_VSCEXT_9, data);
+	dp_write(catalog, io_data, MMSS_DP_VSCEXT_9, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -442,7 +504,7 @@
 static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 header, parity, data;
 	u8 bpc, off = 0;
 	u8 buf[SZ_128];
@@ -452,15 +514,15 @@
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
 	/* HEADER BYTE 1 */
 	header = panel->hdr_data.vsc_header_byte1;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_1_BIT)
 			| (parity << PARITY_BYTE_1_BIT));
-	dp_write(base + MMSS_DP_GENERIC0_0, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_0, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -469,32 +531,32 @@
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_2_BIT)
 			| (parity << PARITY_BYTE_2_BIT));
-	dp_write(base + MMSS_DP_GENERIC0_1, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_1, data);
 
 	/* HEADER BYTE 3 */
 	header = panel->hdr_data.vsc_header_byte3;
 	parity = dp_header_get_parity(header);
 	data   = ((header << HEADER_BYTE_3_BIT)
 			| (parity << PARITY_BYTE_3_BIT));
-	data |= dp_read(base + MMSS_DP_GENERIC0_1);
-	dp_write(base + MMSS_DP_GENERIC0_1, data);
+	data |= dp_read(catalog, io_data, MMSS_DP_GENERIC0_1);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_1, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = 0;
-	dp_write(base + MMSS_DP_GENERIC0_2, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_2, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_3, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_3, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_4, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_4, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_5, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_5, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -517,20 +579,20 @@
 		((panel->hdr_data.dynamic_range & 0x1) << 15) |
 		((panel->hdr_data.content_type & 0x7) << 16);
 
-	dp_write(base + MMSS_DP_GENERIC0_6, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_6, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
 	data = 0;
-	dp_write(base + MMSS_DP_GENERIC0_7, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_7, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_8, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_8, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
-	dp_write(base + MMSS_DP_GENERIC0_9, data);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC0_9, data);
 	memcpy(buf + off, &data, sizeof(data));
 	off += sizeof(data);
 
@@ -541,7 +603,7 @@
 static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 cfg, cfg2, misc;
 
 	if (!panel) {
@@ -549,21 +611,21 @@
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
-	cfg = dp_read(base + MMSS_DP_SDP_CFG);
-	cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
-	misc = dp_read(base + DP_MISC1_MISC0);
+	cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG);
+	cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2);
+	misc = dp_read(catalog, io_data, DP_MISC1_MISC0);
 
 	if (en) {
 		/* VSCEXT_SDP_EN, GEN0_SDP_EN */
 		cfg |= BIT(16) | BIT(17);
-		dp_write(base + MMSS_DP_SDP_CFG, cfg);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG, cfg);
 
 		/* EXTN_SDPSIZE GENERIC0_SDPSIZE */
 		cfg2 |= BIT(15) | BIT(16);
-		dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, cfg2);
 
 		dp_catalog_panel_setup_vsc_sdp(panel);
 		dp_catalog_panel_setup_infoframe_sdp(panel);
@@ -578,11 +640,11 @@
 	} else {
 		/* VSCEXT_SDP_EN, GEN0_SDP_EN */
 		cfg &= ~BIT(16) & ~BIT(17);
-		dp_write(base + MMSS_DP_SDP_CFG, cfg);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG, cfg);
 
 		/* EXTN_SDPSIZE GENERIC0_SDPSIZE */
 		cfg2 &= ~BIT(15) & ~BIT(16);
-		dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
+		dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, cfg2);
 
 		/* switch back to MSA */
 		misc &= ~BIT(14);
@@ -590,78 +652,78 @@
 		pr_debug("Disabled\n");
 	}
 
-	dp_write(base + DP_MISC1_MISC0, misc);
+	dp_write(catalog, io_data, DP_MISC1_MISC0, misc);
 
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x01);
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x00);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x01);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x00);
 }
 
 static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_VALID_BOUNDARY, ctrl->valid_boundary);
-	dp_write(base + DP_TU, ctrl->dp_tu);
-	dp_write(base + DP_VALID_BOUNDARY_2, ctrl->valid_boundary2);
+	dp_write(catalog, io_data, DP_VALID_BOUNDARY, ctrl->valid_boundary);
+	dp_write(catalog, io_data, DP_TU, ctrl->dp_tu);
+	dp_write(catalog, io_data, DP_VALID_BOUNDARY_2, ctrl->valid_boundary2);
 }
 
 static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_STATE_CTRL, state);
+	dp_write(catalog, io_data, DP_STATE_CTRL, state);
 }
 
 static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u32 cfg)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *link_base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	link_base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	pr_debug("DP_CONFIGURATION_CTRL=0x%x\n", cfg);
 
-	dp_write(link_base + DP_CONFIGURATION_CTRL, cfg);
+	dp_write(catalog, io_data, DP_CONFIGURATION_CTRL, cfg);
 }
 
 static void dp_catalog_ctrl_lane_mapping(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_LOGICAL2PHYSICAL_LANE_MAPPING, 0xe4);
+	dp_write(catalog, io_data, DP_LOGICAL2PHYSICAL_LANE_MAPPING, 0xe4);
 }
 
 static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl,
@@ -669,29 +731,29 @@
 {
 	u32 mainlink_ctrl;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	if (enable) {
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000000);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000000);
 		wmb(); /* make sure mainlink is turned off before reset */
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000002);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000002);
 		wmb(); /* make sure mainlink entered reset */
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000000);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000000);
 		wmb(); /* make sure mainlink reset done */
-		dp_write(base + DP_MAINLINK_CTRL, 0x02000001);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x02000001);
 		wmb(); /* make sure mainlink turned on */
 	} else {
-		mainlink_ctrl = dp_read(base + DP_MAINLINK_CTRL);
+		mainlink_ctrl = dp_read(catalog, io_data, DP_MAINLINK_CTRL);
 		mainlink_ctrl &= ~BIT(0);
-		dp_write(base + DP_MAINLINK_CTRL, mainlink_ctrl);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, mainlink_ctrl);
 	}
 }
 
@@ -700,21 +762,23 @@
 {
 	u32 misc_val = cc;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
+	misc_val = dp_read(catalog, io_data, DP_MISC1_MISC0);
+	misc_val |= cc;
 	misc_val |= (tb << 5);
 	misc_val |= BIT(0); /* Configure clock to synchronous mode */
 
 	pr_debug("misc settings = 0x%x\n", misc_val);
-	dp_write(base + DP_MISC1_MISC0, misc_val);
+	dp_write(catalog, io_data, DP_MISC1_MISC0, misc_val);
 }
 
 static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl,
@@ -728,14 +792,14 @@
 	u32 const link_rate_hbr2 = 540000;
 	u32 const link_rate_hbr3 = 810000;
 	struct dp_catalog_private *catalog;
-	void __iomem *base_cc, *base_ctrl;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 	if (fixed_nvid) {
 		pr_debug("use fixed NVID=0x%x\n", nvid_fixed);
 		nvid = nvid_fixed;
@@ -756,10 +820,10 @@
 		 */
 		mvid = (u32) mvid_calc;
 	} else {
-		base_cc = catalog->io->dp_cc_io.base;
+		io_data = catalog->io.dp_mmss_cc;
 
-		pixel_m = dp_read(base_cc + MMSS_DP_PIXEL_M);
-		pixel_n = dp_read(base_cc + MMSS_DP_PIXEL_N);
+		pixel_m = dp_read(catalog, io_data, MMSS_DP_PIXEL_M);
+		pixel_n = dp_read(catalog, io_data, MMSS_DP_PIXEL_N);
 		pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
 
 		mvid = (pixel_m & 0xFFFF) * 5;
@@ -774,10 +838,10 @@
 			nvid *= 3;
 	}
 
-	base_ctrl = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 	pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
-	dp_write(base_ctrl + DP_SOFTWARE_MVID, mvid);
-	dp_write(base_ctrl + DP_SOFTWARE_NVID, nvid);
+	dp_write(catalog, io_data, DP_SOFTWARE_MVID, mvid);
+	dp_write(catalog, io_data, DP_SOFTWARE_NVID, nvid);
 }
 
 static void dp_catalog_ctrl_set_pattern(struct dp_catalog_ctrl *ctrl,
@@ -786,26 +850,26 @@
 	int bit, cnt = 10;
 	u32 data;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	bit = 1;
 	bit <<= (pattern - 1);
 	pr_debug("hw: bit=%d train=%d\n", bit, pattern);
-	dp_write(base + DP_STATE_CTRL, bit);
+	dp_write(catalog, io_data, DP_STATE_CTRL, bit);
 
 	bit = 8;
 	bit <<= (pattern - 1);
 
 	while (cnt--) {
-		data = dp_read(base + DP_MAINLINK_READY);
+		data = dp_read(catalog, io_data, DP_MAINLINK_READY);
 		if (data & bit)
 			break;
 	}
@@ -817,35 +881,35 @@
 static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 
-	base = catalog->io->usb3_dp_com.base;
+	io_data = catalog->io.usb3_dp_com;
 
-	dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x0a);
-	dp_write(base + USB3_DP_COM_PHY_MODE_CTRL, 0x02);
-	dp_write(base + USB3_DP_COM_SW_RESET, 0x01);
+	dp_write(catalog, io_data, USB3_DP_COM_RESET_OVRD_CTRL, 0x0a);
+	dp_write(catalog, io_data, USB3_DP_COM_PHY_MODE_CTRL, 0x02);
+	dp_write(catalog, io_data, USB3_DP_COM_SW_RESET, 0x01);
 	/* make sure usb3 com phy software reset is done */
 	wmb();
 
 	if (!flip) /* CC1 */
-		dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x02);
+		dp_write(catalog, io_data, USB3_DP_COM_TYPEC_CTRL, 0x02);
 	else /* CC2 */
-		dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x03);
+		dp_write(catalog, io_data, USB3_DP_COM_TYPEC_CTRL, 0x03);
 
-	dp_write(base + USB3_DP_COM_SWI_CTRL, 0x00);
-	dp_write(base + USB3_DP_COM_SW_RESET, 0x00);
+	dp_write(catalog, io_data, USB3_DP_COM_SWI_CTRL, 0x00);
+	dp_write(catalog, io_data, USB3_DP_COM_SW_RESET, 0x00);
 	/* make sure the software reset is done */
 	wmb();
 
-	dp_write(base + USB3_DP_COM_POWER_DOWN_CTRL, 0x01);
-	dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
+	dp_write(catalog, io_data, USB3_DP_COM_POWER_DOWN_CTRL, 0x01);
+	dp_write(catalog, io_data, USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
 	/* make sure phy is brought out of reset */
 	wmb();
 }
@@ -854,50 +918,53 @@
 	bool enable)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!panel) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_p0.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_p0;
 
 	if (!enable) {
-		dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x0);
-		dp_write(base + MMSS_DP_BIST_ENABLE, 0x0);
-		dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x0);
+		dp_write(catalog, io_data, MMSS_DP_TPG_MAIN_CONTROL, 0x0);
+		dp_write(catalog, io_data, MMSS_DP_BIST_ENABLE, 0x0);
+		dp_write(catalog, io_data, MMSS_DP_TIMING_ENGINE_EN, 0x0);
 		wmb(); /* ensure Timing generator is turned off */
 		return;
 	}
 
-	dp_write(base + MMSS_DP_INTF_CONFIG, 0x0);
-	dp_write(base + MMSS_DP_INTF_HSYNC_CTL, panel->hsync_ctl);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F0, panel->vsync_period *
-			panel->hsync_period);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, panel->v_sync_width *
-			panel->hsync_period);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F1, 0);
-	dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0);
-	dp_write(base + MMSS_DP_INTF_DISPLAY_HCTL, panel->display_hctl);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_HCTL, 0);
-	dp_write(base + MMSS_INTF_DISPLAY_V_START_F0, panel->display_v_start);
-	dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F0, panel->display_v_end);
-	dp_write(base + MMSS_INTF_DISPLAY_V_START_F1, 0);
-	dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F1, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F0, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F0, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F1, 0);
-	dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F1, 0);
-	dp_write(base + MMSS_DP_INTF_POLARITY_CTL, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_CONFIG, 0x0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_HSYNC_CTL, panel->hsync_ctl);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PERIOD_F0,
+			panel->vsync_period * panel->hsync_period);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0,
+			panel->v_sync_width * panel->hsync_period);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_DISPLAY_HCTL,
+			panel->display_hctl);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_HCTL, 0);
+	dp_write(catalog, io_data, MMSS_INTF_DISPLAY_V_START_F0,
+			panel->display_v_start);
+	dp_write(catalog, io_data, MMSS_DP_INTF_DISPLAY_V_END_F0,
+			panel->display_v_end);
+	dp_write(catalog, io_data, MMSS_INTF_DISPLAY_V_START_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_DISPLAY_V_END_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_START_F0, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_END_F0, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_START_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_ACTIVE_V_END_F1, 0);
+	dp_write(catalog, io_data, MMSS_DP_INTF_POLARITY_CTL, 0);
 	wmb(); /* ensure TPG registers are programmed */
 
-	dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x100);
-	dp_write(base + MMSS_DP_TPG_VIDEO_CONFIG, 0x5);
+	dp_write(catalog, io_data, MMSS_DP_TPG_MAIN_CONTROL, 0x100);
+	dp_write(catalog, io_data, MMSS_DP_TPG_VIDEO_CONFIG, 0x5);
 	wmb(); /* ensure TPG config is programmed */
-	dp_write(base + MMSS_DP_BIST_ENABLE, 0x1);
-	dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x1);
+	dp_write(catalog, io_data, MMSS_DP_BIST_ENABLE, 0x1);
+	dp_write(catalog, io_data, MMSS_DP_TIMING_ENGINE_EN, 0x1);
 	wmb(); /* ensure Timing generator is turned on */
 }
 
@@ -905,24 +972,24 @@
 {
 	u32 sw_reset;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	sw_reset = dp_read(base + DP_SW_RESET);
+	sw_reset = dp_read(catalog, io_data, DP_SW_RESET);
 
 	sw_reset |= BIT(0);
-	dp_write(base + DP_SW_RESET, sw_reset);
+	dp_write(catalog, io_data, DP_SW_RESET, sw_reset);
 	usleep_range(1000, 1010); /* h/w recommended delay */
 
 	sw_reset &= ~BIT(0);
-	dp_write(base + DP_SW_RESET, sw_reset);
+	dp_write(catalog, io_data, DP_SW_RESET, sw_reset);
 }
 
 static bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog_ctrl *ctrl)
@@ -930,19 +997,19 @@
 	u32 data;
 	int cnt = 10;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		goto end;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_link;
 
 	while (--cnt) {
 		/* DP_MAINLINK_READY */
-		data = dp_read(base + DP_MAINLINK_READY);
+		data = dp_read(catalog, io_data, DP_MAINLINK_READY);
 		if (data & BIT(0))
 			return true;
 
@@ -957,52 +1024,51 @@
 						bool enable)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
 	if (enable) {
-		dp_write(base + DP_INTR_STATUS, DP_INTR_MASK1);
-		dp_write(base + DP_INTR_STATUS2, DP_INTR_MASK2);
+		dp_write(catalog, io_data, DP_INTR_STATUS, DP_INTR_MASK1);
+		dp_write(catalog, io_data, DP_INTR_STATUS2, DP_INTR_MASK2);
 	} else {
-		dp_write(base + DP_INTR_STATUS, 0x00);
-		dp_write(base + DP_INTR_STATUS2, 0x00);
+		dp_write(catalog, io_data, DP_INTR_STATUS, 0x00);
+		dp_write(catalog, io_data, DP_INTR_STATUS2, 0x00);
 	}
 }
 
 static void dp_catalog_ctrl_hpd_config(struct dp_catalog_ctrl *ctrl, bool en)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_aux.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_aux;
 
 	if (en) {
-		u32 reftimer = dp_read(base + DP_DP_HPD_REFTIMER);
+		u32 reftimer = dp_read(catalog, io_data, DP_DP_HPD_REFTIMER);
 
-		dp_write(base + DP_DP_HPD_INT_ACK, 0xF);
-		dp_write(base + DP_DP_HPD_INT_MASK, 0xF);
-
+		dp_write(catalog, io_data, DP_DP_HPD_INT_ACK, 0xF);
+		dp_write(catalog, io_data, DP_DP_HPD_INT_MASK, 0xF);
 		/* Enabling REFTIMER */
 		reftimer |= BIT(16);
-		dp_write(base + DP_DP_HPD_REFTIMER, 0xF);
+		dp_write(catalog, io_data, DP_DP_HPD_REFTIMER, 0xF);
 		/* Enable HPD */
-		dp_write(base + DP_DP_HPD_CTRL, 0x1);
+		dp_write(catalog, io_data, DP_DP_HPD_CTRL, 0x1);
 	} else {
 		/*Disable HPD */
-		dp_write(base + DP_DP_HPD_CTRL, 0x0);
+		dp_write(catalog, io_data, DP_DP_HPD_CTRL, 0x0);
 	}
 }
 
@@ -1010,40 +1076,40 @@
 {
 	u32 ack = 0;
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	ctrl->isr = dp_read(base + DP_INTR_STATUS2);
+	ctrl->isr = dp_read(catalog, io_data, DP_INTR_STATUS2);
 	ctrl->isr &= ~DP_INTR_MASK2;
 	ack = ctrl->isr & DP_INTERRUPT_STATUS2;
 	ack <<= 1;
 	ack |= DP_INTR_MASK2;
-	dp_write(base + DP_INTR_STATUS2, ack);
+	dp_write(catalog, io_data, DP_INTR_STATUS2, ack);
 }
 
 static void dp_catalog_ctrl_phy_reset(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base = catalog->io->dp_ahb.base;
+	catalog = dp_catalog_get_priv(ctrl);
+	io_data = catalog->io.dp_ahb;
 
-	dp_write(base + DP_PHY_CTRL, 0x5); /* bit 0 & 2 */
+	dp_write(catalog, io_data, DP_PHY_CTRL, 0x5); /* bit 0 & 2 */
 	usleep_range(1000, 1010); /* h/w recommended delay */
-	dp_write(base + DP_PHY_CTRL, 0x0);
+	dp_write(catalog, io_data, DP_PHY_CTRL, 0x0);
 	wmb(); /* make sure PHY reset done */
 }
 
@@ -1052,6 +1118,7 @@
 {
 	u32 info = 0x0;
 	struct dp_catalog_private *catalog;
+	struct dp_io_data *io_data;
 	u8 orientation = BIT(!!flipped);
 
 	if (!ctrl) {
@@ -1059,20 +1126,22 @@
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
+
+	io_data = catalog->io.dp_phy;
 
 	info |= (ln_cnt & 0x0F);
 	info |= ((orientation & 0x0F) << 4);
 	pr_debug("Shared Info = 0x%x\n", info);
 
-	dp_write(catalog->io->phy_io.base + DP_PHY_SPARE0, info);
+	dp_write(catalog, io_data, DP_PHY_SPARE0, info);
 }
 
 static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
 		u8 v_level, u8 p_level)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base0, *base1;
+	struct dp_io_data *io_data;
 	u8 value0, value1;
 
 	if (!ctrl) {
@@ -1080,9 +1149,7 @@
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
-	base0 = catalog->io->ln_tx0_io.base;
-	base1 = catalog->io->ln_tx1_io.base;
+	catalog = dp_catalog_get_priv(ctrl);
 
 	pr_debug("hw: v=%d p=%d\n", v_level, p_level);
 
@@ -1090,10 +1157,14 @@
 	value1 = vm_pre_emphasis[v_level][p_level];
 
 	/* program default setting first */
-	dp_write(base0 + TXn_TX_DRV_LVL, 0x2A);
-	dp_write(base1 + TXn_TX_DRV_LVL, 0x2A);
-	dp_write(base0 + TXn_TX_EMP_POST1_LVL, 0x20);
-	dp_write(base1 + TXn_TX_EMP_POST1_LVL, 0x20);
+
+	io_data = catalog->io.dp_ln_tx0;
+	dp_write(catalog, io_data, TXn_TX_DRV_LVL, 0x2A);
+	dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, 0x20);
+
+	io_data = catalog->io.dp_ln_tx1;
+	dp_write(catalog, io_data, TXn_TX_DRV_LVL, 0x2A);
+	dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, 0x20);
 
 	/* Enable MUX to use Cursor values from these registers */
 	value0 |= BIT(5);
@@ -1101,10 +1172,13 @@
 
 	/* Configure host and panel only if both values are allowed */
 	if (value0 != 0xFF && value1 != 0xFF) {
-		dp_write(base0 + TXn_TX_DRV_LVL, value0);
-		dp_write(base1 + TXn_TX_DRV_LVL, value0);
-		dp_write(base0 + TXn_TX_EMP_POST1_LVL, value1);
-		dp_write(base1 + TXn_TX_EMP_POST1_LVL, value1);
+		io_data = catalog->io.dp_ln_tx0;
+		dp_write(catalog, io_data, TXn_TX_DRV_LVL, value0);
+		dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, value1);
+
+		io_data = catalog->io.dp_ln_tx1;
+		dp_write(catalog, io_data, TXn_TX_DRV_LVL, value0);
+		dp_write(catalog, io_data, TXn_TX_EMP_POST1_LVL, value1);
 
 		pr_debug("hw: vx_value=0x%x px_value=0x%x\n",
 			value0, value1);
@@ -1119,54 +1193,61 @@
 {
 	struct dp_catalog_private *catalog;
 	u32 value = 0x0;
-	void __iomem *base = NULL;
+	struct dp_io_data *io_data = NULL;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 
-	base = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_STATE_CTRL, 0x0);
+	dp_write(catalog, io_data, DP_STATE_CTRL, 0x0);
 
 	switch (pattern) {
 	case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
-		dp_write(base + DP_STATE_CTRL, 0x1);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x1);
 		break;
 	case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
 		value &= ~(1 << 16);
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
 		value |= 0xFC;
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
-		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
-		dp_write(base + DP_STATE_CTRL, 0x10);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
+		dp_write(catalog, io_data, DP_MAINLINK_LEVELS, 0x2);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x10);
 		break;
 	case DP_TEST_PHY_PATTERN_PRBS7:
-		dp_write(base + DP_STATE_CTRL, 0x20);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x20);
 		break;
 	case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
-		dp_write(base + DP_STATE_CTRL, 0x40);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x40);
 		/* 00111110000011111000001111100000 */
-		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0);
+		dp_write(catalog, io_data, DP_TEST_80BIT_CUSTOM_PATTERN_REG0,
+			0x3E0F83E0);
 		/* 00001111100000111110000011111000 */
-		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8);
+		dp_write(catalog, io_data, DP_TEST_80BIT_CUSTOM_PATTERN_REG1,
+			0x0F83E0F8);
 		/* 1111100000111110 */
-		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E);
+		dp_write(catalog, io_data, DP_TEST_80BIT_CUSTOM_PATTERN_REG2,
+			0x0000F83E);
 		break;
 	case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1:
 		value = BIT(16);
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
 		value |= 0xFC;
-		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
-		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
-		dp_write(base + DP_STATE_CTRL, 0x10);
+		dp_write(catalog, io_data, DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
+			value);
+		dp_write(catalog, io_data, DP_MAINLINK_LEVELS, 0x2);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x10);
 		break;
 	case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3:
-		dp_write(base + DP_MAINLINK_CTRL, 0x11);
-		dp_write(base + DP_STATE_CTRL, 0x8);
+		dp_write(catalog, io_data, DP_MAINLINK_CTRL, 0x11);
+		dp_write(catalog, io_data, DP_STATE_CTRL, 0x8);
 		break;
 	default:
 		pr_debug("No valid test pattern requested: 0x%x\n", pattern);
@@ -1180,38 +1261,101 @@
 static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base = NULL;
+	struct dp_io_data *io_data = NULL;
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
 		return 0;
 	}
 
-	dp_catalog_get_priv(ctrl);
+	catalog = dp_catalog_get_priv(ctrl);
 
-	base = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 
-	return dp_read(base + DP_MAINLINK_READY);
+	return dp_read(catalog, io_data, DP_MAINLINK_READY);
+}
+
+static int dp_catalog_reg_dump(struct dp_catalog *dp_catalog,
+		char *name, u8 **out_buf, u32 *out_buf_len)
+{
+	int ret = 0;
+	u8 *buf;
+	u32 len;
+	struct dp_io_data *io_data;
+	struct dp_catalog_private *catalog;
+	struct dp_parser *parser;
+
+	if (!dp_catalog) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	catalog = container_of(dp_catalog, struct dp_catalog_private,
+		dp_catalog);
+
+	parser = catalog->parser;
+	parser->get_io_buf(parser, name);
+	io_data = parser->get_io(parser, name);
+	if (!io_data) {
+		pr_err("IO %s not found\n", name);
+		ret = -EINVAL;
+		goto end;
+	}
+
+	buf = io_data->buf;
+	len = io_data->io.len;
+
+	if (!buf || !len) {
+		pr_err("no buffer available\n");
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	if (!strcmp(catalog->exe_mode, "hw") ||
+	    !strcmp(catalog->exe_mode, "all")) {
+		u32 i, data;
+		u32 const rowsize = 4;
+		void __iomem *addr = io_data->io.base;
+
+		memset(buf, 0, len);
+
+		for (i = 0; i < len / rowsize; i++) {
+			data = readl_relaxed(addr);
+			memcpy(buf + (rowsize * i), &data, sizeof(u32));
+
+			addr += rowsize;
+		}
+	}
+
+	*out_buf = buf;
+	*out_buf_len = len;
+end:
+	if (ret)
+		parser->clear_io_buf(parser);
+
+	return ret;
 }
 
 /* panel related catalog functions */
 static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 
 	if (!panel) {
 		pr_err("invalid input\n");
 		goto end;
 	}
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
-	dp_write(base + DP_TOTAL_HOR_VER, panel->total);
-	dp_write(base + DP_START_HOR_VER_FROM_SYNC, panel->sync_start);
-	dp_write(base + DP_HSYNC_VSYNC_WIDTH_POLARITY, panel->width_blanking);
-	dp_write(base + DP_ACTIVE_HOR_VER, panel->dp_active);
+	dp_write(catalog, io_data, DP_TOTAL_HOR_VER, panel->total);
+	dp_write(catalog, io_data, DP_START_HOR_VER_FROM_SYNC,
+			panel->sync_start);
+	dp_write(catalog, io_data, DP_HSYNC_VSYNC_WIDTH_POLARITY,
+		panel->width_blanking);
+	dp_write(catalog, io_data, DP_ACTIVE_HOR_VER, panel->dp_active);
 end:
 	return 0;
 }
@@ -1250,7 +1394,7 @@
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
 	catalog->audio_map = sdp_map;
 }
@@ -1258,17 +1402,17 @@
 static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 sdp_cfg = 0;
 	u32 sdp_cfg2 = 0;
 
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(audio);
+	io_data = catalog->io.dp_link;
 
-	sdp_cfg = dp_read(base + MMSS_DP_SDP_CFG);
+	sdp_cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG);
 
 	/* AUDIO_TIMESTAMP_SDP_EN */
 	sdp_cfg |= BIT(1);
@@ -1282,44 +1426,44 @@
 	sdp_cfg |= BIT(20);
 
 	pr_debug("sdp_cfg = 0x%x\n", sdp_cfg);
-	dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG, sdp_cfg);
 
-	sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+	sdp_cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2);
 	/* IFRM_REGSRC -> Do not use reg values */
 	sdp_cfg2 &= ~BIT(0);
 	/* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
 	sdp_cfg2 &= ~BIT(1);
 
 	pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2);
-	dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, sdp_cfg2);
 }
 
 static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
 	u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	enum dp_catalog_audio_sdp_type sdp;
 	enum dp_catalog_audio_header_type header;
 
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base    = catalog->io->dp_link.base;
+	io_data    = catalog->io.dp_link;
 	sdp_map = catalog->audio_map;
 	sdp     = audio->sdp_type;
 	header  = audio->sdp_header;
 
-	audio->data = dp_read(base + sdp_map[sdp][header]);
+	audio->data = dp_read(catalog, io_data, sdp_map[sdp][header]);
 }
 
 static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
 	u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	enum dp_catalog_audio_sdp_type sdp;
 	enum dp_catalog_audio_header_type header;
 	u32 data;
@@ -1327,69 +1471,69 @@
 	if (!audio)
 		return;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base    = catalog->io->dp_link.base;
+	io_data    = catalog->io.dp_link;
 	sdp_map = catalog->audio_map;
 	sdp     = audio->sdp_type;
 	header  = audio->sdp_header;
 	data    = audio->data;
 
-	dp_write(base + sdp_map[sdp][header], data);
+	dp_write(catalog, io_data, sdp_map[sdp][header], data);
 }
 
 static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 acr_ctrl, select;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
 	select = audio->data;
-	base   = catalog->io->dp_link.base;
+	io_data   = catalog->io.dp_link;
 
 	acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14);
 
 	pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl);
 
-	dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
+	dp_write(catalog, io_data, MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
 }
 
 static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 mainlink_levels, safe_to_exit_level;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base   = catalog->io->dp_link.base;
+	io_data   = catalog->io.dp_link;
 	safe_to_exit_level = audio->data;
 
-	mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS);
+	mainlink_levels = dp_read(catalog, io_data, DP_MAINLINK_LEVELS);
 	mainlink_levels &= 0xFE0;
 	mainlink_levels |= safe_to_exit_level;
 
 	pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
 			mainlink_levels, safe_to_exit_level);
 
-	dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels);
+	dp_write(catalog, io_data, DP_MAINLINK_LEVELS, mainlink_levels);
 }
 
 static void dp_catalog_audio_enable(struct dp_catalog_audio *audio)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	bool enable;
 	u32 audio_ctrl;
 
-	dp_catalog_get_priv(audio);
+	catalog = dp_catalog_get_priv(audio);
 
-	base   = catalog->io->dp_link.base;
+	io_data = catalog->io.dp_link;
 	enable = !!audio->data;
 
-	audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG);
+	audio_ctrl = dp_read(catalog, io_data, MMSS_DP_AUDIO_CFG);
 
 	if (enable)
 		audio_ctrl |= BIT(0);
@@ -1397,7 +1541,7 @@
 		audio_ctrl &= ~BIT(0);
 
 	pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl);
-	dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl);
+	dp_write(catalog, io_data, MMSS_DP_AUDIO_CFG, audio_ctrl);
 
 	/* make sure audio engine is disabled */
 	wmb();
@@ -1406,18 +1550,18 @@
 static void dp_catalog_config_spd_header(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 value, new_value;
 	u8 parity_byte;
 
 	if (!panel)
 		return;
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
 	/* Config header and parity byte 1 */
-	value = dp_read(base + MMSS_DP_GENERIC1_0);
+	value = dp_read(catalog, io_data, MMSS_DP_GENERIC1_0);
 
 	new_value = 0x83;
 	parity_byte = dp_header_get_parity(new_value);
@@ -1425,10 +1569,10 @@
 			| (parity_byte << PARITY_BYTE_1_BIT));
 	pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
 			value, parity_byte);
-	dp_write(base + MMSS_DP_GENERIC1_0, value);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_0, value);
 
 	/* Config header and parity byte 2 */
-	value = dp_read(base + MMSS_DP_GENERIC1_1);
+	value = dp_read(catalog, io_data, MMSS_DP_GENERIC1_1);
 
 	new_value = 0x1b;
 	parity_byte = dp_header_get_parity(new_value);
@@ -1436,10 +1580,10 @@
 			| (parity_byte << PARITY_BYTE_2_BIT));
 	pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
 			value, parity_byte);
-	dp_write(base + MMSS_DP_GENERIC1_1, value);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_1, value);
 
 	/* Config header and parity byte 3 */
-	value = dp_read(base + MMSS_DP_GENERIC1_1);
+	value = dp_read(catalog, io_data, MMSS_DP_GENERIC1_1);
 
 	new_value = (0x0 | (0x12 << 2));
 	parity_byte = dp_header_get_parity(new_value);
@@ -1447,13 +1591,13 @@
 			| (parity_byte << PARITY_BYTE_3_BIT));
 	pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
 			new_value, parity_byte);
-	dp_write(base + MMSS_DP_GENERIC1_1, value);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_1, value);
 }
 
 static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel)
 {
 	struct dp_catalog_private *catalog;
-	void __iomem *base;
+	struct dp_io_data *io_data;
 	u32 spd_cfg = 0, spd_cfg2 = 0;
 	u8 *vendor = NULL, *product = NULL;
 	/*
@@ -1479,56 +1623,110 @@
 	if (!panel)
 		return;
 
-	dp_catalog_get_priv(panel);
-	base = catalog->io->dp_link.base;
+	catalog = dp_catalog_get_priv(panel);
+	io_data = catalog->io.dp_link;
 
 	dp_catalog_config_spd_header(panel);
 
 	vendor = panel->spd_vendor_name;
 	product = panel->spd_product_description;
 
-	dp_write(base + MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) |
 				((vendor[1] & 0x7f) << 8) |
 				((vendor[2] & 0x7f) << 16) |
 				((vendor[3] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) |
 				((vendor[5] & 0x7f) << 8) |
 				((vendor[6] & 0x7f) << 16) |
 				((vendor[7] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) |
 			((product[1] & 0x7f) << 8) |
 			((product[2] & 0x7f) << 16) |
 			((product[3] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) |
 			((product[5] & 0x7f) << 8) |
 			((product[6] & 0x7f) << 16) |
 			((product[7] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) |
 			((product[9] & 0x7f) << 8) |
 			((product[10] & 0x7f) << 16) |
 			((product[11] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) |
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) |
 			((product[13] & 0x7f) << 8) |
 			((product[14] & 0x7f) << 16) |
 			((product[15] & 0x7f) << 24)));
-	dp_write(base + MMSS_DP_GENERIC1_8, device_type);
-	dp_write(base + MMSS_DP_GENERIC1_9, 0x00);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_8, device_type);
+	dp_write(catalog, io_data, MMSS_DP_GENERIC1_9, 0x00);
 
-	spd_cfg = dp_read(base + MMSS_DP_SDP_CFG);
+	spd_cfg = dp_read(catalog, io_data, MMSS_DP_SDP_CFG);
 	/* GENERIC1_SDP for SPD Infoframe */
 	spd_cfg |= BIT(18);
-	dp_write(base + MMSS_DP_SDP_CFG, spd_cfg);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG, spd_cfg);
 
-	spd_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+	spd_cfg2 = dp_read(catalog, io_data, MMSS_DP_SDP_CFG2);
 	/* 28 data bytes for SPD Infoframe with GENERIC1 set */
 	spd_cfg2 |= BIT(17);
-	dp_write(base + MMSS_DP_SDP_CFG2, spd_cfg2);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG2, spd_cfg2);
 
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x1);
-	dp_write(base + MMSS_DP_SDP_CFG3, 0x0);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x1);
+	dp_write(catalog, io_data, MMSS_DP_SDP_CFG3, 0x0);
 }
 
-struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
+static void dp_catalog_get_io_buf(struct dp_catalog_private *catalog)
+{
+	struct dp_parser *parser = catalog->parser;
+
+	dp_catalog_fill_io_buf(dp_ahb);
+	dp_catalog_fill_io_buf(dp_aux);
+	dp_catalog_fill_io_buf(dp_link);
+	dp_catalog_fill_io_buf(dp_p0);
+	dp_catalog_fill_io_buf(dp_phy);
+	dp_catalog_fill_io_buf(dp_ln_tx0);
+	dp_catalog_fill_io_buf(dp_ln_tx1);
+	dp_catalog_fill_io_buf(dp_pll);
+	dp_catalog_fill_io_buf(usb3_dp_com);
+	dp_catalog_fill_io_buf(dp_mmss_cc);
+	dp_catalog_fill_io_buf(hdcp_physical);
+}
+
+static void dp_catalog_get_io(struct dp_catalog_private *catalog)
+{
+	struct dp_parser *parser = catalog->parser;
+
+	dp_catalog_fill_io(dp_ahb);
+	dp_catalog_fill_io(dp_aux);
+	dp_catalog_fill_io(dp_link);
+	dp_catalog_fill_io(dp_p0);
+	dp_catalog_fill_io(dp_phy);
+	dp_catalog_fill_io(dp_ln_tx0);
+	dp_catalog_fill_io(dp_ln_tx1);
+	dp_catalog_fill_io(dp_pll);
+	dp_catalog_fill_io(usb3_dp_com);
+	dp_catalog_fill_io(dp_mmss_cc);
+	dp_catalog_fill_io(hdcp_physical);
+}
+
+static void dp_catalog_set_exe_mode(struct dp_catalog *dp_catalog, char *mode)
+{
+	struct dp_catalog_private *catalog;
+
+	if (!dp_catalog) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	catalog = container_of(dp_catalog, struct dp_catalog_private,
+		dp_catalog);
+
+	strlcpy(catalog->exe_mode, mode, sizeof(catalog->exe_mode));
+
+	if (!strcmp(catalog->exe_mode, "hw"))
+		catalog->parser->clear_io_buf(catalog->parser);
+	else
+		dp_catalog_get_io_buf(catalog);
+}
+
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
 {
 	int rc = 0;
 	struct dp_catalog *dp_catalog;
@@ -1583,7 +1781,7 @@
 		.config_spd = dp_catalog_panel_config_spd,
 	};
 
-	if (!io) {
+	if (!dev || !parser) {
 		pr_err("invalid input\n");
 		rc = -EINVAL;
 		goto error;
@@ -1596,7 +1794,11 @@
 	}
 
 	catalog->dev = dev;
-	catalog->io = io;
+	catalog->parser = parser;
+
+	dp_catalog_get_io(catalog);
+
+	strlcpy(catalog->exe_mode, "hw", sizeof(catalog->exe_mode));
 
 	dp_catalog = &catalog->dp_catalog;
 
@@ -1605,6 +1807,9 @@
 	dp_catalog->audio = audio;
 	dp_catalog->panel = panel;
 
+	dp_catalog->set_exe_mode = dp_catalog_set_exe_mode;
+	dp_catalog->get_reg_dump = dp_catalog_reg_dump;
+
 	return dp_catalog;
 error:
 	return ERR_PTR(rc);
@@ -1620,5 +1825,6 @@
 	catalog = container_of(dp_catalog, struct dp_catalog_private,
 				dp_catalog);
 
+	catalog->parser->clear_io_buf(catalog->parser);
 	devm_kfree(catalog->dev, catalog);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index d03be6a..743468d 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -181,6 +181,10 @@
 	struct dp_catalog_ctrl ctrl;
 	struct dp_catalog_audio audio;
 	struct dp_catalog_panel panel;
+
+	void (*set_exe_mode)(struct dp_catalog *dp_catalog, char *mode);
+	int (*get_reg_dump)(struct dp_catalog *dp_catalog,
+		char *mode, u8 **out_buf, u32 *out_buf_len);
 };
 
 static inline u8 dp_ecc_get_g0_value(u8 data)
@@ -248,7 +252,7 @@
 	return parity_byte;
 }
 
-struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io);
+struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser);
 void dp_catalog_put(struct dp_catalog *catalog);
 
 #endif /* _DP_CATALOG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index cb54b5f..2e2887e 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -820,6 +820,10 @@
 	u8 link_status[DP_LINK_STATUS_SIZE];
 	int const maximum_retries = 5;
 
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED;
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED;
+	ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED;
+
 	dp_ctrl_state_ctrl(ctrl, 0);
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
@@ -829,13 +833,13 @@
 		DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	ret = dp_ctrl_update_vx_px(ctrl);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	tries = 0;
@@ -879,6 +883,13 @@
 			break;
 		}
 	}
+end:
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED;
+
+	if (ret)
+		ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED;
 
 	return ret;
 }
@@ -922,6 +933,10 @@
 	int const maximum_retries = 5;
 	u8 link_status[DP_LINK_STATUS_SIZE];
 
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED;
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED;
+	ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED;
+
 	dp_ctrl_state_ctrl(ctrl, 0);
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
@@ -934,14 +949,14 @@
 	ret = dp_ctrl_update_vx_px(ctrl);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 	ctrl->catalog->set_pattern(ctrl->catalog, pattern);
 	ret = dp_ctrl_train_pattern_set(ctrl,
 		pattern | DP_RECOVERED_CLOCK_OUT_EN);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	do  {
@@ -968,7 +983,13 @@
 			break;
 		}
 	} while (!atomic_read(&ctrl->aborted));
+end:
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED;
 
+	if (ret)
+		ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED;
 	return ret;
 }
 
@@ -1109,8 +1130,7 @@
 	return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false);
 }
 
-static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl,
-	bool flip, bool multi_func)
+static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
 {
 	struct dp_ctrl_private *ctrl;
 	struct dp_catalog_ctrl *catalog;
@@ -1125,7 +1145,7 @@
 	ctrl->orientation = flip;
 	catalog = ctrl->catalog;
 
-	if (!multi_func) {
+	if (reset) {
 		catalog->usb_reset(ctrl->catalog, flip);
 		catalog->phy_reset(ctrl->catalog);
 	}
@@ -1192,6 +1212,10 @@
 		return -EINVAL;
 	}
 
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;
+	ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;
+
 	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
 	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
 
@@ -1231,6 +1255,13 @@
 		ret = dp_ctrl_setup_main_link(ctrl, true);
 	} while (ret == -EAGAIN);
 
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED;
+
+	if (ret)
+		ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED;
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 229c779..31d8f07 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,7 +23,7 @@
 #include "dp_catalog.h"
 
 struct dp_ctrl {
-	int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func);
+	int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
 	void (*deinit)(struct dp_ctrl *dp_ctrl);
 	int (*on)(struct dp_ctrl *dp_ctrl);
 	void (*off)(struct dp_ctrl *dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 054b3c8..78bea02 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -16,7 +16,6 @@
 
 #include <linux/debugfs.h>
 
-#include "dp_parser.h"
 #include "dp_power.h"
 #include "dp_catalog.h"
 #include "dp_aux.h"
@@ -36,15 +35,56 @@
 	u8 *dpcd;
 	u32 dpcd_size;
 
+	int vdo;
+
+	char exe_mode[SZ_32];
+	char reg_dump[SZ_32];
+
 	struct dp_usbpd *usbpd;
 	struct dp_link *link;
 	struct dp_panel *panel;
+	struct dp_aux *aux;
+	struct dp_catalog *catalog;
 	struct drm_connector **connector;
 	struct device *dev;
-
+	struct work_struct sim_work;
 	struct dp_debug dp_debug;
 };
 
+static int dp_debug_get_edid_buf(struct dp_debug_private *debug)
+{
+	int rc = 0;
+
+	if (!debug->edid) {
+		debug->edid = devm_kzalloc(debug->dev, SZ_256, GFP_KERNEL);
+		if (!debug->edid) {
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		debug->edid_size = SZ_256;
+	}
+end:
+	return rc;
+}
+
+static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug)
+{
+	int rc = 0;
+
+	if (!debug->dpcd) {
+		debug->dpcd = devm_kzalloc(debug->dev, SZ_1K, GFP_KERNEL);
+		if (!debug->dpcd) {
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		debug->dpcd_size = SZ_1K;
+	}
+end:
+	return rc;
+}
+
 static ssize_t dp_debug_write_edid(struct file *file,
 		const char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -75,7 +115,8 @@
 	edid_size = size / char_to_nib;
 	buf_t = buf;
 
-	memset(debug->edid, 0, debug->edid_size);
+	if (dp_debug_get_edid_buf(debug))
+		goto bail;
 
 	if (edid_size != debug->edid_size) {
 		pr_debug("clearing debug edid\n");
@@ -100,13 +141,13 @@
 		buf_t += char_to_nib;
 	}
 
-	print_hex_dump(KERN_DEBUG, "DEBUG EDID: ", DUMP_PREFIX_NONE,
-		16, 1, debug->edid, debug->edid_size, false);
-
 	edid = debug->edid;
 bail:
 	kfree(buf);
-	debug->panel->set_edid(debug->panel, edid);
+
+	if (!debug->dp_debug.sim_mode)
+		debug->panel->set_edid(debug->panel, edid);
+
 	return rc;
 }
 
@@ -119,8 +160,8 @@
 	size_t dpcd_size = 0;
 	size_t size = 0, dpcd_buf_index = 0;
 	ssize_t rc = count;
-
-	pr_debug("count=%zu\n", count);
+	char offset_ch[5];
+	u32 offset;
 
 	if (!debug)
 		return -ENODEV;
@@ -128,7 +169,7 @@
 	if (*ppos)
 		goto bail;
 
-	size = min_t(size_t, count, SZ_32);
+	size = min_t(size_t, count, SZ_2K);
 
 	buf = kzalloc(size, GFP_KERNEL);
 	if (!buf) {
@@ -139,16 +180,30 @@
 	if (copy_from_user(buf, user_buff, size))
 		goto bail;
 
-	dpcd_size = size / char_to_nib;
-	buf_t = buf;
+	memcpy(offset_ch, buf, 4);
+	offset_ch[4] = '\0';
 
-	memset(debug->dpcd, 0, debug->dpcd_size);
-
-	if (dpcd_size != debug->dpcd_size) {
-		pr_debug("clearing debug dpcd\n");
+	if (kstrtoint(offset_ch, 16, &offset)) {
+		pr_err("offset kstrtoint error\n");
 		goto bail;
 	}
 
+	if (dp_debug_get_dpcd_buf(debug))
+		goto bail;
+
+	if (offset == 0xFFFF) {
+		pr_err("clearing dpcd\n");
+		memset(debug->dpcd, 0, debug->dpcd_size);
+		goto bail;
+	}
+
+	size -= 4;
+
+	dpcd_size = size / char_to_nib;
+	buf_t = buf + 4;
+
+	dpcd_buf_index = offset;
+
 	while (dpcd_size--) {
 		char t[3];
 		int d;
@@ -167,16 +222,39 @@
 		buf_t += char_to_nib;
 	}
 
-	print_hex_dump(KERN_DEBUG, "DEBUG DPCD: ", DUMP_PREFIX_NONE,
-		8, 1, debug->dpcd, debug->dpcd_size, false);
-
 	dpcd = debug->dpcd;
 bail:
 	kfree(buf);
-	debug->panel->set_dpcd(debug->panel, dpcd);
+	if (debug->dp_debug.sim_mode)
+		debug->aux->dpcd_updated(debug->aux);
+	else
+		debug->panel->set_dpcd(debug->panel, dpcd);
+
 	return rc;
 }
 
+static ssize_t dp_debug_read_dpcd(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	u32 len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	len += snprintf(buf, SZ_8, "0x%x\n", debug->aux->reg);
+
+	if (copy_to_user(user_buff, buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+	return len;
+}
+
 static ssize_t dp_debug_write_hpd(struct file *file,
 		const char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -323,6 +401,36 @@
 	return len;
 }
 
+static ssize_t dp_debug_write_exe_mode(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char *buf;
+	size_t len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	len = min_t(size_t, count, SZ_32 - 1);
+	buf = memdup_user(user_buff, len);
+	buf[len] = '\0';
+
+	if (sscanf(buf, "%3s", debug->exe_mode) != 1)
+		goto end;
+
+	if (strcmp(debug->exe_mode, "hw") &&
+	    strcmp(debug->exe_mode, "sw") &&
+	    strcmp(debug->exe_mode, "all"))
+		goto end;
+
+	debug->catalog->set_exe_mode(debug->catalog, debug->exe_mode);
+end:
+	return len;
+}
+
 static ssize_t dp_debug_read_connected(struct file *file,
 		char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -421,7 +529,6 @@
 	struct dp_debug_private *debug = file->private_data;
 	char *buf;
 	u32 len = 0, rc = 0;
-	u64 lclk = 0;
 	u32 max_size = SZ_4K;
 
 	if (!debug)
@@ -434,124 +541,60 @@
 	if (!buf)
 		return -ENOMEM;
 
-	rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
+	rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\tdp_panel\n\t\tmax_pclk_khz = %d\n",
-		debug->panel->max_pclk_khz);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\tdrm_dp_link\n\t\trate = %u\n",
+	rc = snprintf(buf + len, max_size, "\tlink_rate=%u\n",
 		debug->panel->link_info.rate);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tnum_lanes = %u\n",
+	rc = snprintf(buf + len, max_size, "\tnum_lanes=%u\n",
 		debug->panel->link_info.num_lanes);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tcapabilities = %lu\n",
-		debug->panel->link_info.capabilities);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\tdp_panel_info:\n\t\tactive = %dx%d\n",
+	rc = snprintf(buf + len, max_size, "\tresolution=%dx%d@%dHz\n",
 		debug->panel->pinfo.h_active,
-		debug->panel->pinfo.v_active);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tback_porch = %dx%d\n",
-		debug->panel->pinfo.h_back_porch,
-		debug->panel->pinfo.v_back_porch);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tfront_porch = %dx%d\n",
-		debug->panel->pinfo.h_front_porch,
-		debug->panel->pinfo.v_front_porch);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tsync_width = %dx%d\n",
-		debug->panel->pinfo.h_sync_width,
-		debug->panel->pinfo.v_sync_width);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tactive_low = %dx%d\n",
-		debug->panel->pinfo.h_active_low,
-		debug->panel->pinfo.v_active_low);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\th_skew = %d\n",
-		debug->panel->pinfo.h_skew);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\trefresh rate = %d\n",
+		debug->panel->pinfo.v_active,
 		debug->panel->pinfo.refresh_rate);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tpixel clock khz = %d\n",
+	rc = snprintf(buf + len, max_size, "\tpclock=%dKHz\n",
 		debug->panel->pinfo.pixel_clk_khz);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tbpp = %d\n",
+	rc = snprintf(buf + len, max_size, "\tbpp=%d\n",
 		debug->panel->pinfo.bpp);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	/* Link Information */
-	rc = snprintf(buf + len, max_size,
-		"\tdp_link:\n\t\ttest_requested = %d\n",
-		debug->link->sink_request);
+	rc = snprintf(buf + len, max_size, "\ttest_req=%s\n",
+		dp_link_get_test_name(debug->link->sink_request));
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tlane_count = %d\n", debug->link->link_params.lane_count);
+		"\tlane_count=%d\n", debug->link->link_params.lane_count);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tbw_code = %d\n", debug->link->link_params.bw_code);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	lclk = drm_dp_bw_code_to_link_rate(
-			debug->link->link_params.bw_code) * 1000;
-	rc = snprintf(buf + len, max_size,
-		"\t\tlclk = %lld\n", lclk);
+		"\tbw_code=%d\n", debug->link->link_params.bw_code);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tv_level = %d\n", debug->link->phy_params.v_level);
+		"\tv_level=%d\n", debug->link->phy_params.v_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tp_level = %d\n", debug->link->phy_params.p_level);
+		"\tp_level=%d\n", debug->link->phy_params.p_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
@@ -816,6 +859,155 @@
 	return rc;
 }
 
+static ssize_t dp_debug_write_sim(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	size_t len = 0;
+	int sim;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_8 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto end;
+
+	buf[len] = '\0';
+
+	if (kstrtoint(buf, 10, &sim) != 0)
+		goto end;
+
+	if (sim) {
+		if (dp_debug_get_edid_buf(debug))
+			goto end;
+
+		if (dp_debug_get_dpcd_buf(debug))
+			goto error;
+	} else {
+		if (debug->edid) {
+			devm_kfree(debug->dev, debug->edid);
+			debug->edid = NULL;
+		}
+
+		if (debug->dpcd) {
+			devm_kfree(debug->dev, debug->dpcd);
+			debug->dpcd = NULL;
+		}
+	}
+
+	debug->dp_debug.sim_mode = !!sim;
+
+	debug->aux->set_sim_mode(debug->aux, debug->dp_debug.sim_mode,
+			debug->edid, debug->dpcd);
+end:
+	return len;
+error:
+	devm_kfree(debug->dev, debug->edid);
+	return len;
+}
+
+static ssize_t dp_debug_write_attention(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	size_t len = 0;
+	int vdo;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_8 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto end;
+
+	buf[len] = '\0';
+
+	if (kstrtoint(buf, 10, &vdo) != 0)
+		goto end;
+
+	debug->vdo = vdo;
+
+	schedule_work(&debug->sim_work);
+end:
+	return len;
+}
+
+static ssize_t dp_debug_write_dump(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_32];
+	size_t len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_32 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto end;
+
+	buf[len] = '\0';
+
+	if (sscanf(buf, "%31s", debug->reg_dump) != 1)
+		goto end;
+
+	/* qfprom register dump not supported */
+	if (!strcmp(debug->reg_dump, "qfprom_physical"))
+		strlcpy(debug->reg_dump, "clear", sizeof(debug->reg_dump));
+end:
+	return len;
+}
+
+static ssize_t dp_debug_read_dump(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	int rc = 0;
+	struct dp_debug_private *debug = file->private_data;
+	u8 *buf = NULL;
+	u32 len = 0;
+	char prefix[SZ_32];
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	if (!debug->usbpd->hpd_high || !strlen(debug->reg_dump))
+		goto end;
+
+	rc = debug->catalog->get_reg_dump(debug->catalog,
+		debug->reg_dump, &buf, &len);
+	if (rc)
+		goto end;
+
+	snprintf(prefix, sizeof(prefix), "%s: ", debug->reg_dump);
+	print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_NONE,
+		16, 4, buf, len, false);
+
+	if (copy_to_user(user_buff, buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+end:
+	return len;
+}
+
 static const struct file_operations dp_debug_fops = {
 	.open = simple_open,
 	.read = dp_debug_read_info,
@@ -840,6 +1032,7 @@
 static const struct file_operations dpcd_fops = {
 	.open = simple_open,
 	.write = dp_debug_write_dpcd,
+	.read = dp_debug_read_dpcd,
 };
 
 static const struct file_operations connected_fops = {
@@ -852,6 +1045,10 @@
 	.read = dp_debug_bw_code_read,
 	.write = dp_debug_bw_code_write,
 };
+static const struct file_operations exe_mode_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_exe_mode,
+};
 
 static const struct file_operations tpg_fops = {
 	.open = simple_open,
@@ -865,6 +1062,22 @@
 	.read = dp_debug_read_hdr,
 };
 
+static const struct file_operations sim_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_sim,
+};
+
+static const struct file_operations attention_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_attention,
+};
+
+static const struct file_operations dump_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_dump,
+	.read = dp_debug_read_dump,
+};
+
 static int dp_debug_init(struct dp_debug *dp_debug)
 {
 	int rc = 0;
@@ -927,7 +1140,14 @@
 		rc = PTR_ERR(file);
 		pr_err("[%s] debugfs max_bw_code failed, rc=%d\n",
 		       DEBUG_NAME, rc);
-		goto error_remove_dir;
+	}
+
+	file = debugfs_create_file("exe_mode", 0644, dir,
+			debug, &exe_mode_fops);
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs register failed, rc=%d\n",
+		       DEBUG_NAME, rc);
 	}
 
 	file = debugfs_create_file("edid", 0644, dir,
@@ -967,6 +1187,36 @@
 		goto error_remove_dir;
 	}
 
+	file = debugfs_create_file("sim", 0644, dir,
+		debug, &sim_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs sim failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	file = debugfs_create_file("attention", 0644, dir,
+		debug, &attention_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs attention failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	file = debugfs_create_file("dump", 0644, dir,
+		debug, &dump_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs dump failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
 	return 0;
 
 error_remove_dir:
@@ -977,15 +1227,24 @@
 	return rc;
 }
 
+static void dp_debug_sim_work(struct work_struct *work)
+{
+	struct dp_debug_private *debug =
+		container_of(work, typeof(*debug), sim_work);
+
+	debug->usbpd->simulate_attention(debug->usbpd, debug->vdo);
+}
+
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 			struct dp_usbpd *usbpd, struct dp_link *link,
-			struct drm_connector **connector)
+			struct dp_aux *aux, struct drm_connector **connector,
+			struct dp_catalog *catalog)
 {
 	int rc = 0;
 	struct dp_debug_private *debug;
 	struct dp_debug *dp_debug;
 
-	if (!dev || !panel || !usbpd || !link) {
+	if (!dev || !panel || !usbpd || !link || !catalog) {
 		pr_err("invalid input\n");
 		rc = -EINVAL;
 		goto error;
@@ -997,30 +1256,16 @@
 		goto error;
 	}
 
-	debug->edid = devm_kzalloc(dev, SZ_256, GFP_KERNEL);
-	if (!debug->edid) {
-		rc = -ENOMEM;
-		kfree(debug);
-		goto error;
-	}
-
-	debug->edid_size = SZ_256;
-
-	debug->dpcd = devm_kzalloc(dev, SZ_16, GFP_KERNEL);
-	if (!debug->dpcd) {
-		rc = -ENOMEM;
-		kfree(debug);
-		goto error;
-	}
-
-	debug->dpcd_size = SZ_16;
+	INIT_WORK(&debug->sim_work, dp_debug_sim_work);
 
 	debug->dp_debug.debug_en = false;
 	debug->usbpd = usbpd;
 	debug->link = link;
 	debug->panel = panel;
+	debug->aux = aux;
 	debug->dev = dev;
 	debug->connector = connector;
+	debug->catalog = catalog;
 
 	dp_debug = &debug->dp_debug;
 	dp_debug->vdisplay = 0;
@@ -1063,7 +1308,11 @@
 
 	dp_debug_deinit(dp_debug);
 
-	devm_kfree(debug->dev, debug->edid);
-	devm_kfree(debug->dev, debug->dpcd);
+	if (debug->edid)
+		devm_kfree(debug->dev, debug->edid);
+
+	if (debug->dpcd)
+		devm_kfree(debug->dev, debug->dpcd);
+
 	devm_kfree(debug->dev, debug);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
index 3b2d23e..2643f70 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.h
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,7 @@
 #include "dp_panel.h"
 #include "dp_link.h"
 #include "dp_usbpd.h"
+#include "dp_aux.h"
 
 /**
  * struct dp_debug
@@ -29,6 +30,7 @@
  */
 struct dp_debug {
 	bool debug_en;
+	bool sim_mode;
 	bool psm_enabled;
 	int aspect_ratio;
 	int vdisplay;
@@ -45,6 +47,7 @@
  * @usbpd: instance of usbpd module
  * @link: instance of link module
  * @connector: double pointer to display connector
+ * @catalog: instance of catalog module
  * return: pointer to allocated debug module data
  *
  * This function sets up the debug module and provides a way
@@ -52,7 +55,8 @@
  */
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 			struct dp_usbpd *usbpd, struct dp_link *link,
-			struct drm_connector **connector);
+			struct dp_aux *aux, struct drm_connector **connector,
+			struct dp_catalog *catalog);
 /**
  * dp_debug_put()
  *
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index d19058f..b1d03d6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -274,6 +274,7 @@
 static int dp_display_initialize_hdcp(struct dp_display_private *dp)
 {
 	struct sde_hdcp_init_data hdcp_init_data;
+	struct dp_parser *parser;
 	int rc = 0;
 
 	if (!dp) {
@@ -281,6 +282,8 @@
 		return -EINVAL;
 	}
 
+	parser = dp->parser;
+
 	mutex_init(&dp->hdcp_mutex);
 
 	hdcp_init_data.client_id     = HDCP_CLIENT_DP;
@@ -290,13 +293,14 @@
 	hdcp_init_data.mutex         = &dp->hdcp_mutex;
 	hdcp_init_data.sec_access    = true;
 	hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb;
-	hdcp_init_data.core_io       = &dp->parser->io.ctrl_io;
-	hdcp_init_data.dp_ahb        = &dp->parser->io.dp_ahb;
-	hdcp_init_data.dp_aux        = &dp->parser->io.dp_aux;
-	hdcp_init_data.dp_link       = &dp->parser->io.dp_link;
-	hdcp_init_data.dp_p0         = &dp->parser->io.dp_p0;
-	hdcp_init_data.qfprom_io     = &dp->parser->io.qfprom_io;
-	hdcp_init_data.hdcp_io       = &dp->parser->io.hdcp_io;
+	hdcp_init_data.dp_ahb        = &parser->get_io(parser, "dp_ahb")->io;
+	hdcp_init_data.dp_aux        = &parser->get_io(parser, "dp_aux")->io;
+	hdcp_init_data.dp_link       = &parser->get_io(parser, "dp_link")->io;
+	hdcp_init_data.dp_p0         = &parser->get_io(parser, "dp_p0")->io;
+	hdcp_init_data.qfprom_io     = &parser->get_io(parser,
+						"qfprom_physical")->io;
+	hdcp_init_data.hdcp_io       = &parser->get_io(parser,
+						"hdcp_physical")->io;
 	hdcp_init_data.revision      = &dp->panel->link_info.revision;
 
 	dp->hdcp.hdcp1 = sde_hdcp_1x_init(&hdcp_init_data);
@@ -466,6 +470,7 @@
 		bool hpd)
 {
 	u32 timeout_sec;
+	int ret = 0;
 
 	dp->dp_display.is_connected = hpd;
 
@@ -474,16 +479,20 @@
 	else
 		timeout_sec = 10;
 
+	dp->aux->state |= DP_STATE_NOTIFICATION_SENT;
+
 	reinit_completion(&dp->notification_comp);
 	dp_display_send_hpd_event(dp);
 
 	if (!wait_for_completion_timeout(&dp->notification_comp,
 						HZ * timeout_sec)) {
 		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
-		return -EINVAL;
+		ret = -EINVAL;
 	}
 
-	return 0;
+	dp->aux->state &= ~DP_STATE_NOTIFICATION_SENT;
+
+	return ret;
 }
 
 static int dp_display_process_hpd_high(struct dp_display_private *dp)
@@ -532,6 +541,7 @@
 static void dp_display_host_init(struct dp_display_private *dp)
 {
 	bool flip = false;
+	bool reset;
 
 	if (dp->core_initialized) {
 		pr_debug("DP core already initialized\n");
@@ -541,8 +551,10 @@
 	if (dp->usbpd->orientation == ORIENTATION_CC2)
 		flip = true;
 
+	reset = dp->debug->sim_mode ? false : !dp->usbpd->multi_func;
+
 	dp->power->init(dp->power, flip);
-	dp->ctrl->init(dp->ctrl, flip, dp->usbpd->multi_func);
+	dp->ctrl->init(dp->ctrl, flip, reset);
 	enable_irq(dp->irq);
 	dp->core_initialized = true;
 }
@@ -558,6 +570,7 @@
 	dp->power->deinit(dp->power);
 	disable_irq(dp->irq);
 	dp->core_initialized = false;
+	dp->aux->state = 0;
 }
 
 static int dp_display_process_hpd_low(struct dp_display_private *dp)
@@ -664,6 +677,13 @@
 		goto end;
 	}
 
+	/*
+	 * In case cable/dongle is disconnected during adb shell stop,
+	 * reset psm_enabled flag to false since it is no more needed
+	 */
+	if (dp->dp_display.post_open)
+		dp->debug->psm_enabled = false;
+
 	if (dp->debug->psm_enabled)
 		dp->link->psm_config(dp->link, &dp->panel->link_info, true);
 
@@ -837,7 +857,7 @@
 		goto error_catalog;
 	}
 
-	dp->catalog = dp_catalog_get(dev, &dp->parser->io);
+	dp->catalog = dp_catalog_get(dev, dp->parser);
 	if (IS_ERR(dp->catalog)) {
 		rc = PTR_ERR(dp->catalog);
 		pr_err("failed to initialize catalog, rc = %d\n", rc);
@@ -929,7 +949,8 @@
 	}
 
 	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
-				dp->link, &dp->dp_display.connector);
+				dp->link, dp->aux, &dp->dp_display.connector,
+				dp->catalog);
 	if (IS_ERR(dp->debug)) {
 		rc = PTR_ERR(dp->debug);
 		pr_err("failed to initialize debug, rc = %d\n", rc);
@@ -1095,6 +1116,7 @@
 end:
 	/* clear framework event notifier */
 	dp_display->post_open = NULL;
+	dp->aux->state |= DP_STATE_CTRL_POWERED_ON;
 
 	complete_all(&dp->notification_comp);
 	mutex_unlock(&dp->session_lock);
@@ -1127,6 +1149,14 @@
 			dp->hdcp.ops->off(dp->hdcp.data);
 	}
 
+	if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
+		if (dp->audio_supported)
+			dp->audio->off(dp->audio);
+
+		dp->link->psm_config(dp->link, &dp->panel->link_info, true);
+		dp->debug->psm_enabled = true;
+	}
+
 	dp->ctrl->push_idle(dp->ctrl);
 end:
 	mutex_unlock(&dp->session_lock);
@@ -1167,8 +1197,17 @@
 
 	memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
 
+	/*
+	 * In case of framework reboot, the DP off sequence is executed without
+	 * any notification from driver. Initialize post_open callback to notify
+	 * DP connection once framework restarts.
+	 */
+	if (dp->usbpd->hpd_high && dp->usbpd->alt_mode_cfg_done) {
+		dp_display->post_open = dp_display_post_open;
+		dp->dp_display.is_connected = false;
+	}
 	dp->power_on = false;
-
+	dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
 end:
 	complete_all(&dp->notification_comp);
 	mutex_unlock(&dp->session_lock);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 3ca247c..05629dd 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -724,24 +724,6 @@
 	return ret;
 }
 
-static char *dp_link_get_test_name(u32 test_requested)
-{
-	switch (test_requested) {
-	case DP_TEST_LINK_TRAINING:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
-	case DP_TEST_LINK_VIDEO_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
-	case DP_TEST_LINK_EDID_READ:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
-	case DP_TEST_LINK_PHY_TEST_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
-	case DP_TEST_LINK_AUDIO_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
-	default:
-		return "unknown";
-	}
-}
-
 /**
  * dp_link_is_video_audio_test_requested() - checks for audio/video link request
  * @link: link requested by the sink
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 6f79b6a..46d30a7 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -83,6 +83,24 @@
 	u32 bw_code;
 };
 
+static inline char *dp_link_get_test_name(u32 test_requested)
+{
+	switch (test_requested) {
+	case DP_TEST_LINK_TRAINING:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
+	case DP_TEST_LINK_VIDEO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
+	case DP_TEST_LINK_EDID_READ:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
+	case DP_TEST_LINK_PHY_TEST_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
+	case DP_TEST_LINK_AUDIO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
+	default:
+		return "unknown";
+	}
+}
+
 struct dp_link {
 	u32 sink_request;
 	u32 test_response;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index e0aedc0..7132699 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -136,9 +136,6 @@
 
 			goto end;
 		}
-
-		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ",
-			DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);
 	}
 
 	rlen = drm_dp_dpcd_read(panel->aux->drm_aux,
@@ -275,35 +272,31 @@
 static int dp_panel_read_edid(struct dp_panel *dp_panel,
 	struct drm_connector *connector)
 {
+	int ret = 0;
 	struct dp_panel_private *panel;
 
 	if (!dp_panel) {
 		pr_err("invalid input\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto end;
 	}
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 
 	if (panel->custom_edid) {
 		pr_debug("skip edid read in debug mode\n");
-		return 0;
+		goto end;
 	}
 
 	sde_get_edid(connector, &panel->aux->drm_aux->ddc,
 		(void **)&dp_panel->edid_ctrl);
 	if (!dp_panel->edid_ctrl->edid) {
 		pr_err("EDID read failed\n");
-	} else {
-		u8 *buf = (u8 *)dp_panel->edid_ctrl->edid;
-		u32 size = buf[0x7E] ? 256 : 128;
-
-		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK EDID: ",
-			DUMP_PREFIX_NONE, 16, 1, buf, size, false);
-
-		return 0;
+		ret = -EINVAL;
+		goto end;
 	}
-
-	return -EINVAL;
+end:
+	return ret;
 }
 
 static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index c112cdc..adcc762 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,101 +20,45 @@
 
 static void dp_parser_unmap_io_resources(struct dp_parser *parser)
 {
+	int i = 0;
 	struct dp_io *io = &parser->io;
 
-	msm_dss_iounmap(&io->dp_ahb);
-	msm_dss_iounmap(&io->dp_aux);
-	msm_dss_iounmap(&io->dp_link);
-	msm_dss_iounmap(&io->dp_p0);
-	msm_dss_iounmap(&io->phy_io);
-	msm_dss_iounmap(&io->ln_tx0_io);
-	msm_dss_iounmap(&io->ln_tx0_io);
-	msm_dss_iounmap(&io->dp_pll_io);
-	msm_dss_iounmap(&io->dp_cc_io);
-	msm_dss_iounmap(&io->usb3_dp_com);
-	msm_dss_iounmap(&io->qfprom_io);
-	msm_dss_iounmap(&io->hdcp_io);
+	for (i = 0; i < io->len; i++)
+		msm_dss_iounmap(&io->data[i].io);
 }
 
-static int dp_parser_ctrl_res(struct dp_parser *parser)
+static int dp_parser_reg(struct dp_parser *parser)
 {
-	int rc = 0;
-	u32 index;
+	int rc = 0, i = 0;
+	u32 reg_count;
 	struct platform_device *pdev = parser->pdev;
-	struct device_node *of_node = parser->pdev->dev.of_node;
 	struct dp_io *io = &parser->io;
+	struct device *dev = &pdev->dev;
 
-	rc = of_property_read_u32(of_node, "cell-index", &index);
-	if (rc) {
-		pr_err("cell-index not specified, rc=%d\n", rc);
-		goto err;
+	reg_count = of_property_count_strings(dev->of_node, "reg-names");
+	if (reg_count <= 0) {
+		pr_err("no reg defined\n");
+		return -EINVAL;
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_ahb, "dp_ahb");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
+	io->len = reg_count;
+	io->data = devm_kzalloc(dev, sizeof(struct dp_io_data) * reg_count,
+			GFP_KERNEL);
+	if (!io->data)
+		return -ENOMEM;
+
+	for (i = 0; i < reg_count; i++) {
+		of_property_read_string_index(dev->of_node,
+				"reg-names", i,	&io->data[i].name);
+		rc = msm_dss_ioremap_byname(pdev, &io->data[i].io,
+			io->data[i].name);
+		if (rc) {
+			pr_err("unable to remap %s resources\n",
+				io->data[i].name);
+			goto err;
+		}
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_aux, "dp_aux");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_link, "dp_link");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_p0, "dp_p0");
-	if (rc) {
-		pr_err("unable to remap dp io resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->phy_io, "dp_phy");
-	if (rc) {
-		pr_err("unable to remap dp PHY resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->ln_tx0_io, "dp_ln_tx0");
-	if (rc) {
-		pr_err("unable to remap dp TX0 resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->ln_tx1_io, "dp_ln_tx1");
-	if (rc) {
-		pr_err("unable to remap dp TX1 resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->dp_pll_io, "dp_pll");
-	if (rc) {
-		pr_err("unable to remap DP PLL resources\n");
-		goto err;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &io->usb3_dp_com, "usb3_dp_com");
-	if (rc) {
-		pr_err("unable to remap USB3 DP com resources\n");
-		goto err;
-	}
-
-	if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) {
-		pr_err("unable to remap dp MMSS_CC resources\n");
-		goto err;
-	}
-
-	if (msm_dss_ioremap_byname(pdev, &io->qfprom_io, "qfprom_physical"))
-		pr_warn("unable to remap dp qfprom resources\n");
-
-	if (msm_dss_ioremap_byname(pdev, &io->hdcp_io, "hdcp_physical"))
-		pr_warn("unable to remap dp hdcp resources\n");
-
 	return 0;
 err:
 	dp_parser_unmap_io_resources(parser);
@@ -618,7 +562,7 @@
 		goto err;
 	}
 
-	rc = dp_parser_ctrl_res(parser);
+	rc = dp_parser_reg(parser);
 	if (rc)
 		goto err;
 
@@ -647,6 +591,74 @@
 	return rc;
 }
 
+static struct dp_io_data *dp_parser_get_io(struct dp_parser *dp_parser,
+				char *name)
+{
+	int i = 0;
+	struct dp_io *io;
+
+	if (!dp_parser) {
+		pr_err("invalid input\n");
+		goto err;
+	}
+
+	io = &dp_parser->io;
+
+	for (i = 0; i < io->len; i++) {
+		struct dp_io_data *data = &io->data[i];
+
+		if (!strcmp(data->name, name))
+			return data;
+	}
+err:
+	return NULL;
+}
+
+static void dp_parser_get_io_buf(struct dp_parser *dp_parser, char *name)
+{
+	int i = 0;
+	struct dp_io *io;
+
+	if (!dp_parser) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	io = &dp_parser->io;
+
+	for (i = 0; i < io->len; i++) {
+		struct dp_io_data *data = &io->data[i];
+
+		if (!strcmp(data->name, name)) {
+			if (!data->buf)
+				data->buf = devm_kzalloc(&dp_parser->pdev->dev,
+					data->io.len, GFP_KERNEL);
+		}
+	}
+}
+
+static void dp_parser_clear_io_buf(struct dp_parser *dp_parser)
+{
+	int i = 0;
+	struct dp_io *io;
+
+	if (!dp_parser) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	io = &dp_parser->io;
+
+	for (i = 0; i < io->len; i++) {
+		struct dp_io_data *data = &io->data[i];
+
+		if (data->buf)
+			devm_kfree(&dp_parser->pdev->dev, data->buf);
+
+		data->buf = NULL;
+	}
+}
+
 struct dp_parser *dp_parser_get(struct platform_device *pdev)
 {
 	struct dp_parser *parser;
@@ -656,6 +668,9 @@
 		return ERR_PTR(-ENOMEM);
 
 	parser->parse = dp_parser_parse;
+	parser->get_io = dp_parser_get_io;
+	parser->get_io_buf = dp_parser_get_io_buf;
+	parser->clear_io_buf = dp_parser_clear_io_buf;
 	parser->pdev = pdev;
 
 	return parser;
@@ -679,5 +694,7 @@
 		dp_parser_put_gpio_data(&parser->pdev->dev, &power[i]);
 	}
 
+	dp_parser_clear_io_buf(parser);
+	devm_kfree(&parser->pdev->dev, parser->io.data);
 	devm_kfree(&parser->pdev->dev, parser);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index 72da381..6e78db2 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -56,35 +56,25 @@
 };
 
 /**
- * struct dp_ctrl_resource - controller's IO related data
- *
- * @dp_ahb: controller's ahb mapped memory address
- * @dp_aux: controller's aux mapped memory address
- * @dp_link: controller's link mapped memory address
- * @dp_p0: controller's p0 mapped memory address
- * @phy_io: phy's mapped memory address
- * @ln_tx0_io: USB-DP lane TX0's mapped memory address
- * @ln_tx1_io: USB-DP lane TX1's mapped memory address
- * @dp_cc_io: DP cc's mapped memory address
- * @qfprom_io: qfprom's mapped memory address
- * @dp_pll_io: DP PLL mapped memory address
- * @usb3_dp_com: USB3 DP PHY combo mapped memory address
- * @hdcp_io: hdcp's mapped memory address
+ * struct dp_io_data - data structure to store DP IO related info
+ * @name: name of the IO
+ * @buf: buffer corresponding to IO for debugging
+ * @io: io data which give len and mapped address
+ */
+struct dp_io_data {
+	const char *name;
+	u8 *buf;
+	struct dss_io_data io;
+};
+
+/**
+ * struct dp_io - data struct to store array of DP IO info
+ * @len: total number of IOs
+ * @data: pointer to an array of DP IO data structures.
  */
 struct dp_io {
-	struct dss_io_data ctrl_io;
-	struct dss_io_data dp_ahb;
-	struct dss_io_data dp_aux;
-	struct dss_io_data dp_link;
-	struct dss_io_data dp_p0;
-	struct dss_io_data phy_io;
-	struct dss_io_data ln_tx0_io;
-	struct dss_io_data ln_tx1_io;
-	struct dss_io_data dp_cc_io;
-	struct dss_io_data qfprom_io;
-	struct dss_io_data dp_pll_io;
-	struct dss_io_data usb3_dp_com;
-	struct dss_io_data hdcp_io;
+	u32 len;
+	struct dp_io_data *data;
 };
 
 /**
@@ -171,6 +161,9 @@
  * @ctrl_resouce: controller's register address realated data
  * @disp_data: controller's display related data
  * @parse: function to be called by client to parse device tree.
+ * @get_io: function to be called by client to get io data.
+ * @get_io_buf: function to be called by client to get io buffers.
+ * @clear_io_buf: function to be called by client to clear io buffers.
  */
 struct dp_parser {
 	struct platform_device *pdev;
@@ -184,6 +177,9 @@
 	u32 max_pclk_khz;
 
 	int (*parse)(struct dp_parser *parser);
+	struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name);
+	void (*get_io_buf)(struct dp_parser *parser, char *name);
+	void (*clear_io_buf)(struct dp_parser *parser);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 2bd3bd4..42eb9b0 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -426,6 +426,28 @@
 	return rc;
 }
 
+static int dp_usbpd_simulate_attention(struct dp_usbpd *dp_usbpd, int vdo)
+{
+	int rc = 0;
+	struct dp_usbpd_private *pd;
+
+	if (!dp_usbpd) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
+
+	pd->vdo = vdo;
+	dp_usbpd_get_status(pd);
+
+	if (pd->dp_cb && pd->dp_cb->attention)
+		pd->dp_cb->attention(pd->dev);
+error:
+	return rc;
+}
+
 struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb)
 {
 	int rc = 0;
@@ -475,6 +497,7 @@
 
 	dp_usbpd = &usbpd->dp_usbpd;
 	dp_usbpd->simulate_connect = dp_usbpd_simulate_connect;
+	dp_usbpd->simulate_attention = dp_usbpd_simulate_attention;
 
 	return dp_usbpd;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h
index e70ad7d..0a7efd9 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.h
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -50,6 +50,7 @@
  * @alt_mode_cfg_done: bool to specify alt mode status
  * @debug_en: bool to specify debug mode
  * @simulate_connect: simulate disconnect or connect for debug mode
+ * @simulate_attention: simulate attention messages for debug mode
  */
 struct dp_usbpd {
 	enum dp_usbpd_port port;
@@ -65,6 +66,7 @@
 	bool debug_en;
 
 	int (*simulate_connect)(struct dp_usbpd *dp_usbpd, bool hpd);
+	int (*simulate_attention)(struct dp_usbpd *dp_usbpd, int vdo);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index 1fd10d9..fa80317 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -239,8 +239,7 @@
  *
  * return: error code in case of failure or 0 for success.
  */
-int dsi_display_clk_ctrl(void *handle,
-	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state);
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state);
 
 /**
  * dsi_clk_set_link_frequencies() - set frequencies for link clks
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index 38eba8d..bff8627 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1071,8 +1071,7 @@
 
 DEFINE_MUTEX(dsi_mngr_clk_mutex);
 
-int dsi_display_clk_ctrl(void *handle,
-	enum dsi_clk_type clk_type, enum dsi_clk_state clk_state)
+int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state)
 {
 	int rc = 0;
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index bfbcf54..0113c83 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -401,6 +401,21 @@
 	return rc;
 }
 
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl)
+{
+	struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state;
+
+	if (!state) {
+		pr_err("Invalid host state for DSI controller\n");
+		return -EINVAL;
+	}
+
+	if (!state->host_initialized)
+		return true;
+
+	return false;
+}
+
 static void dsi_ctrl_update_state(struct dsi_ctrl *dsi_ctrl,
 				  enum dsi_ctrl_driver_ops op,
 				  u32 op_state)
@@ -1072,10 +1087,10 @@
 
 		cmdbuf = (u8 *)(dsi_ctrl->vaddr);
 
+		msm_gem_sync(dsi_ctrl->tx_cmd_buf);
 		for (cnt = 0; cnt < length; cnt++)
 			cmdbuf[dsi_ctrl->cmd_len + cnt] = buffer[cnt];
 
-		msm_gem_sync(dsi_ctrl->tx_cmd_buf);
 		dsi_ctrl->cmd_len += length;
 
 		if (!(msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) {
@@ -2087,11 +2102,14 @@
 	}
 
 	mutex_lock(&dsi_ctrl->ctrl_lock);
-	if (!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) {
+	if ((!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) ||
+			dsi_ctrl->modeupdated) {
 		*changed = true;
 		memcpy(&dsi_ctrl->roi, roi, sizeof(dsi_ctrl->roi));
+		dsi_ctrl->modeupdated = false;
 	} else
 		*changed = false;
+
 	mutex_unlock(&dsi_ctrl->ctrl_lock);
 	return rc;
 }
@@ -2647,6 +2665,7 @@
 	ctrl->mode_bounds.w = ctrl->host_config.video_timing.h_active;
 	ctrl->mode_bounds.h = ctrl->host_config.video_timing.v_active;
 	memcpy(&ctrl->roi, &ctrl->mode_bounds, sizeof(ctrl->mode_bounds));
+	ctrl->modeupdated = true;
 	ctrl->roi.x = 0;
 error:
 	mutex_unlock(&ctrl->ctrl_lock);
@@ -2673,9 +2692,6 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&dsi_ctrl->ctrl_lock);
-	mutex_unlock(&dsi_ctrl->ctrl_lock);
-
 	return rc;
 }
 
@@ -3293,6 +3309,25 @@
 	return misr;
 }
 
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl)
+{
+	if (!dsi_ctrl || !dsi_ctrl->hw.ops.error_intr_ctrl
+			|| !dsi_ctrl->hw.ops.clear_error_status) {
+		pr_err("Invalid params\n");
+		return;
+	}
+
+	/*
+	 * Mask DSI error status interrupts and clear error status
+	 * register
+	 */
+	mutex_lock(&dsi_ctrl->ctrl_lock);
+	dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false);
+	dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
+					DSI_ERROR_INTERRUPT_COUNT);
+	mutex_unlock(&dsi_ctrl->ctrl_lock);
+}
+
 /**
  * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
  *				interrupts at any time.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index ca58896..9636dbe 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -211,6 +211,7 @@
  *                          dsi controller and run only dsi controller.
  * @null_insertion_enabled:  A boolean property to allow dsi controller to
  *                           insert null packet.
+ * @modeupdated:	  Boolean to send new roi if mode is updated.
  */
 struct dsi_ctrl {
 	struct platform_device *pdev;
@@ -258,6 +259,7 @@
 
 	bool phy_isolation_enabled;
 	bool null_insertion_enabled;
+	bool modeupdated;
 };
 
 /**
@@ -547,6 +549,16 @@
 				  enum dsi_engine_state state);
 
 /**
+ * dsi_ctrl_validate_host_state() - validate DSI ctrl host state
+ * @dsi_ctrl:            DSI Controller handle.
+ *
+ * Validate DSI cotroller host state
+ *
+ * Return: boolean indicating whether host is not initalized.
+ */
+bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl);
+
+/**
  * dsi_ctrl_set_vid_engine_state() - set video engine state
  * @dsi_ctrl:            DSI Controller handle.
  * @state:               Engine state.
@@ -711,6 +723,13 @@
 void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable);
 
 /**
+ * dsi_ctrl_mask_error_status_interrupts() - API to mask dsi ctrl error status
+ *                                           interrupts
+ * @dsi_ctrl:              DSI controller handle.
+ */
+void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl);
+
+/**
  * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
  *				interrupts at any time.
  * @dsi_ctrl:              DSI controller handle.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index c8edb09..fd18905 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -16,6 +16,7 @@
 
 #include <linux/list.h>
 #include <linux/of.h>
+#include <linux/of_graph.h>
 #include <linux/err.h>
 
 #include "msm_drv.h"
@@ -51,6 +52,40 @@
 
 static struct dsi_display *main_display;
 
+static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display)
+{
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!display)
+		return;
+
+	for (i = 0; (i < display->ctrl_count) &&
+			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl)
+			continue;
+		dsi_ctrl_mask_error_status_interrupts(ctrl->ctrl);
+	}
+}
+
+static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
+{
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!display)
+		return;
+
+	for (i = 0; (i < display->ctrl_count) &&
+			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl)
+			continue;
+		dsi_ctrl_irq_update(ctrl->ctrl, en);
+	}
+}
+
 void dsi_rect_intersect(const struct dsi_rect *r1,
 		const struct dsi_rect *r2,
 		struct dsi_rect *result)
@@ -88,8 +123,11 @@
 
 	panel = dsi_display->panel;
 
-	if (!dsi_panel_initialized(panel))
-		return -EINVAL;
+	mutex_lock(&panel->panel_lock);
+	if (!dsi_panel_initialized(panel)) {
+		rc = -EINVAL;
+		goto error;
+	}
 
 	panel->bl_config.bl_level = bl_lvl;
 
@@ -124,6 +162,7 @@
 	}
 
 error:
+	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -390,9 +429,17 @@
 	struct dsi_cmd_desc *cmds;
 	u32 flags = 0;
 
-	if (!panel)
+	if (!panel || !ctrl || !ctrl->ctrl)
 		return -EINVAL;
 
+	/*
+	 * When DSI controller is not in initialized state, we do not want to
+	 * report a false ESD failure and hence we defer until next read
+	 * happen.
+	 */
+	if (dsi_ctrl_validate_host_state(ctrl->ctrl))
+		return 1;
+
 	/* acquire panel_lock to make sure no commands are in progress */
 	dsi_panel_acquire_panel_lock(panel);
 
@@ -497,6 +544,11 @@
 		}
 	}
 exit:
+	if (rc <= 0) {
+		dsi_display_ctrl_irq_update(display, false);
+		dsi_display_mask_ctrl_error_interrupts(display);
+	}
+
 	dsi_display_cmd_engine_disable(display);
 done:
 	return rc;
@@ -865,6 +917,62 @@
 	return rc;
 }
 
+static ssize_t debugfs_esd_trigger_check(struct file *file,
+				  const char __user *user_buf,
+				  size_t user_len,
+				  loff_t *ppos)
+{
+	struct dsi_display *display = file->private_data;
+	char *buf;
+	int rc = 0;
+	u32 esd_trigger;
+
+	if (!display)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	if (user_len > sizeof(u32))
+		return -EINVAL;
+
+	buf = kzalloc(user_len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, user_buf, user_len)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	buf[user_len] = '\0'; /* terminate the string */
+
+	if (kstrtouint(buf, 10, &esd_trigger)) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (esd_trigger != 1) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	display->esd_trigger = esd_trigger;
+
+	if (display->esd_trigger) {
+		rc = dsi_panel_trigger_esd_attack(display->panel);
+		if (rc) {
+			pr_err("Failed to trigger ESD attack\n");
+			return rc;
+		}
+	}
+
+	rc = user_len;
+error:
+	kfree(buf);
+	return rc;
+}
+
 static ssize_t debugfs_misr_read(struct file *file,
 				 char __user *user_buf,
 				 size_t user_len,
@@ -941,6 +1049,11 @@
 	.write = debugfs_misr_setup,
 };
 
+static const struct file_operations esd_trigger_fops = {
+	.open = simple_open,
+	.write = debugfs_esd_trigger_check,
+};
+
 static int dsi_display_debugfs_init(struct dsi_display *display)
 {
 	int rc = 0;
@@ -968,6 +1081,18 @@
 		goto error_remove_dir;
 	}
 
+	dump_file = debugfs_create_file("esd_trigger",
+					0644,
+					dir,
+					display,
+					&esd_trigger_fops);
+	if (IS_ERR_OR_NULL(dump_file)) {
+		rc = PTR_ERR(dump_file);
+		pr_err("[%s] debugfs for esd trigger file failed, rc=%d\n",
+		       display->name, rc);
+		goto error_remove_dir;
+	}
+
 	misr_data = debugfs_create_file("misr_data",
 					0600,
 					dir,
@@ -2162,15 +2287,111 @@
 	return rc;
 }
 
+/* initialize dsi_panel using ext bridge's setting */
+static int dsi_display_populate_ext_bridge_config(struct dsi_display *display,
+	struct mipi_dsi_device *dsi)
+{
+	struct dsi_panel *panel = display->panel;
+
+	if (!panel) {
+		pr_err("Invalid param\n");
+		return -EINVAL;
+	}
+
+	pr_debug("DSI[%s]: channel=%d, lanes=%d, format=%d, mode_flags=%lx\n",
+		dsi->name, dsi->channel, dsi->lanes,
+		dsi->format, dsi->mode_flags);
+
+	panel->host_config.data_lanes = 0;
+	if (dsi->lanes > 0)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_0;
+	if (dsi->lanes > 1)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_1;
+	if (dsi->lanes > 2)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_2;
+	if (dsi->lanes > 3)
+		panel->host_config.data_lanes |= DSI_DATA_LANE_3;
+
+	switch (dsi->format) {
+	case MIPI_DSI_FMT_RGB888:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB888;
+		break;
+	case MIPI_DSI_FMT_RGB666:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666_LOOSE;
+		break;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666;
+		break;
+	case MIPI_DSI_FMT_RGB565:
+	default:
+		panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB565;
+		break;
+	}
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+		panel->panel_mode = DSI_OP_VIDEO_MODE;
+
+		if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_BURST_MODE;
+		else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_SYNC_PULSES;
+		else
+			panel->video_config.traffic_mode =
+					DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS;
+
+		panel->video_config.hsa_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA;
+		panel->video_config.hbp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP;
+		panel->video_config.hfp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP;
+		panel->video_config.pulse_mode_hsa_he =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE;
+		panel->video_config.bllp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BLLP;
+		panel->video_config.eof_bllp_lp11_en =
+			dsi->mode_flags & MIPI_DSI_MODE_VIDEO_EOF_BLLP;
+	} else {
+		panel->panel_mode = DSI_OP_CMD_MODE;
+		pr_err("command mode not supported by ext bridge\n");
+		return -ENOTSUPP;
+	}
+
+	/* TODO: add calc for these 2 values */
+	panel->host_config.t_clk_post = 0x03;
+	panel->host_config.t_clk_pre = 0x24;
+
+	panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN;
+
+	return 0;
+}
+
 static int dsi_host_attach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *dsi)
 {
-	return 0;
+	struct dsi_display *display = to_dsi_display(host);
+	int ret = 0;
+
+	if (!host || !dsi) {
+		pr_err("Invalid param\n");
+		return -EINVAL;
+	}
+
+	pr_debug("host attach\n");
+
+	if (dsi_display_has_ext_bridge(display))
+		ret = dsi_display_populate_ext_bridge_config(display, dsi);
+
+	return ret;
 }
 
+
 static int dsi_host_detach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *dsi)
 {
+	pr_debug("host detach\n");
 	return 0;
 }
 
@@ -2468,23 +2689,6 @@
 	}
 }
 
-static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
-{
-	int i;
-	struct dsi_display_ctrl *ctrl;
-
-	if (!display)
-		return;
-
-	for (i = 0; (i < display->ctrl_count) &&
-			(i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
-		ctrl = &display->ctrl[i];
-		if (!ctrl)
-			continue;
-		dsi_ctrl_irq_update(ctrl->ctrl, en);
-	}
-}
-
 int dsi_pre_clkoff_cb(void *priv,
 			   enum dsi_clk_type clk,
 			   enum dsi_clk_state new_state)
@@ -2847,11 +3051,31 @@
 	of_node = of_parse_phandle(display->pdev->dev.of_node,
 				   "qcom,dsi-panel", 0);
 	if (!of_node) {
-		pr_err("No Panel device present\n");
-		rc = -ENODEV;
-		goto error;
+		struct device_node *endpoint;
+
+		endpoint = of_graph_get_next_endpoint(
+				display->pdev->dev.of_node, NULL);
+		if (!endpoint) {
+			pr_err("no endpoint for ext bridge\n");
+			rc = -ENODEV;
+			goto error;
+		}
+
+		of_node = of_graph_get_remote_port_parent(endpoint);
+		of_node_put(endpoint);
+		if (!of_node) {
+			pr_err("no valid ext bridge\n");
+			rc = -ENODEV;
+			goto error;
+		}
+		of_node_put(of_node);
+
+		display->panel_of = of_node;
+		/* TODO: split support */
+		display->type = DSI_DISPLAY_EXT_BRIDGE;
 	} else {
 		display->panel_of = of_node;
+		display->type = DSI_DISPLAY_SINGLE;
 	}
 
 error:
@@ -2863,6 +3087,8 @@
 	int rc = 0;
 	int i;
 	struct dsi_display_ctrl *ctrl;
+	enum dsi_panel_type panel_type =
+		dsi_display_has_ext_bridge(display) ? EXT_BRIDGE : DSI_PANEL;
 
 	for (i = 0; i < display->ctrl_count; i++) {
 		ctrl = &display->ctrl[i];
@@ -2885,7 +3111,8 @@
 	}
 
 	display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of,
-						display->cmdline_topology);
+					display->cmdline_topology, panel_type);
+
 	if (IS_ERR_OR_NULL(display->panel)) {
 		rc = PTR_ERR(display->panel);
 		pr_err("failed to get panel, rc=%d\n", rc);
@@ -3300,9 +3527,9 @@
 	struct dsi_display_mode_priv_info *priv_info;
 
 	priv_info = mode->priv_info;
-	if (!priv_info) {
+	if (!dsi_display_has_ext_bridge(display) && !priv_info) {
 		pr_err("[%s] failed to get private info of the display mode",
-			display->name);
+				display->name);
 		return -EINVAL;
 	}
 
@@ -3339,7 +3566,8 @@
 		}
 	}
 
-	if (priv_info->phy_timing_len) {
+	/* ext bridge calculates these timing params by phy driver */
+	if (priv_info && priv_info->phy_timing_len) {
 		for (i = 0; i < display->ctrl_count; i++) {
 			ctrl = &display->ctrl[i];
 			 rc = dsi_phy_set_timing_params(ctrl->phy,
@@ -3424,6 +3652,12 @@
 {
 	int rc = 0;
 
+	/* Continuous splash not supported by external bridge */
+	if (dsi_display_has_ext_bridge(display)) {
+		display->is_cont_splash_enabled = false;
+		return 0;
+	}
+
 	/* Vote for gdsc required to read register address space */
 
 	display->cont_splash_client = sde_power_client_create(display->phandle,
@@ -3436,7 +3670,9 @@
 		return -EINVAL;
 	}
 
-	/* Verify whether continuous splash is enabled or not */
+	/*
+	 * Verify whether continuous splash is enabled or not.
+	 */
 	display->is_cont_splash_enabled =
 		dsi_display_get_cont_splash_status(display);
 	if (!display->is_cont_splash_enabled) {
@@ -4029,7 +4265,7 @@
 	}
 
 	if (display->bridge) {
-		pr_err("display is already initialize\n");
+		pr_err("display is already initialized\n");
 		goto error;
 	}
 
@@ -4048,6 +4284,56 @@
 	return rc;
 }
 
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+		struct drm_encoder *enc, struct drm_connector *connector)
+{
+	int rc = 0;
+	struct drm_bridge *ext_bridge;
+	struct msm_drm_private *priv = NULL;
+
+	if (!display || !display->drm_dev || !enc) {
+		pr_err("invalid param(s)\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+	priv = display->drm_dev->dev_private;
+
+	if (!priv) {
+		pr_err("Private data is not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!display->bridge) {
+		pr_err("dsi bridge is not initialize\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	ext_bridge = of_drm_find_bridge(display->panel_of);
+	if (!ext_bridge) {
+		pr_err("ext brige not found\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	/* update connector ops in ext bridge */
+	drm_bridge_connector_init(ext_bridge, connector);
+
+	/* insert ext bridge to the bridge chain */
+	display->bridge->base.next = ext_bridge;
+	ext_bridge->encoder = enc;
+	priv->bridges[priv->num_bridges++] = ext_bridge;
+
+	drm_bridge_attach(display->drm_dev, ext_bridge);
+
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+
+}
+
 int dsi_display_drm_bridge_deinit(struct dsi_display *display)
 {
 	int rc = 0;
@@ -4127,6 +4413,44 @@
 	return rc;
 }
 
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp)
+{
+	struct dsi_display *display;
+	int i;
+
+	if (!info || !disp) {
+		pr_err("invalid params\n");
+		return -EINVAL;
+	}
+
+	display = disp;
+	if (!display->panel) {
+		pr_err("invalid display panel\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	memset(info, 0, sizeof(struct msm_display_info));
+
+	info->intf_type = DRM_MODE_CONNECTOR_DSI;
+	info->num_of_h_tiles = display->ctrl_count;
+	for (i = 0; i < info->num_of_h_tiles; i++)
+		info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
+
+	/*
+	 * TODO: these info need come from ext bridge.
+	 * using drm_connector->status, connector->polled.
+	 */
+	info->is_connected = true;
+	info->is_primary = true;
+	info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE |
+		MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG);
+
+	mutex_unlock(&display->display_lock);
+	return 0;
+}
+
 static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
 			u32 *count)
 {
@@ -4851,12 +5175,15 @@
 	mode = display->panel->cur_mode;
 
 	if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
+		if (display->is_cont_splash_enabled) {
+			pr_err("DMS is not supposed to be set on first frame\n");
+			return -EINVAL;
+		}
 		/* update dsi ctrl for new mode */
 		rc = dsi_display_pre_switch(display);
 		if (rc)
 			pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
-				   display->name, rc);
-
+					display->name, rc);
 		goto error;
 	}
 
@@ -4990,6 +5317,9 @@
 	struct dsi_rect req_roi = { 0 };
 	int rc = 0;
 
+	if (dsi_display_has_ext_bridge(display))
+		return 0;
+
 	cur_mode = display->panel->cur_mode;
 	if (!cur_mode)
 		return 0;
@@ -5043,6 +5373,9 @@
 	if (!display || !rois || !display->panel)
 		return -EINVAL;
 
+	if (dsi_display_has_ext_bridge(display))
+		return 0;
+
 	cur_mode = display->panel->cur_mode;
 	if (!cur_mode)
 		return 0;
@@ -5197,7 +5530,7 @@
 		}
 	}
 
-	if (mode->priv_info->dsc_enabled) {
+	if (mode->priv_info && mode->priv_info->dsc_enabled) {
 		mode->priv_info->dsc.pic_width *= display->ctrl_count;
 		rc = dsi_panel_update_pps(display->panel);
 		if (rc) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 4cfd4a9..53004e4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation.All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation.All rights reserved.
  *
  * 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
@@ -160,6 +160,7 @@
  * @root:             Debugfs root directory
  * @misr_enable       Frame MISR enable/disable
  * @misr_frame_count  Number of frames to accumulate the MISR value
+ * @esd_trigger       field indicating ESD trigger through debugfs
  */
 struct dsi_display {
 	struct platform_device *pdev;
@@ -218,6 +219,7 @@
 
 	bool misr_enable;
 	u32 misr_frame_count;
+	u32 esd_trigger;
 	/* multiple dsi error handlers */
 	struct workqueue_struct *err_workq;
 	struct work_struct fifo_underflow_work;
@@ -225,6 +227,18 @@
 	struct work_struct lp_rx_timeout_work;
 };
 
+/**
+ * dsi_display_has_ext_bridge() - check whether display has ext bridge
+ *                                connected.
+ *
+ * Return: True - ext bridge, False - no ext bridge.
+ */
+static inline bool dsi_display_has_ext_bridge(const struct dsi_display *display)
+{
+	return display->type == DSI_DISPLAY_EXT_BRIDGE ||
+		display->type == DSI_DISPLAY_SPLIT_EXT_BRIDGE;
+}
+
 int dsi_display_dev_probe(struct platform_device *pdev);
 int dsi_display_dev_remove(struct platform_device *pdev);
 
@@ -288,6 +302,19 @@
 int dsi_display_drm_bridge_deinit(struct dsi_display *display);
 
 /**
+ * dsi_display_drm_ext_bridge_init() - initializes DRM bridge for ext bridge
+ * @display:            Handle to the display.
+ * @enc:                Pointer to the encoder object which is connected to the
+ *			display.
+ * @connector:          Pointer to the connector object which is connected to
+ *                      the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
+		struct drm_encoder *enc, struct drm_connector *connector);
+
+/**
  * dsi_display_get_info() - returns the display properties
  * @info:             Pointer to the structure where info is stored.
  * @disp:             Handle to the display.
@@ -297,6 +324,15 @@
 int dsi_display_get_info(struct msm_display_info *info, void *disp);
 
 /**
+ * dsi_display_ext_bridge_get_info() - returns the ext bridge's display info
+ * @info:             Pointer to the structure where info is stored.
+ * @disp:             Handle to the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_ext_bridge_get_info(struct msm_display_info *info, void *disp);
+
+/**
  * dsi_display_get_mode_count() - get number of modes supported by the display
  * @display:            Handle to display.
  * @count:              Number of modes supported
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index a1e4685..5b47865 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -63,6 +63,11 @@
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
 	if (msm_is_mode_seamless_vrr(drm_mode))
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
+
+	dsi_mode->timing.h_sync_polarity =
+			!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
+	dsi_mode->timing.v_sync_polarity =
+			!!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC);
 }
 
 void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
@@ -101,6 +106,11 @@
 	if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
 		drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
 
+	if (dsi_mode->timing.h_sync_polarity)
+		drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+	if (dsi_mode->timing.v_sync_polarity)
+		drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+
 	drm_mode_set_name(drm_mode);
 }
 
@@ -288,17 +298,23 @@
 
 	convert_to_dsi_mode(mode, &dsi_mode);
 
-	/*
-	 * retrieve dsi mode from dsi driver's cache since not safe to take
-	 * the drm mode config mutex in all paths
-	 */
-	rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
-	if (rc)
-		return rc;
+	/* external bridge doesn't use priv_info and dsi_mode_flags */
+	if (!dsi_display_has_ext_bridge(display)) {
+		/*
+		 * retrieve dsi mode from dsi driver's cache since not safe to
+		 * take the drm mode config mutex in all paths
+		 */
+		rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
+		if (rc)
+			return rc;
 
-	/* propagate the private info to the adjusted_mode derived dsi mode */
-	dsi_mode.priv_info = panel_dsi_mode->priv_info;
-	dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+		/*
+		 * propagate the private info to the adjusted_mode derived dsi
+		 * mode
+		 */
+		dsi_mode.priv_info = panel_dsi_mode->priv_info;
+		dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
+	}
 
 	rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode,
 			DSI_VALIDATE_FLAG_ALLOW_ADJUST);
@@ -377,6 +393,35 @@
 	return 0;
 }
 
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+	struct msm_mode_info *mode_info,
+	u32 max_mixer_width, void *display)
+{
+	struct msm_display_topology *topology;
+	struct dsi_display_mode dsi_mode;
+	struct dsi_mode_info *timing;
+
+	if (!drm_mode || !mode_info)
+		return -EINVAL;
+
+	convert_to_dsi_mode(drm_mode, &dsi_mode);
+
+	memset(mode_info, 0, sizeof(*mode_info));
+
+	timing = &dsi_mode.timing;
+	mode_info->frame_rate = dsi_mode.timing.refresh_rate;
+	mode_info->vtotal = DSI_V_TOTAL(timing);
+
+	topology = &mode_info->topology;
+	topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? 2 : 1;
+	topology->num_enc = 0;
+	topology->num_intf = topology->num_lm;
+
+	mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
+
+	return 0;
+}
+
 static const struct drm_bridge_funcs dsi_bridge_ops = {
 	.attach       = dsi_bridge_attach,
 	.mode_fixup   = dsi_bridge_mode_fixup,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index ec58479..2bad8c0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -86,6 +86,18 @@
 	void *display);
 
 /**
+ * dsi_conn_ext_bridge_get_mode_info - retrieve information on the mode selected
+ * @drm_mode: Display mode set for the display
+ * @mode_info: Out parameter. information of the mode.
+ * @max_mixer_width: max width supported by HW layer mixer
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode,
+	struct msm_mode_info *mode_info, u32 max_mixer_width,
+	void *display);
+
+/**
  * dsi_conn_mode_valid - callback to determine if specified mode is valid
  * @connector: Pointer to drm connector structure
  * @mode: Pointer to drm mode structure
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 0ffece3..d8b90e3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,7 @@
 #define MAX_TOPOLOGY 5
 
 #define DSI_PANEL_DEFAULT_LABEL  "Default dsi panel"
+#define EXT_BRIDGE_DEFAULT_LABEL  "Default ext bridge"
 
 #define DEFAULT_MDP_TRANSFER_TIME 14000
 
@@ -321,6 +322,30 @@
 	return rc;
 }
 
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel)
+{
+	struct dsi_panel_reset_config *r_config;
+
+	if (!panel) {
+		pr_err("Invalid panel param\n");
+		return -EINVAL;
+	}
+
+	r_config = &panel->reset_config;
+	if (!r_config) {
+		pr_err("Invalid panel reset configuration\n");
+		return -EINVAL;
+	}
+
+	if (gpio_is_valid(r_config->reset_gpio)) {
+		gpio_set_value(r_config->reset_gpio, 0);
+		pr_info("GPIO pulled low to simulate ESD\n");
+		return 0;
+	}
+	pr_err("failed to pull down gpio\n");
+	return -EINVAL;
+}
+
 static int dsi_panel_reset(struct dsi_panel *panel)
 {
 	int rc = 0;
@@ -480,6 +505,9 @@
 	if (!panel || !panel->cur_mode)
 		return -EINVAL;
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mode = panel->cur_mode;
 
 	cmds = mode->priv_info->cmd_sets[type].cmds;
@@ -610,13 +638,10 @@
 
 	dsi = &panel->mipi_device;
 
-	mutex_lock(&panel->panel_lock);
-
 	rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl);
 	if (rc < 0)
 		pr_err("failed to update dcs backlight:%d\n", bl_lvl);
 
-	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -625,13 +650,16 @@
 	int rc = 0;
 	struct dsi_backlight_config *bl = &panel->bl_config;
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	pr_debug("backlight type:%d lvl:%d\n", bl->type, bl_lvl);
 	switch (bl->type) {
 	case DSI_BACKLIGHT_WLED:
 		led_trigger_event(bl->wled, bl_lvl);
 		break;
 	case DSI_BACKLIGHT_DCS:
-		dsi_panel_update_backlight(panel, bl_lvl);
+		rc = dsi_panel_update_backlight(panel, bl_lvl);
 		break;
 	default:
 		pr_err("Backlight type(%d) not supported\n", bl->type);
@@ -2713,7 +2741,8 @@
 
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node,
-				int topology_override)
+				int topology_override,
+				enum dsi_panel_type type)
 {
 	struct dsi_panel *panel;
 	int rc = 0;
@@ -2722,68 +2751,85 @@
 	if (!panel)
 		return ERR_PTR(-ENOMEM);
 
-	panel->name = of_get_property(of_node, "qcom,mdss-dsi-panel-name",
-				      NULL);
-	if (!panel->name)
-		panel->name = DSI_PANEL_DEFAULT_LABEL;
+	if (type == DSI_PANEL) {
+		panel->name = of_get_property(of_node,
+			"qcom,mdss-dsi-panel-name", NULL);
+		if (!panel->name)
+			panel->name = DSI_PANEL_DEFAULT_LABEL;
 
-	rc = dsi_panel_parse_host_config(panel, of_node);
-	if (rc) {
-		pr_err("failed to parse host configuration, rc=%d\n", rc);
+		rc = dsi_panel_parse_host_config(panel, of_node);
+		if (rc) {
+			pr_err("failed to parse host configuration, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_panel_mode(panel, of_node);
+		if (rc) {
+			pr_err("failed to parse panel mode configuration, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps,
+			of_node, panel->name);
+		if (rc)
+			pr_err("failed to parse dfps configuration, rc=%d\n",
+				rc);
+
+		rc = dsi_panel_parse_phy_props(&panel->phy_props,
+			of_node, panel->name);
+		if (rc) {
+			pr_err("failed to parse panel physical dimension, rc=%d\n",
+				rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
+		if (rc)
+			pr_err("failed to parse power config, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_gpios(panel, of_node);
+		if (rc)
+			pr_err("failed to parse panel gpios, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_bl_config(panel, of_node);
+		if (rc)
+			pr_err("failed to parse backlight config, rc=%d\n", rc);
+
+
+		rc = dsi_panel_parse_misc_features(panel, of_node);
+		if (rc)
+			pr_err("failed to parse misc features, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_hdr_config(panel, of_node);
+		if (rc)
+			pr_err("failed to parse hdr config, rc=%d\n", rc);
+
+		rc = dsi_panel_get_mode_count(panel, of_node);
+		if (rc) {
+			pr_err("failed to get mode count, rc=%d\n", rc);
+			goto error;
+		}
+
+		rc = dsi_panel_parse_dms_info(panel, of_node);
+		if (rc)
+			pr_debug("failed to get dms info, rc=%d\n", rc);
+
+		rc = dsi_panel_parse_esd_config(panel, of_node);
+		if (rc)
+			pr_debug("failed to parse esd config, rc=%d\n", rc);
+
+		panel->type = DSI_PANEL;
+	} else if (type == EXT_BRIDGE) {
+		panel->name = EXT_BRIDGE_DEFAULT_LABEL;
+		panel->type = EXT_BRIDGE;
+	} else {
+		pr_err("invalid panel type\n");
+		rc = -ENOTSUPP;
 		goto error;
 	}
 
-	rc = dsi_panel_parse_panel_mode(panel, of_node);
-	if (rc) {
-		pr_err("failed to parse panel mode configuration, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps, of_node, panel->name);
-	if (rc)
-		pr_err("failed to parse dfps configuration, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_phy_props(&panel->phy_props, of_node, panel->name);
-	if (rc) {
-		pr_err("failed to parse panel physical dimension, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_power_cfg(parent, panel, of_node);
-	if (rc)
-		pr_err("failed to parse power config, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_gpios(panel, of_node);
-	if (rc)
-		pr_err("failed to parse panel gpios, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_bl_config(panel, of_node);
-	if (rc)
-		pr_err("failed to parse backlight config, rc=%d\n", rc);
-
-
-	rc = dsi_panel_parse_misc_features(panel, of_node);
-	if (rc)
-		pr_err("failed to parse misc features, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_hdr_config(panel, of_node);
-	if (rc)
-		pr_err("failed to parse hdr config, rc=%d\n", rc);
-
-	rc = dsi_panel_get_mode_count(panel, of_node);
-	if (rc) {
-		pr_err("failed to get mode count, rc=%d\n", rc);
-		goto error;
-	}
-
-	rc = dsi_panel_parse_dms_info(panel, of_node);
-	if (rc)
-		pr_debug("failed to get dms info, rc=%d\n", rc);
-
-	rc = dsi_panel_parse_esd_config(panel, of_node);
-	if (rc)
-		pr_debug("failed to parse esd config, rc=%d\n", rc);
-
 	panel->panel_of_node = of_node;
 	drm_panel_init(&panel->drm_panel);
 	mutex_init(&panel->panel_lock);
@@ -2797,7 +2843,8 @@
 void dsi_panel_put(struct dsi_panel *panel)
 {
 	/* free resources allocated for ESD check */
-	dsi_panel_esd_config_deinit(&panel->esd_config);
+	if (panel->type == DSI_PANEL)
+		dsi_panel_esd_config_deinit(&panel->esd_config);
 
 	kfree(panel);
 }
@@ -2813,6 +2860,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	dev = &panel->mipi_device;
@@ -2877,6 +2927,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_bl_unregister(panel);
@@ -2960,11 +3013,7 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&panel->panel_lock);
-
 	memcpy(phy_props, &panel->phy_props, sizeof(*phy_props));
-
-	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -2978,11 +3027,7 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&panel->panel_lock);
-
 	memcpy(dfps_caps, &panel->dfps_caps, sizeof(*dfps_caps));
-
-	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
 
@@ -3013,6 +3058,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	mode->priv_info = kzalloc(sizeof(*mode->priv_info), GFP_KERNEL);
@@ -3120,10 +3168,12 @@
 
 	memcpy(&config->video_timing, &mode->timing,
 	       sizeof(config->video_timing));
-	config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
-	config->video_timing.dsc = &mode->priv_info->dsc;
 
-	config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+	if (mode->priv_info) {
+		config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
+		config->video_timing.dsc = &mode->priv_info->dsc;
+		config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz;
+	}
 	config->esc_clk_rate_hz = 19200000;
 	mutex_unlock(&panel->panel_lock);
 	return rc;
@@ -3138,6 +3188,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	/* If LP11_INIT is set, panel will be powered up during prepare() */
@@ -3166,6 +3219,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	priv_info = panel->cur_mode->priv_info;
@@ -3201,6 +3257,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1);
 	if (rc)
@@ -3219,6 +3278,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2);
 	if (rc)
@@ -3237,6 +3299,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP);
 	if (rc)
@@ -3255,6 +3320,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	if (panel->lp11_init) {
@@ -3329,7 +3397,7 @@
 	set->cmds[0].msg.rx_len = 0;
 	set->cmds[0].msg.rx_buf = 0;
 	set->cmds[0].last_command = 0;
-	set->cmds[0].post_wait_ms = 1;
+	set->cmds[0].post_wait_ms = 0;
 
 	set->cmds[1].msg.channel = 0;
 	set->cmds[1].msg.type = MIPI_DSI_DCS_LONG_WRITE;
@@ -3340,7 +3408,7 @@
 	set->cmds[1].msg.rx_len = 0;
 	set->cmds[1].msg.rx_buf = 0;
 	set->cmds[1].last_command = 1;
-	set->cmds[1].post_wait_ms = 1;
+	set->cmds[1].post_wait_ms = 0;
 
 	goto exit;
 
@@ -3365,6 +3433,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	priv_info = panel->cur_mode->priv_info;
 	set = &priv_info->cmd_sets[DSI_CMD_SET_ROI];
 
@@ -3400,6 +3471,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH);
@@ -3420,6 +3494,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_TIMING_SWITCH);
@@ -3440,6 +3517,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON);
@@ -3461,6 +3541,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_ON);
@@ -3483,6 +3566,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_OFF);
@@ -3506,6 +3592,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_OFF);
@@ -3530,6 +3619,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_OFF);
@@ -3561,6 +3653,9 @@
 		return -EINVAL;
 	}
 
+	if (panel->type == EXT_BRIDGE)
+		return 0;
+
 	mutex_lock(&panel->panel_lock);
 
 	if (!panel->lp11_init) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 06199f4..3b226b0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -140,8 +140,15 @@
 	u32 groups;
 };
 
+enum dsi_panel_type {
+	DSI_PANEL = 0,
+	EXT_BRIDGE,
+	DSI_PANEL_TYPE_MAX,
+};
+
 struct dsi_panel {
 	const char *name;
+	enum dsi_panel_type type;
 	struct device_node *panel_of_node;
 	struct mipi_dsi_device mipi_device;
 
@@ -204,7 +211,10 @@
 
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node,
-				int topology_override);
+				int topology_override,
+				enum dsi_panel_type type);
+
+int dsi_panel_trigger_esd_attack(struct dsi_panel *panel);
 
 void dsi_panel_put(struct dsi_panel *panel);
 
@@ -269,4 +279,10 @@
 
 void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
 
+struct dsi_panel *dsi_panel_ext_bridge_get(struct device *parent,
+				struct device_node *of_node,
+				int topology_override);
+
+void dsi_panel_ext_bridge_put(struct dsi_panel *panel);
+
 #endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 42aea7e..3e084d5 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published by
@@ -613,6 +613,7 @@
 	if (!node)
 		return;
 
+	spin_lock_irqsave(&node->state_lock, flags);
 	if (node->state == IRQ_DISABLED) {
 		ret = sde_core_irq_enable(kms, &irq_idx, 1);
 		if (ret)
@@ -620,6 +621,7 @@
 		else
 			node->state = IRQ_ENABLED;
 	}
+	spin_unlock_irqrestore(&node->state_lock, flags);
 }
 
 static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
@@ -1623,6 +1625,7 @@
 	struct sde_crtc *crtc;
 	int i;
 	int irq_idx, ret;
+	unsigned long flags;
 	struct sde_cp_node prop_node;
 	struct sde_crtc_irq_info *node = NULL;
 
@@ -1673,6 +1676,7 @@
 
 	if (!en) {
 		if (node) {
+			spin_lock_irqsave(&node->state_lock, flags);
 			if (node->state == IRQ_ENABLED) {
 				ret = sde_core_irq_disable(kms, &irq_idx, 1);
 				if (ret)
@@ -1683,6 +1687,7 @@
 			} else {
 				node->state = IRQ_NOINIT;
 			}
+			spin_unlock_irqrestore(&node->state_lock, flags);
 		} else {
 			DRM_ERROR("failed to get node from crtc event list\n");
 		}
@@ -1701,6 +1706,7 @@
 
 	if (node) {
 		/* device resume or resume from IPC cases */
+		spin_lock_irqsave(&node->state_lock, flags);
 		if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
 			ret = sde_core_irq_enable(kms, &irq_idx, 1);
 			if (ret) {
@@ -1712,6 +1718,7 @@
 				node->state = IRQ_ENABLED;
 			}
 		}
+		spin_unlock_irqrestore(&node->state_lock, flags);
 	} else {
 		/* request from userspace to register the event
 		 * in this case, node has not been added into the event list
@@ -1807,14 +1814,17 @@
 		return;
 	}
 
+	spin_lock_irqsave(&node->state_lock, flags);
 	if (node->state == IRQ_ENABLED) {
 		if (sde_core_irq_disable_nolock(kms, irq_idx)) {
 			DRM_ERROR("failed to disable irq %d, ret %d\n",
 				irq_idx, ret);
+			spin_unlock_irqrestore(&node->state_lock, flags);
 			return;
 		}
 		node->state = IRQ_DISABLED;
 	}
+	spin_unlock_irqrestore(&node->state_lock, flags);
 
 	/* lock histogram buffer */
 	for (i = 0; i < crtc->num_mixers; i++) {
@@ -1886,6 +1896,7 @@
 	struct sde_crtc *crtc;
 	struct sde_crtc_irq_info *node = NULL;
 	int i, irq_idx, ret = 0;
+	unsigned long flags;
 
 	if (!crtc_drm || !hist_irq) {
 		DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, hist_irq);
@@ -1928,6 +1939,7 @@
 	if (!en) {
 		if (node) {
 			/* device suspend case or suspend to IPC cases */
+			spin_lock_irqsave(&node->state_lock, flags);
 			if (node->state == IRQ_ENABLED) {
 				ret = sde_core_irq_disable(kms, &irq_idx, 1);
 				if (ret)
@@ -1938,6 +1950,7 @@
 			} else {
 				node->state = IRQ_NOINIT;
 			}
+			spin_unlock_irqrestore(&node->state_lock, flags);
 		} else {
 			DRM_ERROR("failed to get node from crtc event list\n");
 		}
@@ -1957,6 +1970,7 @@
 
 	if (node) {
 		/* device resume or resume from IPC cases */
+		spin_lock_irqsave(&node->state_lock, flags);
 		if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
 			ret = sde_core_irq_enable(kms, &irq_idx, 1);
 			if (ret) {
@@ -1968,6 +1982,7 @@
 				node->state = IRQ_ENABLED;
 			}
 		}
+		spin_unlock_irqrestore(&node->state_lock, flags);
 	} else {
 		/* request from userspace to register the event
 		 * in this case, node has not been added into the event list
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index df0aad5e..21b67d9 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -68,6 +68,7 @@
 	struct sde_connector *c_conn;
 	int bl_lvl;
 	struct drm_event event;
+	int rc = 0;
 
 	brightness = bd->props.brightness;
 
@@ -93,10 +94,10 @@
 		event.length = sizeof(u32);
 		msm_mode_object_event_notify(&c_conn->base.base,
 				c_conn->base.dev, &event, (u8 *)&brightness);
-		c_conn->ops.set_backlight(c_conn->display, bl_lvl);
+		rc = c_conn->ops.set_backlight(c_conn->display, bl_lvl);
 	}
 
-	return 0;
+	return rc;
 }
 
 static int sde_backlight_device_get_brightness(struct backlight_device *bd)
@@ -471,8 +472,11 @@
 	}
 	c_conn->last_panel_power_mode = mode;
 
-	if (mode != SDE_MODE_DPMS_ON)
+	if (mode != SDE_MODE_DPMS_ON) {
+		mutex_unlock(&c_conn->lock);
 		sde_connector_schedule_status_work(connector, false);
+		mutex_lock(&c_conn->lock);
+	}
 
 	return rc;
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 73e2af0..8d2f115 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -2511,9 +2511,6 @@
 							SDE_EVTLOG_FUNC_CASE3);
 		}
 
-		if (fevent->event & SDE_ENCODER_FRAME_EVENT_DONE)
-			sde_core_perf_crtc_update(crtc, 0, false);
-
 		if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE
 					| SDE_ENCODER_FRAME_EVENT_ERROR))
 			frame_done = true;
@@ -2597,6 +2594,8 @@
 	SDE_EVT32_VERBOSE(DRMID(crtc));
 	smmu_state = &sde_crtc->smmu_state;
 
+	sde_core_perf_crtc_update(crtc, 0, false);
+
 	/* complete secure transitions if any */
 	if (smmu_state->transition_type == POST_COMMIT)
 		sde_crtc_secure_ctrl(crtc, true);
@@ -4582,10 +4581,13 @@
 {
 	struct drm_encoder *encoder;
 	struct sde_crtc_state *cstate;
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_smmu_state_data *smmu_state;
 	uint32_t secure;
 	uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
 	int encoder_cnt = 0, i;
 	int rc;
+	bool is_video_mode = false;
 
 	if (!crtc || !state) {
 		SDE_ERROR("invalid arguments\n");
@@ -4643,6 +4645,37 @@
 
 		}
 	}
+
+	drm_for_each_encoder(encoder, crtc->dev) {
+		if (encoder->crtc != crtc)
+			continue;
+
+		is_video_mode |= sde_encoder_check_mode(encoder,
+						MSM_DISPLAY_CAP_VID_MODE);
+	}
+
+	sde_crtc = to_sde_crtc(crtc);
+	smmu_state = &sde_crtc->smmu_state;
+	/*
+	 * In video mode check for null commit before transition
+	 * from secure to non secure and vice versa
+	 */
+	if (is_video_mode && smmu_state &&
+		state->plane_mask && crtc->state->plane_mask &&
+		((fb_sec_dir && ((smmu_state->state == ATTACHED) &&
+				(secure == SDE_DRM_SEC_ONLY))) ||
+			(fb_ns && ((smmu_state->state == DETACHED) ||
+				(smmu_state->state == DETACH_ALL_REQ))))) {
+
+		SDE_EVT32(DRMID(&sde_crtc->base), fb_ns, fb_sec_dir,
+		  smmu_state->state, crtc->state->plane_mask,
+			crtc->state->plane_mask);
+		SDE_DEBUG("crtc %d, Invalid secure transition %x\n",
+				crtc->base.id, smmu_state->state);
+		return -EINVAL;
+
+	}
+
 	SDE_DEBUG("crtc:%d Secure validation successful\n", crtc->base.id);
 
 	return 0;
@@ -6134,6 +6167,7 @@
 			INIT_LIST_HEAD(&node->list);
 			node->func = custom_events[i].func;
 			node->event = event;
+			spin_lock_init(&node->state_lock);
 			break;
 		}
 	}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 33d2b8fa..78f15ec 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -445,7 +445,8 @@
  * @event: event type of the interrupt
  * @func: function pointer to enable/disable the interrupt
  * @list: list of user customized event in crtc
- * @ref_count: reference count for the interrupt
+ * @state: state of the interrupt
+ * @state_lock: spin lock for interrupt state
  */
 struct sde_crtc_irq_info {
 	struct sde_irq_callback irq;
@@ -454,6 +455,7 @@
 			struct sde_irq_callback *irq);
 	struct list_head list;
 	enum sde_crtc_irq_state state;
+	spinlock_t state_lock;
 };
 
 #define to_sde_crtc_state(x) \
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 92ab669..e0023d0 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -2257,7 +2257,7 @@
 			if (autorefresh_enabled) {
 				SDE_DEBUG_ENC(sde_enc,
 					"not handling early wakeup since auto refresh is enabled\n");
-				mutex_lock(&sde_enc->rc_lock);
+				mutex_unlock(&sde_enc->rc_lock);
 				return 0;
 			}
 
@@ -2328,6 +2328,16 @@
 
 	SDE_EVT32(DRMID(drm_enc));
 
+	/*
+	 * 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;
+
 	list_for_each_entry(conn_iter, connector_list, head)
 		if (conn_iter->encoder == drm_enc)
 			conn = conn_iter;
@@ -2530,16 +2540,6 @@
 		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");
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 69dc385..a3f09b6 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -405,7 +405,7 @@
 			to_sde_encoder_phys_vid(phys_enc);
 	struct sde_hw_ctl *hw_ctl;
 	unsigned long lock_flags;
-	u32 flush_register = 0;
+	u32 flush_register = ~0;
 	u32 reset_status = 0;
 	int new_cnt = -1, old_cnt = -1;
 	u32 event = 0;
@@ -419,42 +419,45 @@
 
 	SDE_ATRACE_BEGIN("vblank_irq");
 
-	/* signal only for master, where there is a pending kickoff */
-	if (sde_encoder_phys_vid_is_master(phys_enc)
-			&& atomic_add_unless(
-				&phys_enc->pending_retire_fence_cnt, -1, 0)) {
-		event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
-				| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
-
-		if (phys_enc->parent_ops.handle_frame_done)
-			phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
-				phys_enc, event);
-	}
-
-	if (phys_enc->parent_ops.handle_vblank_virt)
-		phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
-				phys_enc);
-
-	old_cnt  = atomic_read(&phys_enc->pending_kickoff_cnt);
-
 	/*
 	 * only decrement the pending flush count if we've actually flushed
 	 * hardware. due to sw irq latency, vblank may have already happened
 	 * so we need to double-check with hw that it accepted the flush bits
 	 */
 	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+
+	old_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
+
 	if (hw_ctl && hw_ctl->ops.get_flush_register)
 		flush_register = hw_ctl->ops.get_flush_register(hw_ctl);
 
-	if (flush_register == 0)
-		new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt,
-				-1, 0);
+	if (flush_register)
+		goto not_flushed;
 
+	new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
+
+	/* signal only for master, where there is a pending kickoff */
+	if (sde_encoder_phys_vid_is_master(phys_enc)) {
+		if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
+					-1, 0))
+			event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE |
+				SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
+	}
+
+not_flushed:
 	if (hw_ctl && hw_ctl->ops.get_reset)
 		reset_status = hw_ctl->ops.get_reset(hw_ctl);
 
 	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
 
+	if (event && phys_enc->parent_ops.handle_frame_done)
+		phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
+			phys_enc, event);
+
+	if (phys_enc->parent_ops.handle_vblank_virt)
+		phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
+				phys_enc);
+
 	SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
 			old_cnt, new_cnt, reset_status ? SDE_EVTLOG_ERROR : 0,
 			flush_register, event);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
index 994bf3d..593e972 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -786,6 +786,7 @@
 	blk_offset += 4;
 	val = (ad_cfg->cfg_param_027 & (BIT(16) - 1));
 	val |= ((ad_cfg->cfg_param_028 & (BIT(16) - 1)) << 16);
+	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
 	blk_offset += 4;
 	val = (ad_cfg->cfg_param_029 & (BIT(16) - 1));
 	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 6ccf957..02d593b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -474,6 +474,7 @@
 	struct sde_hw_blk_reg_map hw;
 
 	memset(&hw, 0, sizeof(hw));
+	msm_gem_sync(cfg->dma_buf->buf);
 	cmd1 = (cfg->op == REG_DMA_READ) ?
 		(dspp_read_sel[cfg->block_select] << 30) : 0;
 	cmd1 |= (cfg->last_command) ? BIT(24) : 0;
@@ -481,7 +482,6 @@
 	cmd1 |= (cfg->op == REG_DMA_WRITE) ? (BIT(22)) : 0;
 	cmd1 |= (SIZE_DWORD(cfg->dma_buf->index) & MAX_DWORDS_SZ);
 
-	msm_gem_sync(cfg->dma_buf->buf);
 	SET_UP_REG_DMA_REG(hw, reg_dma);
 	SDE_REG_WRITE(&hw, REG_DMA_OP_MODE_OFF, BIT(0));
 	SDE_REG_WRITE(&hw, reg_dma_clear_status_off,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 5d3835c..5895a4d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -952,6 +952,17 @@
 		.config_hdr = dp_connector_config_hdr,
 		.cmd_transfer = NULL,
 	};
+	static const struct sde_connector_ops ext_bridge_ops = {
+		.set_info_blob = dsi_conn_set_info_blob,
+		.mode_valid = dsi_conn_mode_valid,
+		.get_info = dsi_display_ext_bridge_get_info,
+		.soft_reset = dsi_display_soft_reset,
+		.clk_ctrl = dsi_display_clk_ctrl,
+		.get_mode_info = dsi_conn_ext_bridge_get_mode_info,
+		.get_dst_format = dsi_display_get_dst_format,
+		.enable_event = dsi_conn_enable_event,
+		.cmd_transfer = NULL,
+	};
 	struct msm_display_info info;
 	struct drm_encoder *encoder;
 	void *display, *connector;
@@ -976,39 +987,95 @@
 		display = sde_kms->dsi_displays[i];
 		encoder = NULL;
 
-		memset(&info, 0x0, sizeof(info));
-		rc = dsi_display_get_info(&info, display);
-		if (rc) {
-			SDE_ERROR("dsi get_info %d failed\n", i);
-			continue;
-		}
+		if (!dsi_display_has_ext_bridge(display)) {
+			memset(&info, 0x0, sizeof(info));
+			rc = dsi_display_get_info(&info, display);
+			if (rc) {
+				SDE_ERROR("dsi get_info %d failed\n", i);
+				continue;
+			}
 
-		encoder = sde_encoder_init(dev, &info);
-		if (IS_ERR_OR_NULL(encoder)) {
-			SDE_ERROR("encoder init failed for dsi %d\n", i);
-			continue;
-		}
+			encoder = sde_encoder_init(dev, &info);
+			if (IS_ERR_OR_NULL(encoder)) {
+				SDE_ERROR("encoder init failed for dsi %d\n",
+					i);
+				continue;
+			}
 
-		rc = dsi_display_drm_bridge_init(display, encoder);
-		if (rc) {
-			SDE_ERROR("dsi bridge %d init failed, %d\n", i, rc);
-			sde_encoder_destroy(encoder);
-			continue;
-		}
+			rc = dsi_display_drm_bridge_init(display, encoder);
+			if (rc) {
+				SDE_ERROR("dsi bridge %d init failed, %d\n",
+					i, rc);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
 
-		connector = sde_connector_init(dev,
-					encoder,
-					0,
-					display,
-					&dsi_ops,
-					DRM_CONNECTOR_POLL_HPD,
-					DRM_MODE_CONNECTOR_DSI);
-		if (connector) {
-			priv->encoders[priv->num_encoders++] = encoder;
+			connector = sde_connector_init(dev,
+						encoder,
+						NULL,
+						display,
+						&dsi_ops,
+						DRM_CONNECTOR_POLL_HPD,
+						DRM_MODE_CONNECTOR_DSI);
+			if (connector) {
+				priv->encoders[priv->num_encoders++] = encoder;
+			} else {
+				SDE_ERROR("dsi %d connector init failed\n", i);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+			}
 		} else {
-			SDE_ERROR("dsi %d connector init failed\n", i);
-			dsi_display_drm_bridge_deinit(display);
-			sde_encoder_destroy(encoder);
+			memset(&info, 0x0, sizeof(info));
+			rc = dsi_display_ext_bridge_get_info(&info, display);
+			if (rc) {
+				SDE_ERROR("ext get_info %d failed\n", i);
+				continue;
+			}
+
+			encoder = sde_encoder_init(dev, &info);
+			if (IS_ERR_OR_NULL(encoder)) {
+				SDE_ERROR("encoder init failed for ext %d\n",
+					i);
+				continue;
+			}
+
+			rc = dsi_display_drm_bridge_init(display, encoder);
+			if (rc) {
+				SDE_ERROR("dsi bridge %d init failed for ext\n",
+					i);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
+
+			connector = sde_connector_init(dev,
+						encoder,
+						NULL,
+						display,
+						&ext_bridge_ops,
+						DRM_CONNECTOR_POLL_HPD,
+						DRM_MODE_CONNECTOR_DSI);
+			if (connector) {
+				priv->encoders[priv->num_encoders++] = encoder;
+			} else {
+				SDE_ERROR("connector init %d failed for ext\n",
+					i);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
+
+			rc = dsi_display_drm_ext_bridge_init(display,
+				encoder, connector);
+			if (rc) {
+				struct drm_connector *conn = connector;
+
+				SDE_ERROR("ext bridge %d init failed, %d\n",
+					i, rc);
+				conn->funcs->destroy(connector);
+				dsi_display_drm_bridge_deinit(display);
+				sde_encoder_destroy(encoder);
+				continue;
+			}
 		}
 	}
 
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index ed1079d..4c281666 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2379,6 +2379,29 @@
 					(u64) &rstate->rot_hw->base);
 			rstate->out_fbo = NULL;
 		}
+
+		/*
+		 * For video mode, reject any downscale factor greater than or
+		 * equal to 1.1x
+		 *
+		 * Check the downscale factor first to avoid querying the
+		 * interface mode unnecessarily.
+		 */
+		if ((rstate->out_src_h >> 16) * 10 >= state->crtc_h * 11 &&
+				sde_crtc_get_intf_mode(state->crtc) ==
+				INTF_MODE_VIDEO) {
+			SDE_DEBUG_PLANE(psde,
+					"inline %d with invalid scale, %dx%d, %dx%d\n",
+					rstate->sequence_id,
+					rstate->out_src_w, rstate->out_src_h,
+					state->crtc_w, state->crtc_h);
+			SDE_EVT32(DRMID(plane), rstate->sequence_id,
+					rstate->out_src_w >> 16,
+					rstate->out_src_h >> 16,
+					state->crtc_w, state->crtc_h,
+					SDE_EVTLOG_ERROR);
+			return -EINVAL;
+		}
 	} else {
 
 		SDE_DEBUG("plane%d.%d bypass rotator\n", plane->base.id,
@@ -3257,7 +3280,8 @@
 
 	if (!fb || !old_fb) {
 		SDE_DEBUG_PLANE(psde, "can't compare fb handles\n");
-	} else if (fb->pixel_format != old_fb->pixel_format) {
+	} else if ((fb->pixel_format != old_fb->pixel_format) ||
+			pstate->const_alpha_en != old_pstate->const_alpha_en) {
 		SDE_DEBUG_PLANE(psde, "format change\n");
 		pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | SDE_PLANE_DIRTY_RECTS;
 	} else {
@@ -3569,7 +3593,8 @@
 
 	pstate->const_alpha_en = fmt->alpha_enable &&
 		(SDE_DRM_BLEND_OP_OPAQUE !=
-		 sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP));
+		 sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP)) &&
+		(pstate->stage != SDE_STAGE_0);
 
 modeset_update:
 	if (!ret)
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index f9092e2..93304e16 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1129,17 +1129,29 @@
 	return ret;
 }
 
-/**
- * poll_intr_status - Gets HW interrupt status based on
- *			given lookup IRQ index.
- * @intr:	HW interrupt handle
- * @irq_idx:	Lookup irq index return from irq_idx_lookup
- * @msec:	Maximum delay allowed to check intr status
- * return:	return zero on success.
- */
-static u32 _sde_rm_poll_intr_status_for_cont_splash
-			(struct sde_hw_intr *intr,
-			int irq_idx, u32 const msec)
+static void _sde_rm_clear_irq_status(struct sde_hw_intr *hw_intr,
+	int irq_idx_pp_done, int irq_idx_autorefresh)
+{
+	u32 intr_value = 0;
+
+	if ((irq_idx_pp_done >= 0) && (hw_intr->ops.get_intr_status_nomask)) {
+		intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr,
+			irq_idx_pp_done, false);
+		hw_intr->ops.clear_intr_status_force_mask(hw_intr,
+			irq_idx_pp_done, intr_value);
+	}
+
+	if ((irq_idx_autorefresh >= 0) &&
+			(hw_intr->ops.get_intr_status_nomask)) {
+		intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr,
+			irq_idx_autorefresh, false);
+		hw_intr->ops.clear_intr_status_force_mask(hw_intr,
+			irq_idx_autorefresh, intr_value);
+	}
+}
+
+static u32 _sde_rm_poll_intr_status_for_cont_splash(struct sde_hw_intr *intr,
+	int irq_idx_pp_done, int irq_idx_autorefresh, u32 const msec)
 {
 	int i;
 	u32 status = 0;
@@ -1153,19 +1165,112 @@
 
 	for (i = 0; i < loop; i++) {
 		status = intr->ops.get_intr_status_nomask
-				(intr, irq_idx, false);
+				(intr, irq_idx_pp_done, false);
 
-		if (status & BIT(irq_idx)) {
-			SDE_DEBUG(" Poll success. i=%d, status=0x%x\n",
+		if (status & BIT(irq_idx_pp_done)) {
+			SDE_DEBUG("pp_done received i=%d, status=0x%x\n",
 							i, status);
-			return 0;
+			SDE_EVT32(status, i, irq_idx_pp_done);
+
+			if (status & BIT(irq_idx_autorefresh))
+				_sde_rm_clear_irq_status(intr,
+					irq_idx_pp_done, irq_idx_autorefresh);
+			else
+				return 0;
 		}
 		usleep_range(delay_us, delay_us + 10);
 	}
+
+	SDE_EVT32(status, irq_idx_pp_done, SDE_EVTLOG_ERROR);
 	SDE_ERROR("polling timed out. status = 0x%x\n", status);
 	return -ETIMEDOUT;
 }
 
+static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp,
+		struct sde_hw_intr *hw_intr)
+{
+	u32 const timeout_ms = 35; /* Max two vsyncs delay */
+	int rc = 0, i, loop = 3;
+	struct sde_hw_pp_vsync_info info;
+	int irq_idx_pp_done = -1, irq_idx_autorefresh = -1;
+	struct sde_hw_autorefresh cfg = {0};
+
+	if (!pp->ops.get_autorefresh || !pp->ops.setup_autorefresh ||
+		!pp->ops.connect_external_te || !pp->ops.get_vsync_info) {
+		SDE_ERROR("autorefresh update api not supported\n");
+		return 0;
+	}
+
+	/* read default autorefresh configuration */
+	pp->ops.get_autorefresh(pp, &cfg);
+	if (!cfg.enable) {
+		SDE_DEBUG("autorefresh already disabled\n");
+		SDE_EVT32(pp->idx - PINGPONG_0, SDE_EVTLOG_FUNC_CASE1);
+		return 0;
+	}
+
+	/* disable external TE first */
+	pp->ops.connect_external_te(pp, false);
+
+	/* get all IRQ indexes */
+	if (hw_intr->ops.irq_idx_lookup) {
+		irq_idx_pp_done = hw_intr->ops.irq_idx_lookup(
+				SDE_IRQ_TYPE_PING_PONG_COMP, pp->idx);
+		irq_idx_autorefresh = hw_intr->ops.irq_idx_lookup(
+				SDE_IRQ_TYPE_PING_PONG_AUTO_REF, pp->idx);
+		SDE_DEBUG("pp_done itr_idx = %d autorefresh irq_idx:%d\n",
+				irq_idx_pp_done, irq_idx_autorefresh);
+	}
+
+	/* disable autorefresh */
+	cfg.enable = false;
+	pp->ops.setup_autorefresh(pp, &cfg);
+
+	SDE_EVT32(pp->idx - PINGPONG_0, irq_idx_pp_done, irq_idx_autorefresh);
+	_sde_rm_clear_irq_status(hw_intr, irq_idx_pp_done, irq_idx_autorefresh);
+
+	/*
+	 * Check the line count again if
+	 * the line count is equal to the active
+	 * height to make sure their is no
+	 * additional frame updates
+	 */
+	for (i = 0; i < loop; i++) {
+		info.wr_ptr_line_count = 0;
+		info.rd_ptr_init_val = 0;
+		pp->ops.get_vsync_info(pp, &info);
+
+		SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count,
+			info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE1);
+
+		/* wait for read ptr intr */
+		rc = _sde_rm_poll_intr_status_for_cont_splash(hw_intr,
+			irq_idx_pp_done, irq_idx_autorefresh, timeout_ms);
+
+		info.wr_ptr_line_count = 0;
+		info.rd_ptr_init_val = 0;
+		pp->ops.get_vsync_info(pp, &info);
+		SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count);
+
+		SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count,
+			info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE2);
+
+		/* log line count and return */
+		if (!rc)
+			break;
+		/*
+		 * Wait for few milli seconds for line count
+		 * to increase if any frame transfer is
+		 * pending.
+		 */
+		usleep_range(3000, 4000);
+	}
+
+	pp->ops.connect_external_te(pp, true);
+
+	return rc;
+}
+
 /**
  * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks
  *	and disable autorefresh if enabled.
@@ -1181,9 +1286,7 @@
 {
 	int index = 0;
 	int value, dsc_cnt = 0;
-	struct sde_hw_autorefresh cfg;
 	struct sde_rm_hw_iter iter_pp;
-	int irq_idx_pp_done = -1;
 
 	if (!rm || !sde_kms || !dsc_ids) {
 		SDE_ERROR("invalid input parameters\n");
@@ -1195,11 +1298,7 @@
 	while (_sde_rm_get_hw_locked(rm, &iter_pp)) {
 		struct sde_hw_pingpong *pp =
 				to_sde_hw_pingpong(iter_pp.blk->hw);
-		u32 intr_value = 0;
-		u32 const timeout_ms = 35; /* Max two vsyncs delay */
-		int rc = 0, i, loop = 2;
 		struct sde_hw_intr *hw_intr = NULL;
-		struct sde_hw_pp_vsync_info info;
 
 		if (!pp->ops.get_dsc_status) {
 			SDE_ERROR("get_dsc_status ops not initialized\n");
@@ -1219,70 +1318,7 @@
 		}
 		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)) {
-			if (hw_intr->ops.irq_idx_lookup) {
-				irq_idx_pp_done = hw_intr->ops.irq_idx_lookup
-					(SDE_IRQ_TYPE_PING_PONG_COMP,
-								pp->idx);
-				SDE_DEBUG(" itr_idx = %d\n", irq_idx_pp_done);
-			}
-
-			if ((irq_idx_pp_done >= 0) &&
-					(hw_intr->ops.get_intr_status_nomask)) {
-				intr_value = hw_intr->ops.get_intr_status_nomask
-					(hw_intr, irq_idx_pp_done, false);
-				hw_intr->ops.clear_intr_status_force_mask
-					(hw_intr, irq_idx_pp_done, intr_value);
-			}
-			cfg.enable = false;
-			SDE_DEBUG("Disabling autorefresh\n");
-			pp->ops.setup_autorefresh(pp, &cfg);
-
-			/*
-			 * Check the line count again if
-			 * the line count is equal to the active
-			 * height to make sure their is no
-			 * additional frame updates
-			 */
-			for (i = 0; i < loop; i++) {
-				info.wr_ptr_line_count = 0;
-				info.rd_ptr_init_val = 0;
-				if (pp->ops.get_vsync_info)
-					pp->ops.get_vsync_info(pp, &info);
-				/*
-				 * For cmd-mode using external-TE logic,
-				 * the rd_ptr_init_val is equal to
-				 * active-height. Use this init_val to
-				 * compare that with lane count. Need
-				 * to implement a different check
-				 * if external-TE is not used.
-				 */
-				if (info.wr_ptr_line_count
-						< info.rd_ptr_init_val) {
-					/* wait for read ptr intr */
-					rc =
-					_sde_rm_poll_intr_status_for_cont_splash
-					(hw_intr, irq_idx_pp_done, timeout_ms);
-					if (!rc)
-						break;
-				}
-				SDE_DEBUG("i=%d, line count=%d\n",
-						i, info.wr_ptr_line_count);
-				/*
-				 * Wait for few milli seconds for line count
-				 * to increase if any frame transfer is
-				 * pending.
-				 */
-				usleep_range(3000, 4000);
-			}
-		}
+		_sde_rm_autorefresh_disable(pp, hw_intr);
 	}
 
 	return dsc_cnt;
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
index 4ceed7a9..4b83e9e 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -638,7 +638,8 @@
 		match = of_match_node(dmm_of_match, dev->dev.of_node);
 		if (!match) {
 			dev_err(&dev->dev, "failed to find matching device node\n");
-			return -ENODEV;
+			ret = -ENODEV;
+			goto fail;
 		}
 
 		omap_dmm->plat_data = match->data;
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 094bc6a..d96c084 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -225,6 +225,9 @@
 	/* Clear any pending interrupts we might have left. */
 	V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
 
+	/* Finish any interrupt handler still in flight. */
+	disable_irq(dev->irq);
+
 	cancel_work_sync(&vc4->overflow_mem_work);
 }
 
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 7cc346a..ce7c21d 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -173,6 +173,9 @@
 	struct vc4_dev *vc4 = v3d->vc4;
 
 	vc4_v3d_init_hw(vc4->dev);
+
+	/* We disabled the IRQ as part of vc4_irq_uninstall in suspend. */
+	enable_irq(vc4->dev->irq);
 	vc4_irq_postinstall(vc4->dev);
 
 	return 0;
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index da37baf..2aff383 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -367,7 +367,7 @@
 		.major = 1,
 		.minor = 5,
 		.patchid = ANY_ID,
-		.features = ADRENO_64BIT | ADRENO_RPMH |
+		.features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_PREEMPTION |
 			ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC,
 		.sqefw_name = "a630_sqe.fw",
 		.zap_name = "a615_zap",
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 942621e..ab9f203 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -19,7 +19,6 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <soc/qcom/scm.h>
-#include <linux/nvmem-consumer.h>
 
 #include <linux/msm-bus-board.h>
 #include <linux/msm-bus.h>
@@ -614,7 +613,6 @@
 	struct adreno_irq *irq_params = gpudev->irq;
 	irqreturn_t ret = IRQ_NONE;
 	unsigned int status = 0, fence = 0, fence_retries = 0, tmp, int_bit;
-	unsigned int status_retries = 0;
 	int i;
 
 	atomic_inc(&adreno_dev->pending_irq_refcnt);
@@ -654,32 +652,6 @@
 	adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status);
 
 	/*
-	 * Read status again to make sure the bits aren't transitory.
-	 * Transitory bits mean that they are spurious interrupts and are
-	 * seen while preemption is on going. Empirical experiments have
-	 * shown that the transitory bits are a timing thing and they
-	 * go away in the small time window between two or three consecutive
-	 * reads. If they don't go away, log the message and return.
-	 */
-	while (status_retries < STATUS_RETRY_MAX) {
-		unsigned int new_status;
-
-		adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS,
-			&new_status);
-
-		if (status == new_status)
-			break;
-
-		status = new_status;
-		status_retries++;
-	}
-
-	if (status_retries == STATUS_RETRY_MAX) {
-		KGSL_DRV_CRIT_RATELIMIT(device, "STATUS bits are not stable\n");
-			return ret;
-	}
-
-	/*
 	 * Clear all the interrupt bits but ADRENO_INT_RBBM_AHB_ERROR. Because
 	 * even if we clear it here, it will stay high until it is cleared
 	 * in its respective handler. Otherwise, the interrupt handler will
@@ -772,64 +744,33 @@
 	{ ADRENO_QUIRK_SECVID_SET_ONCE, "qcom,gpu-quirk-secvid-set-once" },
 	{ ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW,
 			"qcom,gpu-quirk-limit-uche-gbif-rw" },
+	{ ADRENO_QUIRK_MMU_SECURE_CB_ALT, "qcom,gpu-quirk-mmu-secure-cb-alt" },
 };
 
-#if defined(CONFIG_NVMEM) && defined(CONFIG_QCOM_QFPROM)
 static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
+adreno_get_soc_hw_revision_node(struct adreno_device *adreno_dev,
+	struct platform_device *pdev)
 {
 	struct device_node *node, *child;
-	struct nvmem_cell *cell;
-	ssize_t len;
-	u32 *buf, hw_rev, rev;
+	unsigned int rev;
 
 	node = of_find_node_by_name(pdev->dev.of_node, "qcom,soc-hw-revisions");
 	if (node == NULL)
-		goto err;
-
-	/* read the soc hw revision and select revision node */
-	cell = nvmem_cell_get(&pdev->dev, "minor_rev");
-	if (IS_ERR_OR_NULL(cell)) {
-		if (PTR_ERR(cell) == -EPROBE_DEFER)
-			return (void *)cell;
-
-		KGSL_CORE_ERR("Unable to get nvmem cell: ret=%ld\n",
-				PTR_ERR(cell));
-		goto err;
-	}
-
-	buf = nvmem_cell_read(cell, &len);
-	nvmem_cell_put(cell);
-
-	if (IS_ERR_OR_NULL(buf)) {
-		KGSL_CORE_ERR("Unable to read nvmem cell: ret=%ld\n",
-				PTR_ERR(buf));
-		goto err;
-	}
-
-	hw_rev = *buf;
-	kfree(buf);
+		return NULL;
 
 	for_each_child_of_node(node, child) {
-		if (of_property_read_u32(child, "reg", &rev))
+		if (of_property_read_u32(child, "qcom,soc-hw-revision", &rev))
 			continue;
 
-		if (rev == hw_rev)
+		if (rev == adreno_dev->soc_hw_rev)
 			return child;
 	}
 
-err:
-	/* fall back to parent node */
-	return pdev->dev.of_node;
+	KGSL_DRV_WARN(KGSL_DEVICE(adreno_dev),
+		"No matching SOC HW revision found for efused HW rev=%u\n",
+		adreno_dev->soc_hw_rev);
+	return NULL;
 }
-#else
-static struct device_node *
-adreno_get_soc_hw_revision_node(struct platform_device *pdev)
-{
-	return pdev->dev.of_node;
-}
-#endif
-
 
 static int adreno_update_soc_hw_revision_quirks(
 		struct adreno_device *adreno_dev, struct platform_device *pdev)
@@ -837,9 +778,9 @@
 	struct device_node *node;
 	int i;
 
-	node = adreno_get_soc_hw_revision_node(pdev);
-	if (IS_ERR(node))
-		return PTR_ERR(node);
+	node = adreno_get_soc_hw_revision_node(adreno_dev, pdev);
+	if (node == NULL)
+		node = pdev->dev.of_node;
 
 	/* get chip id, fall back to parent if revision node does not have it */
 	if (of_property_read_u32(node, "qcom,chipid", &adreno_dev->chipid))
@@ -1158,6 +1099,36 @@
 		KGSL_DRV_WARN(device, "cx_dbgc ioremap failed\n");
 }
 
+static void adreno_efuse_read_soc_hw_rev(struct adreno_device *adreno_dev)
+{
+	unsigned int val;
+	unsigned int soc_hw_rev[3];
+	int ret;
+
+	if (of_property_read_u32_array(
+		KGSL_DEVICE(adreno_dev)->pdev->dev.of_node,
+		"qcom,soc-hw-rev-efuse", soc_hw_rev, 3))
+		return;
+
+	ret = adreno_efuse_map(adreno_dev);
+	if (ret) {
+		KGSL_CORE_ERR(
+			"Unable to map hardware revision fuse: ret=%d\n", ret);
+		return;
+	}
+
+	ret = adreno_efuse_read_u32(adreno_dev, soc_hw_rev[0], &val);
+	adreno_efuse_unmap(adreno_dev);
+
+	if (ret) {
+		KGSL_CORE_ERR(
+			"Unable to read hardware revision fuse: ret=%d\n", ret);
+		return;
+	}
+
+	adreno_dev->soc_hw_rev = (val >> soc_hw_rev[1]) & soc_hw_rev[2];
+}
+
 static bool adreno_is_gpu_disabled(struct adreno_device *adreno_dev)
 {
 	unsigned int row0;
@@ -1206,11 +1177,10 @@
 		return -ENODEV;
 	}
 
-	status = adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
-	if (status) {
-		device->pdev = NULL;
-		return status;
-	}
+	/* Identify SOC hardware revision to be used */
+	adreno_efuse_read_soc_hw_rev(adreno_dev);
+
+	adreno_update_soc_hw_revision_quirks(adreno_dev, pdev);
 
 	/* Get the chip ID from the DT and set up target specific parameters */
 	adreno_identify_gpu(adreno_dev);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 4fb0089..8785d62 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -150,6 +150,8 @@
  * between GBIF, SMMU and MEMNOC.
  */
 #define ADRENO_QUIRK_LIMIT_UCHE_GBIF_RW BIT(8)
+/* Select alternate secure context bank for mmu */
+#define ADRENO_QUIRK_MMU_SECURE_CB_ALT BIT(9)
 
 /* Flags to control command packet settings */
 #define KGSL_CMD_FLAGS_NONE             0
@@ -175,9 +177,6 @@
 /* Number of times to poll the AHB fence in ISR */
 #define FENCE_RETRY_MAX 100
 
-/* Number of times to see if INT_0_STATUS changed or not */
-#define STATUS_RETRY_MAX 3
-
 /* One cannot wait forever for the core to idle, so set an upper limit to the
  * amount of time to wait for the core to go idle
  */
@@ -468,6 +467,7 @@
  * @gpuhtw_llc_slice: GPU pagetables system cache slice descriptor
  * @gpuhtw_llc_slice_enable: To enable the GPUHTW system cache slice or not
  * @zap_loaded: Used to track if zap was successfully loaded or not
+ * @soc_hw_rev: Indicate which SOC hardware revision to use
  */
 struct adreno_device {
 	struct kgsl_device dev;    /* Must be first field in this struct */
@@ -540,6 +540,7 @@
 	void *gpuhtw_llc_slice;
 	bool gpuhtw_llc_slice_enable;
 	unsigned int zap_loaded;
+	unsigned int soc_hw_rev;
 };
 
 /**
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index d8b347d..7b783a9 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1273,7 +1273,7 @@
 	wmb();
 }
 
-#define GMU_START_TIMEOUT	10	/* ms */
+#define GMU_START_TIMEOUT	100	/* ms */
 #define GPU_START_TIMEOUT	100	/* ms */
 #define GPU_RESET_TIMEOUT	1	/* ms */
 #define GPU_RESET_TIMEOUT_US	10	/* us */
@@ -2031,17 +2031,17 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct gmu_device *gmu = &device->gmu;
-	unsigned int status, status2;
+	unsigned int status2;
+	uint64_t ts1;
 
+	ts1 = read_AO_counter(device);
 	if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS,
 			0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
 		kgsl_gmu_regread(device,
-				A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, &status);
-		kgsl_gmu_regread(device,
 				A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2, &status2);
 		dev_err(&gmu->pdev->dev,
-				"GMU not idling: status=0x%x, status2=0x%x\n",
-				status, status2);
+				"GMU not idling: status2=0x%x %llx %llx\n",
+				status2, ts1, read_AO_counter(device));
 		return -ETIMEDOUT;
 	}
 
diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c
index b9dd5f4..97b0cb2 100644
--- a/drivers/gpu/msm/adreno_a6xx_preempt.c
+++ b/drivers/gpu/msm/adreno_a6xx_preempt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -370,14 +370,6 @@
 	/* Trigger the preemption */
 	adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_PREEMPT, cntl,
 		FENCE_STATUS_WRITEDROPPED1_MASK);
-
-	/*
-	 * Once preemption has been requested with the final register write,
-	 * the preemption process starts and the GPU is considered busy.
-	 * We can now safely clear the preemption keepalive bit, allowing
-	 * power collapse to resume its regular activity.
-	 */
-	kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x2, 0x0);
 }
 
 void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit)
@@ -405,6 +397,13 @@
 		return;
 	}
 
+	/*
+	 * We can now safely clear the preemption keepalive bit, allowing
+	 * power collapse to resume its regular activity.
+	 */
+	kgsl_gmu_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GMU_AO_SPARE_CNTL, 0x2,
+			0x0);
+
 	del_timer(&adreno_dev->preempt.timer);
 
 	adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_LEVEL_STATUS, &status);
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 97f2c58..afd1be5 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -376,6 +376,7 @@
 	A6XX_DBGBUS_CX           = 0x17,
 	A6XX_DBGBUS_GMU_GX       = 0x18,
 	A6XX_DBGBUS_TPFCHE       = 0x19,
+	A6XX_DBGBUS_GBIF_GX      = 0x1a,
 	A6XX_DBGBUS_GPC          = 0x1d,
 	A6XX_DBGBUS_LARC         = 0x1e,
 	A6XX_DBGBUS_HLSQ_SPTP    = 0x1f,
@@ -1161,11 +1162,14 @@
 	}
 
 	header->id = block->block_id;
+	if ((block->block_id == A6XX_DBGBUS_VBIF) &&
+		adreno_has_gbif(adreno_dev))
+		header->id = A6XX_DBGBUS_GBIF_GX;
 	header->count = dwords * 2;
 
 	block_id = block->block_id;
 	/* GMU_GX data is read using the GMU_CX block id on A630 */
-	if (adreno_is_a630(adreno_dev) &&
+	if ((adreno_is_a630(adreno_dev) || adreno_is_a615(adreno_dev)) &&
 		(block_id == A6XX_DBGBUS_GMU_GX))
 		block_id = A6XX_DBGBUS_GMU_CX;
 
@@ -1428,18 +1432,18 @@
 				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);
 		}
+		/*
+		 * 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);
 	}
 }
 
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 472f78e..9a878fb 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2253,6 +2253,14 @@
 
 	atomic_add(halt, &adreno_dev->halt);
 
+	/*
+	 * At this point it is safe to assume that we recovered. Setting
+	 * this field allows us to take a new snapshot for the next failure
+	 * if we are prioritizing the first unrecoverable snapshot.
+	 */
+	if (device->snapshot)
+		device->snapshot->recovered = true;
+
 	return 1;
 }
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 5168d9e..a8075fe 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -261,7 +261,8 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
-	int i, status;
+	int i;
+	int status = -ENOMEM;
 
 	if (!adreno_is_a3xx(adreno_dev)) {
 		status = kgsl_allocate_global(device, &device->scratch,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index f57fbb6..5039a06 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2998,7 +2998,7 @@
 	long ret = 0;
 	bool full_flush = false;
 	uint64_t size = 0;
-	int i, count = 0;
+	int i;
 	void __user *ptr;
 
 	if (param->count == 0 || param->count > 128)
@@ -3010,8 +3010,8 @@
 
 	entries = kcalloc(param->count, sizeof(*entries), GFP_KERNEL);
 	if (entries == NULL) {
-		ret = -ENOMEM;
-		goto out;
+		kfree(objs);
+		return -ENOMEM;
 	}
 
 	ptr = to_user_ptr(param->objs);
@@ -3028,8 +3028,6 @@
 		if (entries[i] == NULL)
 			continue;
 
-		count++;
-
 		if (!(objs[i].op & KGSL_GPUMEM_CACHE_RANGE))
 			size += entries[i]->memdesc.size;
 		else if (objs[i].offset < entries[i]->memdesc.size)
@@ -3038,25 +3036,23 @@
 		full_flush = check_full_flush(size, objs[i].op);
 		if (full_flush) {
 			trace_kgsl_mem_sync_full_cache(i, size);
-			break;
+			goto out;
 		}
 
 		ptr += sizeof(*objs);
 	}
 
-	if (!full_flush) {
-		for (i = 0; !ret && i < param->count; i++)
-			if (entries[i])
-				ret = _kgsl_gpumem_sync_cache(entries[i],
-						objs[i].offset, objs[i].length,
-						objs[i].op);
-	}
+	for (i = 0; !ret && i < param->count; i++)
+		if (entries[i])
+			ret = _kgsl_gpumem_sync_cache(entries[i],
+					objs[i].offset, objs[i].length,
+					objs[i].op);
 
+out:
 	for (i = 0; i < param->count; i++)
 		if (entries[i])
 			kgsl_mem_entry_put(entries[i]);
 
-out:
 	kfree(entries);
 	kfree(objs);
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7c3bff7..b6a2edb 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -303,6 +303,7 @@
 
 	u32 snapshot_faultcount;	/* Total number of faults since boot */
 	bool force_panic;		/* Force panic after snapshot dump */
+	bool prioritize_unrecoverable;	/* Overwrite with new GMU snapshots */
 
 	/* Use CP Crash dumper to get GPU snapshot*/
 	bool snapshot_crashdumper;
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 52d45bb..10446f7 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1638,6 +1638,8 @@
 		unsigned int fence_mask)
 {
 	unsigned int status, i;
+	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+	unsigned int reg_offset = gpudev->reg_offsets->offsets[offset];
 
 	adreno_writereg(adreno_dev, offset, val);
 
@@ -1662,6 +1664,6 @@
 	}
 
 	dev_err(adreno_dev->dev.dev,
-		"GMU fenced register write timed out: reg %x\n", offset);
+		"GMU fenced register write timed out: reg 0x%x\n", reg_offset);
 	return -ETIMEDOUT;
 }
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 4b11bbe..c4296c8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -165,14 +165,19 @@
 }
 
 void kgsl_iommu_unmap_global_secure_pt_entry(struct kgsl_device *device,
-				struct kgsl_memdesc *entry)
+				struct kgsl_memdesc *memdesc)
 {
-	if (!kgsl_mmu_is_secured(&device->mmu))
+	if (!kgsl_mmu_is_secured(&device->mmu) || memdesc == NULL)
 		return;
 
-	if (entry != NULL && entry->pagetable->name == KGSL_MMU_SECURE_PT)
-		kgsl_mmu_unmap(entry->pagetable, entry);
+	/* Check if an empty memdesc got passed in */
+	if ((memdesc->gpuaddr == 0) || (memdesc->size == 0))
+		return;
 
+	if (memdesc->pagetable) {
+		if (memdesc->pagetable->name == KGSL_MMU_SECURE_PT)
+			kgsl_mmu_unmap(memdesc->pagetable, memdesc);
+	}
 }
 
 int kgsl_iommu_map_global_secure_pt_entry(struct kgsl_device *device,
@@ -2522,6 +2527,7 @@
 } kgsl_iommu_cbs[] = {
 	{ KGSL_IOMMU_CONTEXT_USER, "gfx3d_user", },
 	{ KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure" },
+	{ KGSL_IOMMU_CONTEXT_SECURE, "gfx3d_secure_alt" },
 };
 
 static int _kgsl_iommu_cb_probe(struct kgsl_device *device,
@@ -2529,12 +2535,20 @@
 {
 	struct platform_device *pdev = of_find_device_by_node(node);
 	struct kgsl_iommu_context *ctx = NULL;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(kgsl_iommu_cbs); i++) {
 		if (!strcmp(node->name, kgsl_iommu_cbs[i].name)) {
 			int id = kgsl_iommu_cbs[i].id;
 
+			if (ADRENO_QUIRK(adreno_dev,
+				ADRENO_QUIRK_MMU_SECURE_CB_ALT)) {
+				if (!strcmp(node->name, "gfx3d_secure"))
+					continue;
+			} else if (!strcmp(node->name, "gfx3d_secure_alt"))
+				continue;
+
 			ctx = &iommu->ctx[id];
 			ctx->id = id;
 			ctx->cb_num = -1;
@@ -2545,8 +2559,8 @@
 	}
 
 	if (ctx == NULL) {
-		KGSL_CORE_ERR("dt: Unknown context label %s\n", node->name);
-		return -EINVAL;
+		KGSL_CORE_ERR("dt: Unused context label %s\n", node->name);
+		return 0;
 	}
 
 	if (ctx->id == KGSL_IOMMU_CONTEXT_SECURE)
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index 462ff3b..65460f7 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -25,7 +25,7 @@
  */
 #define KGSL_IOMMU_GLOBAL_MEM_SIZE	(20 * SZ_1M)
 #define KGSL_IOMMU_GLOBAL_MEM_BASE32	0xf8000000
-#define KGSL_IOMMU_GLOBAL_MEM_BASE64	TASK_SIZE_32
+#define KGSL_IOMMU_GLOBAL_MEM_BASE64	0xfc000000
 
 #define KGSL_IOMMU_GLOBAL_MEM_BASE(__mmu)	\
 	(MMU_FEATURE(__mmu, KGSL_MMU_64BIT) ? \
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 7509ceb..2cd132e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2222,7 +2222,7 @@
 
 int kgsl_pwrctrl_init(struct kgsl_device *device)
 {
-	int i, k, m, n = 0, result;
+	int i, k, m, n = 0, result, freq;
 	struct platform_device *pdev = device->pdev;
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct device_node *ocmem_bus_node;
@@ -2269,7 +2269,7 @@
 	pwr->wakeup_maxpwrlevel = 0;
 
 	for (i = 0; i < pwr->num_pwrlevels; i++) {
-		unsigned int freq = pwr->pwrlevels[i].gpu_freq;
+		freq = pwr->pwrlevels[i].gpu_freq;
 
 		if (freq > 0)
 			freq = clk_round_rate(pwr->grp_clks[0], freq);
@@ -2282,11 +2282,10 @@
 
 	kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
 
-	if (pwr->grp_clks[6] != NULL)
+	freq = clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ);
+	if (freq > 0)
 		kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[6],
-			clk_round_rate(pwr->grp_clks[6],
-			KGSL_RBBMTIMER_CLK_FREQ),
-			clocks[6]);
+			freq, clocks[6]);
 
 	_isense_clk_set_rate(pwr, pwr->num_pwrlevels - 1);
 
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index c4ff22f..3f7ea18 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -910,12 +910,12 @@
 	min_level = pwr->thermal_pwrlevel_floor;
 
 	/* Thermal limit cannot be lower than lowest non-zero operating freq */
-	for (level = 0; level < (pwr->num_pwrlevels - 1); level++)
+	for (level = 0; level < (pwr->num_pwrlevels - 1); level++) {
 		if (pwr->pwrlevels[level].gpu_freq == max_freq)
 			max_level = level;
 		if (pwr->pwrlevels[level].gpu_freq == min_freq)
 			min_level = level;
-
+	}
 
 	pwr->thermal_pwrlevel = max_level;
 	pwr->thermal_pwrlevel_floor = min_level;
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 33ce60d..5e41611 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -663,7 +663,8 @@
 	 * Overwrite a non-GMU fault snapshot if a GMU fault occurs.
 	 */
 	if (device->snapshot != NULL) {
-		if (!gmu_fault || !device->snapshot->recovered)
+		if (!device->prioritize_unrecoverable ||
+				!device->snapshot->recovered)
 			return;
 
 		/*
@@ -954,6 +955,28 @@
 	return (ssize_t) ret < 0 ? ret : count;
 }
 
+/* Show the prioritize_unrecoverable status */
+static ssize_t prioritize_unrecoverable_show(
+		struct kgsl_device *device, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			device->prioritize_unrecoverable);
+}
+
+/* Store the priority value to prioritize unrecoverable */
+static ssize_t prioritize_unrecoverable_store(
+		struct kgsl_device *device, const char *buf, size_t count)
+{
+	unsigned int val = 0;
+	int ret = 0;
+
+	ret = kgsl_sysfs_store(buf, &val);
+	if (!ret && device)
+		device->prioritize_unrecoverable = (bool) val;
+
+	return (ssize_t) ret < 0 ? ret : count;
+}
+
 /* Show the snapshot_crashdumper request status */
 static ssize_t snapshot_crashdumper_show(struct kgsl_device *device, char *buf)
 {
@@ -1026,6 +1049,8 @@
 static SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
 static SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
 static SNAPSHOT_ATTR(force_panic, 0644, force_panic_show, force_panic_store);
+static SNAPSHOT_ATTR(prioritize_unrecoverable, 0644,
+		prioritize_unrecoverable_show, prioritize_unrecoverable_store);
 static SNAPSHOT_ATTR(snapshot_crashdumper, 0644, snapshot_crashdumper_show,
 	snapshot_crashdumper_store);
 static SNAPSHOT_ATTR(snapshot_legacy, 0644, snapshot_legacy_show,
@@ -1110,6 +1135,7 @@
 	device->snapshot = NULL;
 	device->snapshot_faultcount = 0;
 	device->force_panic = 0;
+	device->prioritize_unrecoverable = true;
 	device->snapshot_crashdumper = 1;
 	device->snapshot_legacy = 0;
 
@@ -1135,6 +1161,11 @@
 	if (ret)
 		goto done;
 
+	ret = sysfs_create_file(&device->snapshot_kobj,
+			&attr_prioritize_unrecoverable.attr);
+	if (ret)
+		goto done;
+
 	ret  = sysfs_create_file(&device->snapshot_kobj,
 			&attr_snapshot_crashdumper.attr);
 	if (ret)
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index d4165b3..a4de6a0 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -734,7 +734,8 @@
 			fput(sync_file->file);
 		else if (sfence)
 			fence_put(&sfence->fence);
-		kgsl_syncsource_put(syncsource);
+		else
+			kgsl_syncsource_put(syncsource);
 	}
 
 	return ret;
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index d72dfb2..7a4d39c 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -2192,23 +2192,23 @@
 	int i;
 	unsigned long flags;
 
-	spin_lock_irqsave(&remote->remote_lock, flags);
-	remote->remotes[index].registered = false;
-	spin_unlock_irqrestore(&remote->remote_lock, flags);
-
-	if (remote->remotes[index].battery.battery)
-		devres_release_group(&wacom->hdev->dev,
-				     &remote->remotes[index].battery.bat_desc);
-
-	if (remote->remotes[index].group.name)
-		devres_release_group(&wacom->hdev->dev,
-				     &remote->remotes[index]);
-
 	for (i = 0; i < WACOM_MAX_REMOTES; i++) {
 		if (remote->remotes[i].serial == serial) {
+
+			spin_lock_irqsave(&remote->remote_lock, flags);
+			remote->remotes[i].registered = false;
+			spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+			if (remote->remotes[i].battery.battery)
+				devres_release_group(&wacom->hdev->dev,
+						     &remote->remotes[i].battery.bat_desc);
+
+			if (remote->remotes[i].group.name)
+				devres_release_group(&wacom->hdev->dev,
+						     &remote->remotes[i]);
+
 			remote->remotes[i].serial = 0;
 			remote->remotes[i].group.name = NULL;
-			remote->remotes[i].registered = false;
 			remote->remotes[i].battery.battery = NULL;
 			wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
 		}
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index ba59eae..d013acf 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -20,6 +20,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -476,8 +477,8 @@
 static long pmbus_reg2data_direct(struct pmbus_data *data,
 				  struct pmbus_sensor *sensor)
 {
-	long val = (s16) sensor->data;
-	long m, b, R;
+	s64 b, val = (s16)sensor->data;
+	s32 m, R;
 
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
@@ -505,11 +506,12 @@
 		R--;
 	}
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val = div_s64(val + 5LL, 10L);  /* round closest */
 		R++;
 	}
 
-	return (val - b) / m;
+	val = div_s64(val - b, m);
+	return clamp_val(val, LONG_MIN, LONG_MAX);
 }
 
 /*
@@ -629,7 +631,8 @@
 static u16 pmbus_data2reg_direct(struct pmbus_data *data,
 				 struct pmbus_sensor *sensor, long val)
 {
-	long m, b, R;
+	s64 b, val64 = val;
+	s32 m, R;
 
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
@@ -646,18 +649,18 @@
 		R -= 3;		/* Adjust R and b for data in milli-units */
 		b *= 1000;
 	}
-	val = val * m + b;
+	val64 = val64 * m + b;
 
 	while (R > 0) {
-		val *= 10;
+		val64 *= 10;
 		R--;
 	}
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val64 = div_s64(val64 + 5LL, 10L);  /* round closest */
 		R++;
 	}
 
-	return val;
+	return (u16)clamp_val(val64, S16_MIN, S16_MAX);
 }
 
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c
index 7ef2710..81889b6 100644
--- a/drivers/hwtracing/coresight/coresight-byte-cntr.c
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,17 +23,23 @@
 static struct tmc_drvdata *tmcdrvdata;
 
 static void tmc_etr_read_bytes(struct byte_cntr *byte_cntr_data, loff_t *ppos,
-			       size_t bytes, size_t *len)
+			       size_t bytes, size_t *len, char **bufp)
 {
-	if (*len >= bytes) {
-		atomic_dec(&byte_cntr_data->irq_cnt);
+
+	if (*bufp >= (char *)(tmcdrvdata->vaddr + tmcdrvdata->size))
+		*bufp = tmcdrvdata->vaddr;
+
+	if (*len >= bytes)
 		*len = bytes;
-	} else {
-		if (((uint32_t)*ppos % bytes) + *len > bytes)
-			*len = bytes - ((uint32_t)*ppos % bytes);
-		if ((*len + (uint32_t)*ppos) % bytes == 0)
-			atomic_dec(&byte_cntr_data->irq_cnt);
-	}
+	else if (((uint32_t)*ppos % bytes) + *len > bytes)
+		*len = bytes - ((uint32_t)*ppos % bytes);
+
+	if ((*bufp + *len) > (char *)(tmcdrvdata->vaddr +
+		tmcdrvdata->size))
+		*len = (char *)(tmcdrvdata->vaddr + tmcdrvdata->size) -
+			*bufp;
+	if (*len == bytes || (*len + (uint32_t)*ppos) % bytes == 0)
+		atomic_dec(&byte_cntr_data->irq_cnt);
 }
 
 static void tmc_etr_sg_read_pos(loff_t *ppos,
@@ -96,7 +102,7 @@
 		if (*len >= (bytes - ((uint32_t)*ppos % bytes)))
 			*len = bytes - ((uint32_t)*ppos % bytes);
 
-		if ((*len + (uint32_t)*ppos) % bytes == 0)
+		if (*len == bytes || (*len + (uint32_t)*ppos) % bytes == 0)
 			atomic_dec(&tmcdrvdata->byte_cntr->irq_cnt);
 	}
 
@@ -153,11 +159,12 @@
 			if (!byte_cntr_data->read_active)
 				goto err0;
 		}
-		bufp = (char *)(tmcdrvdata->vaddr + *ppos);
+		bufp = (char *)(tmcdrvdata->buf + *ppos);
 
 		if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
 			tmc_etr_read_bytes(byte_cntr_data, ppos,
-					   byte_cntr_data->block_size, &len);
+					   byte_cntr_data->block_size, &len,
+					   &bufp);
 		else
 			tmc_etr_sg_read_pos(ppos, byte_cntr_data->block_size, 0,
 					    &len, &bufp);
@@ -179,7 +186,7 @@
 			if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
 				tmc_etr_read_bytes(byte_cntr_data, ppos,
 						   byte_cntr_data->block_size,
-						   &len);
+						   &len, &bufp);
 			else
 				tmc_etr_sg_read_pos(ppos,
 						    byte_cntr_data->block_size,
@@ -229,7 +236,7 @@
 
 	mutex_lock(&byte_cntr_data->byte_cntr_lock);
 	byte_cntr_data->enable = false;
-	coresight_csr_set_byte_cntr(0);
+	coresight_csr_set_byte_cntr(byte_cntr_data->csr, 0);
 	mutex_unlock(&byte_cntr_data->byte_cntr_lock);
 
 }
@@ -243,7 +250,7 @@
 	mutex_lock(&byte_cntr_data->byte_cntr_lock);
 	byte_cntr_data->read_active = false;
 
-	coresight_csr_set_byte_cntr(0);
+	coresight_csr_set_byte_cntr(byte_cntr_data->csr, 0);
 	mutex_unlock(&byte_cntr_data->byte_cntr_lock);
 
 	return 0;
@@ -261,7 +268,8 @@
 		return -EINVAL;
 	}
 
-	coresight_csr_set_byte_cntr(byte_cntr_data->block_size);
+	coresight_csr_set_byte_cntr(byte_cntr_data->csr,
+				byte_cntr_data->block_size);
 	fp->private_data = byte_cntr_data;
 	nonseekable_open(in, fp);
 	byte_cntr_data->enable = true;
@@ -364,6 +372,7 @@
 
 	tmcdrvdata = drvdata;
 	byte_cntr_data->byte_cntr_irq = byte_cntr_irq;
+	byte_cntr_data->csr = drvdata->csr;
 	atomic_set(&byte_cntr_data->irq_cnt, 0);
 	init_waitqueue_head(&byte_cntr_data->wq);
 	mutex_init(&byte_cntr_data->byte_cntr_lock);
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.h b/drivers/hwtracing/coresight/coresight-byte-cntr.h
index 94e9089..b104d92 100644
--- a/drivers/hwtracing/coresight/coresight-byte-cntr.h
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.h
@@ -16,6 +16,7 @@
 	atomic_t		irq_cnt;
 	wait_queue_head_t	wq;
 	struct mutex		byte_cntr_lock;
+	struct coresight_csr		*csr;
 };
 
 extern void tmc_etr_byte_cntr_start(struct byte_cntr *byte_cntr_data);
diff --git a/drivers/hwtracing/coresight/coresight-csr.c b/drivers/hwtracing/coresight/coresight-csr.c
index 1ec73a5..9069530 100644
--- a/drivers/hwtracing/coresight/coresight-csr.c
+++ b/drivers/hwtracing/coresight/coresight-csr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, 2015-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 2015-2016,2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/coresight.h>
+#include <linux/clk.h>
 
 #include "coresight-priv.h"
 
@@ -77,15 +78,32 @@
 	struct device		*dev;
 	struct coresight_device	*csdev;
 	uint32_t		blksize;
+	struct coresight_csr		csr;
+	struct clk		*clk;
+	spinlock_t		spin_lock;
+	bool			usb_bam_support;
+	bool			hwctrl_set_support;
+	bool			set_byte_cntr_support;
+	bool			timestamp_support;
 };
 
-static struct csr_drvdata *csrdrvdata;
+static LIST_HEAD(csr_list);
+#define to_csr_drvdata(c) container_of(c, struct csr_drvdata, csr)
 
-void msm_qdss_csr_enable_bam_to_usb(void)
+void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	uint32_t usbbamctrl, usbflshctrl;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
@@ -102,14 +120,24 @@
 	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(msm_qdss_csr_enable_bam_to_usb);
 
-void msm_qdss_csr_disable_bam_to_usb(void)
+void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	uint32_t usbbamctrl;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	usbbamctrl = csr_readl(drvdata, CSR_USBBAMCTRL);
@@ -117,14 +145,24 @@
 	csr_writel(drvdata, usbbamctrl, CSR_USBBAMCTRL);
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(msm_qdss_csr_disable_bam_to_usb);
 
-void msm_qdss_csr_disable_flush(void)
+void msm_qdss_csr_disable_flush(struct coresight_csr *csr)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	uint32_t usbflshctrl;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->usb_bam_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	usbflshctrl = csr_readl(drvdata, CSR_USBFLSHCTRL);
@@ -132,14 +170,25 @@
 	csr_writel(drvdata, usbflshctrl, CSR_USBFLSHCTRL);
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
 
-int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val)
+int coresight_csr_hwctrl_set(struct coresight_csr *csr, uint64_t addr,
+			 uint32_t val)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
 	int ret = 0;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return -EINVAL;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->hwctrl_set_support)
+		return -EINVAL;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL0))
@@ -154,15 +203,24 @@
 		ret = -EINVAL;
 
 	CSR_LOCK(drvdata);
-
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(coresight_csr_hwctrl_set);
 
-void coresight_csr_set_byte_cntr(uint32_t count)
+void coresight_csr_set_byte_cntr(struct coresight_csr *csr, uint32_t count)
 {
-	struct csr_drvdata *drvdata = csrdrvdata;
+	struct csr_drvdata *drvdata;
+	unsigned long flags;
 
+	if (csr == NULL)
+		return;
+
+	drvdata = to_csr_drvdata(csr);
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->set_byte_cntr_support)
+		return;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	CSR_UNLOCK(drvdata);
 
 	csr_writel(drvdata, count, CSR_BYTECNTVAL);
@@ -171,9 +229,85 @@
 	mb();
 
 	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 }
 EXPORT_SYMBOL(coresight_csr_set_byte_cntr);
 
+struct coresight_csr *coresight_csr_get(const char *name)
+{
+	struct coresight_csr *csr;
+
+	list_for_each_entry(csr, &csr_list, link) {
+		if (!strcmp(csr->name, name))
+			return csr;
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL(coresight_csr_get);
+
+static ssize_t csr_show_timestamp(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	ssize_t size = 0;
+	uint64_t time_tick = 0;
+	uint32_t val, time_val0, time_val1;
+	int ret;
+	unsigned long flags;
+
+	struct csr_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+	if (IS_ERR_OR_NULL(drvdata) || !drvdata->timestamp_support) {
+		dev_err(dev, "Invalid param\n");
+		return 0;
+	}
+
+	ret = clk_prepare_enable(drvdata->clk);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
+	CSR_UNLOCK(drvdata);
+
+	val = csr_readl(drvdata, CSR_TIMESTAMPCTRL);
+
+	val  = val & ~BIT(0);
+	csr_writel(drvdata, val, CSR_TIMESTAMPCTRL);
+
+	val  = val | BIT(0);
+	csr_writel(drvdata, val, CSR_TIMESTAMPCTRL);
+
+	time_val0 = csr_readl(drvdata, CSR_QDSSTIMEVAL0);
+	time_val1 = csr_readl(drvdata, CSR_QDSSTIMEVAL1);
+
+	CSR_LOCK(drvdata);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
+
+	clk_disable_unprepare(drvdata->clk);
+
+	time_tick |= (uint64_t)time_val1 << 32;
+	time_tick |= (uint64_t)time_val0;
+	size = scnprintf(buf, PAGE_SIZE, "%llu\n", time_tick);
+	dev_dbg(dev, "timestamp : %s\n", buf);
+	return size;
+}
+
+static DEVICE_ATTR(timestamp, 0444, csr_show_timestamp, NULL);
+
+static struct attribute *csr_attrs[] = {
+	&dev_attr_timestamp.attr,
+	NULL,
+};
+
+static struct attribute_group csr_attr_grp = {
+	.attrs = csr_attrs,
+};
+static const struct attribute_group *csr_attr_grps[] = {
+	&csr_attr_grp,
+	NULL,
+};
+
 static int csr_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -194,6 +328,10 @@
 	drvdata->dev = &pdev->dev;
 	platform_set_drvdata(pdev, drvdata);
 
+	drvdata->clk = devm_clk_get(dev, "apb_pclk");
+	if (IS_ERR(drvdata->clk))
+		dev_dbg(dev, "csr not config clk\n");
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
 	if (!res)
 		return -ENODEV;
@@ -208,27 +346,65 @@
 	if (ret)
 		drvdata->blksize = BLKSIZE_256;
 
+	drvdata->usb_bam_support = of_property_read_bool(pdev->dev.of_node,
+						"qcom,usb-bam-support");
+	if (!drvdata->usb_bam_support)
+		dev_dbg(dev, "usb_bam support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "usb_bam operation supported\n");
+
+	drvdata->hwctrl_set_support = of_property_read_bool(pdev->dev.of_node,
+						"qcom,hwctrl-set-support");
+	if (!drvdata->hwctrl_set_support)
+		dev_dbg(dev, "hwctrl_set_support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "hwctrl_set_support operation supported\n");
+
+	drvdata->set_byte_cntr_support = of_property_read_bool(
+			pdev->dev.of_node, "qcom,set-byte-cntr-support");
+	if (!drvdata->set_byte_cntr_support)
+		dev_dbg(dev, "set byte_cntr_support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "set_byte_cntr_support operation supported\n");
+
+	drvdata->timestamp_support = of_property_read_bool(pdev->dev.of_node,
+						"qcom,timestamp-support");
+	if (!drvdata->timestamp_support)
+		dev_dbg(dev, "timestamp_support handled by other subsystem\n");
+	else
+		dev_dbg(dev, "timestamp_support operation supported\n");
+
 	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc)
 		return -ENOMEM;
 	desc->type = CORESIGHT_DEV_TYPE_NONE;
 	desc->pdata = pdev->dev.platform_data;
 	desc->dev = &pdev->dev;
+	if (drvdata->timestamp_support)
+		desc->groups = csr_attr_grps;
+
 	drvdata->csdev = coresight_register(desc);
 	if (IS_ERR(drvdata->csdev))
 		return PTR_ERR(drvdata->csdev);
 
 	/* Store the driver data pointer for use in exported functions */
-	csrdrvdata = drvdata;
-	dev_info(dev, "CSR initialized\n");
+	spin_lock_init(&drvdata->spin_lock);
+	drvdata->csr.name = ((struct coresight_platform_data *)
+					 (pdev->dev.platform_data))->name;
+	list_add_tail(&drvdata->csr.link, &csr_list);
+
+	dev_info(dev, "CSR initialized: %s\n", drvdata->csr.name);
 	return 0;
 }
 
 static int csr_remove(struct platform_device *pdev)
 {
+	unsigned long flags;
 	struct csr_drvdata *drvdata = platform_get_drvdata(pdev);
 
+	spin_lock_irqsave(&drvdata->spin_lock, flags);
 	coresight_unregister(drvdata->csdev);
+	spin_unlock_irqrestore(&drvdata->spin_lock, flags);
 	return 0;
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-hwevent.c b/drivers/hwtracing/coresight/coresight-hwevent.c
index 22e9d6f..1e8872b 100644
--- a/drivers/hwtracing/coresight/coresight-hwevent.c
+++ b/drivers/hwtracing/coresight/coresight-hwevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -42,6 +42,8 @@
 	struct regulator			**hreg;
 	int					nr_hmux;
 	struct hwevent_mux			*hmux;
+	struct coresight_csr			*csr;
+	const char				*csr_name;
 };
 
 static int hwevent_enable(struct hwevent_drvdata *drvdata)
@@ -132,7 +134,7 @@
 	}
 
 	if (i == drvdata->nr_hmux) {
-		ret = coresight_csr_hwctrl_set(addr, val);
+		ret = coresight_csr_hwctrl_set(drvdata->csr, addr,  val);
 		if (ret) {
 			dev_err(dev, "invalid mux control register address\n");
 			ret = -EINVAL;
@@ -185,6 +187,17 @@
 	drvdata->dev = &pdev->dev;
 	platform_set_drvdata(pdev, drvdata);
 
+	ret = of_get_coresight_csr_name(dev->of_node, &drvdata->csr_name);
+	if (ret) {
+		dev_err(dev, "No csr data\n");
+	} else{
+		drvdata->csr = coresight_csr_get(drvdata->csr_name);
+		if (IS_ERR(drvdata->csr)) {
+			dev_err(dev, "failed to get csr, defer probe\n");
+			return -EPROBE_DEFER;
+		}
+	}
+
 	drvdata->nr_hmux = of_property_count_strings(pdev->dev.of_node,
 						     "reg-names");
 
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index afe9f3d..ba721fd 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2011-2012, 2016-2017, The Linux Foundation.
- * All rights reserved.
+/* Copyright (c) 2011-2012, 2016-2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -73,6 +72,11 @@
 	CS_MODE_PERF,
 };
 
+struct coresight_csr {
+	const char *name;
+	struct list_head link;
+};
+
 /**
  * struct cs_buffer - keep track of a recording session' specifics
  * @cur:	index of the current buffer
@@ -149,18 +153,24 @@
 #endif
 
 #ifdef CONFIG_CORESIGHT_CSR
-extern void msm_qdss_csr_enable_bam_to_usb(void);
-extern void msm_qdss_csr_disable_bam_to_usb(void);
-extern void msm_qdss_csr_disable_flush(void);
-extern int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val);
-extern void coresight_csr_set_byte_cntr(uint32_t count);
+extern void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr);
+extern void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr);
+extern void msm_qdss_csr_disable_flush(struct coresight_csr *csr);
+extern int coresight_csr_hwctrl_set(struct coresight_csr *csr, uint64_t addr,
+				 uint32_t val);
+extern void coresight_csr_set_byte_cntr(struct coresight_csr *csr,
+				 uint32_t count);
+extern struct coresight_csr *coresight_csr_get(const char *name);
 #else
-static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
-static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
-static inline void msm_qdss_csr_disable_flush(void) {}
-static inline int coresight_csr_hwctrl_set(uint64_t addr,
-					   uint32_t val) { return -EINVAL; }
-static inline void coresight_csr_set_byte_cntr(uint32_t count) {}
+static inline void msm_qdss_csr_enable_bam_to_usb(struct coresight_csr *csr) {}
+static inline void msm_qdss_csr_disable_bam_to_usb(struct coresight_csr *csr) {}
+static inline void msm_qdss_csr_disable_flush(struct coresight_csr *csr) {}
+static inline int coresight_csr_hwctrl_set(struct coresight_csr *csr,
+	uint64_t addr, uint32_t val) { return -EINVAL; }
+static inline void coresight_csr_set_byte_cntr(struct coresight_csr *csr,
+					   uint32_t count) {}
+static inline struct coresight_csr *coresight_csr_get(const char *name)
+					{ return NULL; }
 #endif
 
 #endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index eb70e7a..dcdc3f2 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  * Copyright(C) 2016 Linaro Limited. All rights reserved.
  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
  *
@@ -579,7 +579,7 @@
 		return;
 
 	/* Configure and enable required CSR registers */
-	msm_qdss_csr_enable_bam_to_usb();
+	msm_qdss_csr_enable_bam_to_usb(drvdata->csr);
 
 	/* Configure and enable ETR for usb bam output */
 
@@ -675,7 +675,7 @@
 		return;
 
 	/* Ensure periodic flush is disabled in CSR block */
-	msm_qdss_csr_disable_flush();
+	msm_qdss_csr_disable_flush(drvdata->csr);
 
 	CS_UNLOCK(drvdata->base);
 
@@ -685,7 +685,7 @@
 	CS_LOCK(drvdata);
 
 	/* Disable CSR configuration */
-	msm_qdss_csr_disable_bam_to_usb();
+	msm_qdss_csr_disable_bam_to_usb(drvdata->csr);
 	drvdata->enable_to_bam = false;
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 6f13eb3..802d4f1 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2017-2018, The Linux Foundation. All rights reserved.
  *
  * Description: CoreSight Trace Memory Controller driver
  *
@@ -611,6 +611,17 @@
 			dev_err(dev, "failed to get reset cti\n");
 	}
 
+	ret = of_get_coresight_csr_name(adev->dev.of_node, &drvdata->csr_name);
+	if (ret) {
+		dev_err(dev, "No csr data\n");
+	} else{
+		drvdata->csr = coresight_csr_get(drvdata->csr_name);
+		if (IS_ERR(drvdata->csr)) {
+			dev_err(dev, "failed to get csr, defer probe\n");
+			return -EPROBE_DEFER;
+		}
+	}
+
 	desc.pdata = pdata;
 	desc.dev = dev;
 	if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index fe6bc76..36117ec 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -189,6 +189,8 @@
 	bool			sticky_enable;
 	struct coresight_cti	*cti_flush;
 	struct coresight_cti	*cti_reset;
+	struct coresight_csr	*csr;
+	const char		*csr_name;
 	struct byte_cntr	*byte_cntr;
 };
 
diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c
index 5473fcf..be810fe 100644
--- a/drivers/hwtracing/coresight/of_coresight.c
+++ b/drivers/hwtracing/coresight/of_coresight.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -238,3 +238,21 @@
 	return ctidata;
 }
 EXPORT_SYMBOL(of_get_coresight_cti_data);
+
+int of_get_coresight_csr_name(struct device_node *node, const char **csr_name)
+{
+	int  ret;
+	struct device_node *csr_node;
+
+	csr_node = of_parse_phandle(node, "coresight-csr", 0);
+	if (!csr_node)
+		return -EINVAL;
+
+	ret = of_property_read_string(csr_node, "coresight-name", csr_name);
+	of_node_put(csr_node);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(of_get_coresight_csr_name);
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index a2120ff..5e29fbd 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -2575,6 +2575,18 @@
 	return ret;
 }
 
+static u8 mlx5_get_umr_fence(u8 umr_fence_cap)
+{
+	switch (umr_fence_cap) {
+	case MLX5_CAP_UMR_FENCE_NONE:
+		return MLX5_FENCE_MODE_NONE;
+	case MLX5_CAP_UMR_FENCE_SMALL:
+		return MLX5_FENCE_MODE_INITIATOR_SMALL;
+	default:
+		return MLX5_FENCE_MODE_STRONG_ORDERING;
+	}
+}
+
 static int create_dev_resources(struct mlx5_ib_resources *devr)
 {
 	struct ib_srq_init_attr attr;
@@ -3101,6 +3113,8 @@
 
 	mlx5_ib_internal_fill_odp_caps(dev);
 
+	dev->umr_fence = mlx5_get_umr_fence(MLX5_CAP_GEN(mdev, umr_fence));
+
 	if (MLX5_CAP_GEN(mdev, imaicl)) {
 		dev->ib_dev.alloc_mw		= mlx5_ib_alloc_mw;
 		dev->ib_dev.dealloc_mw		= mlx5_ib_dealloc_mw;
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 86e1e081..d5cc954 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -345,7 +345,7 @@
 	struct mlx5_ib_wq	rq;
 
 	u8			sq_signal_bits;
-	u8			fm_cache;
+	u8			next_fence;
 	struct mlx5_ib_wq	sq;
 
 	/* serialize qp state modifications
@@ -643,6 +643,7 @@
 	struct list_head	qp_list;
 	/* Array with num_ports elements */
 	struct mlx5_ib_port	*port;
+	u8			umr_fence;
 };
 
 static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 2665414..fdd1561 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -3755,24 +3755,6 @@
 	}
 }
 
-static u8 get_fence(u8 fence, struct ib_send_wr *wr)
-{
-	if (unlikely(wr->opcode == IB_WR_LOCAL_INV &&
-		     wr->send_flags & IB_SEND_FENCE))
-		return MLX5_FENCE_MODE_STRONG_ORDERING;
-
-	if (unlikely(fence)) {
-		if (wr->send_flags & IB_SEND_FENCE)
-			return MLX5_FENCE_MODE_SMALL_AND_FENCE;
-		else
-			return fence;
-	} else if (unlikely(wr->send_flags & IB_SEND_FENCE)) {
-		return MLX5_FENCE_MODE_FENCE;
-	}
-
-	return 0;
-}
-
 static int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
 		     struct mlx5_wqe_ctrl_seg **ctrl,
 		     struct ib_send_wr *wr, unsigned *idx,
@@ -3801,8 +3783,7 @@
 static void finish_wqe(struct mlx5_ib_qp *qp,
 		       struct mlx5_wqe_ctrl_seg *ctrl,
 		       u8 size, unsigned idx, u64 wr_id,
-		       int nreq, u8 fence, u8 next_fence,
-		       u32 mlx5_opcode)
+		       int nreq, u8 fence, u32 mlx5_opcode)
 {
 	u8 opmod = 0;
 
@@ -3810,7 +3791,6 @@
 					     mlx5_opcode | ((u32)opmod << 24));
 	ctrl->qpn_ds = cpu_to_be32(size | (qp->trans_qp.base.mqp.qpn << 8));
 	ctrl->fm_ce_se |= fence;
-	qp->fm_cache = next_fence;
 	if (unlikely(qp->wq_sig))
 		ctrl->signature = wq_sig(ctrl);
 
@@ -3870,7 +3850,6 @@
 			goto out;
 		}
 
-		fence = qp->fm_cache;
 		num_sge = wr->num_sge;
 		if (unlikely(num_sge > qp->sq.max_gs)) {
 			mlx5_ib_warn(dev, "\n");
@@ -3887,6 +3866,19 @@
 			goto out;
 		}
 
+		if (wr->opcode == IB_WR_LOCAL_INV ||
+		    wr->opcode == IB_WR_REG_MR) {
+			fence = dev->umr_fence;
+			next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
+		} else if (wr->send_flags & IB_SEND_FENCE) {
+			if (qp->next_fence)
+				fence = MLX5_FENCE_MODE_SMALL_AND_FENCE;
+			else
+				fence = MLX5_FENCE_MODE_FENCE;
+		} else {
+			fence = qp->next_fence;
+		}
+
 		switch (ibqp->qp_type) {
 		case IB_QPT_XRC_INI:
 			xrc = seg;
@@ -3913,7 +3905,6 @@
 				goto out;
 
 			case IB_WR_LOCAL_INV:
-				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
 				ctrl->imm = cpu_to_be32(wr->ex.invalidate_rkey);
 				set_linv_wr(qp, &seg, &size);
@@ -3921,7 +3912,6 @@
 				break;
 
 			case IB_WR_REG_MR:
-				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				qp->sq.wr_data[idx] = IB_WR_REG_MR;
 				ctrl->imm = cpu_to_be32(reg_wr(wr)->key);
 				err = set_reg_wr(qp, reg_wr(wr), &seg, &size);
@@ -3944,9 +3934,8 @@
 					goto out;
 				}
 
-				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
-					   nreq, get_fence(fence, wr),
-					   next_fence, MLX5_OPCODE_UMR);
+				finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
+					   fence, MLX5_OPCODE_UMR);
 				/*
 				 * SET_PSV WQEs are not signaled and solicited
 				 * on error
@@ -3971,9 +3960,8 @@
 					goto out;
 				}
 
-				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
-					   nreq, get_fence(fence, wr),
-					   next_fence, MLX5_OPCODE_SET_PSV);
+				finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
+					   fence, MLX5_OPCODE_SET_PSV);
 				err = begin_wqe(qp, &seg, &ctrl, wr,
 						&idx, &size, nreq);
 				if (err) {
@@ -3983,7 +3971,6 @@
 					goto out;
 				}
 
-				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->wire,
 						 mr->sig->psv_wire.psv_idx, &seg,
 						 &size);
@@ -3993,9 +3980,9 @@
 					goto out;
 				}
 
-				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
-					   nreq, get_fence(fence, wr),
-					   next_fence, MLX5_OPCODE_SET_PSV);
+				finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
+					   fence, MLX5_OPCODE_SET_PSV);
+				qp->next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
 				num_sge = 0;
 				goto skip_psv;
 
@@ -4100,8 +4087,8 @@
 			}
 		}
 
-		finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
-			   get_fence(fence, wr), next_fence,
+		qp->next_fence = next_fence;
+		finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq, fence,
 			   mlx5_ib_opcode[wr->opcode]);
 skip_psv:
 		if (0)
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 39d2837..0983470 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -747,6 +747,7 @@
 {
 	struct isert_conn *isert_conn = cma_id->qp->qp_context;
 
+	ib_drain_qp(isert_conn->qp);
 	list_del_init(&isert_conn->node);
 	isert_conn->cm_id = NULL;
 	isert_put_conn(isert_conn);
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index caa5a62..15929d8 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -178,12 +178,14 @@
 			 twl4030_vibra_suspend, twl4030_vibra_resume);
 
 static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
-			      struct device_node *node)
+			      struct device_node *parent)
 {
+	struct device_node *node;
+
 	if (pdata && pdata->coexist)
 		return true;
 
-	node = of_find_node_by_name(node, "codec");
+	node = of_get_child_by_name(parent, "codec");
 	if (node) {
 		of_node_put(node);
 		return true;
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 5690eb7..15e0d35 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -248,8 +248,7 @@
 	int vddvibr_uV = 0;
 	int error;
 
-	of_node_get(twl6040_core_dev->of_node);
-	twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
+	twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node,
 						 "vibra");
 	if (!twl6040_core_node) {
 		dev_err(&pdev->dev, "parent of node is missing?\n");
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index f26807c..af83d2e 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1247,29 +1247,32 @@
 	case SS4_PACKET_ID_MULTI:
 		if (priv->flags & ALPS_BUTTONPAD) {
 			if (IS_SS4PLUS_DEV(priv->dev_id)) {
-				f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
-				f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+				f->mt[2].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
+				f->mt[3].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
+				no_data_x = SS4_PLUS_MFPACKET_NO_AX_BL;
 			} else {
 				f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
 				f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
+				no_data_x = SS4_MFPACKET_NO_AX_BL;
 			}
+			no_data_y = SS4_MFPACKET_NO_AY_BL;
 
 			f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0);
 			f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1);
-			no_data_x = SS4_MFPACKET_NO_AX_BL;
-			no_data_y = SS4_MFPACKET_NO_AY_BL;
 		} else {
 			if (IS_SS4PLUS_DEV(priv->dev_id)) {
-				f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0);
-				f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+				f->mt[2].x = SS4_PLUS_STD_MF_X_V2(p, 0);
+				f->mt[3].x = SS4_PLUS_STD_MF_X_V2(p, 1);
+				no_data_x = SS4_PLUS_MFPACKET_NO_AX;
 			} else {
-				f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
-				f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
+				f->mt[2].x = SS4_STD_MF_X_V2(p, 0);
+				f->mt[3].x = SS4_STD_MF_X_V2(p, 1);
+				no_data_x = SS4_MFPACKET_NO_AX;
 			}
+			no_data_y = SS4_MFPACKET_NO_AY;
+
 			f->mt[2].y = SS4_STD_MF_Y_V2(p, 0);
 			f->mt[3].y = SS4_STD_MF_Y_V2(p, 1);
-			no_data_x = SS4_MFPACKET_NO_AX;
-			no_data_y = SS4_MFPACKET_NO_AY;
 		}
 
 		f->first_mp = 0;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 7931237..9bc2bab 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -120,10 +120,12 @@
 #define SS4_IS_5F_DETECTED(_b)	((_b[2] & 0x10) == 0x10)
 
 
-#define SS4_MFPACKET_NO_AX	8160	/* X-Coordinate value */
-#define SS4_MFPACKET_NO_AY	4080	/* Y-Coordinate value */
-#define SS4_MFPACKET_NO_AX_BL	8176	/* Buttonless X-Coordinate value */
-#define SS4_MFPACKET_NO_AY_BL	4088	/* Buttonless Y-Coordinate value */
+#define SS4_MFPACKET_NO_AX		8160	/* X-Coordinate value */
+#define SS4_MFPACKET_NO_AY		4080	/* Y-Coordinate value */
+#define SS4_MFPACKET_NO_AX_BL		8176	/* Buttonless X-Coord value */
+#define SS4_MFPACKET_NO_AY_BL		4088	/* Buttonless Y-Coord value */
+#define SS4_PLUS_MFPACKET_NO_AX		4080	/* SS4 PLUS, X */
+#define SS4_PLUS_MFPACKET_NO_AX_BL	4088	/* Buttonless SS4 PLUS, X */
 
 /*
  * enum V7_PACKET_ID - defines the packet type for V7
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 7e2dc5e..0b49f29 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -383,6 +383,9 @@
 	if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
 		psmouse_warn(psmouse, "failed to get extended button data, assuming 3 buttons\n");
 		button_info = 0x33;
+	} else if (!button_info) {
+		psmouse_warn(psmouse, "got 0 in extended button data, assuming 3 buttons\n");
+		button_info = 0x33;
 	}
 
 	psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index 251ff2a..7a0dbce 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -126,7 +126,7 @@
 	int data, n, ret;
 	if (!np)
 		return -ENODEV;
-	np = of_find_node_by_name(np, "touch");
+	np = of_get_child_by_name(np, "touch");
 	if (!np) {
 		dev_err(&pdev->dev, "Can't find touch node\n");
 		return -EINVAL;
@@ -144,13 +144,13 @@
 	if (data) {
 		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	/* set tsi prebias time */
 	if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) {
 		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	/* set prebias & prechg time of pen detect */
 	data = 0;
@@ -161,10 +161,18 @@
 	if (data) {
 		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
 		if (ret < 0)
-			return -EINVAL;
+			goto err_put_node;
 	}
 	of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x);
+
+	of_node_put(np);
+
 	return 0;
+
+err_put_node:
+	of_node_put(np);
+
+	return -EINVAL;
 }
 #else
 #define pm860x_touch_dt_init(x, y, z)	(-1)
diff --git a/drivers/input/touchscreen/synaptics_dsx/Kconfig b/drivers/input/touchscreen/synaptics_dsx/Kconfig
index b2fa115..b54e792 100644
--- a/drivers/input/touchscreen/synaptics_dsx/Kconfig
+++ b/drivers/input/touchscreen/synaptics_dsx/Kconfig
@@ -59,6 +59,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_dsx_fw_update.
 
+config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
+	bool "Synaptics DSX firmware update sysfs attributes"
+	depends on TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE
+	help
+	  Say Y here to enable support for sysfs attributes for
+	  performing firmware update in a development environment.
+	  This does not affect the core or other subsystem attributes.
+
+	  If unsure, say N.
+
 config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING
 	tristate "Synaptics DSX test reporting module"
 	depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 7f62e01..395def9 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -137,6 +137,7 @@
 
 static int fwu_recovery_check_status(void);
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count);
@@ -201,6 +202,8 @@
 		struct device_attribute *attr, char *buf);
 #endif
 
+#endif
+
 enum f34_version {
 	F34_V0 = 0,
 	F34_V1,
@@ -757,6 +760,7 @@
 	struct work_struct fwu_work;
 };
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static struct bin_attribute dev_attr_data = {
 	.attr = {
 		.name = "data",
@@ -766,8 +770,10 @@
 	.read = fwu_sysfs_show_image,
 	.write = fwu_sysfs_store_image,
 };
+#endif
 
 static struct device_attribute attrs[] = {
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	__ATTR(dorecovery, 0220,
 			synaptics_rmi4_show_error,
 			fwu_sysfs_do_recovery_store),
@@ -821,13 +827,16 @@
 			fwu_sysfs_read_lockdown_code_show,
 			fwu_sysfs_write_lockdown_code_store),
 #endif
+#endif
 };
 
 static struct synaptics_rmi4_fwu_handle *fwu;
 
 DECLARE_COMPLETION(fwu_remove_complete);
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 DEFINE_MUTEX(fwu_sysfs_mutex);
+#endif
 
 static void calculate_checksum(unsigned short *data, unsigned long len,
 		unsigned long *result)
@@ -3061,6 +3070,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_check_pm_configuration_size(void)
 {
 	unsigned short block_count;
@@ -3077,6 +3087,7 @@
 
 	return 0;
 }
+#endif
 
 static int fwu_check_bl_configuration_size(void)
 {
@@ -3444,6 +3455,7 @@
 	return fwu_write_configuration();
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_write_pm_configuration(void)
 {
 	fwu->config_area = PM_CONFIG_AREA;
@@ -3469,6 +3481,7 @@
 	return 0;
 }
 #endif
+#endif
 
 static int fwu_write_flash_configuration(void)
 {
@@ -3757,6 +3770,7 @@
 	return retval;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_do_read_config(void)
 {
 	int retval;
@@ -3984,6 +3998,7 @@
 	return retval;
 }
 #endif
+#endif
 
 static int fwu_do_lockdown_v7(void)
 {
@@ -4134,6 +4149,7 @@
 }
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_start_write_guest_code(void)
 {
 	int retval;
@@ -4339,6 +4355,7 @@
 
 	return retval;
 }
+#endif
 
 static int fwu_start_reflash(void)
 {
@@ -4970,6 +4987,7 @@
 }
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count)
@@ -5566,6 +5584,7 @@
 	return count;
 }
 #endif
+#endif
 static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
 		unsigned char intr_mask)
 {
@@ -5668,6 +5687,7 @@
 	if (ENABLE_SYS_REFLASH == false)
 		return 0;
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
 			&dev_attr_data);
 	if (retval < 0) {
@@ -5676,6 +5696,7 @@
 				__func__);
 		goto exit_free_mem;
 	}
+#endif
 
 	for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
 		retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
@@ -5697,7 +5718,9 @@
 				&attrs[attr_count].attr);
 	}
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+#endif
 
 exit_free_mem:
 	kfree(fwu->image_name);
@@ -5739,7 +5762,9 @@
 				&attrs[attr_count].attr);
 	}
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+#endif
 
 exit:
 	complete(&fwu_remove_complete);
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
index 8776d4a..7725cd3 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
@@ -402,11 +402,11 @@
 	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
 	struct i2c_msg msg[2];
 
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+
 	retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
 	if (retval < 0)
-		return retval;
-
-	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+		goto exit;
 
 	retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
 	if (retval != PAGE_SELECT_LEN) {
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
index 61cf979..331274e 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
@@ -567,16 +567,22 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto clean_up;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
+	if (count == 0) {
+		retval = 0;
+		goto clean_up;
+	}
 	address = (unsigned short)(*f_pos);
 
-	mutex_lock(&(dev_data->file_mutex));
-
 	rmidev_allocate_buffer(count);
 
 	retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
@@ -638,18 +644,26 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto unlock;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
-	mutex_lock(&(dev_data->file_mutex));
-
+	if (count == 0) {
+		retval = 0;
+		goto unlock;
+	}
 	rmidev_allocate_buffer(count);
 
-	if (copy_from_user(rmidev->tmpbuf, buf, count))
+	if (copy_from_user(rmidev->tmpbuf, buf, count)) {
 		return -EFAULT;
+		goto unlock;
+	}
 
 	retval = synaptics_rmi4_reg_write(rmidev->rmi4_data,
 			*f_pos,
@@ -658,6 +672,7 @@
 	if (retval >= 0)
 		*f_pos += retval;
 
+unlock:
 	mutex_unlock(&(dev_data->file_mutex));
 
 	return retval;
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig b/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
index 78b995e..5389628 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
@@ -114,4 +114,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called synaptics_dsx_video.
 
+config SECURE_TOUCH_SYNAPTICS_DSX_V26
+	bool "Secure Touch support for Synaptics V2.6 Touchscreen"
+	depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
+	help
+	  Say Y here
+	  -Synaptics DSX V2.6 touch driver is connected
+	  -To enable secure touch for Synaptics DSX V2.6 touch driver
+
+	  If unsure, say N.
+
 endif
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
index b2f3bf5..7633767 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -117,11 +118,11 @@
 static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
 		bool *was_in_bl_mode);
 static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data);
-static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data);
 static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
 		bool rebuild);
 
 #ifdef CONFIG_FB
+static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work);
 static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
 		unsigned long event, void *data);
 #endif
@@ -172,6 +173,19 @@
 static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
 		struct kobj_attribute *attr, char *buf);
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+#endif
+
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data);
+
 struct synaptics_rmi4_f01_device_status {
 	union {
 		struct {
@@ -597,26 +611,34 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(reset, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			synaptics_rmi4_f01_reset_store),
 	__ATTR(productinfo, 0444,
 			synaptics_rmi4_f01_productinfo_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(buildid, 0444,
 			synaptics_rmi4_f01_buildid_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(flashprog, 0444,
 			synaptics_rmi4_f01_flashprog_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(0dbutton, 0664,
 			synaptics_rmi4_0dbutton_show,
 			synaptics_rmi4_0dbutton_store),
 	__ATTR(suspend, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			synaptics_rmi4_suspend_store),
 	__ATTR(wake_gesture, 0664,
 			synaptics_rmi4_wake_gesture_show,
 			synaptics_rmi4_wake_gesture_store),
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	__ATTR(secure_touch_enable, 0664,
+			synaptics_rmi4_secure_touch_enable_show,
+			synaptics_rmi4_secure_touch_enable_store),
+	__ATTR(secure_touch, 0444,
+			synaptics_rmi4_secure_touch_show,
+			NULL),
+#endif
 };
 
 static struct kobj_attribute virtual_key_map_attr = {
@@ -627,6 +649,205 @@
 	.show = synaptics_rmi4_virtual_key_map_show,
 };
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data)
+{
+	data->st_initialized = 0;
+	init_completion(&data->st_powerdown);
+	init_completion(&data->st_irq_processed);
+
+	/* Get clocks */
+	data->core_clk = devm_clk_get(data->pdev->dev.parent, "core_clk");
+	if (IS_ERR(data->core_clk)) {
+		dev_warn(data->pdev->dev.parent,
+			"%s: error on clk_get(core_clk): %ld\n", __func__,
+			PTR_ERR(data->core_clk));
+		data->core_clk = NULL;
+	}
+
+	data->iface_clk = devm_clk_get(data->pdev->dev.parent, "iface_clk");
+	if (IS_ERR(data->iface_clk)) {
+		dev_warn(data->pdev->dev.parent,
+			"%s: error on clk_get(iface_clk): %ld\n", __func__,
+			PTR_ERR(data->iface_clk));
+		data->iface_clk = NULL;
+	}
+
+	data->st_initialized = 1;
+}
+
+static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data)
+{
+	sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch");
+}
+
+static irqreturn_t synaptics_filter_interrupt(
+	struct synaptics_rmi4_data *rmi4_data)
+{
+	if (atomic_read(&rmi4_data->st_enabled)) {
+		if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) {
+			reinit_completion(&rmi4_data->st_irq_processed);
+			synaptics_secure_touch_notify(rmi4_data);
+			wait_for_completion_interruptible(
+				&rmi4_data->st_irq_processed);
+		}
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/*
+ * 'blocking' variable will have value 'true' when we want to prevent the driver
+ * from accessing the xPU/SMMU protected HW resources while the session is
+ * active.
+ */
+static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data,
+					bool blocking)
+{
+	if (atomic_read(&rmi4_data->st_enabled)) {
+		atomic_set(&rmi4_data->st_pending_irqs, -1);
+		synaptics_secure_touch_notify(rmi4_data);
+		if (blocking)
+			wait_for_completion_interruptible(
+				&rmi4_data->st_powerdown);
+	}
+}
+
+#else
+static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data)
+{
+}
+
+static irqreturn_t synaptics_filter_interrupt(
+				struct synaptics_rmi4_data *rmi4_data)
+{
+	return IRQ_NONE;
+}
+
+static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data,
+					bool blocking)
+{
+}
+#endif
+
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d",
+			atomic_read(&rmi4_data->st_enabled));
+}
+/*
+ * Accept only "0" and "1" valid values.
+ * "0" will reset the st_enabled flag, then wake up the reading process and
+ * the interrupt handler.
+ * The bus driver is notified via pm_runtime that it is not required to stay
+ * awake anymore.
+ * It will also make sure the queue of events is emptied in the controller,
+ * in case a touch happened in between the secure touch being disabled and
+ * the local ISR being ungated.
+ * "1" will set the st_enabled flag and clear the st_pending_irqs flag.
+ * The bus driver is requested via pm_runtime to stay awake.
+ */
+static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	unsigned long value;
+	int err = 0;
+
+	if (count > 2)
+		return -EINVAL;
+
+	err = kstrtoul(buf, 10, &value);
+	if (err != 0)
+		return err;
+
+	if (!rmi4_data->st_initialized)
+		return -EIO;
+
+	err = count;
+
+	switch (value) {
+	case 0:
+		if (atomic_read(&rmi4_data->st_enabled) == 0)
+			break;
+
+		synaptics_rmi4_bus_put(rmi4_data);
+		atomic_set(&rmi4_data->st_enabled, 0);
+		synaptics_secure_touch_notify(rmi4_data);
+		complete(&rmi4_data->st_irq_processed);
+		synaptics_rmi4_irq(rmi4_data->irq, rmi4_data);
+		complete(&rmi4_data->st_powerdown);
+
+		break;
+	case 1:
+		if (atomic_read(&rmi4_data->st_enabled)) {
+			err = -EBUSY;
+			break;
+		}
+
+		synchronize_irq(rmi4_data->irq);
+
+		if (synaptics_rmi4_bus_get(rmi4_data) < 0) {
+			dev_err(
+				rmi4_data->pdev->dev.parent,
+				"synaptics_rmi4_bus_get failed\n");
+			err = -EIO;
+			break;
+		}
+		reinit_completion(&rmi4_data->st_powerdown);
+		reinit_completion(&rmi4_data->st_irq_processed);
+		atomic_set(&rmi4_data->st_enabled, 1);
+		atomic_set(&rmi4_data->st_pending_irqs,  0);
+		break;
+	default:
+		dev_err(
+			rmi4_data->pdev->dev.parent,
+			"unsupported value: %lu\n", value);
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+/*
+ * This function returns whether there are pending interrupts, or
+ * other error conditions that need to be signaled to the userspace library,
+ * according tot he following logic:
+ * - st_enabled is 0 if secure touch is not enabled, returning -EBADF
+ * - st_pending_irqs is -1 to signal that secure touch is in being stopped,
+ *   returning -EINVAL
+ * - st_pending_irqs is 1 to signal that there is a pending irq, returning
+ *   the value "1" to the sysfs read operation
+ * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt
+ *   has been processed, so the interrupt handler can be allowed to continue.
+ */
+static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	int val = 0;
+
+	if (atomic_read(&rmi4_data->st_enabled) == 0)
+		return -EBADF;
+
+	if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1)
+		return -EINVAL;
+
+	if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1)
+		val = 1;
+	else
+		complete(&rmi4_data->st_irq_processed);
+
+	return scnprintf(buf, PAGE_SIZE, "%u", val);
+
+}
+#endif
+
 static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
@@ -1173,7 +1394,6 @@
 #ifndef TYPE_B_PROTOCOL
 			input_mt_sync(rmi4_data->input_dev);
 #endif
-			input_sync(rmi4_data->input_dev);
 
 			dev_dbg(rmi4_data->pdev->dev.parent,
 					"%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n",
@@ -1245,7 +1465,6 @@
 #ifndef TYPE_B_PROTOCOL
 		input_mt_sync(rmi4_data->input_dev);
 #endif
-		input_sync(rmi4_data->input_dev);
 
 		if (rmi4_data->stylus_enable) {
 			stylus_presence = 0;
@@ -1261,6 +1480,8 @@
 		}
 	}
 
+	input_sync(rmi4_data->input_dev);
+
 	mutex_unlock(&(rmi4_data->rmi4_report_mutex));
 
 	return touch_count;
@@ -1465,12 +1686,6 @@
 	}
 	if (status.unconfigured && !status.flash_prog) {
 		pr_notice("%s: spontaneous reset detected\n", __func__);
-		retval = synaptics_rmi4_reinit_device(rmi4_data);
-		if (retval < 0) {
-			dev_err(rmi4_data->pdev->dev.parent,
-					"%s: Failed to reinit device\n",
-					__func__);
-		}
 	}
 
 	if (!report)
@@ -1512,6 +1727,9 @@
 	const struct synaptics_dsx_board_data *bdata =
 			rmi4_data->hw_if->board_data;
 
+	if (synaptics_filter_interrupt(data) == IRQ_HANDLED)
+		return IRQ_HANDLED;
+
 	if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state)
 		goto exit;
 
@@ -2911,7 +3129,9 @@
 	unsigned char buf[16];
 
 	if (config) {
-		snprintf(buf, PAGE_SIZE, "dsx_gpio_%u\n", gpio);
+		retval = snprintf(buf, ARRAY_SIZE(buf), "dsx_gpio_%u\n", gpio);
+		if (retval >= 16)
+			return -EINVAL;
 
 		retval = gpio_request(gpio, buf);
 		if (retval) {
@@ -3434,49 +3654,6 @@
 	return;
 }
 
-static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data)
-{
-	int retval;
-	struct synaptics_rmi4_fn *fhandler;
-	struct synaptics_rmi4_exp_fhandler *exp_fhandler;
-	struct synaptics_rmi4_device_info *rmi;
-
-	rmi = &(rmi4_data->rmi4_mod_info);
-
-	mutex_lock(&(rmi4_data->rmi4_reset_mutex));
-
-	synaptics_rmi4_free_fingers(rmi4_data);
-
-	if (!list_empty(&rmi->support_fn_list)) {
-		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
-			if (fhandler->fn_number == SYNAPTICS_RMI4_F12) {
-				synaptics_rmi4_f12_set_enables(rmi4_data, 0);
-				break;
-			}
-		}
-	}
-
-	retval = synaptics_rmi4_int_enable(rmi4_data, true);
-	if (retval < 0)
-		goto exit;
-
-	mutex_lock(&exp_data.mutex);
-	if (!list_empty(&exp_data.list)) {
-		list_for_each_entry(exp_fhandler, &exp_data.list, link)
-			if (exp_fhandler->exp_fn->reinit != NULL)
-				exp_fhandler->exp_fn->reinit(rmi4_data);
-	}
-	mutex_unlock(&exp_data.mutex);
-
-	synaptics_rmi4_set_configured(rmi4_data);
-
-	retval = 0;
-
-exit:
-	mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
-	return retval;
-}
-
 static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
 		bool rebuild)
 {
@@ -3688,6 +3865,57 @@
 }
 EXPORT_SYMBOL(synaptics_rmi4_new_function);
 
+static int synaptics_dsx_pinctrl_init(struct synaptics_rmi4_data *rmi4_data)
+{
+	int retval;
+
+	/* Get pinctrl if target uses pinctrl */
+	rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent));
+	if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) {
+		retval = PTR_ERR(rmi4_data->ts_pinctrl);
+		dev_err(rmi4_data->pdev->dev.parent,
+			"Target does not use pinctrl %d\n", retval);
+		goto err_pinctrl_get;
+	}
+
+	rmi4_data->pinctrl_state_active
+		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active");
+	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) {
+		retval = PTR_ERR(rmi4_data->pinctrl_state_active);
+		dev_err(rmi4_data->pdev->dev.parent,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_ACTIVE, retval);
+		goto err_pinctrl_lookup;
+	}
+
+	rmi4_data->pinctrl_state_suspend
+		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend");
+	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) {
+		retval = PTR_ERR(rmi4_data->pinctrl_state_suspend);
+		dev_dbg(rmi4_data->pdev->dev.parent,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_SUSPEND, retval);
+		goto err_pinctrl_lookup;
+	}
+
+	rmi4_data->pinctrl_state_release
+		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_release");
+	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+		retval = PTR_ERR(rmi4_data->pinctrl_state_release);
+		dev_dbg(rmi4_data->pdev->dev.parent,
+			"Can not lookup %s pinstate %d\n",
+			PINCTRL_STATE_RELEASE, retval);
+	}
+
+	return 0;
+
+err_pinctrl_lookup:
+	devm_pinctrl_put(rmi4_data->ts_pinctrl);
+err_pinctrl_get:
+	rmi4_data->ts_pinctrl = NULL;
+	return retval;
+}
+
 static int synaptics_rmi4_probe(struct platform_device *pdev)
 {
 	int retval;
@@ -3757,6 +3985,21 @@
 		goto err_enable_reg;
 	}
 
+	retval = synaptics_dsx_pinctrl_init(rmi4_data);
+	if (!retval && rmi4_data->ts_pinctrl) {
+		/*
+		 * Pinctrl handle is optional. If pinctrl handle is found
+		 * let pins to be configured in active state. If not
+		 * found continue further without error.
+		 */
+		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+		rmi4_data->pinctrl_state_active);
+		if (retval < 0) {
+			dev_err(&pdev->dev,
+				"%s: Failed to select %s pinstate %d\n",
+				__func__, PINCTRL_STATE_ACTIVE, retval);
+		}
+	}
 	retval = synaptics_rmi4_set_gpio(rmi4_data);
 	if (retval < 0) {
 		dev_err(&pdev->dev,
@@ -3784,6 +4027,8 @@
 	}
 
 #ifdef CONFIG_FB
+	INIT_WORK(&rmi4_data->fb_notify_work,
+		  synaptics_rmi4_fb_notify_resume_work);
 	rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb;
 	retval = fb_register_client(&rmi4_data->fb_notifier);
 	if (retval < 0) {
@@ -3849,25 +4094,52 @@
 
 	rmi4_data->rb_workqueue =
 			create_singlethread_workqueue("dsx_rebuild_workqueue");
+	if (!rmi4_data->rb_workqueue) {
+		retval = -ENOMEM;
+		goto err_rb_workqueue;
+	}
 	INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work);
 
 	exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
+	if (!exp_data.workqueue) {
+		retval = -ENOMEM;
+		goto err_exp_data_workqueue;
+	}
 	INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
 	exp_data.rmi4_data = rmi4_data;
 	exp_data.queue_work = true;
-	queue_delayed_work(exp_data.workqueue,
-			&exp_data.work,
-			0);
+	queue_delayed_work(exp_data.workqueue, &exp_data.work, 0);
 
 #ifdef FB_READY_RESET
 	rmi4_data->reset_workqueue =
 			create_singlethread_workqueue("dsx_reset_workqueue");
+	if (!rmi4_data->reset_workqueue) {
+		retval = -ENOMEM;
+		goto err_reset_workqueue;
+	}
 	INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work);
 	queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work);
 #endif
 
+	/* Initialize secure touch */
+	synaptics_secure_touch_init(rmi4_data);
+	synaptics_secure_touch_stop(rmi4_data, true);
+
 	return retval;
 
+#ifdef FB_READY_RESET
+err_reset_workqueue:
+#endif
+	cancel_delayed_work_sync(&exp_data.work);
+	flush_workqueue(exp_data.workqueue);
+	destroy_workqueue(exp_data.workqueue);
+
+err_exp_data_workqueue:
+	cancel_delayed_work_sync(&rmi4_data->rb_work);
+	flush_workqueue(rmi4_data->rb_workqueue);
+	destroy_workqueue(rmi4_data->rb_workqueue);
+
+err_rb_workqueue:
 err_sysfs:
 	for (attr_count--; attr_count >= 0; attr_count--) {
 		sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
@@ -3913,6 +4185,21 @@
 err_set_gpio:
 	synaptics_rmi4_enable_reg(rmi4_data, false);
 
+	if (rmi4_data->ts_pinctrl) {
+		if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+			devm_pinctrl_put(rmi4_data->ts_pinctrl);
+			rmi4_data->ts_pinctrl = NULL;
+		} else {
+			retval = pinctrl_select_state(
+			rmi4_data->ts_pinctrl,
+			rmi4_data->pinctrl_state_release);
+			if (retval)
+				dev_err(&pdev->dev,
+					"%s: Failed to create sysfs attributes\n",
+					__func__);
+		}
+	}
+
 err_enable_reg:
 	synaptics_rmi4_get_reg(rmi4_data, false);
 
@@ -3925,6 +4212,7 @@
 static int synaptics_rmi4_remove(struct platform_device *pdev)
 {
 	unsigned char attr_count;
+	int err;
 	struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev);
 	const struct synaptics_dsx_board_data *bdata =
 			rmi4_data->hw_if->board_data;
@@ -3980,6 +4268,22 @@
 	if (bdata->power_gpio >= 0)
 		synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0);
 
+
+	if (rmi4_data->ts_pinctrl) {
+		if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+			devm_pinctrl_put(rmi4_data->ts_pinctrl);
+			rmi4_data->ts_pinctrl = NULL;
+		} else {
+			err = pinctrl_select_state(
+			rmi4_data->ts_pinctrl,
+			rmi4_data->pinctrl_state_release);
+			if (err)
+				dev_err(&pdev->dev,
+					"Failed to select release pinctrl state %d\n",
+					err);
+		}
+	}
+
 	synaptics_rmi4_enable_reg(rmi4_data, false);
 	synaptics_rmi4_get_reg(rmi4_data, false);
 
@@ -4096,6 +4400,14 @@
 }
 
 #ifdef CONFIG_FB
+static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work)
+{
+	struct synaptics_rmi4_data *rmi4_data =
+		container_of(work, struct synaptics_rmi4_data, fb_notify_work);
+	synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+	rmi4_data->fb_ready = true;
+}
+
 static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
 		unsigned long event, void *data)
 {
@@ -4106,14 +4418,36 @@
 			fb_notifier);
 
 	if (evdata && evdata->data && rmi4_data) {
-		if (event == FB_EVENT_BLANK) {
-			transition = evdata->data;
-			if (*transition == FB_BLANK_POWERDOWN) {
-				synaptics_rmi4_suspend(&rmi4_data->pdev->dev);
-				rmi4_data->fb_ready = false;
-			} else if (*transition == FB_BLANK_UNBLANK) {
-				synaptics_rmi4_resume(&rmi4_data->pdev->dev);
-				rmi4_data->fb_ready = true;
+		if (rmi4_data->hw_if->board_data->resume_in_workqueue) {
+			if (event == FB_EARLY_EVENT_BLANK) {
+				synaptics_secure_touch_stop(rmi4_data, false);
+			} else if (event == FB_EVENT_BLANK) {
+				transition = evdata->data;
+				if (*transition == FB_BLANK_POWERDOWN) {
+					flush_work(
+						&(rmi4_data->fb_notify_work));
+					synaptics_rmi4_suspend(
+						&rmi4_data->pdev->dev);
+					rmi4_data->fb_ready = false;
+				} else if (*transition == FB_BLANK_UNBLANK) {
+					schedule_work(
+						&(rmi4_data->fb_notify_work));
+				}
+			}
+		} else {
+			if (event == FB_EARLY_EVENT_BLANK) {
+				synaptics_secure_touch_stop(rmi4_data, false);
+			} else if (event == FB_EVENT_BLANK) {
+				transition = evdata->data;
+				if (*transition == FB_BLANK_POWERDOWN) {
+					synaptics_rmi4_suspend(
+						&rmi4_data->pdev->dev);
+					rmi4_data->fb_ready = false;
+				} else if (*transition == FB_BLANK_UNBLANK) {
+					synaptics_rmi4_resume(
+						&rmi4_data->pdev->dev);
+					rmi4_data->fb_ready = true;
+				}
 			}
 		}
 	}
@@ -4133,6 +4467,14 @@
 	if (rmi4_data->stay_awake)
 		return;
 
+	/*
+	 * During early suspend/late resume, the driver doesn't access xPU/SMMU
+	 * protected HW resources. So, there is no compelling need to block,
+	 * but notifying the userspace that a power event has occurred is
+	 * enough. Hence 'blocking' variable can be set to false.
+	 */
+	synaptics_secure_touch_stop(rmi4_data, false);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, true);
 		enable_irq_wake(rmi4_data->irq);
@@ -4170,6 +4512,8 @@
 	if (rmi4_data->stay_awake)
 		return;
 
+	synaptics_secure_touch_stop(rmi4_data, false);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, false);
 		disable_irq_wake(rmi4_data->irq);
@@ -4212,10 +4556,13 @@
 {
 	struct synaptics_rmi4_exp_fhandler *exp_fhandler;
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+	int retval;
 
 	if (rmi4_data->stay_awake)
 		return 0;
 
+	synaptics_secure_touch_stop(rmi4_data, true);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, true);
 		enable_irq_wake(rmi4_data->irq);
@@ -4228,6 +4575,13 @@
 		synaptics_rmi4_free_fingers(rmi4_data);
 	}
 
+	if (rmi4_data->ts_pinctrl) {
+		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+		rmi4_data->pinctrl_state_suspend);
+		if (retval < 0)
+			dev_err(dev, "Cannot get idle pinctrl state\n");
+			goto err_pinctrl;
+	}
 exit:
 	mutex_lock(&exp_data.mutex);
 	if (!list_empty(&exp_data.list)) {
@@ -4237,9 +4591,19 @@
 	}
 	mutex_unlock(&exp_data.mutex);
 
+	if (!rmi4_data->suspend) {
+		synaptics_rmi4_enable_reg(rmi4_data, false);
+		synaptics_rmi4_get_reg(rmi4_data, false);
+	}
 	rmi4_data->suspend = true;
 
 	return 0;
+
+err_pinctrl:
+	synaptics_rmi4_sleep_enable(rmi4_data, false);
+	synaptics_rmi4_irq_enable(rmi4_data, true, false);
+	return retval;
+
 }
 
 static int synaptics_rmi4_resume(struct device *dev)
@@ -4253,6 +4617,8 @@
 	if (rmi4_data->stay_awake)
 		return 0;
 
+	synaptics_secure_touch_stop(rmi4_data, true);
+
 	if (rmi4_data->enable_wakeup_gesture) {
 		synaptics_rmi4_wakeup_gesture(rmi4_data, false);
 		disable_irq_wake(rmi4_data->irq);
@@ -4261,8 +4627,19 @@
 
 	rmi4_data->current_page = MASK_8BIT;
 
+	if (rmi4_data->suspend) {
+		synaptics_rmi4_get_reg(rmi4_data, true);
+		synaptics_rmi4_enable_reg(rmi4_data, true);
+	}
+
 	synaptics_rmi4_sleep_enable(rmi4_data, false);
 	synaptics_rmi4_irq_enable(rmi4_data, true, false);
+	if (rmi4_data->ts_pinctrl) {
+		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+		rmi4_data->pinctrl_state_active);
+		if (retval < 0)
+			dev_err(dev, "Cannot get default pinctrl state\n");
+	}
 
 exit:
 #ifdef FB_READY_RESET
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
index 0de0e99..39fec9a 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -48,6 +49,13 @@
 #include <linux/earlysuspend.h>
 #endif
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+#include <linux/completion.h>
+#include <linux/atomic.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#endif
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
 #define KERNEL_ABOVE_2_6_38
 #endif
@@ -115,6 +123,9 @@
 #define MASK_2BIT 0x03
 #define MASK_1BIT 0x01
 
+#define PINCTRL_STATE_ACTIVE    "pmx_ts_active"
+#define PINCTRL_STATE_SUSPEND   "pmx_ts_suspend"
+#define PINCTRL_STATE_RELEASE   "pmx_ts_release"
 enum exp_fn {
 	RMI_DEV = 0,
 	RMI_FW_UPDATER,
@@ -324,6 +335,7 @@
 	struct delayed_work rb_work;
 	struct workqueue_struct *rb_workqueue;
 #ifdef CONFIG_FB
+	struct work_struct fb_notify_work;
 	struct notifier_block fb_notifier;
 	struct work_struct reset_work;
 	struct workqueue_struct *reset_workqueue;
@@ -374,6 +386,19 @@
 			bool enable);
 	void (*report_touch)(struct synaptics_rmi4_data *rmi4_data,
 			struct synaptics_rmi4_fn *fhandler);
+	struct pinctrl *ts_pinctrl;
+	struct pinctrl_state *pinctrl_state_active;
+	struct pinctrl_state *pinctrl_state_suspend;
+	struct pinctrl_state *pinctrl_state_release;
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	atomic_t st_enabled;
+	atomic_t st_pending_irqs;
+	struct completion st_powerdown;
+	struct completion st_irq_processed;
+	bool st_initialized;
+	struct clk *core_clk;
+	struct clk *iface_clk;
+#endif
 };
 
 struct synaptics_dsx_bus_access {
@@ -382,6 +407,10 @@
 		unsigned char *data, unsigned short length);
 	int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
 		unsigned char *data, unsigned short length);
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	int (*get)(struct synaptics_rmi4_data *rmi4_data);
+	void (*put)(struct synaptics_rmi4_data *rmi4_data);
+#endif
 };
 
 struct synaptics_dsx_hw_interface {
@@ -432,21 +461,16 @@
 	return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
 }
 
-static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
-		struct device_attribute *attr, char *buf)
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static inline int synaptics_rmi4_bus_get(struct synaptics_rmi4_data *rmi4_data)
 {
-	dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
-			__func__, attr->attr.name);
-	return -EPERM;
+	return rmi4_data->hw_if->bus_access->get(rmi4_data);
 }
-
-static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
+static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data)
 {
-	dev_warn(dev, "%s Attempted to write to read-only attribute %s\n",
-			__func__, attr->attr.name);
-	return -EPERM;
+	rmi4_data->hw_if->bus_access->put(rmi4_data);
 }
+#endif
 
 static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
 		const unsigned char *src, unsigned int src_size,
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
index 9fb9beb..344f4c3 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -127,6 +128,7 @@
 
 static int fwu_recovery_check_status(void);
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count);
@@ -179,6 +181,7 @@
 
 static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count);
+#endif
 
 enum f34_version {
 	F34_V0 = 0,
@@ -650,6 +653,7 @@
 	struct work_struct fwu_work;
 };
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static struct bin_attribute dev_attr_data = {
 	.attr = {
 		.name = "data",
@@ -659,53 +663,56 @@
 	.read = fwu_sysfs_show_image,
 	.write = fwu_sysfs_store_image,
 };
+#endif
 
 static struct device_attribute attrs[] = {
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 	__ATTR(dorecovery, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_do_recovery_store),
 	__ATTR(doreflash, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_do_reflash_store),
 	__ATTR(writeconfig, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_write_config_store),
 	__ATTR(readconfig, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_read_config_store),
 	__ATTR(configarea, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_config_area_store),
 	__ATTR(imagename, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_image_name_store),
 	__ATTR(imagesize, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_image_size_store),
 	__ATTR(blocksize, 0444,
 			fwu_sysfs_block_size_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(fwblockcount, 0444,
 			fwu_sysfs_firmware_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(configblockcount, 0444,
 			fwu_sysfs_configuration_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(dispconfigblockcount, 0444,
 			fwu_sysfs_disp_config_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(permconfigblockcount, 0444,
 			fwu_sysfs_perm_config_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(blconfigblockcount, 0444,
 			fwu_sysfs_bl_config_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(guestcodeblockcount, 0444,
 			fwu_sysfs_guest_code_block_count_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(writeguestcode, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			fwu_sysfs_write_guest_code_store),
+#endif
 };
 
 static struct synaptics_rmi4_fwu_handle *fwu;
@@ -2218,10 +2225,12 @@
 					__func__);
 			return -ENOMEM;
 		}
-		while (strptr[index] >= '0' && strptr[index] <= '9') {
+		while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0'
+						&& strptr[index] <= '9') {
 			firmware_id[index] = strptr[index];
 			index++;
 		}
+		firmware_id[index] = '\0';
 
 		retval = sstrtoul(firmware_id, 10, (unsigned long *)fw_id);
 		kfree(firmware_id);
@@ -2608,6 +2617,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_check_pm_configuration_size(void)
 {
 	unsigned short block_count;
@@ -2624,6 +2634,7 @@
 
 	return 0;
 }
+#endif
 
 static int fwu_check_bl_configuration_size(void)
 {
@@ -2823,6 +2834,7 @@
 	return fwu_write_configuration();
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_write_pm_configuration(void)
 {
 	fwu->config_area = PM_CONFIG_AREA;
@@ -2832,6 +2844,7 @@
 
 	return fwu_write_configuration();
 }
+#endif
 
 static int fwu_write_flash_configuration(void)
 {
@@ -3039,6 +3052,7 @@
 	return retval;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_do_read_config(void)
 {
 	int retval;
@@ -3116,6 +3130,7 @@
 
 	return retval;
 }
+#endif
 
 static int fwu_do_lockdown_v7(void)
 {
@@ -3190,6 +3205,7 @@
 	return retval;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_start_write_guest_code(void)
 {
 	int retval;
@@ -3395,6 +3411,7 @@
 
 	return retval;
 }
+#endif
 
 static int fwu_start_reflash(void)
 {
@@ -3596,6 +3613,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static int fwu_recovery_erase_all(void)
 {
 	int retval;
@@ -3789,6 +3807,7 @@
 
 	return retval;
 }
+#endif
 
 int synaptics_fw_updater(const unsigned char *fw_data)
 {
@@ -3847,6 +3866,7 @@
 }
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
 static ssize_t fwu_sysfs_show_image(struct file *data_file,
 		struct kobject *kobj, struct bin_attribute *attributes,
 		char *buf, loff_t pos, size_t count)
@@ -4218,6 +4238,7 @@
 	fwu->image = NULL;
 	return retval;
 }
+#endif
 
 static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
 		unsigned char intr_mask)
@@ -4231,6 +4252,28 @@
 	return;
 }
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
+static int synaptics_create_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+	return sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
+			&dev_attr_data);
+}
+
+static void synaptics_remove_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+}
+#else
+static int synaptics_create_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+	return 0;
+}
+
+static void synaptics_remove_fwu_bin_file(struct synaptics_rmi4_data *rmi4_data)
+{
+}
+#endif
+
 static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
 {
 	int retval;
@@ -4302,8 +4345,7 @@
 	fwu->do_lockdown = DO_LOCKDOWN;
 	fwu->initialized = true;
 
-	retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
-			&dev_attr_data);
+	retval = synaptics_create_fwu_bin_file(rmi4_data);
 	if (retval < 0) {
 		dev_err(rmi4_data->pdev->dev.parent,
 				"%s: Failed to create sysfs bin file\n",
@@ -4338,7 +4380,7 @@
 				&attrs[attr_count].attr);
 	}
 
-	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+	synaptics_remove_fwu_bin_file(rmi4_data);
 
 exit_free_mem:
 	kfree(fwu->image_name);
@@ -4369,7 +4411,7 @@
 				&attrs[attr_count].attr);
 	}
 
-	sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+	synaptics_remove_fwu_bin_file(rmi4_data);
 
 	kfree(fwu->read_config_buf);
 	kfree(fwu->image_name);
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
index 0bd342c..ae1a55af 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -389,47 +390,47 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(engine_enable, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_engine_enable_store),
 	__ATTR(detection_enable, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_detection_enable_store),
 	__ATTR(detection_score, 0444,
 			udg_sysfs_detection_score_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(detection_index, 0444,
 			udg_sysfs_detection_index_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(registration_enable, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_registration_enable_store),
 	__ATTR(registration_begin, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_registration_begin_store),
 	__ATTR(registration_status, 0444,
 			udg_sysfs_registration_status_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_size, 0444,
 			udg_sysfs_template_size_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_max_index, 0444,
 			udg_sysfs_template_max_index_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_detection, 0444,
 			udg_sysfs_template_detection_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(template_index, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_template_index_store),
 	__ATTR(template_valid, 0664,
 			udg_sysfs_template_valid_show,
 			udg_sysfs_template_valid_store),
 	__ATTR(template_clear, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			udg_sysfs_template_clear_store),
 	__ATTR(trace_size, 0444,
 			udg_sysfs_trace_size_show,
-			synaptics_rmi4_store_error),
+			NULL),
 };
 
 static struct bin_attribute template_data = {
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
index 45951a4..df17a0b 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -77,6 +78,9 @@
 	else
 		bdata->irq_on_state = value;
 
+	bdata->resume_in_workqueue = of_property_read_bool(np,
+			"synaptics,resume-in-workqueue");
+
 	retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
 	if (retval < 0)
 		bdata->pwr_reg_name = NULL;
@@ -432,11 +436,11 @@
 	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
 	struct i2c_msg msg[1];
 
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+
 	retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
 	if (retval < 0)
-		return retval;
-
-	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+		goto exit;
 
 	retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
 	if (retval != PAGE_SELECT_LEN) {
@@ -487,10 +491,73 @@
 	return retval;
 }
 
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+static int synaptics_rmi4_clk_prepare_enable(
+		struct synaptics_rmi4_data *rmi4_data)
+{
+	int ret;
+
+	ret = clk_prepare_enable(rmi4_data->iface_clk);
+	if (ret) {
+		dev_err(rmi4_data->pdev->dev.parent,
+			"error on clk_prepare_enable(iface_clk):%d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(rmi4_data->core_clk);
+	if (ret) {
+		clk_disable_unprepare(rmi4_data->iface_clk);
+		dev_err(rmi4_data->pdev->dev.parent,
+			"error clk_prepare_enable(core_clk):%d\n", ret);
+	}
+	return ret;
+}
+
+static void synaptics_rmi4_clk_disable_unprepare(
+		struct synaptics_rmi4_data *rmi4_data)
+{
+	clk_disable_unprepare(rmi4_data->core_clk);
+	clk_disable_unprepare(rmi4_data->iface_clk);
+}
+
+static int synaptics_rmi4_i2c_get(struct synaptics_rmi4_data *rmi4_data)
+{
+	int retval;
+	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
+
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+	retval = pm_runtime_get_sync(i2c->adapter->dev.parent);
+	if (retval >= 0 && rmi4_data->core_clk != NULL &&
+				rmi4_data->iface_clk != NULL) {
+		retval = synaptics_rmi4_clk_prepare_enable(rmi4_data);
+		if (retval)
+			pm_runtime_put_sync(i2c->adapter->dev.parent);
+	}
+	mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
+
+	return retval;
+}
+
+static void synaptics_rmi4_i2c_put(struct synaptics_rmi4_data *rmi4_data)
+{
+	struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
+
+	mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+	if (rmi4_data->core_clk != NULL && rmi4_data->iface_clk != NULL)
+		synaptics_rmi4_clk_disable_unprepare(rmi4_data);
+	pm_runtime_put_sync(i2c->adapter->dev.parent);
+	mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
+}
+#endif
+
 static struct synaptics_dsx_bus_access bus_access = {
 	.type = BUS_I2C,
 	.read = synaptics_rmi4_i2c_read,
 	.write = synaptics_rmi4_i2c_write,
+#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
+	.get = synaptics_rmi4_i2c_get,
+	.put = synaptics_rmi4_i2c_put,
+#endif
 };
 
 static void synaptics_rmi4_i2c_dev_release(struct device *dev)
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
index 3f57d13..4392374 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -127,19 +128,19 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(open, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			rmidev_sysfs_open_store),
 	__ATTR(release, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			rmidev_sysfs_release_store),
 	__ATTR(attn_state, 0444,
 			rmidev_sysfs_attn_state_show,
-			synaptics_rmi4_store_error),
+			NULL),
 	__ATTR(pid, 0664,
 			rmidev_sysfs_pid_show,
 			rmidev_sysfs_pid_store),
 	__ATTR(term, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			rmidev_sysfs_term_store),
 	__ATTR(intr_mask, 0444,
 			rmidev_sysfs_intr_mask_show,
@@ -562,18 +563,24 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto clean_up;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
+	if (count == 0) {
+		retval = 0;
+		goto clean_up;
+	}
 	address = (unsigned short)(*f_pos);
 
 	rmidev_allocate_buffer(count);
 
-	mutex_lock(&(dev_data->file_mutex));
-
 	retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
 			*f_pos,
 			rmidev->tmpbuf,
@@ -633,18 +640,26 @@
 		return -EBADF;
 	}
 
-	if (count == 0)
-		return 0;
+	mutex_lock(&(dev_data->file_mutex));
+
+	if (*f_pos > REG_ADDR_LIMIT) {
+		retval = -EFAULT;
+		goto unlock;
+	}
 
 	if (count > (REG_ADDR_LIMIT - *f_pos))
 		count = REG_ADDR_LIMIT - *f_pos;
 
+	if (count == 0) {
+		retval = 0;
+		goto unlock;
+	}
 	rmidev_allocate_buffer(count);
 
-	if (copy_from_user(rmidev->tmpbuf, buf, count))
+	if (copy_from_user(rmidev->tmpbuf, buf, count)) {
 		return -EFAULT;
-
-	mutex_lock(&(dev_data->file_mutex));
+		goto unlock;
+	}
 
 	retval = synaptics_rmi4_reg_write(rmidev->rmi4_data,
 			*f_pos,
@@ -653,6 +668,7 @@
 	if (retval >= 0)
 		*f_pos += retval;
 
+unlock:
 	mutex_unlock(&(dev_data->file_mutex));
 
 	return retval;
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
index 1fdd89f..49bec56 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -198,23 +199,13 @@
 static ssize_t concat(test_sysfs, _##propname##_show)(\
 		struct device *dev,\
 		struct device_attribute *attr,\
-		char *buf);\
-\
-static struct device_attribute dev_attr_##propname =\
-		__ATTR(propname, 0444,\
-		concat(test_sysfs, _##propname##_show),\
-		synaptics_rmi4_store_error);
+		char *buf);
 
 #define store_prototype(propname)\
 static ssize_t concat(test_sysfs, _##propname##_store)(\
 		struct device *dev,\
 		struct device_attribute *attr,\
-		const char *buf, size_t count);\
-\
-static struct device_attribute dev_attr_##propname =\
-		__ATTR(propname, 0220,\
-		synaptics_rmi4_show_error,\
-		concat(test_sysfs, _##propname##_store));
+		const char *buf, size_t count);
 
 #define show_store_prototype(propname)\
 static ssize_t concat(test_sysfs, _##propname##_show)(\
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
index 312d203..bfd03cf 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -113,10 +114,10 @@
 
 static struct device_attribute attrs[] = {
 	__ATTR(dcs_write, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			video_sysfs_dcs_write_store),
 	__ATTR(param, 0220,
-			synaptics_rmi4_show_error,
+			NULL,
 			video_sysfs_param_store),
 };
 
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index f0e510f..868be8b 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -56,6 +56,7 @@
 #include <linux/ktime.h>
 #include <trace/events/iommu.h>
 #include <linux/notifier.h>
+#include <dt-bindings/arm/arm-smmu.h>
 
 #include <linux/amba/bus.h>
 #include <soc/qcom/msm_tz_smmu.h>
@@ -355,13 +356,11 @@
 	enum arm_smmu_s2cr_privcfg	privcfg;
 	u8				cbndx;
 	bool				cb_handoff;
-	bool				write_protected;
 };
 
 #define s2cr_init_val (struct arm_smmu_s2cr){				\
 	.type = disable_bypass ? S2CR_TYPE_FAULT : S2CR_TYPE_BYPASS,	\
 	.cb_handoff = false,						\
-	.write_protected = false,					\
 }
 
 struct arm_smmu_smr {
@@ -433,16 +432,6 @@
 #define ARM_SMMU_FEAT_FMT_AARCH32_S	(1 << 11)
 	u32				features;
 
-#define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
-#define ARM_SMMU_OPT_FATAL_ASF		(1 << 1)
-#define ARM_SMMU_OPT_SKIP_INIT		(1 << 2)
-#define ARM_SMMU_OPT_DYNAMIC		(1 << 3)
-#define ARM_SMMU_OPT_3LVL_TABLES	(1 << 4)
-#define ARM_SMMU_OPT_NO_ASID_RETENTION	(1 << 5)
-#define ARM_SMMU_OPT_DISABLE_ATOS	(1 << 6)
-#define ARM_SMMU_OPT_MMU500_ERRATA1	(1 << 7)
-#define ARM_SMMU_OPT_STATIC_CB		(1 << 8)
-#define ARM_SMMU_OPT_HALT		(1 << 9)
 	u32				options;
 	enum arm_smmu_arch_version	version;
 	enum arm_smmu_implementation	model;
@@ -450,6 +439,7 @@
 	u32				num_context_banks;
 	u32				num_s2_context_banks;
 	DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
+	DECLARE_BITMAP(secure_context_map, ARM_SMMU_MAX_CBS);
 	atomic_t			irptndx;
 
 	u32				num_mapping_groups;
@@ -2052,6 +2042,11 @@
 	arm_smmu_unassign_table(smmu_domain);
 	arm_smmu_secure_domain_unlock(smmu_domain);
 	__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
+	/* As the nonsecure context bank index is any way set to zero,
+	 * so, directly clearing up the secure cb bitmap.
+	 */
+	if (arm_smmu_is_slave_side_secure(smmu_domain))
+		__arm_smmu_free_bitmap(smmu->secure_context_map, cfg->cbndx);
 
 	arm_smmu_power_off(smmu->pwr);
 	arm_smmu_domain_reinit(smmu_domain);
@@ -2777,8 +2772,7 @@
 bool arm_smmu_skip_write(void __iomem *addr)
 {
 	struct arm_smmu_device *smmu;
-	unsigned long cb;
-	int i;
+	int cb;
 
 	smmu = arm_smmu_get_by_addr(addr);
 
@@ -2792,11 +2786,8 @@
 
 	/* Finally skip writing to secure CB */
 	cb = ((unsigned long)addr & ((smmu->size >> 1) - 1)) >> PAGE_SHIFT;
-	for (i = 0; i < smmu->num_mapping_groups; i++) {
-		if ((smmu->s2crs[i].cbndx == cb) &&
-		    (smmu->s2crs[i].write_protected))
-			return true;
-	}
+	if (test_bit(cb, smmu->secure_context_map))
+		return true;
 
 	return false;
 }
@@ -3736,8 +3727,7 @@
 		smmu_domain->slave_side_secure = true;
 
 		if (arm_smmu_is_slave_side_secure(smmu_domain))
-			for_each_cfg_sme(fwspec, i, idx)
-				smmu->s2crs[idx].write_protected = true;
+			bitmap_set(smmu->secure_context_map, cb, 1);
 	}
 
 	if (cb < 0 && !arm_smmu_is_static_cb(smmu)) {
@@ -4406,8 +4396,12 @@
 	smmu->arch_ops = data->arch_ops;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res)
-		smmu->phys_addr = res->start;
+	if (res == NULL) {
+		dev_err(dev, "no MEM resource info\n");
+		return -EINVAL;
+	}
+
+	smmu->phys_addr = res->start;
 	smmu->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(smmu->base))
 		return PTR_ERR(smmu->base);
@@ -4553,7 +4547,8 @@
 	if (arm_smmu_power_on(smmu->pwr))
 		return -EINVAL;
 
-	if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
+	if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS) ||
+	    !bitmap_empty(smmu->secure_context_map, ARM_SMMU_MAX_CBS))
 		dev_err(&pdev->dev, "removing device with active domains!\n");
 
 	idr_destroy(&smmu->asid_idr);
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index ad7ee11..eac7b41 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -927,7 +927,7 @@
 int fast_smmu_init_mapping(struct device *dev,
 			    struct dma_iommu_mapping *mapping)
 {
-	int err;
+	int err = 0;
 	struct iommu_domain *domain = mapping->domain;
 	struct iommu_pgtbl_info info;
 	u64 size = (u64)mapping->bits << PAGE_SHIFT;
diff --git a/drivers/irqchip/qcom/Kconfig b/drivers/irqchip/qcom/Kconfig
index b892109..0038047 100644
--- a/drivers/irqchip/qcom/Kconfig
+++ b/drivers/irqchip/qcom/Kconfig
@@ -20,3 +20,10 @@
         default y if ARCH_SDM670
         help
           QTI Power Domain Controller for SDM670
+
+config QTI_PDC_SDXPOORWILLS
+        bool "QTI PDC SDxPOORWILLS"
+        select QTI_PDC
+        default y if ARCH_SDXPOORWILLS
+        help
+          QTI Power Domain Controller for SDxPoorwills
diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile
index 5e99040..c4ff9ef 100644
--- a/drivers/irqchip/qcom/Makefile
+++ b/drivers/irqchip/qcom/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_QTI_PDC)			+= pdc.o
 obj-$(CONFIG_QTI_PDC_SDM845)		+= pdc-sdm845.o
 obj-$(CONFIG_QTI_PDC_SDM670)		+= pdc-sdm670.o
+obj-$(CONFIG_QTI_PDC_SDXPOORWILLS)	+= pdc-sdxpoorwills.o
diff --git a/drivers/irqchip/qcom/pdc-sdxpoorwills.c b/drivers/irqchip/qcom/pdc-sdxpoorwills.c
new file mode 100644
index 0000000..5bbca03
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc-sdxpoorwills.c
@@ -0,0 +1,76 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/irqchip.h>
+#include "pdc.h"
+
+static struct pdc_pin sdxpoorwills_data[] = {
+	{0, 179}, /* rpmh_wake */
+	{1, 180}, /* ee0_apps_hlos_spmi_periph_irq */
+	{2, 181}, /* ee1_apps_trustzone_spmi_periph_irq */
+	{3, 182}, /* secure_wdog_expired */
+	{4, 183}, /* secure_wdog_bark_irq */
+	{5, 184}, /* aop_wdog_expired_irq */
+	{8, 187}, /* aoss_pmic_arb_mpu_xpu_summary_irq */
+	{9, 188}, /* rpmh_wake */
+	{12, 191}, /* pdc_apps_epcb_timeout_summary_irq	*/
+	{13, 192}, /* spmi_protocol_irq	*/
+	{14, 193}, /* tsense0_tsense_max_min_int */
+	{15, 194}, /* apps_pdc_irq_in_15 */
+	{16, 195}, /* tsense0_upper_lower_intr */
+	{17, 196}, /* apps_pdc_irq_in_17 */
+	{18, 197}, /* tsense0_critical_intr	*/
+	{19, 198}, /* apps_pdc_irq_in_19 */
+	{20, 199}, /* apps_pdc.gp_irq_mux[0] */
+	{21, 200}, /* apps_pdc.gp_irq_mux[1] */
+	{22, 201}, /* apps_pdc.gp_irq_mux[2] */
+	{23, 202}, /* apps_pdc.gp_irq_mux[3] */
+	{24, 203}, /* apps_pdc.gp_irq_mux[4] */
+	{25, 204}, /* apps_pdc.gp_irq_mux[5] */
+	{26, 205}, /* apps_pdc.gp_irq_mux[6] */
+	{27, 206}, /* apps_pdc.gp_irq_mux[7] */
+	{28, 207}, /* apps_pdc.gp_irq_mux[8] */
+	{29, 208}, /* apps_pdc.gp_irq_mux[9] */
+	{30, 209}, /* apps_pdc.gp_irq_mux[10] */
+	{31, 210}, /* apps_pdc.gp_irq_mux[11] */
+	{32, 211}, /* apps_pdc.gp_irq_mux[12] */
+	{33, 212}, /* apps_pdc.gp_irq_mux[13] */
+	{34, 213}, /* apps_pdc.gp_irq_mux[14] */
+	{35, 214}, /* apps_pdc.gp_irq_mux[15] */
+	{36, 215}, /* apps_pdc.gp_irq_mux[16] */
+	{37, 216}, /* apps_pdc.gp_irq_mux[17] */
+	{38, 217}, /* apps_pdc.gp_irq_mux[18] */
+	{39, 218}, /* apps_pdc.gp_irq_mux[19] */
+	{40, 219}, /* apps_pdc.gp_irq_mux[20] */
+	{41, 220}, /* apps_pdc.gp_irq_mux[21] */
+	{42, 221}, /* apps_pdc.gp_irq_mux[22] */
+	{43, 222}, /* apps_pdc.gp_irq_mux[23] */
+	{44, 223}, /* apps_pdc.gp_irq_mux[24] */
+	{45, 224}, /* apps_pdc.gp_irq_mux[25] */
+	{46, 225}, /* apps_pdc.gp_irq_mux[26] */
+	{47, 226}, /* apps_pdc.gp_irq_mux[27] */
+	{48, 227}, /* apps_pdc.gp_irq_mux[28] */
+	{49, 228}, /* apps_pdc.gp_irq_mux[29] */
+	{50, 229}, /* apps_pdc.gp_irq_mux[30] */
+	{51, 230}, /* apps_pdc.gp_irq_mux[31] */
+	{-1}
+};
+
+static int __init qcom_pdc_gic_init(struct device_node *node,
+		struct device_node *parent)
+{
+	pr_info("PDC sdxpoowills initialized\n");
+	return qcom_pdc_init(node, parent, sdxpoorwills_data);
+}
+
+IRQCHIP_DECLARE(pdc_sdxpoorwills, "qcom,pdc-sdxpoorwills", qcom_pdc_gic_init);
diff --git a/drivers/irqchip/qcom/pdc.c b/drivers/irqchip/qcom/pdc.c
index 923552f..f4e9799 100644
--- a/drivers/irqchip/qcom/pdc.c
+++ b/drivers/irqchip/qcom/pdc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/irqchip.h>
+#include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -95,6 +96,20 @@
 	return 0;
 }
 
+static int qcom_pdc_gic_get_irqchip_state(struct irq_data *d,
+		enum irqchip_irq_state which, bool *state)
+{
+	return d->parent_data->chip->irq_get_irqchip_state(d->parent_data,
+		which, state);
+}
+
+static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d,
+		enum irqchip_irq_state which, bool value)
+{
+	return d->parent_data->chip->irq_set_irqchip_state(d->parent_data,
+		which, value);
+}
+
 static void qcom_pdc_gic_mask(struct irq_data *d)
 {
 	pdc_enable_intr(d, false);
@@ -220,6 +235,8 @@
 #ifdef CONFIG_SMP
 	.irq_set_affinity	= irq_chip_set_affinity_parent,
 #endif
+	.irq_get_irqchip_state	= qcom_pdc_gic_get_irqchip_state,
+	.irq_set_irqchip_state	= qcom_pdc_gic_set_irqchip_state,
 };
 
 static int qcom_pdc_translate(struct irq_domain *d,
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 96df61b..e9eaa50 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -73,8 +73,8 @@
 obj-$(CONFIG_LEDS_PM8058)		+= leds-pm8058.o
 obj-$(CONFIG_LEDS_MLXCPLD)		+= leds-mlxcpld.o
 obj-$(CONFIG_LEDS_QPNP)			+= leds-qpnp.o
-obj-$(CONFIG_LEDS_QPNP_FLASH)		+= leds-qpnp-flash.o
-obj-$(CONFIG_LEDS_QPNP_FLASH_V2)	+= leds-qpnp-flash-v2.o
+obj-$(CONFIG_LEDS_QPNP_FLASH)		+= leds-qpnp-flash.o leds-qpnp-flash-common.o
+obj-$(CONFIG_LEDS_QPNP_FLASH_V2)	+= leds-qpnp-flash-v2.o leds-qpnp-flash-common.o
 obj-$(CONFIG_LEDS_QPNP_WLED)		+= leds-qpnp-wled.o
 obj-$(CONFIG_LEDS_QPNP_HAPTICS)	+= leds-qpnp-haptics.o
 obj-$(CONFIG_LEDS_QPNP_VIBRATOR_LDO)	+= leds-qpnp-vibrator-ldo.o
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index d400dca..0ac3fa0 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 
 struct gpio_led_data {
 	struct led_classdev cdev;
@@ -144,6 +145,7 @@
 
 struct gpio_leds_priv {
 	int num_leds;
+	struct regulator *vdd_ldo_1, *vdd_ldo_2;
 	struct gpio_led_data leds[];
 };
 
@@ -158,8 +160,7 @@
 	struct device *dev = &pdev->dev;
 	struct fwnode_handle *child;
 	struct gpio_leds_priv *priv;
-	int count, ret;
-
+	int count, ret, error;
 	count = device_get_child_node_count(dev);
 	if (!count)
 		return ERR_PTR(-ENODEV);
@@ -214,7 +215,28 @@
 		led_dat->cdev.dev->of_node = np;
 		priv->num_leds++;
 	}
-
+	priv->vdd_ldo_1 = regulator_get(&pdev->dev, "vdd_ldo_1");
+	if (IS_ERR(priv->vdd_ldo_1)) {
+		error = PTR_ERR(priv->vdd_ldo_1);
+		pr_err("%s: regulator get failed vdd_ldo_1 rc=%d\n",
+			__func__, error);
+	}
+	ret = regulator_enable(priv->vdd_ldo_1);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_1 enable failed rc=%d\n",
+			__func__, ret);
+	}
+	priv->vdd_ldo_2 = regulator_get(&pdev->dev, "vdd_ldo_2");
+	if (IS_ERR(priv->vdd_ldo_2)) {
+		error = PTR_ERR(priv->vdd_ldo_2);
+		pr_err("%s: regulator get failed vdd_ldo_2 rc=%d\n",
+			__func__, error);
+	}
+	ret = regulator_enable(priv->vdd_ldo_2);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_2 enable failed rc=%d\n",
+			__func__, ret);
+	}
 	return priv;
 }
 
@@ -230,7 +252,6 @@
 	struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct gpio_leds_priv *priv;
 	int i, ret = 0;
-
 	if (pdata && pdata->num_leds) {
 		priv = devm_kzalloc(&pdev->dev,
 				sizeof_gpio_leds_priv(pdata->num_leds),
@@ -269,6 +290,50 @@
 	}
 }
 
+static int gpio_led_suspend(struct platform_device *pdev, pm_message_t message)
+{
+	int ret;
+	struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
+
+	if (priv->vdd_ldo_1) {
+		ret = regulator_disable(priv->vdd_ldo_1);
+		if (ret) {
+			pr_err("%s: Regulator vdd_ldo_1 disable failed rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	if (priv->vdd_ldo_2) {
+		ret = regulator_disable(priv->vdd_ldo_2);
+		if (ret) {
+			pr_err("%s: Regulator vdd_ldo_2 disable failed rc=%d\n",
+				__func__, ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static int gpio_led_resume(struct platform_device *pdev)
+{
+	int ret;
+	struct gpio_leds_priv *priv = platform_get_drvdata(pdev);
+
+	ret = regulator_enable(priv->vdd_ldo_1);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_1 enable failed rc=%d\n",
+			__func__, ret);
+		return ret;
+	}
+	ret = regulator_enable(priv->vdd_ldo_2);
+	if (ret) {
+		pr_err("%s: Regulator vdd_ldo_2 enable failed rc=%d\n",
+			__func__, ret);
+		return ret;
+	}
+	return 0;
+}
+
 static struct platform_driver gpio_led_driver = {
 	.probe		= gpio_led_probe,
 	.shutdown	= gpio_led_shutdown,
@@ -276,6 +341,8 @@
 		.name	= "leds-gpio",
 		.of_match_table = of_gpio_leds_match,
 	},
+	.suspend = gpio_led_suspend,
+	.resume = gpio_led_resume,
 };
 
 module_platform_driver(gpio_led_driver);
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/drivers/leds/leds-qpnp-flash-common.c
similarity index 60%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to drivers/leds/leds-qpnp-flash-common.c
index 194bfeb..5aed910 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/drivers/leds/leds-qpnp-flash-common.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -11,14 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/dts-v1/;
+#include <linux/leds-qpnp-flash.h>
 
-#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>;
-
-};
+int (*qpnp_flash_led_prepare)(struct led_trigger *trig, int options,
+					int *max_current);
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 7cf17c9..f3f9a1a 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -1216,7 +1216,7 @@
 	return 0;
 }
 
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+static int qpnp_flash_led_prepare_v2(struct led_trigger *trig, int options,
 					int *max_current)
 {
 	struct led_classdev *led_cdev;
@@ -2217,6 +2217,7 @@
 	if (!led->pdata)
 		return -ENOMEM;
 
+	qpnp_flash_led_prepare = qpnp_flash_led_prepare_v2;
 	rc = qpnp_flash_led_parse_common_dt(led, node);
 	if (rc < 0) {
 		pr_err("Failed to parse common flash LED device tree\n");
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index 3b07af8..ce2b055 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1207,7 +1207,7 @@
 	return rc;
 }
 
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+static int qpnp_flash_led_prepare_v1(struct led_trigger *trig, int options,
 					int *max_current)
 {
 	struct led_classdev *led_cdev = trigger_to_lcdev(trig);
@@ -2468,6 +2468,7 @@
 	led->pdev = pdev;
 	led->current_addr = FLASH_LED0_CURRENT(led->base);
 	led->current2_addr = FLASH_LED1_CURRENT(led->base);
+	qpnp_flash_led_prepare = qpnp_flash_led_prepare_v1;
 
 	led->pdata = devm_kzalloc(&pdev->dev, sizeof(*led->pdata), GFP_KERNEL);
 	if (!led->pdata)
diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c
index ebdff87..764657a 100644
--- a/drivers/leds/leds-qpnp-haptics.c
+++ b/drivers/leds/leds-qpnp-haptics.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2014-2015, 2017-2018, The Linux Foundation.
- * All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -275,6 +274,7 @@
  *  @ last_rate_cfg - Last rate config updated
  *  @ wave_rep_cnt - waveform repeat count
  *  @ wave_s_rep_cnt - waveform sample repeat count
+ *  @ wf_samp_len - waveform sample length
  *  @ ext_pwm_freq_khz - external pwm frequency in KHz
  *  @ ext_pwm_dtest_line - DTEST line for external pwm
  *  @ status_flags - status
@@ -330,6 +330,7 @@
 	u16				last_rate_cfg;
 	u32				wave_rep_cnt;
 	u32				wave_s_rep_cnt;
+	u32				wf_samp_len;
 	u32				ext_pwm_freq_khz;
 	u8				ext_pwm_dtest_line;
 	u32				status_flags;
@@ -445,6 +446,19 @@
 	return rc;
 }
 
+static inline int get_buffer_mode_duration(struct hap_chip *chip)
+{
+	int sample_count, sample_duration;
+
+	sample_count = chip->wave_rep_cnt * chip->wave_s_rep_cnt *
+			chip->wf_samp_len;
+	sample_duration = sample_count * chip->wave_play_rate_us;
+	pr_debug("sample_count: %d sample_duration: %d\n", sample_count,
+		sample_duration);
+
+	return (sample_duration / 1000);
+}
+
 static bool is_sw_lra_auto_resonance_control(struct hap_chip *chip)
 {
 	if (chip->act_type != HAP_LRA)
@@ -468,7 +482,8 @@
 {
 	int rc = 0;
 	u32 delay_us = HAPTICS_BACK_EMF_DELAY_US;
-	u8 val, auto_res_mode_qwd;
+	u8 val;
+	bool auto_res_mode_qwd;
 
 	if (chip->act_type != HAP_LRA)
 		return 0;
@@ -482,7 +497,7 @@
 
 	/*
 	 * Do not enable auto resonance if auto mode is enabled and auto
-	 * resonance mode is QWD, meaning short pattern.
+	 * resonance mode is QWD, meaning long pattern.
 	 */
 	if (chip->lra_auto_mode && auto_res_mode_qwd && enable) {
 		pr_debug("auto_mode enabled, not enabling auto_res\n");
@@ -735,11 +750,12 @@
 			goto out;
 		}
 
-		if (chip->play_mode != HAP_BUFFER)
-			hrtimer_start(&chip->stop_timer,
-				ktime_set(time_ms / MSEC_PER_SEC,
-				(time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC),
-				HRTIMER_MODE_REL);
+		if (chip->play_mode == HAP_BUFFER)
+			time_ms = get_buffer_mode_duration(chip);
+		hrtimer_start(&chip->stop_timer,
+			ktime_set(time_ms / MSEC_PER_SEC,
+			(time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
 
 		rc = qpnp_haptics_auto_res_enable(chip, true);
 		if (rc < 0) {
@@ -766,6 +782,9 @@
 
 		if (chip->play_mode == HAP_PWM)
 			pwm_disable(chip->pwm_data.pwm_dev);
+
+		if (chip->play_mode == HAP_BUFFER)
+			chip->wave_samp_idx = 0;
 	}
 
 out:
@@ -1182,8 +1201,11 @@
 	if (time_ms <= 20) {
 		wave_samp[0] = HAP_WF_SAMP_MAX;
 		wave_samp[1] = HAP_WF_SAMP_MAX;
-		if (time_ms > 15)
+		chip->wf_samp_len = 2;
+		if (time_ms > 15) {
 			wave_samp[2] = HAP_WF_SAMP_MAX;
+			chip->wf_samp_len = 3;
+		}
 
 		/* short pattern */
 		rc = qpnp_haptics_parse_buffer_dt(chip);
@@ -1211,7 +1233,7 @@
 			ares_cfg.lra_qwd_drive_duration = 0;
 			ares_cfg.calibrate_at_eop = 0;
 		} else {
-			ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
 			ares_cfg.lra_qwd_drive_duration = -EINVAL;
 			ares_cfg.calibrate_at_eop = -EINVAL;
 		}
@@ -1221,16 +1243,13 @@
 		if (rc < 0)
 			return rc;
 
-		rc = qpnp_haptics_brake_config(chip, brake_pat);
-		if (rc < 0)
-			return rc;
-
 		/* enable play_irq for buffer mode */
 		if (chip->play_irq >= 0 && !chip->play_irq_en) {
 			enable_irq(chip->play_irq);
 			chip->play_irq_en = true;
 		}
 
+		brake_pat[0] = BRAKE_VMAX;
 		chip->play_mode = HAP_BUFFER;
 		chip->wave_shape = HAP_WAVE_SQUARE;
 	} else {
@@ -1243,7 +1262,7 @@
 			ares_cfg.lra_qwd_drive_duration = 0;
 			ares_cfg.calibrate_at_eop = 1;
 		} else {
-			ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP;
+			ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD;
 			ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX;
 			ares_cfg.lra_qwd_drive_duration = -EINVAL;
 			ares_cfg.calibrate_at_eop = -EINVAL;
@@ -1254,11 +1273,6 @@
 		if (rc < 0)
 			return rc;
 
-		brake_pat[0] = 0x3;
-		rc = qpnp_haptics_brake_config(chip, brake_pat);
-		if (rc < 0)
-			return rc;
-
 		/* enable play_irq for direct mode */
 		if (chip->play_irq >= 0 && chip->play_irq_en) {
 			disable_irq(chip->play_irq);
@@ -1282,6 +1296,10 @@
 		return rc;
 	}
 
+	rc = qpnp_haptics_brake_config(chip, brake_pat);
+	if (rc < 0)
+		return rc;
+
 	rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip),
 			HAP_LRA_RES_TYPE_MASK, chip->wave_shape);
 	if (rc < 0)
@@ -1302,33 +1320,20 @@
 		chip->wave_samp_idx += HAP_WAVE_SAMP_LEN;
 		if (chip->wave_samp_idx >= ARRAY_SIZE(chip->wave_samp)) {
 			pr_debug("Samples over\n");
-			/* fall through to stop playing */
 		} else {
 			pr_debug("moving to next sample set %d\n",
 				chip->wave_samp_idx);
 
+			/* Moving to next set of wave sample */
 			rc = qpnp_haptics_buffer_config(chip, NULL, false);
 			if (rc < 0) {
 				pr_err("Error in configuring buffer, rc=%d\n",
 					rc);
 				goto irq_handled;
 			}
-
-			/*
-			 * Moving to next set of wave sample. No need to stop
-			 * or change the play control. Just return.
-			 */
-			goto irq_handled;
 		}
 	}
 
-	rc = qpnp_haptics_play_control(chip, HAP_STOP);
-	if (rc < 0) {
-		pr_err("Error in disabling play, rc=%d\n", rc);
-		goto irq_handled;
-	}
-	chip->wave_samp_idx = 0;
-
 irq_handled:
 	return IRQ_HANDLED;
 }
@@ -1638,6 +1643,7 @@
 		pos += bytes_read;
 	}
 
+	chip->wf_samp_len = i;
 	for (i = 0; i < ARRAY_SIZE(chip->wave_samp); i++)
 		chip->wave_samp[i] = samp[i];
 
@@ -1986,7 +1992,10 @@
 		/* Use default values */
 		for (i = 0; i < HAP_WAVE_SAMP_LEN; i++)
 			chip->wave_samp[i] = HAP_WF_SAMP_MAX;
+
+		wf_samp_len = HAP_WAVE_SAMP_LEN;
 	}
+	chip->wf_samp_len = wf_samp_len;
 
 	return 0;
 }
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 2efdce0..cac297f 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -803,7 +803,10 @@
 	c->shrink.scan_objects = bch_mca_scan;
 	c->shrink.seeks = 4;
 	c->shrink.batch = c->btree_pages * 2;
-	register_shrinker(&c->shrink);
+
+	if (register_shrinker(&c->shrink))
+		pr_warn("bcache: %s: could not register shrinker",
+				__func__);
 
 	return 0;
 }
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 4477bf9..e976f4f 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -81,10 +81,14 @@
 #define SECTOR_TO_BLOCK_SHIFT 3
 
 /*
+ * For btree insert:
  *  3 for btree insert +
  *  2 for btree lookup used within space map
+ * For btree remove:
+ *  2 for shadow spine +
+ *  4 for rebalance 3 child node
  */
-#define THIN_MAX_CONCURRENT_LOCKS 5
+#define THIN_MAX_CONCURRENT_LOCKS 6
 
 /* This should be plenty */
 #define SPACE_MAP_ROOT_SIZE 128
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index 7a75b50..e4ececd 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -678,23 +678,8 @@
 	pn->keys[1] = rn->keys[0];
 	memcpy_disk(value_ptr(pn, 1), &val, sizeof(__le64));
 
-	/*
-	 * rejig the spine.  This is ugly, since it knows too
-	 * much about the spine
-	 */
-	if (s->nodes[0] != new_parent) {
-		unlock_block(s->info, s->nodes[0]);
-		s->nodes[0] = new_parent;
-	}
-	if (key < le64_to_cpu(rn->keys[0])) {
-		unlock_block(s->info, right);
-		s->nodes[1] = left;
-	} else {
-		unlock_block(s->info, left);
-		s->nodes[1] = right;
-	}
-	s->count = 2;
-
+	unlock_block(s->info, left);
+	unlock_block(s->info, right);
 	return 0;
 }
 
diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig
index 484819d..4367048 100644
--- a/drivers/media/platform/msm/Kconfig
+++ b/drivers/media/platform/msm/Kconfig
@@ -13,8 +13,8 @@
       Enabling this adds support for the camera driver stack including sensor,
       IFE and postprocessing drivers.
 
+source "drivers/media/platform/msm/vidc_3x/Kconfig"
 source "drivers/media/platform/msm/vidc/Kconfig"
-
 source "drivers/media/platform/msm/sde/Kconfig"
 source "drivers/media/platform/msm/dvb/Kconfig"
 source "drivers/media/platform/msm/broadcast/Kconfig"
diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile
index e64bcd1..fea242a 100644
--- a/drivers/media/platform/msm/Makefile
+++ b/drivers/media/platform/msm/Makefile
@@ -3,6 +3,7 @@
 # based on V4L2.
 #
 obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/
+obj-$(CONFIG_MSM_VIDC_3X_V4L2) += vidc_3x/
 obj-y += sde/
 obj-$(CONFIG_SPECTRA_CAMERA) += camera/
 obj-y += broadcast/
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.c b/drivers/media/platform/msm/camera/cam_core/cam_context.c
index 7e6d999..d1222aa 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -196,6 +196,30 @@
 	return rc;
 }
 
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *process_evt)
+{
+	int rc = 0;
+
+	if (!ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context is not ready");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].crm_ops.process_evt) {
+		rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx,
+			process_evt);
+	} else {
+		/* handling of this message is optional */
+		CAM_DBG(CAM_CORE, "No crm process evt in dev %d, state %d",
+			ctx->dev_hdl, ctx->state);
+	}
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
 int cam_context_handle_acquire_dev(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
@@ -257,10 +281,10 @@
 int cam_context_handle_flush_dev(struct cam_context *ctx,
 	struct cam_flush_dev_cmd *cmd)
 {
-	int rc;
+	int rc = 0;
 
 	if (!ctx->state_machine) {
-		CAM_ERR(CAM_CORE, "context is not ready");
+		CAM_ERR(CAM_CORE, "Context is not ready");
 		return -EINVAL;
 	}
 
@@ -274,9 +298,8 @@
 		rc = ctx->state_machine[ctx->state].ioctl_ops.flush_dev(
 			ctx, cmd);
 	} else {
-		CAM_ERR(CAM_CORE, "No flush device in dev %d, state %d",
+		CAM_WARN(CAM_CORE, "No flush device in dev %d, state %d",
 			ctx->dev_hdl, ctx->state);
-		rc = -EPROTO;
 	}
 	mutex_unlock(&ctx->ctx_mutex);
 
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context.h b/drivers/media/platform/msm/camera/cam_core/cam_context.h
index c823b7a..af92b7e 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context.h
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -110,6 +110,7 @@
  * @unlink:                Unlink the context
  * @apply_req:             Apply setting for the context
  * @flush_req:             Flush request to remove request ids
+ * @process_evt:           Handle event notification from CRM.(optional)
  *
  */
 struct cam_ctx_crm_ops {
@@ -123,6 +124,8 @@
 			struct cam_req_mgr_apply_request *apply);
 	int (*flush_req)(struct cam_context *ctx,
 			struct cam_req_mgr_flush_request *flush);
+	int (*process_evt)(struct cam_context *ctx,
+			struct cam_req_mgr_link_evt_data *evt_data);
 };
 
 
@@ -273,6 +276,18 @@
 		struct cam_req_mgr_flush_request *apply);
 
 /**
+ * cam_context_handle_crm_process_evt()
+ *
+ * @brief:        Handle process event command
+ *
+ * @ctx:          Object pointer for cam_context
+ * @process_evt:  process event command payload
+ *
+ */
+int cam_context_handle_crm_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *process_evt);
+
+/**
  * cam_context_handle_acquire_dev()
  *
  * @brief:        Handle acquire device command
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index aab1a1a..8ea920d 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -430,6 +430,8 @@
 	uint32_t i;
 	int rc = 0;
 
+	CAM_DBG(CAM_CTXT, "E: NRT flush ctx");
+
 	/*
 	 * flush pending requests, take the sync lock to synchronize with the
 	 * sync callback thread so that the sync cb thread does not try to
@@ -444,23 +446,33 @@
 	while (!list_empty(&temp_list)) {
 		req = list_first_entry(&temp_list,
 				struct cam_ctx_request, list);
+
 		list_del_init(&req->list);
 		req->flushed = 1;
+
 		flush_args.flush_req_pending[flush_args.num_req_pending++] =
 			req->req_priv;
 		for (i = 0; i < req->num_out_map_entries; i++)
-			if (req->out_map_entries[i].sync_id != -1)
-				cam_sync_signal(req->out_map_entries[i].sync_id,
+			if (req->out_map_entries[i].sync_id != -1) {
+				rc = cam_sync_signal(
+					req->out_map_entries[i].sync_id,
 					CAM_SYNC_STATE_SIGNALED_ERROR);
+				if (rc == -EALREADY) {
+					CAM_ERR(CAM_CTXT,
+						"Req: %llu already signalled, sync_id:%d",
+						req->request_id,
+						req->out_map_entries[i].
+						sync_id);
+					break;
+				}
+			}
 	}
 	mutex_unlock(&ctx->sync_mutex);
 
 	if (ctx->hw_mgr_intf->hw_flush) {
 		flush_args.num_req_active = 0;
 		spin_lock(&ctx->lock);
-		INIT_LIST_HEAD(&temp_list);
-		list_splice_init(&ctx->active_req_list, &temp_list);
-		list_for_each_entry(req, &temp_list, list) {
+		list_for_each_entry(req, &ctx->active_req_list, list) {
 			flush_args.flush_req_active[flush_args.num_req_active++]
 				= req->req_priv;
 		}
@@ -474,24 +486,42 @@
 		}
 	}
 
+	INIT_LIST_HEAD(&temp_list);
+	spin_lock(&ctx->lock);
+	list_splice_init(&ctx->active_req_list, &temp_list);
+	INIT_LIST_HEAD(&ctx->active_req_list);
+	spin_unlock(&ctx->lock);
+
 	while (!list_empty(&temp_list)) {
 		req = list_first_entry(&temp_list,
 			struct cam_ctx_request, list);
 		list_del_init(&req->list);
-		for (i = 0; i < req->num_out_map_entries; i++)
+		for (i = 0; i < req->num_out_map_entries; i++) {
 			if (req->out_map_entries[i].sync_id != -1) {
-				cam_sync_signal(req->out_map_entries[i].sync_id,
+				rc = cam_sync_signal(
+					req->out_map_entries[i].sync_id,
 					CAM_SYNC_STATE_SIGNALED_ERROR);
+				if (rc == -EALREADY) {
+					CAM_ERR(CAM_CTXT,
+						"Req: %llu already signalled ctx: %pK dev_name: %s dev_handle: %d ctx_state: %d",
+						req->request_id, req->ctx,
+						req->ctx->dev_name,
+						req->ctx->dev_hdl,
+						req->ctx->state);
+					break;
+				}
 			}
+		}
 
 		spin_lock(&ctx->lock);
 		list_add_tail(&req->list, &ctx->free_req_list);
 		spin_unlock(&ctx->lock);
 		req->ctx = NULL;
 	}
-	INIT_LIST_HEAD(&ctx->active_req_list);
 
-	return rc;
+	CAM_DBG(CAM_CTXT, "X: NRT flush ctx");
+
+	return 0;
 }
 
 int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
@@ -502,6 +532,8 @@
 	uint32_t i;
 	int rc = 0;
 
+	CAM_DBG(CAM_CTXT, "E: NRT flush req");
+
 	flush_args.num_req_pending = 0;
 	flush_args.num_req_active = 0;
 	mutex_lock(&ctx->sync_mutex);
@@ -510,7 +542,9 @@
 		if (req->request_id != cmd->req_id)
 			continue;
 
+		list_del_init(&req->list);
 		req->flushed = 1;
+
 		flush_args.flush_req_pending[flush_args.num_req_pending++] =
 			req->req_priv;
 		break;
@@ -525,6 +559,8 @@
 				if (req->request_id != cmd->req_id)
 					continue;
 
+				list_del_init(&req->list);
+
 				flush_args.flush_req_active[
 					flush_args.num_req_active++] =
 					req->req_priv;
@@ -543,20 +579,31 @@
 
 	if (req) {
 		if (flush_args.num_req_pending || flush_args.num_req_active) {
-			list_del_init(&req->list);
 			for (i = 0; i < req->num_out_map_entries; i++)
-				if (req->out_map_entries[i].sync_id != -1)
-					cam_sync_signal(
+				if (req->out_map_entries[i].sync_id != -1) {
+					rc = cam_sync_signal(
 						req->out_map_entries[i].sync_id,
 						CAM_SYNC_STATE_SIGNALED_ERROR);
-			spin_lock(&ctx->lock);
-			list_add_tail(&req->list, &ctx->free_req_list);
-			spin_unlock(&ctx->lock);
-			req->ctx = NULL;
+					if (rc == -EALREADY) {
+						CAM_ERR(CAM_CTXT,
+							"Req: %llu already signalled, sync_id:%d",
+							req->request_id,
+							req->out_map_entries[i].
+							sync_id);
+						break;
+					}
+				}
+			if (flush_args.num_req_active) {
+				spin_lock(&ctx->lock);
+				list_add_tail(&req->list, &ctx->free_req_list);
+				spin_unlock(&ctx->lock);
+				req->ctx = NULL;
+			}
 		}
 	}
+	CAM_DBG(CAM_CTXT, "X: NRT flush req");
 
-	return rc;
+	return 0;
 }
 
 int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx,
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index a5977b3..4e9034e 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -220,7 +220,7 @@
 
 	rc = cam_context_handle_flush_dev(ctx, flush);
 	if (rc)
-		CAM_ERR(CAM_CORE, "FLush failure for node %s", node->name);
+		CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name);
 
 	return rc;
 }
@@ -342,6 +342,25 @@
 	return cam_context_handle_crm_flush_req(ctx, flush);
 }
 
+static int __cam_node_crm_process_evt(
+	struct cam_req_mgr_link_evt_data *evt_data)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!evt_data) {
+		CAM_ERR(CAM_CORE, "Invalid process event request payload");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl);
+	if (!ctx) {
+		CAM_ERR(CAM_CORE, "Can not get context for handle %d",
+			evt_data->dev_hdl);
+		return -EINVAL;
+	}
+	return cam_context_handle_crm_process_evt(ctx, evt_data);
+}
+
 int cam_node_deinit(struct cam_node *node)
 {
 	if (node)
@@ -394,6 +413,7 @@
 	node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info;
 	node->crm_node_intf.link_setup = __cam_node_crm_link_setup;
 	node->crm_node_intf.flush_req = __cam_node_crm_flush_req;
+	node->crm_node_intf.process_evt = __cam_node_crm_process_evt;
 
 	mutex_init(&node->list_mutex);
 	INIT_LIST_HEAD(&node->free_ctx_list);
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 3ebe7a1..b04bc23 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,12 +16,19 @@
 #include <linux/msm-bus.h>
 #include <linux/pm_opp.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include "cam_cpas_hw.h"
 #include "cam_cpas_hw_intf.h"
 #include "cam_cpas_soc.h"
 
-#define CAM_CPAS_AXI_MIN_BW (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_MNOC_AB_BW   (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_MNOC_IB_BW   (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024)
+#define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000L)
+
+static uint cam_min_camnoc_ib_bw;
+module_param(cam_min_camnoc_ib_bw, uint, 0644);
 
 int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw,
 	enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info)
@@ -84,11 +91,19 @@
 }
 
 static int cam_cpas_util_vote_bus_client_bw(
-	struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib)
+	struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib,
+	bool camnoc_bw)
 {
 	struct msm_bus_paths *path;
 	struct msm_bus_scale_pdata *pdata;
 	int idx = 0;
+	uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW;
+
+	if (cam_min_camnoc_ib_bw > 0)
+		min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L;
+
+	CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu",
+		cam_min_camnoc_ib_bw, min_camnoc_ib_bw);
 
 	if (!bus_client->valid) {
 		CAM_ERR(CAM_CPAS, "bus client not valid");
@@ -118,11 +133,19 @@
 	bus_client->curr_vote_level = idx;
 	mutex_unlock(&bus_client->lock);
 
-	if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_BW))
-		ab = CAM_CPAS_AXI_MIN_BW;
+	if (camnoc_bw == true) {
+		if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW))
+			ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW;
 
-	if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_BW))
-		ib = CAM_CPAS_AXI_MIN_BW;
+		if ((ib > 0) && (ib < min_camnoc_ib_bw))
+			ib = min_camnoc_ib_bw;
+	} else {
+		if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW))
+			ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW;
+
+		if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW))
+			ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW;
+	}
 
 	pdata = bus_client->pdata;
 	path = &(pdata->usecase[idx]);
@@ -205,7 +228,7 @@
 		return -EINVAL;
 
 	if (bus_client->dyn_vote)
-		cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0);
+		cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false);
 	else
 		cam_cpas_util_vote_bus_client_level(bus_client, 0);
 
@@ -370,7 +393,7 @@
 	list_for_each_entry_safe(curr_port, temp_port,
 		&cpas_core->axi_ports_list_head, sibling_port) {
 		rc = cam_cpas_util_vote_bus_client_bw(&curr_port->mnoc_bus,
-			mnoc_bw, mnoc_bw);
+			mnoc_bw, mnoc_bw, false);
 		if (rc) {
 			CAM_ERR(CAM_CPAS,
 				"Failed in mnoc vote, enable=%d, rc=%d",
@@ -380,13 +403,13 @@
 
 		if (soc_private->axi_camnoc_based) {
 			cam_cpas_util_vote_bus_client_bw(
-				&curr_port->camnoc_bus, 0, camnoc_bw);
+				&curr_port->camnoc_bus, 0, camnoc_bw, true);
 			if (rc) {
 				CAM_ERR(CAM_CPAS,
 					"Failed in mnoc vote, enable=%d, %d",
 					enable, rc);
 				cam_cpas_util_vote_bus_client_bw(
-					&curr_port->mnoc_bus, 0, 0);
+					&curr_port->mnoc_bus, 0, 0, false);
 				goto remove_ahb_vote;
 			}
 		}
@@ -571,7 +594,7 @@
 		camnoc_bw, mnoc_bw);
 
 	rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus,
-		mnoc_bw, mnoc_bw);
+		mnoc_bw, mnoc_bw, false);
 	if (rc) {
 		CAM_ERR(CAM_CPAS,
 			"Failed in mnoc vote ab[%llu] ib[%llu] rc=%d",
@@ -581,7 +604,7 @@
 
 	if (soc_private->axi_camnoc_based) {
 		rc = cam_cpas_util_vote_bus_client_bw(&axi_port->camnoc_bus,
-			0, camnoc_bw);
+			0, camnoc_bw, true);
 		if (rc) {
 			CAM_ERR(CAM_CPAS,
 				"Failed camnoc vote ab[%llu] ib[%llu] rc=%d",
@@ -880,9 +903,11 @@
 		goto done;
 
 	if (cpas_core->streamon_clients == 0) {
+		atomic_set(&cpas_core->irq_count, 1);
 		rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info,
 			applied_level);
 		if (rc) {
+			atomic_set(&cpas_core->irq_count, 0);
 			CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc);
 			goto done;
 		}
@@ -890,14 +915,17 @@
 		if (cpas_core->internal_ops.power_on) {
 			rc = cpas_core->internal_ops.power_on(cpas_hw);
 			if (rc) {
+				atomic_set(&cpas_core->irq_count, 0);
 				cam_cpas_soc_disable_resources(
-					&cpas_hw->soc_info);
+					&cpas_hw->soc_info, true, true);
 				CAM_ERR(CAM_CPAS,
 					"failed in power_on settings rc=%d",
 					rc);
 				goto done;
 			}
 		}
+		CAM_DBG(CAM_CPAS, "irq_count=%d\n",
+			atomic_read(&cpas_core->irq_count));
 		cpas_hw->hw_state = CAM_HW_STATE_POWER_UP;
 	}
 
@@ -912,6 +940,10 @@
 	return rc;
 }
 
+static int _check_irq_count(struct cam_cpas *cpas_core)
+{
+	return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1;
+}
 
 static int cam_cpas_hw_stop(void *hw_priv, void *stop_args,
 	uint32_t arg_size)
@@ -924,6 +956,7 @@
 	struct cam_ahb_vote ahb_vote;
 	struct cam_axi_vote axi_vote;
 	int rc = 0;
+	long result;
 
 	if (!hw_priv || !stop_args) {
 		CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK",
@@ -972,11 +1005,29 @@
 			}
 		}
 
-		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
+		rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info);
+		if (rc) {
+			CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc);
+			goto done;
+		}
+
+		/* Wait for any IRQs still being handled */
+		atomic_dec(&cpas_core->irq_count);
+		result = wait_event_timeout(cpas_core->irq_count_wq,
+			_check_irq_count(cpas_core), HZ);
+		if (result == 0) {
+			CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d",
+				atomic_read(&cpas_core->irq_count));
+		}
+
+		rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info,
+			true, false);
 		if (rc) {
 			CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc);
 			goto done;
 		}
+		CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n",
+			atomic_read(&cpas_core->irq_count));
 		cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
 	}
 
@@ -1427,6 +1478,8 @@
 	soc_private = (struct cam_cpas_private_soc *)
 		cpas_hw->soc_info.soc_private;
 	cpas_core->num_clients = soc_private->num_clients;
+	atomic_set(&cpas_core->irq_count, 0);
+	init_waitqueue_head(&cpas_core->irq_count_wq);
 
 	if (internal_ops->setup_regbase) {
 		rc = internal_ops->setup_regbase(&cpas_hw->soc_info,
@@ -1482,7 +1535,7 @@
 	if (rc)
 		goto disable_soc_res;
 
-	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
+	rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
 	if (rc) {
 		CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc);
 		goto remove_default_vote;
@@ -1500,7 +1553,7 @@
 	return 0;
 
 disable_soc_res:
-	cam_cpas_soc_disable_resources(&cpas_hw->soc_info);
+	cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true);
 remove_default_vote:
 	cam_cpas_util_vote_default_ahb_axi(cpas_hw, false);
 axi_cleanup:
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
index aa3663d..05840bb 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -187,6 +187,8 @@
 	struct list_head axi_ports_list_head;
 	struct cam_cpas_internal_ops internal_ops;
 	struct workqueue_struct *work_queue;
+	atomic_t irq_count;
+	wait_queue_head_t irq_count_wq;
 };
 
 int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops);
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
index d5108f6..0187a64 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -366,7 +366,6 @@
 	switch (cmd->op_code) {
 	case CAM_QUERY_CAP: {
 		struct cam_cpas_query_cap query;
-		uint32_t cam_cpas;
 
 		rc = copy_from_user(&query, (void __user *) cmd->handle,
 			sizeof(query));
@@ -377,7 +376,8 @@
 		}
 
 		rc = cam_cpas_get_hw_info(&query.camera_family,
-			&query.camera_version, &query.cpas_version, &cam_cpas);
+			&query.camera_version, &query.cpas_version,
+			&query.reserved);
 		if (rc)
 			break;
 
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
index f85f461..b18af0a 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -209,13 +209,26 @@
 	return rc;
 }
 
-int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info)
+int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info,
+	bool disable_clocks, bool disble_irq)
 {
 	int rc = 0;
 
-	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+	rc = cam_soc_util_disable_platform_resource(soc_info,
+		disable_clocks, disble_irq);
 	if (rc)
 		CAM_ERR(CAM_CPAS, "disable platform failed, rc=%d", rc);
 
 	return rc;
 }
+
+int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info)
+{
+	int rc = 0;
+
+	rc = cam_soc_util_irq_disable(soc_info);
+	if (rc)
+		CAM_ERR(CAM_CPAS, "disable irq failed, rc=%d", rc);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
index d4fc039..fe0187e 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -61,5 +61,7 @@
 int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info);
 int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info,
 	enum cam_vote_level default_level);
-int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info);
+int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info,
+	bool disable_clocks, bool disble_irq);
+int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info);
 #endif /* _CAM_CPAS_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
index 0e5ce85..0533ed8 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -354,6 +354,11 @@
 	cpas_core = (struct cam_cpas *) cpas_hw->core_info;
 	soc_info = &cpas_hw->soc_info;
 
+	if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
+		CAM_ERR(CAM_CPAS, "CPAS off");
+		return;
+	}
+
 	for (i = 0; i < camnoc_info->irq_err_size; i++) {
 		if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) &&
 			(camnoc_info->irq_err[i].enable)) {
@@ -398,6 +403,9 @@
 				~camnoc_info->irq_err[i].sbm_port;
 		}
 	}
+	atomic_dec(&cpas_core->irq_count);
+	wake_up(&cpas_core->irq_count_wq);
+	CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count));
 
 	if (payload->irq_status)
 		CAM_ERR(CAM_CPAS, "IRQ not handled irq_status=0x%x",
@@ -414,9 +422,14 @@
 	int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
 	struct cam_cpas_work_payload *payload;
 
+	if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
+		CAM_ERR(CAM_CPAS, "CPAS off");
+		return IRQ_HANDLED;
+	}
+
 	payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC);
 	if (!payload)
-		return IRQ_HANDLED;
+		goto done;
 
 	payload->irq_status = cam_io_r_mb(
 		soc_info->reg_map[camnoc_index].mem_base +
@@ -433,6 +446,9 @@
 	cam_cpastop_reset_irq(cpas_hw);
 
 	queue_work(cpas_core->work_queue, &payload->work);
+done:
+	atomic_dec(&cpas_core->irq_count);
+	wake_up(&cpas_core->irq_count_wq);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index b9b59a1..178e734 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -110,7 +110,7 @@
 /**
  * cam_hfi_deinit() - cleanup HFI
  */
-void cam_hfi_deinit(void);
+void cam_hfi_deinit(void __iomem *icp_base);
 /**
  * hfi_set_debug_level() - set debug level
  * @lvl: FW debug message level
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
index 0412b8a..7b2cb8b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,30 @@
 #define HFI_IPEBPS_HANDLE_TYPE_IPE_NON_RT               0x3
 
 /**
+ * struct abort_data
+ * @num_req_ids: Number of req ids
+ * @num_req_id: point to specific req id
+ *
+ * create abort data
+ */
+struct abort_data {
+	uint32_t num_req_ids;
+	uint32_t num_req_id[1];
+};
+
+/**
+ * struct hfi_cmd_data
+ * @abort: abort data
+ * @user data: user supplied argument
+ *
+ * create session abort data
+ */
+struct hfi_cmd_abort {
+	struct abort_data abort;
+	uint64_t user_data;
+} __packed;
+
+/**
  * struct hfi_cmd_abort_destroy
  * @user_data: user supplied data
  *
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index 77f33d0..f95f8eb 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -124,7 +124,7 @@
 	 * firmware to process
 	 */
 	wmb();
-	cam_io_w((uint32_t)INTR_ENABLE,
+	cam_io_w_mb((uint32_t)INTR_ENABLE,
 		g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT);
 err:
 	mutex_unlock(&hfi_cmd_q_mutex);
@@ -222,6 +222,10 @@
 
 	q->qhdr_read_idx = new_read_idx;
 	*words_read = size_in_words;
+	/* Memory Barrier to make sure message
+	 * queue parameters are updated after read
+	 */
+	wmb();
 err:
 	mutex_unlock(&hfi_msg_q_mutex);
 	return rc;
@@ -445,17 +449,17 @@
 
 	val = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	val &= ~(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN);
-	cam_io_w(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+	cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 
 	val = cam_io_r(icp_base + HFI_REG_A5_CSR_NSEC_RESET);
-	cam_io_w(val, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
+	cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
 }
 
 void cam_hfi_enable_cpu(void __iomem *icp_base)
 {
-	cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN,
+	cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN,
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
-	cam_io_w((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
+	cam_io_w_mb((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
 }
 
 int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
@@ -464,23 +468,11 @@
 	int rc = 0;
 	uint32_t data;
 	uint32_t fw_version, status = 0;
+	uint32_t retry_cnt = 0;
 
 	cam_hfi_enable_cpu(icp_base);
 	g_hfi->csr_base = icp_base;
 
-	rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
-		status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
-
-	if (rc) {
-		CAM_ERR(CAM_HFI, "timed out , status = %u", status);
-		return -EINVAL;
-	}
-
-	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
-	CAM_DBG(CAM_HFI, "fw version : [%x]", fw_version);
-
-	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
-
 	if (debug) {
 		cam_io_w_mb(ICP_FLAG_A5_CTRL_DBG_EN,
 			(icp_base + HFI_REG_A5_CSR_A5_CONTROL));
@@ -499,20 +491,54 @@
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	}
 
+	while (retry_cnt < HFI_MAX_POLL_TRY) {
+		readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
+			status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000);
+
+		CAM_DBG(CAM_HFI, "1: status = %u", status);
+		status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
+		CAM_DBG(CAM_HFI, "2: status = %u", status);
+		if (status == ICP_INIT_RESP_SUCCESS)
+			break;
+
+		if (status == ICP_INIT_RESP_FAILED) {
+			CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u",
+				status);
+			fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+			CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version);
+			return -EINVAL;
+		}
+		retry_cnt++;
+	}
+
+	if ((retry_cnt == HFI_MAX_POLL_TRY) &&
+		(status == ICP_INIT_RESP_RESET)) {
+		CAM_ERR(CAM_HFI, "Reached Max retries. status = %u",
+				status);
+		fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+		CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version);
+		return -EINVAL;
+	}
+
+	cam_io_w_mb((uint32_t)INTR_ENABLE,
+		icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+
+	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+	CAM_DBG(CAM_HFI, "fw version : [%x]", fw_version);
+
 	data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS);
 	CAM_DBG(CAM_HFI, "wfi status = %x", (int)data);
 
-	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.iova,
 		icp_base + HFI_REG_SHARED_MEM_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.len,
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.len,
 		icp_base + HFI_REG_SHARED_MEM_SIZE);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova,
 		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len,
 		icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
 
-	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 	return rc;
 }
 
@@ -524,6 +550,7 @@
 	struct hfi_qtbl_hdr *qtbl_hdr;
 	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
 	uint32_t hw_version, soc_version, fw_version, status = 0;
+	uint32_t retry_cnt = 0;
 
 	mutex_lock(&hfi_cmd_q_mutex);
 	mutex_lock(&hfi_msg_q_mutex);
@@ -560,7 +587,7 @@
 		 * disabling the clock gating on both V1 and V2 until the
 		 * hardware team root causes this
 		 */
-		cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
+		cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN |
 			ICP_FLAG_CSR_WAKE_UP_EN |
 			ICP_CSR_EN_CLKGATE_WFI,
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
@@ -677,24 +704,48 @@
 		break;
 	}
 
-	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.iova,
 		icp_base + HFI_REG_SHARED_MEM_PTR);
-	cam_io_w((uint32_t)hfi_mem->shmem.len,
+	cam_io_w_mb((uint32_t)hfi_mem->shmem.len,
 		icp_base + HFI_REG_SHARED_MEM_SIZE);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova,
 		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
-	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
+	cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len,
 		icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
-	cam_io_w((uint32_t)ICP_INIT_REQUEST_SET,
+	cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_SET,
 		icp_base + HFI_REG_HOST_ICP_INIT_REQUEST);
 
 	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
 
-	rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
-		status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
-	if (rc) {
-		CAM_ERR(CAM_HFI, "timed out , status = %u", status);
+	while (retry_cnt < HFI_MAX_POLL_TRY) {
+		readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
+			status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000);
+
+		CAM_DBG(CAM_HFI, "1: status = %u rc = %d", status, rc);
+		status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
+		CAM_DBG(CAM_HFI, "2: status = %u rc = %d", status, rc);
+		if (status == ICP_INIT_RESP_SUCCESS)
+			break;
+
+		if (status == ICP_INIT_RESP_FAILED) {
+			CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u",
+				status);
+			fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+			CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version);
+			goto regions_fail;
+		}
+		retry_cnt++;
+	}
+
+	if ((retry_cnt == HFI_MAX_POLL_TRY) &&
+		(status == ICP_INIT_RESP_RESET)) {
+		CAM_ERR(CAM_HFI, "Reached Max retries. status = %u",
+				status);
+		fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+		CAM_ERR(CAM_HFI,
+			"hw version : : [%x], fw version : [%x]",
+			hw_version, fw_version);
 		goto regions_fail;
 	}
 
@@ -706,7 +757,8 @@
 	g_hfi->hfi_state = HFI_READY;
 	g_hfi->cmd_q_state = true;
 	g_hfi->msg_q_state = true;
-	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+	cam_io_w_mb((uint32_t)INTR_ENABLE,
+		icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 
 	mutex_unlock(&hfi_cmd_q_mutex);
 	mutex_unlock(&hfi_msg_q_mutex);
@@ -714,14 +766,14 @@
 	return rc;
 regions_fail:
 	kfree(g_hfi);
+	g_hfi = NULL;
 alloc_fail:
 	mutex_unlock(&hfi_cmd_q_mutex);
 	mutex_unlock(&hfi_msg_q_mutex);
 	return rc;
 }
 
-
-void cam_hfi_deinit(void)
+void cam_hfi_deinit(void __iomem *icp_base)
 {
 	mutex_lock(&hfi_cmd_q_mutex);
 	mutex_lock(&hfi_msg_q_mutex);
@@ -734,7 +786,10 @@
 	g_hfi->cmd_q_state = false;
 	g_hfi->msg_q_state = false;
 
-	cam_io_w((uint32_t)INTR_DISABLE,
+	cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_RESET,
+		icp_base + HFI_REG_HOST_ICP_INIT_REQUEST);
+
+	cam_io_w_mb((uint32_t)INTR_DISABLE,
 		g_hfi->csr_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 	kzfree(g_hfi);
 	g_hfi = NULL;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
index b7b636c..d2314c4 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -138,9 +138,22 @@
 int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info,
 	uint32_t clk_rate)
 {
+	int32_t src_clk_idx;
+
 	if (!soc_info)
 		return -EINVAL;
 
+	src_clk_idx = soc_info->src_clk_idx;
+
+	if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) &&
+		(soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) &&
+		(clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) {
+		CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d",
+			clk_rate,
+			soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]);
+		clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx];
+	}
+
 	return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx],
 		soc_info->clk_name[soc_info->src_clk_idx], clk_rate);
 }
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 0012b34..5dfb1bc 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
@@ -116,7 +117,12 @@
 		if (ctx_data->clk_info.clk_rate[i] >= base_clk)
 			return i;
 
-	return 0;
+	/*
+	 * Caller has to ensure returned index is within array
+	 * size bounds while accessing that index.
+	 */
+
+	return i;
 }
 
 static bool cam_icp_is_over_clk(struct cam_icp_hw_mgr *hw_mgr,
@@ -132,7 +138,7 @@
 	curr_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data,
 		hw_mgr_clk_info->curr_clk);
 
-	CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %lld %lld",
+	CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %d %d",
 		base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk,
 		hw_mgr_clk_info->curr_clk);
 
@@ -192,9 +198,9 @@
 	struct cam_hw_info *dev = NULL;
 
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
-		dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+		dev_intf = hw_mgr->bps_dev_intf;
 	else
-		dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+		dev_intf = hw_mgr->ipe0_dev_intf;
 
 	if (!dev_intf) {
 		CAM_ERR(CAM_ICP, "dev_intf is invalid");
@@ -254,9 +260,9 @@
 	struct cam_hw_intf *dev_intf = NULL;
 	struct cam_a5_clk_update_cmd clk_upd_cmd;
 
-	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
-	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
-	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+	ipe0_dev_intf = hw_mgr->ipe0_dev_intf;
+	ipe1_dev_intf = hw_mgr->ipe1_dev_intf;
+	bps_dev_intf = hw_mgr->bps_dev_intf;
 
 	clk_info->base_clk = 0;
 	clk_info->curr_clk = 0;
@@ -305,7 +311,120 @@
 	return 0;
 }
 
-static void cam_icp_timer_cb(unsigned long data)
+static int32_t cam_icp_ctx_timer(void *priv, void *data)
+{
+	struct clk_work_data *task_data = (struct clk_work_data *)data;
+	struct cam_icp_hw_ctx_data *ctx_data =
+		(struct cam_icp_hw_ctx_data *)task_data->data;
+	struct cam_icp_hw_mgr *hw_mgr = &icp_hw_mgr;
+	uint32_t id;
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	struct cam_hw_intf *dev_intf = NULL;
+	struct cam_icp_clk_info *clk_info;
+	struct cam_icp_cpas_vote clk_update;
+
+	if (!ctx_data) {
+		CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx_data->ctx_mutex);
+	if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) ||
+		(ctx_data->watch_dog_reset_counter == 0)) {
+		CAM_DBG(CAM_ICP, "state %d, counter=%d",
+			ctx_data->state, ctx_data->watch_dog_reset_counter);
+		mutex_unlock(&ctx_data->ctx_mutex);
+		return 0;
+	}
+
+	CAM_DBG(CAM_ICP,
+		"E :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u",
+		ctx_data->ctx_id,
+		ctx_data->clk_info.uncompressed_bw,
+		ctx_data->clk_info.compressed_bw,
+		ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk);
+
+	ipe0_dev_intf = hw_mgr->ipe0_dev_intf;
+	ipe1_dev_intf = hw_mgr->ipe1_dev_intf;
+	bps_dev_intf = hw_mgr->bps_dev_intf;
+
+	if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+		CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk");
+		mutex_unlock(&ctx_data->ctx_mutex);
+		return -EINVAL;
+	}
+
+	if (!ctx_data->icp_dev_acquire_info) {
+		CAM_WARN(CAM_ICP, "NULL acquire info");
+		mutex_unlock(&ctx_data->ctx_mutex);
+		return -EINVAL;
+	}
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
+		dev_intf = bps_dev_intf;
+		clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
+		id = CAM_ICP_BPS_CMD_VOTE_CPAS;
+	} else {
+		dev_intf = ipe0_dev_intf;
+		clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
+		id = CAM_ICP_IPE_CMD_VOTE_CPAS;
+	}
+
+	clk_info->compressed_bw -= ctx_data->clk_info.compressed_bw;
+	clk_info->uncompressed_bw -= ctx_data->clk_info.uncompressed_bw;
+	ctx_data->clk_info.uncompressed_bw = 0;
+	ctx_data->clk_info.compressed_bw = 0;
+	ctx_data->clk_info.curr_fc = 0;
+	ctx_data->clk_info.base_clk = 0;
+
+	clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC;
+	clk_update.ahb_vote.vote.freq = clk_info->curr_clk;
+	clk_update.ahb_vote_valid = true;
+	clk_update.axi_vote.compressed_bw = clk_info->compressed_bw;
+	clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw;
+	clk_update.axi_vote_valid = true;
+	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
+		&clk_update, sizeof(clk_update));
+
+	CAM_DBG(CAM_ICP,
+		"X :ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u",
+		ctx_data->ctx_id,
+		ctx_data->clk_info.uncompressed_bw,
+		ctx_data->clk_info.compressed_bw,
+		ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk);
+
+	mutex_unlock(&ctx_data->ctx_mutex);
+
+	return 0;
+}
+
+static void cam_icp_ctx_timer_cb(unsigned long data)
+{
+	unsigned long flags;
+	struct crm_workq_task *task;
+	struct clk_work_data *task_data;
+	struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data;
+
+	spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags);
+	task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work);
+	if (!task) {
+		CAM_ERR(CAM_ICP, "no empty task");
+		spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags);
+		return;
+	}
+
+	task_data = (struct clk_work_data *)task->payload;
+	task_data->data = timer->parent;
+	task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
+	task->process_cb = cam_icp_ctx_timer;
+	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+		CRM_TASK_PRIORITY_0);
+	spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags);
+}
+
+static void cam_icp_device_timer_cb(unsigned long data)
 {
 	unsigned long flags;
 	struct crm_workq_task *task;
@@ -342,13 +461,29 @@
 		hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
 		hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
 		hw_mgr->clk_info[i].hw_type = i;
+		hw_mgr->clk_info[i].watch_dog_reset_counter = 0;
 	}
 	hw_mgr->icp_default_clk = ICP_CLK_SVS_HZ;
 
 	return 0;
 }
 
-static int cam_icp_timer_start(struct cam_icp_hw_mgr *hw_mgr)
+static int cam_icp_ctx_timer_start(struct cam_icp_hw_ctx_data *ctx_data)
+{
+	int rc = 0;
+
+	rc = crm_timer_init(&ctx_data->watch_dog,
+		2000, ctx_data, &cam_icp_ctx_timer_cb);
+	if (rc)
+		CAM_ERR(CAM_ICP, "Failed to start timer");
+
+	ctx_data->watch_dog_reset_counter = 0;
+
+	CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id);
+	return rc;
+}
+
+static int cam_icp_device_timer_start(struct cam_icp_hw_mgr *hw_mgr)
 {
 	int rc = 0;
 	int i;
@@ -356,21 +491,70 @@
 	for (i = 0; i < ICP_CLK_HW_MAX; i++)  {
 		if (!hw_mgr->clk_info[i].watch_dog) {
 			rc = crm_timer_init(&hw_mgr->clk_info[i].watch_dog,
-				3000, &hw_mgr->clk_info[i], &cam_icp_timer_cb);
+				3000, &hw_mgr->clk_info[i],
+				&cam_icp_device_timer_cb);
+
 			if (rc)
 				CAM_ERR(CAM_ICP, "Failed to start timer %d", i);
+
+			hw_mgr->clk_info[i].watch_dog_reset_counter = 0;
 		}
 	}
 
 	return rc;
 }
 
-static void cam_icp_timer_stop(struct cam_icp_hw_mgr *hw_mgr)
+static int cam_icp_ctx_timer_stop(struct cam_icp_hw_ctx_data *ctx_data)
 {
-	if (!hw_mgr->bps_ctxt_cnt)
+	if (ctx_data->watch_dog) {
+		CAM_DBG(CAM_ICP, "stop timer : ctx_id = %d", ctx_data->ctx_id);
+		ctx_data->watch_dog_reset_counter = 0;
+		crm_timer_exit(&ctx_data->watch_dog);
+		ctx_data->watch_dog = NULL;
+	}
+
+	return 0;
+}
+
+static void cam_icp_device_timer_stop(struct cam_icp_hw_mgr *hw_mgr)
+{
+	if (!hw_mgr->bps_ctxt_cnt &&
+		hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog) {
+		hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog_reset_counter = 0;
 		crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog);
-	else if (!hw_mgr->ipe_ctxt_cnt)
+		hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog = NULL;
+	}
+
+	if (!hw_mgr->ipe_ctxt_cnt &&
+		hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog) {
+		hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog_reset_counter = 0;
 		crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog);
+		hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog = NULL;
+	}
+}
+
+static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data)
+{
+	if (ctx_data && ctx_data->watch_dog) {
+		ctx_data->watch_dog_reset_counter++;
+		CAM_DBG(CAM_ICP, "reset timer : ctx_id = %d, counter=%d",
+			ctx_data->ctx_id, ctx_data->watch_dog_reset_counter);
+		crm_timer_reset(ctx_data->watch_dog);
+	}
+
+	return 0;
+}
+
+static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr,
+	int device_index)
+{
+	if ((device_index >= ICP_CLK_HW_MAX) || (!hw_mgr))
+		return;
+
+	if (hw_mgr->clk_info[device_index].watch_dog) {
+		crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog);
+		hw_mgr->clk_info[device_index].watch_dog_reset_counter++;
+	}
 }
 
 static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles,
@@ -420,7 +604,9 @@
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
 		ctx_data = &hw_mgr->ctx_data[i];
 		if (ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED &&
-			ctx_data->icp_dev_acquire_info->dev_type == dev_type)
+			ICP_DEV_TYPE_TO_CLK_TYPE(
+			ctx_data->icp_dev_acquire_info->dev_type) ==
+			ICP_DEV_TYPE_TO_CLK_TYPE(dev_type))
 			hw_mgr_clk_info->base_clk +=
 				ctx_data->clk_info.base_clk;
 	}
@@ -575,7 +761,8 @@
 		hw_mgr_clk_info->over_clked = 0;
 		rc = false;
 	}  else if (hw_mgr_clk_info->curr_clk < hw_mgr_clk_info->base_clk) {
-		hw_mgr_clk_info->curr_clk = hw_mgr_clk_info->base_clk;
+		hw_mgr_clk_info->curr_clk = cam_icp_get_actual_clk_rate(hw_mgr,
+			ctx_data, hw_mgr_clk_info->base_clk);
 		rc = true;
 	}
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
@@ -633,7 +820,13 @@
 	 * recalculate bandwidth of all contexts of same hardware and update
 	 * voting of bandwidth
 	 */
-	if (clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw)
+	CAM_DBG(CAM_ICP, "ubw ctx = %lld clk_info ubw = %lld busy = %d",
+		ctx_data->clk_info.uncompressed_bw,
+		clk_info->uncompressed_bw, busy);
+
+	if ((clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw) &&
+		(ctx_data->clk_info.uncompressed_bw ==
+		hw_mgr_clk_info->uncompressed_bw))
 		return false;
 
 	if (busy &&
@@ -647,13 +840,18 @@
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
 		ctx = &hw_mgr->ctx_data[i];
 		if (ctx->state == CAM_ICP_CTX_STATE_ACQUIRED &&
-			ctx->icp_dev_acquire_info->dev_type ==
-			ctx_data->icp_dev_acquire_info->dev_type) {
+			ICP_DEV_TYPE_TO_CLK_TYPE(
+			ctx->icp_dev_acquire_info->dev_type) ==
+			ICP_DEV_TYPE_TO_CLK_TYPE(
+			ctx_data->icp_dev_acquire_info->dev_type)) {
 			mutex_lock(&hw_mgr->hw_mgr_mutex);
 			hw_mgr_clk_info->uncompressed_bw +=
 				ctx->clk_info.uncompressed_bw;
 			hw_mgr_clk_info->compressed_bw +=
 				ctx->clk_info.compressed_bw;
+			CAM_DBG(CAM_ICP, "ubw = %lld, cbw = %lld",
+				hw_mgr_clk_info->uncompressed_bw,
+				hw_mgr_clk_info->compressed_bw);
 			mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		}
 	}
@@ -671,12 +869,13 @@
 	uint64_t req_id;
 	struct cam_icp_clk_info *hw_mgr_clk_info;
 
+	cam_icp_ctx_timer_reset(ctx_data);
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
-		crm_timer_reset(hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog);
+		cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_BPS);
 		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
 		CAM_DBG(CAM_ICP, "Reset bps timer");
 	} else {
-		crm_timer_reset(hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog);
+		cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_IPE);
 		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
 		CAM_DBG(CAM_ICP, "Reset ipe timer");
 	}
@@ -827,11 +1026,13 @@
 	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
 		&clk_update, sizeof(clk_update));
 
-	if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS)
-		if (ipe1_dev_intf)
-			ipe1_dev_intf->hw_ops.process_cmd(
-				ipe1_dev_intf->hw_priv, id,
-				&clk_update, sizeof(clk_update));
+	/*
+	 * Consolidated bw needs to be voted on only one IPE client. Otherwise
+	 * total bw that we vote at bus client would be doubled. So either
+	 * remove voting on IPE1 or divide the vote for each IPE client
+	 * and vote to cpas - cpas will add up and vote full bw to sf client
+	 * anyway.
+	 */
 
 	return 0;
 }
@@ -870,7 +1071,11 @@
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
 		if (hw_mgr->bps_ctxt_cnt++)
 			goto end;
-		bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0);
+		if (!hw_mgr->bps_clk_state) {
+			bps_dev_intf->hw_ops.init(
+				bps_dev_intf->hw_priv, NULL, 0);
+			hw_mgr->bps_clk_state = true;
+		}
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			bps_dev_intf->hw_ops.process_cmd(
 				bps_dev_intf->hw_priv,
@@ -880,15 +1085,18 @@
 	} else {
 		if (hw_mgr->ipe_ctxt_cnt++)
 			goto end;
-
-		ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0);
+		if (!hw_mgr->ipe_clk_state)
+			ipe0_dev_intf->hw_ops.init(
+				ipe0_dev_intf->hw_priv, NULL, 0);
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			ipe0_dev_intf->hw_ops.process_cmd(
 				ipe0_dev_intf->hw_priv,
 				CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
 		}
 
-		if ((icp_hw_mgr.ipe1_enable) && (ipe1_dev_intf)) {
+		if ((icp_hw_mgr.ipe1_enable) &&
+			(ipe1_dev_intf) &&
+			(!hw_mgr->ipe_clk_state)) {
 			ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 
@@ -899,6 +1107,7 @@
 					NULL, 0);
 			}
 		}
+		hw_mgr->ipe_clk_state = true;
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			hw_mgr->core_info = hw_mgr->core_info |
 				(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1);
@@ -908,6 +1117,8 @@
 	CAM_DBG(CAM_ICP, "core_info %X",  hw_mgr->core_info);
 	if (icp_hw_mgr.ipe_bps_pc_flag)
 		rc = hfi_enable_ipe_bps_pc(true, hw_mgr->core_info);
+	else if (icp_hw_mgr.icp_pc_flag)
+		rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info);
 	else
 		rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info);
 end:
@@ -953,7 +1164,11 @@
 				hw_mgr->core_info & (~ICP_PWR_CLP_BPS);
 		}
 
-		bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+		if (hw_mgr->bps_clk_state) {
+			bps_dev_intf->hw_ops.deinit
+				(bps_dev_intf->hw_priv, NULL, 0);
+			hw_mgr->bps_clk_state = false;
+		}
 	} else {
 		CAM_DBG(CAM_ICP, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt);
 		if (ctx_data)
@@ -968,7 +1183,10 @@
 				CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
 
 		}
-		ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+
+		if (hw_mgr->ipe_clk_state)
+			ipe0_dev_intf->hw_ops.deinit(
+				ipe0_dev_intf->hw_priv, NULL, 0);
 
 		if (ipe1_dev_intf) {
 			if (icp_hw_mgr.ipe_bps_pc_flag) {
@@ -978,9 +1196,12 @@
 					NULL, 0);
 			}
 
+		if (hw_mgr->ipe_clk_state)
 			ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 		}
+
+		hw_mgr->ipe_clk_state = false;
 		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			hw_mgr->core_info = hw_mgr->core_info &
 				(~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1));
@@ -1131,7 +1352,7 @@
 				ctx_data->hfi_frame_process.in_resource[i]);
 			cam_sync_destroy(
 				ctx_data->hfi_frame_process.in_resource[i]);
-			ctx_data->hfi_frame_process.in_resource[i] = 0;
+			ctx_data->hfi_frame_process.in_free_resource[i] = 0;
 		}
 		hfi_frame_process->fw_process_flag[i] = false;
 		clear_bit(i, ctx_data->hfi_frame_process.bitmap);
@@ -1141,7 +1362,7 @@
 		if (!hfi_frame_process->in_free_resource[i])
 			continue;
 
-		CAM_INFO(CAM_ICP, "Delete merged sync in object: %d",
+		CAM_DBG(CAM_ICP, "Delete merged sync in object: %d",
 			ctx_data->hfi_frame_process.in_free_resource[i]);
 		cam_sync_destroy(
 			ctx_data->hfi_frame_process.in_free_resource[i]);
@@ -1174,9 +1395,10 @@
 
 	clk_type = ICP_DEV_TYPE_TO_CLK_TYPE(ctx_data->icp_dev_acquire_info->
 		dev_type);
-	crm_timer_reset(icp_hw_mgr.clk_info[clk_type].watch_dog);
+	cam_icp_device_timer_reset(&icp_hw_mgr, clk_type);
 
 	mutex_lock(&ctx_data->ctx_mutex);
+	cam_icp_ctx_timer_reset(ctx_data);
 	if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) {
 		CAM_DBG(CAM_ICP, "ctx %u is in %d state",
 			ctx_data->ctx_id, ctx_data->state);
@@ -1301,6 +1523,7 @@
 {
 	struct hfi_msg_create_handle_ack *create_handle_ack = NULL;
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
+	int rc = 0;
 
 	create_handle_ack = (struct hfi_msg_create_handle_ack *)msg_ptr;
 	if (!create_handle_ack) {
@@ -1317,11 +1540,15 @@
 	if (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE) {
 		ctx_data->fw_handle = create_handle_ack->fw_handle;
 		CAM_DBG(CAM_ICP, "fw_handle = %x", ctx_data->fw_handle);
-		complete(&ctx_data->wait_complete);
-	} else
-		CAM_WARN(CAM_ICP, "Timeout failed to create fw handle");
-
-	return 0;
+	} else {
+		CAM_WARN(CAM_ICP,
+			"This ctx is no longer in use current state: %d",
+			ctx_data->state);
+		ctx_data->fw_handle = 0;
+		rc = -EPERM;
+	}
+	complete(&ctx_data->wait_complete);
+	return rc;
 }
 
 static int cam_icp_mgr_process_msg_ping_ack(uint32_t *msg_ptr)
@@ -1385,21 +1612,38 @@
 {
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
 	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_info *a5_dev = NULL;
 	int rc = 0;
 
+	a5_dev_intf = icp_hw_mgr.a5_dev_intf;
+	if (!a5_dev_intf) {
+		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+		return -EINVAL;
+	}
+	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 	switch (msg_ptr[ICP_PACKET_OPCODE]) {
-	case HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY:
-	case HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY:
 	case HFI_IPEBPS_CMD_OPCODE_IPE_ABORT:
 	case HFI_IPEBPS_CMD_OPCODE_BPS_ABORT:
-		CAM_DBG(CAM_ICP, "received IPE/BPS_DESTROY/ABORT:");
+		ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+		ctx_data =
+			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+		if (ctx_data->state != CAM_ICP_CTX_STATE_FREE)
+			complete(&ctx_data->wait_complete);
+		CAM_DBG(CAM_ICP, "received IPE/BPS/ ABORT: ctx_state =%d",
+			ctx_data->state);
+		break;
+	case HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY:
+	case HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY:
 		ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
 		ctx_data =
 			(struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
 		if ((ctx_data->state == CAM_ICP_CTX_STATE_RELEASE) ||
-			(ctx_data->state == CAM_ICP_CTX_STATE_IN_USE))
+			(ctx_data->state == CAM_ICP_CTX_STATE_IN_USE)) {
 			complete(&ctx_data->wait_complete);
-
+		}
+		CAM_DBG(CAM_ICP, "received IPE/BPS/ DESTROY: ctx_state =%d",
+			ctx_data->state);
 		break;
 	default:
 		CAM_ERR(CAM_ICP, "Invalid opcode : %u",
@@ -1407,7 +1651,6 @@
 		rc = -EINVAL;
 		break;
 	}
-
 	return rc;
 }
 
@@ -1808,12 +2051,20 @@
 		return 0;
 	}
 
-	if (ipe1_dev_intf) {
+	if (ipe1_dev_intf && hw_mgr->ipe_clk_state) {
 		ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 	}
-	ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
-	bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+
+	if (hw_mgr->ipe_clk_state)
+		ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+	if (hw_mgr->bps_clk_state)
+		bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+
+
+	hw_mgr->bps_clk_state = false;
+	hw_mgr->ipe_clk_state = false;
+
 	return 0;
 }
 static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr)
@@ -1831,12 +2082,15 @@
 	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 
-	if (!hw_mgr->icp_pc_flag)
+	if (!hw_mgr->icp_pc_flag) {
+		cam_hfi_disable_cpu(
+			a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 		rc = cam_icp_mgr_hw_close(hw_mgr, NULL);
-	else
+	} else {
 		rc = cam_icp_mgr_send_pc_prep(hw_mgr);
-
-	cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+		cam_hfi_disable_cpu(
+			a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+	}
 	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
 	CAM_DBG(CAM_ICP, "EXIT");
 
@@ -1897,7 +2151,7 @@
 	int rc = 0;
 	unsigned long rem_jiffies;
 	size_t packet_size;
-	int timeout = 5000;
+	int timeout = 100;
 	struct hfi_cmd_work_data *task_data;
 	struct hfi_cmd_ipebps_async *abort_cmd;
 	struct crm_workq_task *task;
@@ -1908,9 +2162,10 @@
 
 	packet_size =
 		sizeof(struct hfi_cmd_ipebps_async) +
-		sizeof(struct hfi_cmd_abort_destroy) -
+		sizeof(struct hfi_cmd_abort) -
 		sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct);
 	abort_cmd = kzalloc(packet_size, GFP_KERNEL);
+	CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size);
 	if (!abort_cmd) {
 		rc = -ENOMEM;
 		return rc;
@@ -1928,8 +2183,6 @@
 	abort_cmd->fw_handles[0] = ctx_data->fw_handle;
 	abort_cmd->user_data1 = (uint64_t)ctx_data;
 	abort_cmd->user_data2 = (uint64_t)0x0;
-	memcpy(abort_cmd->payload.direct, &ctx_data->temp_payload,
-		sizeof(uint64_t));
 
 	task_data = (struct hfi_cmd_work_data *)task->payload;
 	task_data->data = (void *)abort_cmd;
@@ -1960,7 +2213,7 @@
 	struct cam_icp_hw_ctx_data *ctx_data)
 {
 	int rc = 0;
-	int timeout = 5000;
+	int timeout = 100;
 	unsigned long rem_jiffies;
 	size_t packet_size;
 	struct hfi_cmd_work_data *task_data;
@@ -2047,6 +2300,7 @@
 		&hw_mgr->ctx_data[ctx_id], 0);
 	hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE;
 	CAM_DBG(CAM_ICP, "E: ctx_id = %d", ctx_id);
+	cam_icp_mgr_abort_handle(&hw_mgr->ctx_data[ctx_id]);
 	cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]);
 	cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]);
 
@@ -2063,6 +2317,7 @@
 	kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info);
 	hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL;
 	hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_FREE;
+	cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[ctx_id]);
 	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 
 	CAM_DBG(CAM_ICP, "X: ctx_id = %d", ctx_id);
@@ -2091,12 +2346,15 @@
 	ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
 	bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
 	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+	hw_mgr->bps_clk_state = false;
+	hw_mgr->ipe_clk_state = false;
 }
 
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args)
 {
 	struct cam_icp_hw_mgr *hw_mgr = hw_priv;
 	struct cam_hw_intf *a5_dev_intf = NULL;
+	struct cam_hw_info *a5_dev = NULL;
 	struct cam_icp_a5_set_irq_cb irq_cb;
 	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
 	int rc = 0;
@@ -2108,14 +2366,13 @@
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return 0;
 	}
-
 	a5_dev_intf = hw_mgr->a5_dev_intf;
 	if (!a5_dev_intf) {
 		CAM_DBG(CAM_ICP, "a5_dev_intf is NULL");
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return -EINVAL;
 	}
-
+	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 	fw_buf_info.kva = 0;
 	fw_buf_info.iova = 0;
 	fw_buf_info.len = 0;
@@ -2126,9 +2383,8 @@
 		sizeof(fw_buf_info));
 	if (rc)
 		CAM_ERR(CAM_ICP, "nullify the fw buf failed");
-
-	cam_hfi_deinit();
-
+	cam_hfi_deinit(
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 	irq_cb.icp_hw_mgr_cb = NULL;
 	irq_cb.data = NULL;
 	rc = a5_dev_intf->hw_ops.process_cmd(
@@ -2142,7 +2398,6 @@
 	hw_mgr->fw_download = false;
 	hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
-
 	CAM_DBG(CAM_ICP, "Exit");
 	return rc;
 }
@@ -2184,11 +2439,16 @@
 			goto ipe1_dev_init_failed;
 	}
 
+	hw_mgr->bps_clk_state = true;
+	hw_mgr->ipe_clk_state = true;
+
 	return rc;
 ipe1_dev_init_failed:
 	ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+	hw_mgr->ipe_clk_state = false;
 ipe0_dev_init_failed:
 	bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+	hw_mgr->bps_clk_state = false;
 bps_dev_init_failed:
 	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
 a5_dev_init_failed:
@@ -2337,10 +2597,10 @@
 	if (hw_mgr->fw_download  == false) {
 		CAM_DBG(CAM_ICP, "Downloading FW");
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
-		cam_icp_mgr_hw_open(hw_mgr, &downloadFromResume);
+		rc = cam_icp_mgr_hw_open(hw_mgr, &downloadFromResume);
 		mutex_lock(&hw_mgr->hw_mgr_mutex);
 		CAM_DBG(CAM_ICP, "FW Download Done Exit");
-		return 0;
+		return rc;
 	}
 
 	rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
@@ -2386,34 +2646,24 @@
 	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 	rc = cam_icp_allocate_hfi_mem();
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto alloc_hfi_mem_failed;
-	}
 
 	rc = cam_icp_mgr_device_init(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto dev_init_fail;
-	}
 
 	rc = cam_icp_mgr_fw_download(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto fw_download_failed;
-	}
 
 	rc = cam_icp_mgr_hfi_init(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto hfi_init_failed;
-	}
 
 	rc = cam_icp_mgr_send_fw_init(hw_mgr);
-	if (rc) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	if (rc)
 		goto fw_init_failed;
-	}
 
 	hw_mgr->ctxt_cnt = 0;
 	hw_mgr->fw_download = true;
@@ -2428,22 +2678,32 @@
 	if (download_fw_args)
 		icp_pc = *((bool *)download_fw_args);
 
+	if (download_fw_args && icp_pc == true && hw_mgr->icp_pc_flag) {
+		rc = cam_ipe_bps_deint(hw_mgr);
+		CAM_DBG(CAM_ICP, "deinit all clocks");
+	}
+
 	if (download_fw_args && icp_pc == true)
 		return rc;
 
+	rc = cam_ipe_bps_deint(hw_mgr);
 	rc = cam_icp_mgr_icp_power_collapse(hw_mgr);
+	CAM_DBG(CAM_ICP, "deinit all clocks at boot up");
 
 	return rc;
 
 fw_init_failed:
-	cam_hfi_deinit();
+	cam_hfi_deinit(
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 hfi_init_failed:
-	cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+	cam_hfi_disable_cpu(
+		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 fw_download_failed:
 	cam_icp_mgr_device_deinit(hw_mgr);
 dev_init_fail:
 	cam_icp_free_hfi_mem();
 alloc_hfi_mem_failed:
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	return rc;
 }
 
@@ -3173,11 +3433,12 @@
 		mutex_lock(&hw_mgr->hw_mgr_mutex);
 		cam_icp_hw_mgr_reset_clk_info(hw_mgr);
 		hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
+		rc = cam_ipe_bps_deint(hw_mgr);
 	}
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)
-		cam_icp_timer_stop(hw_mgr);
+		cam_icp_device_timer_stop(hw_mgr);
 
 	CAM_DBG(CAM_ICP, "Exit");
 	return rc;
@@ -3266,6 +3527,11 @@
 		CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
 	}
 
+	if (ctx_data->fw_handle == 0) {
+		CAM_ERR(CAM_ICP, "Invalid handle created");
+		rc = -EINVAL;
+	}
+
 	return rc;
 }
 
@@ -3429,12 +3695,13 @@
 	}
 	ctx_data = &hw_mgr->ctx_data[ctx_id];
 	ctx_data->ctx_id = ctx_id;
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	mutex_lock(&ctx_data->ctx_mutex);
 	rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data);
-	if (rc)
+	if (rc) {
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		goto acquire_info_failed;
+	}
 	icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
 
 	rc = cam_mem_get_io_buf(
@@ -3443,6 +3710,7 @@
 		&io_buf_addr, &io_buf_size);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "unable to get src buf info from io desc");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		goto get_io_buf_failed;
 	}
 
@@ -3450,7 +3718,6 @@
 		icp_dev_acquire_info->io_config_cmd_handle,
 		(void *)io_buf_addr, io_buf_size);
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	if (!hw_mgr->ctxt_cnt) {
 		rc = cam_icp_clk_info_init(hw_mgr, ctx_data);
 		if (rc) {
@@ -3464,6 +3731,9 @@
 			goto get_io_buf_failed;
 		}
 
+		if (icp_hw_mgr.a5_debug_q)
+			hfi_set_debug_level(icp_hw_mgr.a5_dbg_lvl);
+
 		rc = cam_icp_send_ubwc_cfg(hw_mgr);
 		if (rc) {
 			mutex_unlock(&hw_mgr->hw_mgr_mutex);
@@ -3472,7 +3742,9 @@
 	}
 
 	if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)
-		cam_icp_timer_start(hw_mgr);
+		cam_icp_device_timer_start(hw_mgr);
+
+	cam_icp_ctx_timer_start(ctx_data);
 
 	rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data);
 	if (rc) {
@@ -3539,6 +3811,7 @@
 send_ping_failed:
 	cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, ctx_data, 0);
 ipe_bps_resume_failed:
+	cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[ctx_id]);
 ubwc_cfg_failed:
 	if (!hw_mgr->ctxt_cnt)
 		cam_icp_mgr_icp_power_collapse(hw_mgr);
@@ -3843,7 +4116,6 @@
 		goto icp_wq_create_failed;
 
 	init_completion(&icp_hw_mgr.a5_complete);
-
 	return rc;
 
 icp_wq_create_failed:
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 85f5b550..aac4a5e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -183,6 +183,8 @@
  * @temp_payload: Payload for destroy handle data
  * @ctx_id: Context Id
  * @clk_info: Current clock info of a context
+ * @watch_dog: watchdog timer handle
+ * @watch_dog_reset_counter: Counter for watch dog reset
  */
 struct cam_icp_hw_ctx_data {
 	void *context_priv;
@@ -200,6 +202,8 @@
 	struct ipe_bps_destroy temp_payload;
 	uint32_t ctx_id;
 	struct cam_ctx_clk_info clk_info;
+	struct cam_req_mgr_timer *watch_dog;
+	uint32_t watch_dog_reset_counter;
 };
 
 /**
@@ -222,6 +226,7 @@
  * @compressed_bw: Current compressed bandwidth voting
  * @hw_type: IPE/BPS device type
  * @watch_dog: watchdog timer handle
+ * @watch_dog_reset_counter: Counter for watch dog reset
  */
 struct cam_icp_clk_info {
 	uint32_t base_clk;
@@ -232,6 +237,7 @@
 	uint64_t compressed_bw;
 	uint32_t hw_type;
 	struct cam_req_mgr_timer *watch_dog;
+	uint32_t watch_dog_reset_counter;
 };
 
 /**
@@ -271,6 +277,12 @@
  * @ipe1_enable: Flag for IPE1
  * @bps_enable: Flag for BPS
  * @core_info: 32 bit value , tells IPE0/1 and BPS
+ * @a5_dev_intf : Device interface for A5
+ * @ipe0_dev_intf: Device interface for IPE0
+ * @ipe1_dev_intf: Device interface for IPE1
+ * @bps_dev_intf: Device interface for BPS
+ * @ipe_clk_state: IPE clock state flag
+ * @bps_clk_state: BPS clock state flag
  */
 struct cam_icp_hw_mgr {
 	struct mutex hw_mgr_mutex;
@@ -313,6 +325,8 @@
 	struct cam_hw_intf *ipe0_dev_intf;
 	struct cam_hw_intf *ipe1_dev_intf;
 	struct cam_hw_intf *bps_dev_intf;
+	bool ipe_clk_state;
+	bool bps_clk_state;
 };
 
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
index d2e04ef..771c4ed 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,7 @@
 #define ICP_CLK_TURBO_HZ         600000000
 #define ICP_CLK_SVS_HZ           400000000
 
-#define CAM_ICP_A5_BW_BYTES_VOTE 100000000
+#define CAM_ICP_A5_BW_BYTES_VOTE 40000000
 
 #define CAM_ICP_CTX_MAX          36
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
index 289d7d4..d24305a 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -141,9 +141,22 @@
 int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info,
 	uint32_t clk_rate)
 {
+	int32_t src_clk_idx;
+
 	if (!soc_info)
 		return -EINVAL;
 
+	src_clk_idx = soc_info->src_clk_idx;
+
+	if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) &&
+		(soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) &&
+		(clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) {
+		CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d",
+			clk_rate,
+			soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]);
+		clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx];
+	}
+
 	return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx],
 		soc_info->clk_name[soc_info->src_clk_idx], clk_rate);
 }
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index d1153ba..d62344d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -86,7 +86,8 @@
 		struct cam_ctx_request, list);
 	req_isp_old = (struct cam_isp_ctx_req *) req_old->req_priv;
 	req_isp_new = (struct cam_isp_ctx_req *) req->req_priv;
-	if (req_isp_old->packet_opcode_type == CAM_ISP_PACKET_INIT_DEV) {
+	if (req_isp_old->hw_update_data.packet_opcode_type ==
+		CAM_ISP_PACKET_INIT_DEV) {
 		if ((req_isp_old->num_cfg + req_isp_new->num_cfg) >=
 			CAM_ISP_CTX_CFG_MAX) {
 			CAM_WARN(CAM_ISP, "Can not merge INIT pkt");
@@ -896,6 +897,29 @@
 	return rc;
 }
 
+static int __cam_isp_ctx_sof_in_flush(
+	struct cam_isp_context *ctx_isp, void *evt_data)
+{
+	int rc = 0;
+	struct cam_isp_hw_sof_event_data      *sof_event_data = evt_data;
+
+	if (!evt_data) {
+		CAM_ERR(CAM_ISP, "in valid sof event data");
+		return -EINVAL;
+	}
+	ctx_isp->frame_id++;
+	ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
+	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
+		ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
+
+	if (--ctx_isp->frame_skip_count == 0)
+		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
+	else
+		CAM_ERR(CAM_ISP, "Skip currect SOF");
+
+	return rc;
+}
+
 static struct cam_isp_ctx_irq_ops
 	cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = {
 	/* SOF */
@@ -967,6 +991,17 @@
 	/* HALT */
 	{
 	},
+	/* FLUSH */
+	{
+		.irq_ops = {
+			NULL,
+			__cam_isp_ctx_sof_in_flush,
+			NULL,
+			NULL,
+			NULL,
+			__cam_isp_ctx_buf_done_in_applied,
+		},
+	},
 };
 
 static int __cam_isp_ctx_apply_req_in_activated_state(
@@ -1037,6 +1072,7 @@
 	cfg.ctxt_to_hw_map = ctx_isp->hw_ctx;
 	cfg.hw_update_entries = req_isp->cfg;
 	cfg.num_hw_update_entries = req_isp->num_cfg;
+	cfg.priv  = &req_isp->hw_update_data;
 
 	rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
 	if (rc) {
@@ -1170,6 +1206,24 @@
 	return rc;
 }
 
+static int __cam_isp_ctx_flush_req_in_activated(
+	struct cam_context *ctx,
+	struct cam_req_mgr_flush_request *flush_req)
+{
+	int rc = 0;
+	struct cam_isp_context *ctx_isp;
+
+	ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
+	spin_lock_bh(&ctx->lock);
+	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_FLUSH;
+	ctx_isp->frame_skip_count = 2;
+	spin_unlock_bh(&ctx->lock);
+
+	CAM_DBG(CAM_ISP, "Flush request in state %d", ctx->state);
+	rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
+	return rc;
+}
+
 static int __cam_isp_ctx_flush_req_in_ready(
 	struct cam_context *ctx,
 	struct cam_req_mgr_flush_request *flush_req)
@@ -1230,12 +1284,24 @@
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* HW ERROR */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 	/* HALT */
 	{
 		.ioctl_ops = {},
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* FLUSH */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 };
 
 static int __cam_isp_ctx_rdi_only_sof_in_top_state(
@@ -1601,10 +1667,23 @@
 			__cam_isp_ctx_buf_done_in_bubble_applied,
 		},
 	},
-
+	/* HW ERROR */
+	{
+	},
 	/* HALT */
 	{
 	},
+	/* FLUSH */
+	{
+		.irq_ops = {
+			NULL,
+			__cam_isp_ctx_sof_in_flush,
+			NULL,
+			NULL,
+			NULL,
+			__cam_isp_ctx_buf_done_in_applied,
+		},
+	},
 };
 
 static int __cam_isp_ctx_rdi_only_apply_req_top_state(
@@ -1660,15 +1739,26 @@
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* HW ERROR */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 	/* HALT */
 	{
 		.ioctl_ops = {},
 		.crm_ops = {},
 		.irq_ops = NULL,
 	},
+	/* FLUSHED */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
 };
 
-
 /* top level state machine */
 static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
 	struct cam_release_dev_cmd *cmd)
@@ -1729,7 +1819,6 @@
 	struct cam_req_mgr_add_request    add_req;
 	struct cam_isp_context           *ctx_isp =
 		(struct cam_isp_context *) ctx->ctx_priv;
-	struct cam_isp_prepare_hw_update_data    hw_update_data;
 
 	CAM_DBG(CAM_ISP, "get free request object......");
 
@@ -1780,7 +1869,7 @@
 	cfg.max_in_map_entries = CAM_ISP_CTX_RES_MAX;
 	cfg.out_map_entries = req_isp->fence_map_out;
 	cfg.in_map_entries = req_isp->fence_map_in;
-	cfg.priv  = &hw_update_data;
+	cfg.priv  = &req_isp->hw_update_data;
 
 	CAM_DBG(CAM_ISP, "try to prepare config packet......");
 
@@ -1795,7 +1884,6 @@
 	req_isp->num_fence_map_out = cfg.num_out_map_entries;
 	req_isp->num_fence_map_in = cfg.num_in_map_entries;
 	req_isp->num_acked = 0;
-	req_isp->packet_opcode_type = hw_update_data.packet_opcode_type;
 
 	CAM_DBG(CAM_ISP, "num_entry: %d, num fence out: %d, num fence in: %d",
 		req_isp->num_cfg, req_isp->num_fence_map_out,
@@ -1805,9 +1893,11 @@
 	req->status = 1;
 
 	CAM_DBG(CAM_ISP, "Packet request id 0x%llx packet opcode:%d",
-		packet->header.request_id, req_isp->packet_opcode_type);
+		packet->header.request_id,
+		req_isp->hw_update_data.packet_opcode_type);
 
-	if (req_isp->packet_opcode_type == CAM_ISP_PACKET_INIT_DEV) {
+	if (req_isp->hw_update_data.packet_opcode_type ==
+		CAM_ISP_PACKET_INIT_DEV) {
 		if (ctx->state < CAM_CTX_ACTIVATED) {
 			rc = __cam_isp_ctx_enqueue_init_request(ctx, req);
 			if (rc)
@@ -2052,7 +2142,7 @@
 	struct cam_start_stop_dev_cmd *cmd)
 {
 	int rc = 0;
-	struct cam_hw_start_args         arg;
+	struct cam_hw_config_args        arg;
 	struct cam_ctx_request          *req;
 	struct cam_isp_ctx_req          *req_isp;
 	struct cam_isp_context          *ctx_isp =
@@ -2080,9 +2170,11 @@
 		rc = -EFAULT;
 		goto end;
 	}
+
 	arg.ctxt_to_hw_map = ctx_isp->hw_ctx;
 	arg.hw_update_entries = req_isp->cfg;
 	arg.num_hw_update_entries = req_isp->num_cfg;
+	arg.priv  = &req_isp->hw_update_data;
 
 	ctx_isp->frame_id = 0;
 	ctx_isp->active_req_cnt = 0;
@@ -2212,6 +2304,58 @@
 	return rc;
 }
 
+static int __cam_isp_ctx_link_pause(struct cam_context *ctx)
+{
+	int rc = 0;
+	struct cam_isp_hw_cmd_args   hw_cmd_args;
+	struct cam_isp_context      *ctx_isp =
+		(struct cam_isp_context *) ctx->ctx_priv;
+
+	hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+	hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_PAUSE_HW;
+	rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
+		&hw_cmd_args);
+
+	return rc;
+}
+
+static int __cam_isp_ctx_link_resume(struct cam_context *ctx)
+{
+	int rc = 0;
+	struct cam_isp_hw_cmd_args   hw_cmd_args;
+	struct cam_isp_context      *ctx_isp =
+		(struct cam_isp_context *) ctx->ctx_priv;
+
+	hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+	hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_RESUME_HW;
+	rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
+		&hw_cmd_args);
+
+	return rc;
+}
+
+static int __cam_isp_ctx_process_evt(struct cam_context *ctx,
+	struct cam_req_mgr_link_evt_data *link_evt_data)
+{
+	int rc = 0;
+
+	switch (link_evt_data->evt_type) {
+	case CAM_REQ_MGR_LINK_EVT_ERR:
+		/* No need to handle this message now */
+		break;
+	case CAM_REQ_MGR_LINK_EVT_PAUSE:
+		__cam_isp_ctx_link_pause(ctx);
+		break;
+	case CAM_REQ_MGR_LINK_EVT_RESUME:
+		__cam_isp_ctx_link_resume(ctx);
+		break;
+	default:
+		CAM_WARN(CAM_ISP, "Unknown event from CRM");
+		break;
+	}
+	return rc;
+}
+
 static int __cam_isp_ctx_unlink_in_activated(struct cam_context *ctx,
 	struct cam_req_mgr_core_dev_link_setup *unlink)
 {
@@ -2343,7 +2487,8 @@
 		.crm_ops = {
 			.unlink = __cam_isp_ctx_unlink_in_activated,
 			.apply_req = __cam_isp_ctx_apply_req,
-			.flush_req = __cam_isp_ctx_flush_req_in_top_state,
+			.flush_req = __cam_isp_ctx_flush_req_in_activated,
+			.process_evt = __cam_isp_ctx_process_evt,
 		},
 		.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
 	},
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
index 88ebc03..f1f3137d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -52,6 +52,7 @@
 	CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED,
 	CAM_ISP_CTX_ACTIVATED_HW_ERROR,
 	CAM_ISP_CTX_ACTIVATED_HALT,
+	CAM_ISP_CTX_ACTIVATED_FLUSH,
 	CAM_ISP_CTX_ACTIVATED_MAX,
 };
 
@@ -81,22 +82,22 @@
  *                         the request has been completed.
  * @bubble_report:         Flag to track if bubble report is active on
  *                         current request
- * @packet_opcode_type:    Request packet opcode type,
- *                         ie INIT packet or update packet
+ * @hw_update_data:        HW update data for this request
  *
  */
 struct cam_isp_ctx_req {
-	struct cam_ctx_request          *base;
+	struct cam_ctx_request               *base;
 
-	struct cam_hw_update_entry       cfg[CAM_ISP_CTX_CFG_MAX];
-	uint32_t                         num_cfg;
-	struct cam_hw_fence_map_entry    fence_map_out[CAM_ISP_CTX_RES_MAX];
-	uint32_t                         num_fence_map_out;
-	struct cam_hw_fence_map_entry    fence_map_in[CAM_ISP_CTX_RES_MAX];
-	uint32_t                         num_fence_map_in;
-	uint32_t                         num_acked;
-	int32_t                          bubble_report;
-	uint32_t                         packet_opcode_type;
+	struct cam_hw_update_entry            cfg[CAM_ISP_CTX_CFG_MAX];
+	uint32_t                              num_cfg;
+	struct cam_hw_fence_map_entry         fence_map_out
+						[CAM_ISP_CTX_RES_MAX];
+	uint32_t                              num_fence_map_out;
+	struct cam_hw_fence_map_entry         fence_map_in[CAM_ISP_CTX_RES_MAX];
+	uint32_t                              num_fence_map_in;
+	uint32_t                              num_acked;
+	int32_t                               bubble_report;
+	struct cam_isp_prepare_hw_update_data hw_update_data;
 };
 
 /**
@@ -116,6 +117,7 @@
  * @subscribe_event:       The irq event mask that CRM subscribes to, IFE will
  *                         invoke CRM cb at those event.
  * @last_applied_req_id:   Last applied request id
+ * @frame_skip_count:      Number of frame to skip before change state
  *
  */
 struct cam_isp_context {
@@ -135,6 +137,7 @@
 	int64_t                          reported_req_id;
 	uint32_t                         subscribe_event;
 	int64_t                          last_applied_req_id;
+	uint32_t                         frame_skip_count;
 };
 
 /**
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 8d41ae7..a6f1cf5 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -860,10 +860,95 @@
 	return rc;
 }
 
-static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp(
+static int cam_ife_mgr_acquire_cid_res(
 	struct cam_ife_hw_mgr_ctx          *ife_ctx,
 	struct cam_isp_in_port_info        *in_port,
-	uint32_t                            cid_res_id)
+	uint32_t                           *cid_res_id,
+	enum cam_ife_pix_path_res_id        csid_path)
+{
+	int rc = -1;
+	int i, j;
+	struct cam_ife_hw_mgr               *ife_hw_mgr;
+	struct cam_ife_hw_mgr_res           *cid_res;
+	struct cam_hw_intf                  *hw_intf;
+	struct cam_csid_hw_reserve_resource_args  csid_acquire;
+
+	ife_hw_mgr = ife_ctx->hw_mgr;
+
+	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "No more free hw mgr resource");
+		goto err;
+	}
+	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res);
+
+	csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
+	csid_acquire.in_port = in_port;
+	csid_acquire.res_id =  csid_path;
+
+	for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
+		if (!ife_hw_mgr->csid_devices[i])
+			continue;
+
+		hw_intf = ife_hw_mgr->csid_devices[i];
+		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire,
+			sizeof(csid_acquire));
+		if (rc)
+			continue;
+		else
+			break;
+	}
+
+	if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
+		CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource");
+		goto err;
+	}
+
+	cid_res->res_type = CAM_IFE_HW_MGR_RES_CID;
+	cid_res->res_id = csid_acquire.node_res->res_id;
+	cid_res->is_dual_vfe = in_port->usage_type;
+	cid_res->hw_res[0] = csid_acquire.node_res;
+	cid_res->hw_res[1] = NULL;
+	/* CID(DT_ID) value of acquire device, require for path */
+	*cid_res_id = csid_acquire.node_res->res_id;
+
+	if (cid_res->is_dual_vfe) {
+		csid_acquire.node_res = NULL;
+		csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
+		csid_acquire.in_port = in_port;
+		for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
+			if (!ife_hw_mgr->csid_devices[j])
+				continue;
+
+			hw_intf = ife_hw_mgr->csid_devices[j];
+			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+				&csid_acquire, sizeof(csid_acquire));
+			if (rc)
+				continue;
+			else
+				break;
+		}
+
+		if (j == CAM_IFE_CSID_HW_NUM_MAX) {
+			CAM_ERR(CAM_ISP,
+				"Can not acquire ife csid rdi resource");
+			goto err;
+		}
+		cid_res->hw_res[1] = csid_acquire.node_res;
+	}
+	cid_res->parent = &ife_ctx->res_list_ife_in;
+	ife_ctx->res_list_ife_in.child[
+		ife_ctx->res_list_ife_in.num_children++] = cid_res;
+
+	return 0;
+err:
+	return rc;
+
+}
+
+static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp(
+	struct cam_ife_hw_mgr_ctx          *ife_ctx,
+	struct cam_isp_in_port_info        *in_port)
 {
 	int rc = -1;
 	int i;
@@ -872,8 +957,17 @@
 	struct cam_ife_hw_mgr_res           *csid_res;
 	struct cam_ife_hw_mgr_res           *cid_res;
 	struct cam_hw_intf                  *hw_intf;
+	uint32_t                             cid_res_id;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
 
+	/* get cid resource */
+	rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
+		CAM_IFE_PIX_PATH_RES_IPP);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
+		goto err;
+	}
+
 	ife_hw_mgr = ife_ctx->hw_mgr;
 
 	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res);
@@ -985,8 +1079,7 @@
 
 static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
 	struct cam_ife_hw_mgr_ctx     *ife_ctx,
-	struct cam_isp_in_port_info   *in_port,
-	uint32_t                       cid_res_id)
+	struct cam_isp_in_port_info   *in_port)
 {
 	int rc = -1;
 	int i, j;
@@ -996,6 +1089,7 @@
 	struct cam_ife_hw_mgr_res           *cid_res;
 	struct cam_hw_intf                  *hw_intf;
 	struct cam_isp_out_port_info        *out_port;
+	uint32_t                            cid_res_id;
 	struct cam_csid_hw_reserve_resource_args  csid_acquire;
 
 	ife_hw_mgr = ife_ctx->hw_mgr;
@@ -1005,6 +1099,15 @@
 		if (!cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
 			continue;
 
+		/* get cid resource */
+		rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
+			cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
+			out_port->res_type));
+		if (rc) {
+			CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
+			goto err;
+		}
+
 		rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
 			&csid_res);
 		if (rc) {
@@ -1135,91 +1238,6 @@
 	return 0;
 }
 
-static int cam_ife_mgr_acquire_cid_res(
-	struct cam_ife_hw_mgr_ctx          *ife_ctx,
-	struct cam_isp_in_port_info        *in_port,
-	uint32_t                           *cid_res_id,
-	int                                 pixel_count)
-{
-	int rc = -1;
-	int i, j;
-	struct cam_ife_hw_mgr               *ife_hw_mgr;
-	struct cam_ife_hw_mgr_res           *cid_res;
-	struct cam_hw_intf                  *hw_intf;
-	struct cam_csid_hw_reserve_resource_args  csid_acquire;
-
-	ife_hw_mgr = ife_ctx->hw_mgr;
-
-	rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "No more free hw mgr resource");
-		goto err;
-	}
-	cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res);
-
-	csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
-	csid_acquire.in_port = in_port;
-	csid_acquire.pixel_count = pixel_count;
-
-	for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
-		if (!ife_hw_mgr->csid_devices[i])
-			continue;
-
-		hw_intf = ife_hw_mgr->csid_devices[i];
-		rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire,
-			sizeof(csid_acquire));
-		if (rc)
-			continue;
-		else
-			break;
-	}
-
-	if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
-		CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource");
-		goto err;
-	}
-
-	cid_res->res_type = CAM_IFE_HW_MGR_RES_CID;
-	cid_res->res_id = csid_acquire.node_res->res_id;
-	cid_res->is_dual_vfe = in_port->usage_type;
-	cid_res->hw_res[0] = csid_acquire.node_res;
-	cid_res->hw_res[1] = NULL;
-	/* CID(DT_ID) value of acquire device, require for path */
-	*cid_res_id = csid_acquire.node_res->res_id;
-
-	if (cid_res->is_dual_vfe) {
-		csid_acquire.node_res = NULL;
-		csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
-		csid_acquire.in_port = in_port;
-		for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
-			if (!ife_hw_mgr->csid_devices[j])
-				continue;
-
-			hw_intf = ife_hw_mgr->csid_devices[j];
-			rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
-				&csid_acquire, sizeof(csid_acquire));
-			if (rc)
-				continue;
-			else
-				break;
-		}
-
-		if (j == CAM_IFE_CSID_HW_NUM_MAX) {
-			CAM_ERR(CAM_ISP,
-				"Can not acquire ife csid rdi resource");
-			goto err;
-		}
-		cid_res->hw_res[1] = csid_acquire.node_res;
-	}
-	cid_res->parent = &ife_ctx->res_list_ife_in;
-	ife_ctx->res_list_ife_in.child[
-		ife_ctx->res_list_ife_in.num_children++] = cid_res;
-
-	return 0;
-err:
-	return rc;
-
-}
 static int cam_ife_mgr_acquire_hw_for_ctx(
 	struct cam_ife_hw_mgr_ctx          *ife_ctx,
 	struct cam_isp_in_port_info        *in_port,
@@ -1229,7 +1247,6 @@
 	int is_dual_vfe                           = 0;
 	int pixel_count                           = 0;
 	int rdi_count                             = 0;
-	uint32_t                                cid_res_id = 0;
 
 	is_dual_vfe = in_port->usage_type;
 
@@ -1248,18 +1265,9 @@
 		return -EINVAL;
 	}
 
-	/* get cid resource */
-	rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
-		pixel_count);
-	if (rc) {
-		CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
-		goto err;
-	}
-
 	if (pixel_count) {
 		/* get ife csid IPP resrouce */
-		rc = cam_ife_hw_mgr_acquire_res_ife_csid_ipp(ife_ctx, in_port,
-				cid_res_id);
+		rc = cam_ife_hw_mgr_acquire_res_ife_csid_ipp(ife_ctx, in_port);
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 				"Acquire IFE CSID IPP resource Failed");
@@ -1269,8 +1277,7 @@
 
 	if (rdi_count) {
 		/* get ife csid rdi resource */
-		rc = cam_ife_hw_mgr_acquire_res_ife_csid_rdi(ife_ctx, in_port,
-			cid_res_id);
+		rc = cam_ife_hw_mgr_acquire_res_ife_csid_rdi(ife_ctx, in_port);
 		if (rc) {
 			CAM_ERR(CAM_ISP,
 				"Acquire IFE CSID RDI resource Failed");
@@ -1437,15 +1444,97 @@
 	return rc;
 }
 
+static int cam_isp_blob_bw_update(
+	struct cam_isp_bw_config              *bw_config,
+	struct cam_ife_hw_mgr_ctx             *ctx)
+{
+	struct cam_ife_hw_mgr_res             *hw_mgr_res;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_vfe_bw_update_args          bw_upd_args;
+	uint64_t                               cam_bw_bps = 0;
+	uint64_t                               ext_bw_bps = 0;
+	int                                    rc = -EINVAL;
+	uint32_t                               i;
+
+	CAM_DBG(CAM_ISP,
+		"usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n"
+		"right cam_bw_bps=%llu ext_bw_bps=%llu",
+		bw_config->usage_type,
+		bw_config->left_pix_vote.cam_bw_bps,
+		bw_config->left_pix_vote.ext_bw_bps,
+		bw_config->right_pix_vote.cam_bw_bps,
+		bw_config->right_pix_vote.ext_bw_bps);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
+				if (i == CAM_ISP_HW_SPLIT_LEFT) {
+					cam_bw_bps =
+					bw_config->left_pix_vote.cam_bw_bps;
+					ext_bw_bps =
+					bw_config->left_pix_vote.ext_bw_bps;
+				} else {
+					cam_bw_bps =
+					bw_config->right_pix_vote.cam_bw_bps;
+					ext_bw_bps =
+					bw_config->right_pix_vote.ext_bw_bps;
+				}
+			else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
+						&& (hw_mgr_res->res_id <=
+						CAM_ISP_HW_VFE_IN_RDI3)) {
+				uint32_t idx = hw_mgr_res->res_id -
+						CAM_ISP_HW_VFE_IN_RDI0;
+				if (idx >= bw_config->num_rdi)
+					continue;
+
+				cam_bw_bps =
+					bw_config->rdi_vote[idx].cam_bw_bps;
+				ext_bw_bps =
+					bw_config->rdi_vote[idx].ext_bw_bps;
+			} else
+				if (hw_mgr_res->hw_res[i]) {
+					CAM_ERR(CAM_ISP, "Invalid res_id %u",
+						hw_mgr_res->res_id);
+					rc = -EINVAL;
+					return rc;
+				}
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				bw_upd_args.node_res =
+					hw_mgr_res->hw_res[i];
+
+				bw_upd_args.camnoc_bw_bytes = cam_bw_bps;
+				bw_upd_args.external_bw_bytes = ext_bw_bps;
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_BW_UPDATE,
+					&bw_upd_args,
+					sizeof(struct cam_vfe_bw_update_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "BW Update failed");
+			} else
+				CAM_WARN(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	return rc;
+}
+
 /* entry function: config_hw */
 static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
 					void *config_hw_args)
 {
 	int rc = -1, i;
-	struct cam_hw_start_args *cfg;
+	struct cam_hw_config_args *cfg;
 	struct cam_hw_update_entry *cmd;
 	struct cam_cdm_bl_request *cdm_cmd;
 	struct cam_ife_hw_mgr_ctx *ctx;
+	struct cam_isp_prepare_hw_update_data *hw_update_data;
 
 	CAM_DBG(CAM_ISP, "Enter");
 	if (!hw_mgr_priv || !config_hw_args) {
@@ -1467,6 +1556,18 @@
 	if (atomic_read(&ctx->overflow_pending))
 		return -EINVAL;
 
+	hw_update_data = (struct cam_isp_prepare_hw_update_data  *) cfg->priv;
+
+	for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
+		if (hw_update_data->bw_config_valid[i] == true) {
+			rc = cam_isp_blob_bw_update(
+				(struct cam_isp_bw_config *)
+				&hw_update_data->bw_config[i], ctx);
+			if (rc)
+				CAM_ERR(CAM_ISP, "Bandwidth Update Failed");
+			}
+	}
+
 	CAM_DBG(CAM_ISP, "Enter ctx id:%d num_hw_upd_entries %d",
 		ctx->ctx_index, cfg->num_hw_update_entries);
 
@@ -1798,7 +1899,7 @@
 static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args)
 {
 	int                               rc = -1;
-	struct cam_hw_start_args         *start_args = start_hw_args;
+	struct cam_hw_config_args        *start_args = start_hw_args;
 	struct cam_ife_hw_mgr_ctx        *ctx;
 	struct cam_ife_hw_mgr_res        *hw_mgr_res;
 	uint32_t                          i;
@@ -2204,92 +2305,6 @@
 	return rc;
 }
 
-static int cam_isp_blob_bw_update(
-	uint32_t                               blob_type,
-	struct cam_isp_generic_blob_info      *blob_info,
-	struct cam_isp_bw_config              *bw_config,
-	struct cam_hw_prepare_update_args     *prepare)
-{
-	struct cam_ife_hw_mgr_ctx             *ctx = NULL;
-	struct cam_ife_hw_mgr_res             *hw_mgr_res;
-	struct cam_hw_intf                    *hw_intf;
-	struct cam_vfe_bw_update_args          bw_upd_args;
-	uint64_t                               cam_bw_bps = 0;
-	uint64_t                               ext_bw_bps = 0;
-	int                                    rc = -EINVAL;
-	uint32_t                               i;
-
-	ctx = prepare->ctxt_to_hw_map;
-
-	CAM_DBG(CAM_ISP,
-		"usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n"
-		"right cam_bw_bps=%llu ext_bw_bps=%llu",
-		bw_config->usage_type,
-		bw_config->left_pix_vote.cam_bw_bps,
-		bw_config->left_pix_vote.ext_bw_bps,
-		bw_config->right_pix_vote.cam_bw_bps,
-		bw_config->right_pix_vote.ext_bw_bps);
-
-	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!hw_mgr_res->hw_res[i])
-				continue;
-
-			if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF)
-				if (i == CAM_ISP_HW_SPLIT_LEFT) {
-					cam_bw_bps =
-					bw_config->left_pix_vote.cam_bw_bps;
-					ext_bw_bps =
-					bw_config->left_pix_vote.ext_bw_bps;
-				} else {
-					cam_bw_bps =
-					bw_config->right_pix_vote.cam_bw_bps;
-					ext_bw_bps =
-					bw_config->right_pix_vote.ext_bw_bps;
-				}
-			else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0)
-						&& (hw_mgr_res->res_id <=
-						CAM_ISP_HW_VFE_IN_RDI3)) {
-				uint32_t idx = hw_mgr_res->res_id -
-						CAM_ISP_HW_VFE_IN_RDI0;
-				if (idx >= bw_config->num_rdi)
-					continue;
-
-				cam_bw_bps =
-					bw_config->rdi_vote[idx].cam_bw_bps;
-				ext_bw_bps =
-					bw_config->rdi_vote[idx].ext_bw_bps;
-			} else
-				if (hw_mgr_res->hw_res[i]) {
-					CAM_ERR(CAM_ISP, "Invalid res_id %u",
-						hw_mgr_res->res_id);
-					rc = -EINVAL;
-					return rc;
-				}
-
-			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
-			if (hw_intf && hw_intf->hw_ops.process_cmd) {
-				bw_upd_args.node_res =
-					hw_mgr_res->hw_res[i];
-
-				bw_upd_args.camnoc_bw_bytes = cam_bw_bps;
-				bw_upd_args.external_bw_bytes = ext_bw_bps;
-
-				rc = hw_intf->hw_ops.process_cmd(
-					hw_intf->hw_priv,
-					CAM_ISP_HW_CMD_BW_UPDATE,
-					&bw_upd_args,
-					sizeof(struct cam_vfe_bw_update_args));
-				if (rc)
-					CAM_ERR(CAM_ISP, "BW Update failed");
-			} else
-				CAM_WARN(CAM_ISP, "NULL hw_intf!");
-		}
-	}
-
-	return rc;
-}
-
 static int cam_isp_packet_generic_blob_handler(void *user_data,
 	uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
 {
@@ -2340,11 +2355,22 @@
 	case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: {
 		struct cam_isp_bw_config    *bw_config =
 			(struct cam_isp_bw_config *)blob_data;
+		struct cam_isp_prepare_hw_update_data   *prepare_hw_data;
 
-		rc = cam_isp_blob_bw_update(blob_type, blob_info,
-			bw_config, prepare);
-		if (rc)
-			CAM_ERR(CAM_ISP, "Bandwidth Update Failed");
+		if (!prepare || !prepare->priv ||
+			(bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) {
+			CAM_ERR(CAM_ISP, "Invalid inputs");
+			rc = -EINVAL;
+			break;
+		}
+
+		prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
+			prepare->priv;
+
+		memcpy(&prepare_hw_data->bw_config[bw_config->usage_type],
+			bw_config, sizeof(prepare_hw_data->bw_config[0]));
+		prepare_hw_data->bw_config_valid[bw_config->usage_type] = true;
+
 	}
 		break;
 	default:
@@ -2375,6 +2401,9 @@
 
 	CAM_DBG(CAM_ISP, "enter");
 
+	prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
+		prepare->priv;
+
 	ctx = (struct cam_ife_hw_mgr_ctx *) prepare->ctxt_to_hw_map;
 	hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv;
 
@@ -2399,6 +2428,13 @@
 	prepare->num_in_map_entries = 0;
 	prepare->num_out_map_entries = 0;
 
+	memset(&prepare_hw_data->bw_config[0], 0x0,
+		sizeof(prepare_hw_data->bw_config[0]) *
+		CAM_IFE_HW_NUM_MAX);
+	memset(&prepare_hw_data->bw_config_valid[0], 0x0,
+		sizeof(prepare_hw_data->bw_config_valid[0]) *
+		CAM_IFE_HW_NUM_MAX);
+
 	for (i = 0; i < ctx->num_base; i++) {
 		CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i);
 
@@ -2452,8 +2488,6 @@
 	 * bits to get the type of operation since UMD definition
 	 * of op_code has some difference from KMD.
 	 */
-	prepare_hw_data = (struct cam_isp_prepare_hw_update_data  *)
-		prepare->priv;
 	if (((prepare->packet->header.op_code + 1) & 0xF) ==
 		CAM_ISP_PACKET_INIT_DEV) {
 		prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV;
@@ -2488,6 +2522,53 @@
 	return rc;
 }
 
+static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx,
+	enum cam_vfe_bw_control_action action)
+{
+	struct cam_ife_hw_mgr_res             *hw_mgr_res;
+	struct cam_hw_intf                    *hw_intf;
+	struct cam_vfe_bw_control_args         bw_ctrl_args;
+	int                                    rc = -EINVAL;
+	uint32_t                               i;
+
+	CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index);
+
+	list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			if (!hw_mgr_res->hw_res[i])
+				continue;
+
+			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
+			if (hw_intf && hw_intf->hw_ops.process_cmd) {
+				bw_ctrl_args.node_res =
+					hw_mgr_res->hw_res[i];
+				bw_ctrl_args.action = action;
+
+				rc = hw_intf->hw_ops.process_cmd(
+					hw_intf->hw_priv,
+					CAM_ISP_HW_CMD_BW_CONTROL,
+					&bw_ctrl_args,
+					sizeof(struct cam_vfe_bw_control_args));
+				if (rc)
+					CAM_ERR(CAM_ISP, "BW Update failed");
+			} else
+				CAM_WARN(CAM_ISP, "NULL hw_intf!");
+		}
+	}
+
+	return rc;
+}
+
+static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx)
+{
+	return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE);
+}
+
+static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx)
+{
+	return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE);
+}
+
 static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 {
 	int rc = 0;
@@ -2513,6 +2594,12 @@
 			hw_cmd_args->u.is_rdi_only_context = 0;
 
 		break;
+	case CAM_ISP_HW_MGR_CMD_PAUSE_HW:
+		cam_ife_mgr_pause_hw(ctx);
+		break;
+	case CAM_ISP_HW_MGR_CMD_RESUME_HW:
+		cam_ife_mgr_resume_hw(ctx);
+		break;
 	default:
 		CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x",
 			hw_cmd_args->cmd_type);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
index 4d26138..c418a41 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -18,9 +18,6 @@
 #include "cam_ife_csid_hw_intf.h"
 #include "cam_tasklet_util.h"
 
-/* MAX IFE instance */
-#define CAM_IFE_HW_NUM_MAX                       4
-
 /* enum cam_ife_hw_mgr_res_type - manager resource node type */
 enum cam_ife_hw_mgr_res_type {
 	CAM_IFE_HW_MGR_RES_UNINIT,
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
index cf044eb..78336d2 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,10 @@
 #include <uapi/media/cam_isp.h>
 #include "cam_hw_mgr_intf.h"
 
+/* MAX IFE instance */
+#define CAM_IFE_HW_NUM_MAX   4
+#define CAM_IFE_RDI_NUM_MAX  4
+
 /**
  *  enum cam_isp_hw_event_type - Collection of the ISP hardware events
  */
@@ -47,15 +51,38 @@
 };
 
 /**
+ * struct cam_isp_bw_config_internal - Internal Bandwidth configuration
+ *
+ * @usage_type:                 Usage type (Single/Dual)
+ * @num_rdi:                    Number of RDI votes
+ * @left_pix_vote:              Bandwidth vote for left ISP
+ * @right_pix_vote:             Bandwidth vote for right ISP
+ * @rdi_vote:                   RDI bandwidth requirements
+ */
+
+struct cam_isp_bw_config_internal {
+	uint32_t                       usage_type;
+	uint32_t                       num_rdi;
+	struct cam_isp_bw_vote         left_pix_vote;
+	struct cam_isp_bw_vote         right_pix_vote;
+	struct cam_isp_bw_vote         rdi_vote[CAM_IFE_RDI_NUM_MAX];
+};
+
+/**
  * struct cam_isp_prepare_hw_update_data - hw prepare data
  *
  * @packet_opcode_type:     Packet header opcode in the packet header
- *                   this opcode defines, packet is init packet or
- *                   update packet
+ *                          this opcode defines, packet is init packet or
+ *                          update packet
+ * @bw_config:              BW config information
+ * @bw_config_valid:        Flag indicating whether the bw_config at the index
+ *                          is valid or not
  *
  */
 struct cam_isp_prepare_hw_update_data {
-	uint32_t      packet_opcode_type;
+	uint32_t                          packet_opcode_type;
+	struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX];
+	bool                              bw_config_valid[CAM_IFE_HW_NUM_MAX];
 };
 
 
@@ -130,6 +157,8 @@
 /* enum cam_isp_hw_mgr_command - Hardware manager command type */
 enum cam_isp_hw_mgr_command {
 	CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT,
+	CAM_ISP_HW_MGR_CMD_PAUSE_HW,
+	CAM_ISP_HW_MGR_CMD_RESUME_HW,
 	CAM_ISP_HW_MGR_CMD_MAX,
 };
 
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 bce0374..ff0c91f 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
@@ -287,7 +287,7 @@
 
 static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw,
 	struct cam_isp_resource_node **res, int32_t vc, uint32_t dt,
-	uint32_t res_type, int pixel_count)
+	uint32_t res_type)
 {
 	int  rc = 0;
 	struct cam_ife_csid_cid_data    *cid_data;
@@ -305,8 +305,7 @@
 					break;
 				}
 			} else {
-				if (cid_data->vc == vc && cid_data->dt == dt &&
-					cid_data->pixel_count == pixel_count) {
+				if (cid_data->vc == vc && cid_data->dt == dt) {
 					cid_data->cnt++;
 					*res = &csid_hw->cid_res[i];
 					break;
@@ -330,7 +329,6 @@
 				cid_data->vc  = vc;
 				cid_data->dt  = dt;
 				cid_data->cnt = 1;
-				cid_data->pixel_count = pixel_count;
 				csid_hw->cid_res[j].res_state =
 					CAM_ISP_RESOURCE_STATE_RESERVED;
 				*res = &csid_hw->cid_res[j];
@@ -570,7 +568,6 @@
 	struct cam_csid_hw_reserve_resource_args  *cid_reserv)
 {
 	int rc = 0;
-	uint32_t i;
 	struct cam_ife_csid_cid_data       *cid_data;
 
 	CAM_DBG(CAM_ISP,
@@ -728,7 +725,6 @@
 		cid_data->vc = cid_reserv->in_port->vc;
 		cid_data->dt = cid_reserv->in_port->dt;
 		cid_data->cnt = 1;
-		cid_data->pixel_count = cid_reserv->pixel_count;
 		cid_reserv->node_res = &csid_hw->cid_res[0];
 		csid_hw->csi2_reserve_cnt++;
 
@@ -737,27 +733,43 @@
 			csid_hw->hw_intf->hw_idx,
 			cid_reserv->node_res->res_id);
 	} else {
-		if (cid_reserv->pixel_count > 0) {
-			for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
-				cid_data = (struct cam_ife_csid_cid_data *)
-					csid_hw->cid_res[i].res_priv;
-				if ((csid_hw->cid_res[i].res_state >=
-					CAM_ISP_RESOURCE_STATE_RESERVED) &&
-					cid_data->pixel_count > 0) {
-					CAM_DBG(CAM_ISP,
-						"CSID:%d IPP resource is full");
-					rc = -EINVAL;
-					goto end;
-				}
+		switch (cid_reserv->res_id) {
+		case CAM_IFE_PIX_PATH_RES_IPP:
+			if (csid_hw->ipp_res.res_state !=
+				CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+				CAM_DBG(CAM_ISP,
+					"CSID:%d IPP resource not available",
+					csid_hw->hw_intf->hw_idx);
+				rc = -EINVAL;
+				goto end;
 			}
+			break;
+		case CAM_IFE_PIX_PATH_RES_RDI_0:
+		case CAM_IFE_PIX_PATH_RES_RDI_1:
+		case CAM_IFE_PIX_PATH_RES_RDI_2:
+		case CAM_IFE_PIX_PATH_RES_RDI_3:
+			if (csid_hw->rdi_res[cid_reserv->res_id].res_state !=
+				CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+				CAM_DBG(CAM_ISP,
+					"CSID:%d RDI:%d resource not available",
+					csid_hw->hw_intf->hw_idx,
+					cid_reserv->res_id);
+				rc = -EINVAL;
+				goto end;
+			}
+			break;
+		default:
+			CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path",
+				csid_hw->hw_intf->hw_idx);
+			rc = -EINVAL;
+			goto end;
 		}
 
 		rc = cam_ife_csid_cid_get(csid_hw,
 			&cid_reserv->node_res,
 			cid_reserv->in_port->vc,
 			cid_reserv->in_port->dt,
-			cid_reserv->in_port->res_type,
-			cid_reserv->pixel_count);
+			cid_reserv->in_port->res_type);
 		/* if success then increment the reserve count */
 		if (!rc) {
 			if (csid_hw->csi2_reserve_cnt == UINT_MAX) {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
index b400d14..4b546ea 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -368,7 +368,6 @@
 	uint32_t                     dt;
 	uint32_t                     cnt;
 	uint32_t                     tpg_set;
-	int                          pixel_count;
 };
 
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
index df97bd6..ceeacbe 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -75,7 +75,6 @@
  * @cid:          cid (DT_ID) value for path, this is applicable for CSID path
  *                reserve
  * @node_res :    Reserved resource structure pointer
- * @pixel_count:  Number of pixel resources
  *
  */
 struct cam_csid_hw_reserve_resource_args {
@@ -87,7 +86,6 @@
 	uint32_t                                  master_idx;
 	uint32_t                                  cid;
 	struct cam_isp_resource_node             *node_res;
-	int                                       pixel_count;
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
index 257a5ac..b9f6d77 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -92,6 +92,7 @@
 	CAM_ISP_HW_CMD_STRIPE_UPDATE,
 	CAM_ISP_HW_CMD_CLOCK_UPDATE,
 	CAM_ISP_HW_CMD_BW_UPDATE,
+	CAM_ISP_HW_CMD_BW_CONTROL,
 	CAM_ISP_HW_CMD_MAX,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
index b771ec6..8927d6a 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -185,6 +185,22 @@
 	uint64_t                           external_bw_bytes;
 };
 
+enum cam_vfe_bw_control_action {
+	CAM_VFE_BW_CONTROL_EXCLUDE       = 0,
+	CAM_VFE_BW_CONTROL_INCLUDE       = 1
+};
+
+/*
+ * struct cam_vfe_bw_control_args:
+ *
+ * @node_res:             Resource to get the time stamp
+ * @action:               Bandwidth control action
+ */
+struct cam_vfe_bw_control_args {
+	struct cam_isp_resource_node      *node_res;
+	enum cam_vfe_bw_control_action     action;
+};
+
 /*
  * struct cam_vfe_top_irq_evt_payload:
  *
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index 02fec28..2c4fe9d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -697,6 +697,7 @@
 	case CAM_ISP_HW_CMD_GET_REG_UPDATE:
 	case CAM_ISP_HW_CMD_CLOCK_UPDATE:
 	case CAM_ISP_HW_CMD_BW_UPDATE:
+	case CAM_ISP_HW_CMD_BW_CONTROL:
 		rc = core_info->vfe_top->hw_ops.process_cmd(
 			core_info->vfe_top->top_priv, cmd_type, cmd_args,
 			arg_size);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
index f166025..f4aa5c3 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,8 +20,9 @@
 #include "cam_cpas_api.h"
 #include "cam_vfe_soc.h"
 
-#define CAM_VFE_HW_RESET_HW_AND_REG_VAL   0x00003F9F
-#define CAM_VFE_HW_RESET_HW_VAL           0x00003F87
+#define CAM_VFE_HW_RESET_HW_AND_REG_VAL       0x00003F9F
+#define CAM_VFE_HW_RESET_HW_VAL               0x00003F87
+#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 3
 
 struct cam_vfe_top_ver2_common_data {
 	struct cam_hw_soc_info                     *soc_info;
@@ -33,7 +34,11 @@
 	struct cam_vfe_top_ver2_common_data common_data;
 	struct cam_isp_resource_node        mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX];
 	unsigned long                       hw_clk_rate;
-	struct cam_axi_vote                 hw_axi_vote;
+	enum cam_vfe_bw_control_action      axi_vote_control[
+						CAM_VFE_TOP_VER2_MUX_MAX];
+	struct cam_axi_vote                 to_be_applied_axi_vote;
+	struct cam_axi_vote                 applied_axi_vote;
+	uint32_t                            counter_to_update_axi_vote;
 	struct cam_axi_vote             req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX];
 	unsigned long                   req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX];
 };
@@ -119,7 +124,8 @@
 }
 
 static int cam_vfe_top_set_axi_bw_vote(
-	struct cam_vfe_top_ver2_priv *top_priv)
+	struct cam_vfe_top_ver2_priv *top_priv,
+	bool start_stop)
 {
 	struct cam_axi_vote sum = {0, 0};
 	int i, rc = 0;
@@ -127,6 +133,7 @@
 		top_priv->common_data.soc_info;
 	struct cam_vfe_soc_private *soc_private =
 		soc_info->soc_private;
+	bool apply_bw_update = false;
 
 	if (!soc_private) {
 		CAM_ERR(CAM_ISP, "Error soc_private NULL");
@@ -134,30 +141,98 @@
 	}
 
 	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
-		sum.uncompressed_bw +=
-			top_priv->req_axi_vote[i].uncompressed_bw;
-		sum.compressed_bw +=
-			top_priv->req_axi_vote[i].compressed_bw;
+		if (top_priv->axi_vote_control[i] ==
+			CAM_VFE_BW_CONTROL_INCLUDE) {
+			sum.uncompressed_bw +=
+				top_priv->req_axi_vote[i].uncompressed_bw;
+			sum.compressed_bw +=
+				top_priv->req_axi_vote[i].compressed_bw;
+		}
 	}
 
-	CAM_DBG(CAM_ISP, "BW Vote: u=%lld c=%lld",
+	CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)",
+		top_priv->applied_axi_vote.uncompressed_bw,
+		top_priv->applied_axi_vote.compressed_bw,
 		sum.uncompressed_bw,
 		sum.compressed_bw);
 
-	if ((top_priv->hw_axi_vote.uncompressed_bw ==
+	if ((top_priv->applied_axi_vote.uncompressed_bw ==
 		sum.uncompressed_bw) &&
-		(top_priv->hw_axi_vote.compressed_bw ==
-		sum.compressed_bw))
+		(top_priv->applied_axi_vote.compressed_bw ==
+		sum.compressed_bw)) {
+		CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu",
+			top_priv->applied_axi_vote.uncompressed_bw,
+			top_priv->applied_axi_vote.compressed_bw);
+		top_priv->counter_to_update_axi_vote = 0;
 		return 0;
+	}
 
-	rc = cam_cpas_update_axi_vote(
+	if ((top_priv->to_be_applied_axi_vote.uncompressed_bw !=
+		sum.uncompressed_bw) ||
+		(top_priv->to_be_applied_axi_vote.compressed_bw !=
+		sum.compressed_bw)) {
+		// we got a new bw value to apply
+		top_priv->counter_to_update_axi_vote = 0;
+
+		top_priv->to_be_applied_axi_vote.uncompressed_bw =
+			sum.uncompressed_bw;
+		top_priv->to_be_applied_axi_vote.compressed_bw =
+			sum.compressed_bw;
+	}
+
+	if (start_stop == true) {
+		CAM_DBG(CAM_ISP,
+			"New bw in start/stop, applying bw now, counter=%d",
+			top_priv->counter_to_update_axi_vote);
+		top_priv->counter_to_update_axi_vote = 0;
+		apply_bw_update = true;
+	} else if ((top_priv->to_be_applied_axi_vote.uncompressed_bw <
+		top_priv->applied_axi_vote.uncompressed_bw) ||
+		(top_priv->to_be_applied_axi_vote.compressed_bw <
+		top_priv->applied_axi_vote.compressed_bw)) {
+		if (top_priv->counter_to_update_axi_vote >=
+			(CAM_VFE_TOP_VER2_MUX_MAX *
+			CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)) {
+			CAM_DBG(CAM_ISP,
+				"New bw is less, applying bw now, counter=%d",
+				top_priv->counter_to_update_axi_vote);
+			top_priv->counter_to_update_axi_vote = 0;
+			apply_bw_update = true;
+		} else {
+			CAM_DBG(CAM_ISP,
+				"New bw is less, Defer applying bw, counter=%d",
+				top_priv->counter_to_update_axi_vote);
+
+			top_priv->counter_to_update_axi_vote++;
+			apply_bw_update = false;
+		}
+	} else {
+		CAM_DBG(CAM_ISP,
+			"New bw is more, applying bw now, counter=%d",
+			top_priv->counter_to_update_axi_vote);
+		top_priv->counter_to_update_axi_vote = 0;
+		apply_bw_update = true;
+	}
+
+	CAM_DBG(CAM_ISP,
+		"counter=%d, apply_bw_update=%d",
+		top_priv->counter_to_update_axi_vote,
+		apply_bw_update);
+
+	if (apply_bw_update == true) {
+		rc = cam_cpas_update_axi_vote(
 			soc_private->cpas_handle,
-			&sum);
-	if (!rc) {
-		top_priv->hw_axi_vote.uncompressed_bw = sum.uncompressed_bw;
-		top_priv->hw_axi_vote.compressed_bw = sum.compressed_bw;
-	} else
-		CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
+			&top_priv->to_be_applied_axi_vote);
+		if (!rc) {
+			top_priv->applied_axi_vote.uncompressed_bw =
+			top_priv->to_be_applied_axi_vote.uncompressed_bw;
+			top_priv->applied_axi_vote.compressed_bw =
+				top_priv->to_be_applied_axi_vote.compressed_bw;
+		} else {
+			CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc);
+		}
+		top_priv->counter_to_update_axi_vote = 0;
+	}
 
 	return rc;
 }
@@ -239,6 +314,8 @@
 				bw_update->camnoc_bw_bytes;
 			top_priv->req_axi_vote[i].compressed_bw =
 				bw_update->external_bw_bytes;
+			top_priv->axi_vote_control[i] =
+				CAM_VFE_BW_CONTROL_INCLUDE;
 			break;
 		}
 	}
@@ -248,7 +325,51 @@
 			res->hw_intf->hw_idx,
 			hw_info->hw_state);
 	} else
-		rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv, false);
+
+	return rc;
+}
+
+static int cam_vfe_top_bw_control(
+	struct cam_vfe_top_ver2_priv *top_priv,
+	 void *cmd_args, uint32_t arg_size)
+{
+	struct cam_vfe_bw_control_args       *bw_ctrl = NULL;
+	struct cam_isp_resource_node         *res = NULL;
+	struct cam_hw_info                   *hw_info = NULL;
+	int                                   rc = 0;
+	int                                   i;
+
+	bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args;
+	res = bw_ctrl->node_res;
+
+	if (!res || !res->hw_intf->hw_priv)
+		return -EINVAL;
+
+	hw_info = res->hw_intf->hw_priv;
+
+	if (res->res_type != CAM_ISP_RESOURCE_VFE_IN ||
+		res->res_id >= CAM_ISP_HW_VFE_IN_MAX) {
+		CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d",
+			res->hw_intf->hw_idx, res->res_type,
+			res->res_id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
+		if (top_priv->mux_rsrc[i].res_id == res->res_id) {
+			top_priv->axi_vote_control[i] = bw_ctrl->action;
+			break;
+		}
+	}
+
+	if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) {
+		CAM_DBG(CAM_ISP, "VFE:%d Not ready to set BW yet :%d",
+			res->hw_intf->hw_idx,
+			hw_info->hw_state);
+	} else {
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
+	}
 
 	return rc;
 }
@@ -412,7 +533,7 @@
 		return rc;
 	}
 
-	rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+	rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
 	if (rc) {
 		CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
 		return rc;
@@ -458,6 +579,8 @@
 				top_priv->req_clk_rate[i] = 0;
 				top_priv->req_axi_vote[i].compressed_bw = 0;
 				top_priv->req_axi_vote[i].uncompressed_bw = 0;
+				top_priv->axi_vote_control[i] =
+					CAM_VFE_BW_CONTROL_EXCLUDE;
 				break;
 			}
 		}
@@ -468,7 +591,7 @@
 			return rc;
 		}
 
-		rc = cam_vfe_top_set_axi_bw_vote(top_priv);
+		rc = cam_vfe_top_set_axi_bw_vote(top_priv, true);
 		if (rc) {
 			CAM_ERR(CAM_ISP, "set_axi_bw_vote failed, rc=%d", rc);
 			return rc;
@@ -518,6 +641,9 @@
 		rc = cam_vfe_top_bw_update(top_priv, cmd_args,
 			arg_size);
 		break;
+	case CAM_ISP_HW_CMD_BW_CONTROL:
+		rc = cam_vfe_top_bw_control(top_priv, cmd_args, arg_size);
+		break;
 	default:
 		rc = -EINVAL;
 		CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type);
@@ -554,8 +680,11 @@
 	}
 	vfe_top->top_priv = top_priv;
 	top_priv->hw_clk_rate = 0;
-	top_priv->hw_axi_vote.compressed_bw = 0;
-	top_priv->hw_axi_vote.uncompressed_bw = 0;
+	top_priv->to_be_applied_axi_vote.compressed_bw = 0;
+	top_priv->to_be_applied_axi_vote.uncompressed_bw = 0;
+	top_priv->applied_axi_vote.compressed_bw = 0;
+	top_priv->applied_axi_vote.uncompressed_bw = 0;
+	top_priv->counter_to_update_axi_vote = 0;
 
 	for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) {
 		top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN;
@@ -565,6 +694,8 @@
 		top_priv->req_clk_rate[i] = 0;
 		top_priv->req_axi_vote[i].compressed_bw = 0;
 		top_priv->req_axi_vote[i].uncompressed_bw = 0;
+		top_priv->axi_vote_control[i] = CAM_VFE_BW_CONTROL_EXCLUDE;
+
 
 		if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) {
 			top_priv->mux_rsrc[i].res_id =
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
index bb952e6..21e66a2 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
@@ -68,6 +68,10 @@
 		cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
 			hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
 			0x1);
+	else if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10)
+		cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+			hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
+			0x22);
 	else
 		CAM_ERR(CAM_LRME, "Unsupported format %d",
 			io_buf->io_cfg->format);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
index 9689698..02f03ea 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -761,7 +761,7 @@
 				"Buffer inactive at idx=%d, continuing", i);
 			continue;
 		} else {
-			CAM_INFO(CAM_CRM,
+			CAM_DBG(CAM_CRM,
 			"Active buffer at idx=%d, possible leak needs unmapping",
 			i);
 			cam_mem_mgr_unmap_active_buf(i);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index d7662f1..3100f91 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2487,6 +2487,12 @@
 		return -EINVAL;
 	}
 
+	if ((!sync_info->link_hdls[0]) || (!sync_info->link_hdls[1])) {
+		CAM_WARN(CAM_CRM, "Invalid link handles 0x%x 0x%x",
+			sync_info->link_hdls[0], sync_info->link_hdls[1]);
+		return -EINVAL;
+	}
+
 	mutex_lock(&g_crm_core_dev->crm_lock);
 	/* session hdl's priv data is cam session struct */
 	cam_session = (struct cam_req_mgr_core_session *)
@@ -2607,9 +2613,12 @@
 int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control)
 {
 	int                               rc = 0;
-	int                               i;
+	int                               i, j;
 	struct cam_req_mgr_core_link     *link = NULL;
 
+	struct cam_req_mgr_connected_device *dev = NULL;
+	struct cam_req_mgr_link_evt_data     evt_data;
+
 	if (!control) {
 		CAM_ERR(CAM_CRM, "Control command is NULL");
 		rc = -EINVAL;
@@ -2639,9 +2648,29 @@
 					link->link_hdl);
 				rc = -EFAULT;
 			}
+			/* notify nodes */
+			for (j = 0; j < link->num_devs; j++) {
+				dev = &link->l_dev[j];
+				evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_RESUME;
+				evt_data.link_hdl =  link->link_hdl;
+				evt_data.dev_hdl = dev->dev_hdl;
+				evt_data.req_id = 0;
+				if (dev->ops && dev->ops->process_evt)
+					dev->ops->process_evt(&evt_data);
+			}
 		} else if (control->ops == CAM_REQ_MGR_LINK_DEACTIVATE) {
 			/* Destroy SOF watchdog timer */
 			crm_timer_exit(&link->watchdog);
+			/* notify nodes */
+			for (j = 0; j < link->num_devs; j++) {
+				dev = &link->l_dev[j];
+				evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_PAUSE;
+				evt_data.link_hdl =  link->link_hdl;
+				evt_data.dev_hdl = dev->dev_hdl;
+				evt_data.req_id = 0;
+				if (dev->ops && dev->ops->process_evt)
+					dev->ops->process_evt(&evt_data);
+			}
 		} else {
 			CAM_ERR(CAM_CRM, "Invalid link control command");
 			rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
index ce8dfa7..45ebc69 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h
@@ -81,9 +81,9 @@
  * @process_evt  : payload to generic event
  */
 struct cam_req_mgr_kmd_ops {
-	cam_req_mgr_get_dev_info      get_dev_info;
-	cam_req_mgr_link_setup        link_setup;
-	cam_req_mgr_apply_req         apply_req;
+	cam_req_mgr_get_dev_info     get_dev_info;
+	cam_req_mgr_link_setup       link_setup;
+	cam_req_mgr_apply_req        apply_req;
 	cam_req_mgr_flush_req        flush_req;
 	cam_req_mgr_process_evt      process_evt;
 };
@@ -182,6 +182,8 @@
  */
 enum cam_req_mgr_link_evt_type {
 	CAM_REQ_MGR_LINK_EVT_ERR,
+	CAM_REQ_MGR_LINK_EVT_PAUSE,
+	CAM_REQ_MGR_LINK_EVT_RESUME,
 	CAM_REQ_MGR_LINK_EVT_MAX,
 };
 
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 9894ca3..d5bb1b0 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -191,14 +191,16 @@
 			CAM_ERR(CAM_SENSOR,
 				"Already some pkt in offset req : %lld",
 				csl_packet->header.request_id);
-			rc = delete_request(i2c_reg_settings);
-			if (rc < 0) {
-				CAM_ERR(CAM_SENSOR,
-				"Failed in Deleting the err: %d", rc);
-				return rc;
-			}
+			/*
+			 * Update req mgr even in case of failure.
+			 * This will help not to wait indefinitely
+			 * and freeze. If this log is triggered then
+			 * fix it.
+			 */
+			cam_sensor_update_req_mgr(s_ctrl, csl_packet);
+			return 0;
 		}
-	break;
+		break;
 	}
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: {
 		if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
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 7a6d7fd..89aad4e 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -98,6 +98,11 @@
 		return -EINVAL;
 	}
 
+	if (!write_setting->reg_setting) {
+		CAM_ERR(CAM_SENSOR, "Invalid Register Settings");
+		return -EINVAL;
+	}
+
 	if (io_master_info->master_type == CCI_MASTER) {
 		return cam_cci_i2c_write_table(io_master_info,
 			write_setting);
@@ -125,6 +130,11 @@
 		return -EINVAL;
 	}
 
+	if (!write_setting->reg_setting) {
+		CAM_ERR(CAM_SENSOR, "Invalid Register Settings");
+		return -EINVAL;
+	}
+
 	if (io_master_info->master_type == CCI_MASTER) {
 		return cam_cci_i2c_write_continuous_table(io_master_info,
 			write_setting, cam_sensor_i2c_write_flag);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index 72ca737..622dae6 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -26,7 +26,7 @@
 #define MAX_REGULATOR 5
 #define MAX_POWER_CONFIG 12
 
-#define MAX_PER_FRAME_ARRAY 8
+#define MAX_PER_FRAME_ARRAY 32
 
 #define CAM_SENSOR_NAME    "cam-sensor"
 #define CAM_ACTUATOR_NAME  "cam-actuator"
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
index c757315..e04c6b9 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -140,6 +140,7 @@
 	struct work_struct smmu_work;
 	struct mutex payload_list_lock;
 	struct list_head payload_list;
+	u32 non_fatal_fault;
 };
 
 static const struct of_device_id msm_cam_smmu_dt_match[] = {
@@ -2902,6 +2903,15 @@
 			rc = -ENODEV;
 			goto end;
 		}
+
+		iommu_cb_set.non_fatal_fault = 1;
+		if (iommu_domain_set_attr(cb->mapping->domain,
+			DOMAIN_ATTR_NON_FATAL_FAULTS,
+			&iommu_cb_set.non_fatal_fault) < 0) {
+			CAM_ERR(CAM_SMMU,
+				"Error: failed to set non fatal fault attribute");
+		}
+
 	} else {
 		CAM_ERR(CAM_SMMU, "Context bank does not have IO region");
 		rc = -ENODEV;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
index 1b5fd9f..8d5f96a 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011-2014, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 2017-2018, The Linux Foundation.
+ * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -36,6 +37,8 @@
 	/* Ensure previous writes are done */
 	wmb();
 	writel_relaxed_no_log(data, addr);
+	/* Ensure previous writes are done */
+	wmb();
 
 	return 0;
 }
@@ -68,6 +71,8 @@
 	rmb();
 	data = readl_relaxed(addr);
 	CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data);
+	/* Ensure previous read is done */
+	rmb();
 
 	return data;
 }
@@ -113,6 +118,8 @@
 		CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s);
 		writel_relaxed(*s++, d++);
 	}
+	/* Ensure previous writes are done */
+	wmb();
 
 	return 0;
 }
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 bd56310..0b1896f 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -859,7 +859,7 @@
 
 	count = of_property_count_strings(of_node, "reg-names");
 	if (count <= 0) {
-		CAM_WARN(CAM_UTIL, "no reg-names found for: %s",
+		CAM_DBG(CAM_UTIL, "no reg-names found for: %s",
 			soc_info->dev_name);
 		count = 0;
 	}
@@ -896,7 +896,7 @@
 	rc = of_property_read_string_index(of_node, "interrupt-names", 0,
 		&soc_info->irq_name);
 	if (rc) {
-		CAM_WARN(CAM_UTIL, "No interrupt line preset for: %s",
+		CAM_DBG(CAM_UTIL, "No interrupt line preset for: %s",
 			soc_info->dev_name);
 		rc = 0;
 	} else {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 349b982..e7ae579 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1613,6 +1613,7 @@
 	mutex_init(&inst->bufq[CAPTURE_PORT].lock);
 	mutex_init(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_init(&inst->lock);
+	mutex_init(&inst->flush_lock);
 
 	INIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	INIT_MSM_VIDC_LIST(&inst->freqs);
@@ -1723,6 +1724,7 @@
 	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
 	mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_destroy(&inst->lock);
+	mutex_destroy(&inst->flush_lock);
 
 	DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
 	DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
@@ -1846,6 +1848,7 @@
 	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
 	mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
 	mutex_destroy(&inst->lock);
+	mutex_destroy(&inst->flush_lock);
 
 	msm_vidc_debugfs_deinit_inst(inst);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 2d1ef10..4be087f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -736,7 +736,7 @@
 
 	operating_rate = operating_rate >> 16;
 
-	if ((curr_operating_rate + ops_left) >= operating_rate ||
+	if ((curr_operating_rate * (1 + ops_left)) >= operating_rate ||
 			!msm_vidc_clock_scaling ||
 			inst->clk_data.buffer_counter < DCVS_FTB_WINDOW) {
 		dprintk(VIDC_DBG,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index fd0fd39..5938bd3 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2044,6 +2044,7 @@
 		return;
 	}
 
+	mutex_lock(&inst->flush_lock);
 	if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
 
@@ -2086,6 +2087,7 @@
 	v4l2_event_queue_fh(&inst->event_handler, &flush_event);
 
 exit:
+	mutex_unlock(&inst->flush_lock);
 	put_inst(inst);
 }
 
@@ -3341,11 +3343,9 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&core->lock);
 	rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data);
 	if (rc)
 		dprintk(VIDC_WARN, "Failed to suspend\n");
-	mutex_unlock(&core->lock);
 
 	return rc;
 }
@@ -3919,13 +3919,17 @@
 		struct eos_buf *binfo = NULL;
 		u32 smem_flags = 0;
 
-		get_inst(inst->core, inst);
+		if (inst->state != MSM_VIDC_START_DONE) {
+			dprintk(VIDC_DBG,
+				"Inst = %pK is not ready for EOS\n", inst);
+			break;
+		}
 
 		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
 		if (!binfo) {
 			dprintk(VIDC_ERR, "%s: Out of memory\n", __func__);
 			rc = -ENOMEM;
-			goto exit;
+			break;
 		}
 
 		if (inst->flags & VIDC_SECURE)
@@ -3935,26 +3939,25 @@
 				SZ_4K, 1, smem_flags,
 				HAL_BUFFER_INPUT, 0, &binfo->smem);
 		if (rc) {
+			kfree(binfo);
 			dprintk(VIDC_ERR,
 				"Failed to allocate output memory\n");
 			rc = -ENOMEM;
-			goto exit;
+			break;
 		}
 
 		mutex_lock(&inst->eosbufs.lock);
 		list_add_tail(&binfo->list, &inst->eosbufs.list);
 		mutex_unlock(&inst->eosbufs.lock);
 
-		if (inst->state != MSM_VIDC_START_DONE) {
-			dprintk(VIDC_DBG,
-				"Inst = %pK is not ready for EOS\n", inst);
-			goto exit;
-		}
-
 		rc = msm_vidc_send_pending_eos_buffers(inst);
-
-exit:
-		put_inst(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed pending_eos_buffers sending\n");
+			list_del(&binfo->list);
+			kfree(binfo);
+			break;
+		}
 		break;
 	}
 	default:
@@ -5116,6 +5119,7 @@
 		return 0;
 	}
 
+	mutex_lock(&inst->flush_lock);
 	/* enable in flush */
 	inst->in_flush = true;
 
@@ -5169,6 +5173,7 @@
 		rc = call_hfi_op(hdev, session_flush, inst->session,
 			HAL_FLUSH_OUTPUT);
 	}
+	mutex_unlock(&inst->flush_lock);
 	if (rc) {
 		dprintk(VIDC_ERR,
 			"Sending flush to firmware failed, flush out all buffers\n");
@@ -6581,6 +6586,7 @@
 	bool found = false;
 	int i = 0;
 
+	mutex_lock(&inst->flush_lock);
 	mutex_lock(&inst->registeredbufs.lock);
 	found = false;
 	/* check if mbuf was not removed by any chance */
@@ -6661,6 +6667,7 @@
 			print_vidc_buffer(VIDC_ERR,
 				"rbr qbuf failed", inst, mbuf);
 	}
+	mutex_unlock(&inst->flush_lock);
 }
 
 int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index eda531e..38c42ca 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -363,7 +363,7 @@
 
 struct msm_vidc_inst {
 	struct list_head list;
-	struct mutex sync_lock, lock;
+	struct mutex sync_lock, lock, flush_lock;
 	struct msm_vidc_core *core;
 	enum session_type session_type;
 	void *session;
diff --git a/drivers/media/platform/msm/vidc_3x/Kconfig b/drivers/media/platform/msm/vidc_3x/Kconfig
new file mode 100644
index 0000000..d95b0b5
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/Kconfig
@@ -0,0 +1,10 @@
+#
+# VIDEO CORE
+#
+menuconfig MSM_VIDC_3X_V4L2
+	tristate "Qualcomm Technologies, Inc. MSM V4L2 3X based video driver"
+		depends on ARCH_QCOM && VIDEO_V4L2
+		select VIDEOBUF2_CORE
+
+source "drivers/media/platform/msm/vidc_3x/governors/Kconfig"
+source "drivers/media/platform/msm/vidc_3x/governors/Kconfig"
diff --git a/drivers/media/platform/msm/vidc_3x/Makefile b/drivers/media/platform/msm/vidc_3x/Makefile
new file mode 100644
index 0000000..749f057
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/Makefile
@@ -0,0 +1,18 @@
+obj-$(CONFIG_MSM_VIDC_3X_V4L2) := 	msm_v4l2_vidc.o \
+				msm_vidc_common.o \
+				msm_vidc.o \
+				msm_vdec.o \
+				msm_venc.o \
+				msm_smem.o \
+				msm_vidc_debug.o \
+				msm_vidc_res_parse.o \
+				venus_hfi.o \
+				hfi_response_handler.o \
+				hfi_packetization.o \
+				vidc_hfi.o \
+				venus_boot.o \
+				msm_vidc_dcvs.o
+
+obj-$(CONFIG_MSM_VIDC_3X_V4L2) += governors/
+
+obj-$(CONFIG_MSM_VIDC_VMEM) += vmem/
diff --git a/drivers/media/platform/msm/vidc_3x/governors/Kconfig b/drivers/media/platform/msm/vidc_3x/governors/Kconfig
new file mode 100644
index 0000000..4378088
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/Kconfig
@@ -0,0 +1,6 @@
+menuconfig MSM_VIDC_3X_GOVERNORS
+	tristate "Clock and bandwidth governors for QTI MSM V4L2 based video driver"
+	depends on MSM_VIDC_3X_V4L2 && PM_DEVFREQ
+	help
+	Chooses a set of devfreq governors aimed at providing accurate bandwidth
+	or clock frequency values for MSM V4L2 video driver.
diff --git a/drivers/media/platform/msm/vidc_3x/governors/Makefile b/drivers/media/platform/msm/vidc_3x/governors/Makefile
new file mode 100644
index 0000000..e834154
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -I$(srctree)/drivers/devfreq/ \
+	-I$(srctree)/drivers/media/platform/msm/vidc_3x/
+
+obj-$(CONFIG_MSM_VIDC_3X_GOVERNORS) := msm_vidc_dyn_gov.o \
+	msm_vidc_table_gov.o
diff --git a/drivers/media/platform/msm/vidc_3x/governors/fixedpoint.h b/drivers/media/platform/msm/vidc_3x/governors/fixedpoint.h
new file mode 100644
index 0000000..cbb1262
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/fixedpoint.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+#ifdef _FIXP_ARITH_H
+#error "This implementation is meant to override fixp-arith.h, don't use both"
+#endif
+
+#ifndef __FP_H__
+#define __FP_H__
+
+/*
+ * Normally would typedef'ed, but checkpatch doesn't like typedef.
+ * Also should be normally typedef'ed to intmax_t but that doesn't seem to be
+ * available in the kernel
+ */
+#define fp_t size_t
+
+/* (Arbitrarily) make the first 25% of the bits to be the fractional bits */
+#define FP_FRACTIONAL_BITS ((sizeof(fp_t) * 8) / 4)
+
+#define FP(__i, __f_n, __f_d) \
+	((((fp_t)(__i)) << FP_FRACTIONAL_BITS) + \
+	(((__f_n) << FP_FRACTIONAL_BITS) / (__f_d)))
+
+#define FP_INT(__i) FP(__i, 0, 1)
+#define FP_ONE FP_INT(1)
+#define FP_ZERO FP_INT(0)
+
+static inline size_t fp_frac_base(void)
+{
+	return GENMASK(FP_FRACTIONAL_BITS - 1, 0);
+}
+
+static inline size_t fp_frac(fp_t a)
+{
+	return a & GENMASK(FP_FRACTIONAL_BITS - 1, 0);
+}
+
+static inline size_t fp_int(fp_t a)
+{
+	return a >> FP_FRACTIONAL_BITS;
+}
+
+static inline size_t fp_round(fp_t a)
+{
+	/* is the fractional part >= frac_max / 2? */
+	bool round_up = fp_frac(a) >= fp_frac_base() / 2;
+
+	return fp_int(a) + round_up;
+}
+
+static inline fp_t fp_mult(fp_t a, fp_t b)
+{
+	return (a * b) >> FP_FRACTIONAL_BITS;
+}
+
+
+static inline fp_t fp_div(fp_t a, fp_t b)
+{
+	return (a << FP_FRACTIONAL_BITS) / b;
+}
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_dyn_gov.c
new file mode 100644
index 0000000..3cbdee0
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_dyn_gov.c
@@ -0,0 +1,1154 @@
+/* Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include "governor.h"
+#include "fixedpoint.h"
+#include "../msm_vidc_internal.h"
+#include "../msm_vidc_debug.h"
+#include "../vidc_hfi_api.h"
+
+static bool debug;
+module_param(debug, bool, 0644);
+
+enum governor_mode {
+	GOVERNOR_DDR,
+	GOVERNOR_VMEM,
+	GOVERNOR_VMEM_PLUS,
+};
+
+struct governor {
+	enum governor_mode mode;
+	struct devfreq_governor devfreq_gov;
+};
+
+enum scenario {
+	SCENARIO_WORST,
+	SCENARIO_SUSTAINED_WORST,
+	SCENARIO_AVERAGE,
+	SCENARIO_MAX,
+};
+
+/*
+ * Minimum dimensions that the governor is willing to calculate
+ * bandwidth for.  This means that anything bandwidth(0, 0) ==
+ * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height)
+ */
+const struct {
+	int height, width;
+} BASELINE_DIMENSIONS = {
+	.width = 1280,
+	.height = 720,
+};
+
+/*
+ * These are hardcoded AB values that the governor votes for in certain
+ * situations, where a certain bus frequency is desired.  It isn't exactly
+ * scalable since different platforms have different bus widths, but we'll
+ * deal with that in the future.
+ */
+const unsigned long NOMINAL_BW_MBPS = 6000 /* ideally 320 Mhz */,
+	SVS_BW_MBPS = 2000 /* ideally 100 Mhz */;
+
+/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */
+#define kbps(__mbps) ((__mbps) * 1000)
+#define bps(__mbps) (kbps(__mbps) * 1000)
+
+#define GENERATE_SCENARIO_PROFILE(__average, __worst) {                        \
+	[SCENARIO_AVERAGE] = (__average),                                      \
+	[SCENARIO_WORST] =  (__worst),                                         \
+	[SCENARIO_SUSTAINED_WORST] = (__worst),                                \
+}
+
+#define GENERATE_COMPRESSION_PROFILE(__bpp, __average, __worst) {              \
+	.bpp = __bpp,                                                          \
+	.ratio = GENERATE_SCENARIO_PROFILE(__average, __worst),                \
+}
+
+/*
+ * The below table is a structural representation of the following table:
+ *  Resolution |    Bitrate |              Compression Ratio          |
+ * ............|............|.........................................|
+ * Width Height|Average High|Avg_8bpc Worst_8bpc Avg_10bpc Worst_10bpc|
+ *  1280    720|      7   14|    1.69       1.28      1.49        1.23|
+ *  1920   1080|     20   40|    1.69       1.28      1.49        1.23|
+ *  2560   1440|     32   64|     2.2       1.26      1.97        1.22|
+ *  3840   2160|     42   84|     2.2       1.26      1.97        1.22|
+ *  4096   2160|     44   88|     2.2       1.26      1.97        1.22|
+ *  4096   2304|     48   96|     2.2       1.26      1.97        1.22|
+ */
+#define COMPRESSION_RATIO_MAX 2
+static struct lut {
+	int frame_size; /* width x height */
+	unsigned long bitrate[SCENARIO_MAX];
+	struct {
+		int bpp;
+		fp_t ratio[SCENARIO_MAX];
+	} compression_ratio[COMPRESSION_RATIO_MAX];
+} const LUT[] = {
+	{
+		.frame_size = 1280 * 720,
+		.bitrate = GENERATE_SCENARIO_PROFILE(7, 14),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 69, 100),
+					FP(1, 28, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 49, 100),
+					FP(1, 23, 100)),
+		}
+	},
+	{
+		.frame_size = 1920 * 1088,
+		.bitrate = GENERATE_SCENARIO_PROFILE(20, 40),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(1, 69, 100),
+					FP(1, 28, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 49, 100),
+					FP(1, 23, 100)),
+		}
+	},
+	{
+		.frame_size = 2560 * 1440,
+		.bitrate = GENERATE_SCENARIO_PROFILE(32, 64),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 3840 * 2160,
+		.bitrate = GENERATE_SCENARIO_PROFILE(42, 84),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 4096 * 2160,
+		.bitrate = GENERATE_SCENARIO_PROFILE(44, 88),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+	{
+		.frame_size = 4096 * 2304,
+		.bitrate = GENERATE_SCENARIO_PROFILE(48, 96),
+		.compression_ratio = {
+			GENERATE_COMPRESSION_PROFILE(8,
+					FP(2, 20, 100),
+					FP(1, 26, 100)),
+			GENERATE_COMPRESSION_PROFILE(10,
+					FP(1, 97, 100),
+					FP(1, 22, 100)),
+		}
+	},
+};
+
+static struct lut const *__lut(int width, int height)
+{
+	int frame_size = height * width, c = 0;
+
+	do {
+		if (LUT[c].frame_size >= frame_size)
+			return &LUT[c];
+	} while (++c < ARRAY_SIZE(LUT));
+
+	return &LUT[ARRAY_SIZE(LUT) - 1];
+}
+
+static fp_t __compression_ratio(struct lut const *entry, int bpp,
+		enum scenario s)
+{
+	int c = 0;
+
+	for (c = 0; c < COMPRESSION_RATIO_MAX; ++c) {
+		if (entry->compression_ratio[c].bpp == bpp)
+			return entry->compression_ratio[c].ratio[s];
+	}
+
+	WARN(true, "Shouldn't be here, LUT possibly corrupted?\n");
+	return FP_ZERO; /* impossible */
+}
+
+#define DUMP_HEADER_MAGIC 0xdeadbeef
+#define DUMP_FP_FMT "%FP" /* special format for fp_t */
+struct dump {
+	char *key;
+	char *format;
+	size_t val;
+};
+
+static void __dump(struct dump dump[], int len)
+{
+	int c = 0;
+
+	for (c = 0; c < len; ++c) {
+		char format_line[128] = "", formatted_line[128] = "";
+
+		if (dump[c].val == DUMP_HEADER_MAGIC) {
+			snprintf(formatted_line, sizeof(formatted_line), "%s\n",
+					dump[c].key);
+		} else {
+			bool fp_format = !strcmp(dump[c].format, DUMP_FP_FMT);
+
+			if (!fp_format) {
+				snprintf(format_line, sizeof(format_line),
+						"    %-35s: %s\n", dump[c].key,
+						dump[c].format);
+				snprintf(formatted_line, sizeof(formatted_line),
+						format_line, dump[c].val);
+			} else {
+				size_t integer_part, fractional_part;
+
+				integer_part = fp_int(dump[c].val);
+				fractional_part = fp_frac(dump[c].val);
+				snprintf(formatted_line, sizeof(formatted_line),
+						"    %-35s: %zd + %zd/%zd\n",
+						dump[c].key, integer_part,
+						fractional_part,
+						fp_frac_base());
+
+
+			}
+		}
+
+		dprintk(VIDC_DBG, "%s", formatted_line);
+	}
+}
+
+static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d,
+		enum governor_mode gm)
+{
+	return 0;
+}
+
+static bool __ubwc(enum hal_uncompressed_format f)
+{
+	switch (f) {
+	case HAL_COLOR_FORMAT_NV12_UBWC:
+	case HAL_COLOR_FORMAT_NV12_TP10_UBWC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int __bpp(enum hal_uncompressed_format f)
+{
+	switch (f) {
+	case HAL_COLOR_FORMAT_NV12:
+	case HAL_COLOR_FORMAT_NV21:
+	case HAL_COLOR_FORMAT_NV12_UBWC:
+		return 8;
+	case HAL_COLOR_FORMAT_NV12_TP10_UBWC:
+		return 10;
+	default:
+		dprintk(VIDC_ERR,
+				"What's this?  We don't support this colorformat (%x)",
+				f);
+		return INT_MAX;
+	}
+}
+
+static unsigned long __calculate_vmem_plus_ab(struct vidc_bus_vote_data *d)
+{
+	unsigned long i = 0, vmem_plus = 0;
+
+	if (!d->imem_ab_tbl || !d->imem_ab_tbl_size) {
+		vmem_plus = 1; /* Vote for the min ab value */
+		goto exit;
+	}
+
+	/* Pick up vmem frequency based on venus core frequency */
+	for (i = 0; i < d->imem_ab_tbl_size; i++) {
+		if (d->imem_ab_tbl[i].core_freq == d->core_freq) {
+			vmem_plus = d->imem_ab_tbl[i].imem_ab;
+			break;
+		}
+	}
+
+	/* Incase we get an unsupported freq throw a warning
+	 * and set ab to the minimum value.
+	 */
+	if (!vmem_plus) {
+		vmem_plus = 1;
+		dprintk(VIDC_WARN,
+			"could not calculate vmem ab value due to core freq mismatch\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+	}
+
+exit:
+	return vmem_plus;
+}
+
+
+static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
+		enum governor_mode gm) {
+	/*
+	 * XXX: Don't fool around with any of the hardcoded numbers unless you
+	 * know /exactly/ what you're doing.  Many of these numbers are
+	 * measured heuristics and hardcoded numbers taken from the firmware.
+	 */
+	/* Decoder parameters */
+	enum scenario scenario;
+	int width, height, lcu_size, dpb_bpp, opb_bpp, fps;
+	bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled;
+	fp_t dpb_opb_scaling_ratio, dpb_compression_factor,
+		opb_compression_factor, qsmmu_bw_overhead_factor;
+	int vmem_size; /* in kB */
+
+	/* Derived parameters */
+	int lcu_per_frame, tnbr_per_lcu_10bpc, tnbr_per_lcu_8bpc, tnbr_per_lcu,
+		colocated_bytes_per_lcu, vmem_line_buffer, vmem_chroma_cache,
+		vmem_luma_cache, vmem_chroma_luma_cache;
+	unsigned long bitrate;
+	fp_t bins_to_bit_factor, dpb_write_factor, ten_bpc_packing_factor,
+		ten_bpc_bpp_factor, vsp_read_factor, vsp_write_factor,
+		ocmem_usage_lcu_factor, ref_ocmem_bw_factor_read,
+		ref_ocmem_bw_factor_write, bw_for_1x_8bpc, dpb_bw_for_1x,
+		motion_vector_complexity, row_cache_penalty, opb_bw;
+
+	/* Output parameters */
+	struct {
+		fp_t vsp_read, vsp_write, collocated_read, collocated_write,
+			line_buffer_read, line_buffer_write, recon_read,
+			recon_write, opb_read, opb_write, dpb_read, dpb_write,
+			total;
+	} ddr, vmem;
+
+	unsigned long ret = 0;
+
+	/* Decoder parameters setup */
+	scenario = SCENARIO_WORST;
+
+	width = max(d->width, BASELINE_DIMENSIONS.width);
+	height = max(d->height, BASELINE_DIMENSIONS.height);
+
+	lcu_size = 32;
+
+	dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
+	opb_bpp = d->num_formats >= 2 ?  __bpp(d->color_formats[1]) : dpb_bpp;
+
+	fps = d->fps;
+
+	unified_dpb_opb = d->num_formats == 1;
+
+	dpb_opb_scaling_ratio = FP_ONE;
+
+	dpb_compression_enabled = d->num_formats >= 1 &&
+		__ubwc(d->color_formats[0]);
+	opb_compression_enabled = d->num_formats >= 2 &&
+		__ubwc(d->color_formats[1]);
+
+	dpb_compression_factor = !dpb_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height), dpb_bpp, scenario);
+
+	opb_compression_factor = !opb_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height), opb_bpp, scenario);
+
+	vmem_size = 512; /* in kB */
+
+	/* Derived parameters setup */
+	lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
+		DIV_ROUND_UP(height, lcu_size);
+
+	bitrate = __lut(width, height)->bitrate[scenario];
+
+	bins_to_bit_factor = FP(1, 60, 100);
+
+	dpb_write_factor = scenario == SCENARIO_AVERAGE ?
+		FP_ONE : FP(1, 5, 100);
+
+	ten_bpc_packing_factor = FP(1, 67, 1000);
+	ten_bpc_bpp_factor = FP(1, 1, 4);
+
+	vsp_read_factor = bins_to_bit_factor + FP_INT(2);
+	vsp_write_factor = bins_to_bit_factor;
+
+	tnbr_per_lcu_10bpc = lcu_size == 16 ? 384 + 192 :
+				lcu_size == 32 ? 640 + 256 :
+						1280 + 384;
+	tnbr_per_lcu_8bpc = lcu_size == 16 ? 256 + 192 :
+				lcu_size == 32 ? 512 + 256 :
+						1024 + 384;
+	tnbr_per_lcu = dpb_bpp == 10 ? tnbr_per_lcu_10bpc : tnbr_per_lcu_8bpc;
+
+	colocated_bytes_per_lcu = lcu_size == 16 ? 16 :
+				lcu_size == 32 ? 64 : 256;
+
+	ocmem_usage_lcu_factor = lcu_size == 16 ? FP(1, 8, 10) :
+				lcu_size == 32 ? FP(1, 2, 10) :
+						FP_ONE;
+	ref_ocmem_bw_factor_read = vmem_size < 296 ? FP_ZERO :
+				vmem_size < 648 ? FP(0, 1, 4) :
+						FP(0, 55, 100);
+	ref_ocmem_bw_factor_write = vmem_size < 296 ? FP_ZERO :
+				vmem_size < 648 ? FP(0, 7, 10) :
+						FP(1, 4, 10);
+
+	/* Prelim b/w calculation */
+	bw_for_1x_8bpc = fp_mult(FP_INT(width * height * fps),
+			fp_mult(FP(1, 50, 100), dpb_write_factor));
+	bw_for_1x_8bpc = fp_div(bw_for_1x_8bpc, FP_INT(bps(1)));
+
+	dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc :
+		fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor,
+					ten_bpc_bpp_factor));
+	/* VMEM adjustments */
+	vmem_line_buffer = tnbr_per_lcu * DIV_ROUND_UP(width, lcu_size) / 1024;
+	vmem_chroma_cache = dpb_bpp == 10 ? 176 : 128;
+	vmem_luma_cache = dpb_bpp == 10 ? 353 : 256;
+	vmem_chroma_luma_cache = vmem_chroma_cache + vmem_luma_cache;
+
+	motion_vector_complexity = scenario == SCENARIO_AVERAGE ?
+		FP(2, 66, 100) : FP_INT(4);
+
+	row_cache_penalty = FP_ZERO;
+	if (vmem_size < vmem_line_buffer + vmem_chroma_cache)
+		row_cache_penalty = fp_mult(FP(0, 5, 100),
+				motion_vector_complexity);
+	else if (vmem_size < vmem_line_buffer + vmem_luma_cache)
+		row_cache_penalty = fp_mult(FP(0, 7, 100),
+				motion_vector_complexity);
+	else if (vmem_size < vmem_line_buffer + vmem_chroma_cache
+			+ vmem_luma_cache)
+		row_cache_penalty = fp_mult(FP(0, 3, 100),
+				motion_vector_complexity);
+	else
+		row_cache_penalty = FP_ZERO;
+
+
+	opb_bw = unified_dpb_opb ? FP_ZERO :
+		fp_div(fp_div(bw_for_1x_8bpc, dpb_opb_scaling_ratio),
+				opb_compression_factor);
+
+	/* B/W breakdown on a per buffer type basis for VMEM */
+	vmem.vsp_read = FP_ZERO;
+	vmem.vsp_write = FP_ZERO;
+
+	vmem.collocated_read = FP_ZERO;
+	vmem.collocated_write = FP_ZERO;
+
+	vmem.line_buffer_read = FP_INT(tnbr_per_lcu *
+			lcu_per_frame * fps / bps(1));
+	vmem.line_buffer_write = vmem.line_buffer_read;
+
+	vmem.recon_read = FP_ZERO;
+	vmem.recon_write = FP_ZERO;
+
+	vmem.opb_read = FP_ZERO;
+	vmem.opb_write = FP_ZERO;
+
+	vmem.dpb_read = fp_mult(ocmem_usage_lcu_factor, fp_mult(
+					ref_ocmem_bw_factor_read,
+					dpb_bw_for_1x));
+	vmem.dpb_write = fp_mult(ocmem_usage_lcu_factor, fp_mult(
+					ref_ocmem_bw_factor_write,
+					dpb_bw_for_1x));
+
+	vmem.total = vmem.vsp_read + vmem.vsp_write +
+		vmem.collocated_read + vmem.collocated_write +
+		vmem.line_buffer_read + vmem.line_buffer_write +
+		vmem.recon_read + vmem.recon_write +
+		vmem.opb_read + vmem.opb_write +
+		vmem.dpb_read + vmem.dpb_write;
+
+	/*
+	 * Attempt to force VMEM to a certain frequency for 4K
+	 */
+	if (width * height * fps >= 3840 * 2160 * 60)
+		vmem.total = FP_INT(NOMINAL_BW_MBPS);
+	else if (width * height * fps >= 3840 * 2160 * 30)
+		vmem.total = FP_INT(SVS_BW_MBPS);
+
+	/* ........................................ for DDR */
+	ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate),
+				vsp_read_factor), FP_INT(8));
+	ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate),
+				vsp_write_factor), FP_INT(8));
+
+	ddr.collocated_read = FP_INT(lcu_per_frame *
+			colocated_bytes_per_lcu * fps / bps(1));
+	ddr.collocated_write = FP_INT(lcu_per_frame *
+			colocated_bytes_per_lcu * fps / bps(1));
+
+	ddr.line_buffer_read = vmem_size ? FP_ZERO : vmem.line_buffer_read;
+	ddr.line_buffer_write = vmem_size ? FP_ZERO : vmem.line_buffer_write;
+
+	ddr.recon_read = FP_ZERO;
+	ddr.recon_write = fp_div(dpb_bw_for_1x, dpb_compression_factor);
+
+	ddr.opb_read = FP_ZERO;
+	ddr.opb_write = opb_bw;
+
+	ddr.dpb_read = fp_div(fp_mult(dpb_bw_for_1x,
+				motion_vector_complexity + row_cache_penalty),
+			dpb_compression_factor);
+	ddr.dpb_write = FP_ZERO;
+
+	ddr.total = ddr.vsp_read + ddr.vsp_write +
+		ddr.collocated_read + ddr.collocated_write +
+		ddr.line_buffer_read + ddr.line_buffer_write +
+		ddr.recon_read + ddr.recon_write +
+		ddr.opb_read + ddr.opb_write +
+		ddr.dpb_read + ddr.dpb_write;
+
+	qsmmu_bw_overhead_factor = FP(1, 3, 100);
+	ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
+
+	/* Dump all the variables for easier debugging */
+	if (debug) {
+		struct dump dump[] = {
+		{"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC},
+		{"content", "%d", scenario},
+		{"LCU size", "%d", lcu_size},
+		{"DPB bitdepth", "%d", dpb_bpp},
+		{"frame rate", "%d", fps},
+		{"DPB/OPB unified", "%d", unified_dpb_opb},
+		{"DPB/OPB downscaling ratio", DUMP_FP_FMT,
+			dpb_opb_scaling_ratio},
+		{"DPB compression", "%d", dpb_compression_enabled},
+		{"OPB compression", "%d", opb_compression_enabled},
+		{"DPB compression factor", DUMP_FP_FMT,
+			dpb_compression_factor},
+		{"OPB compression factor", DUMP_FP_FMT,
+			opb_compression_factor},
+		{"VMEM size", "%dkB", vmem_size},
+		{"frame width", "%d", width},
+		{"frame height", "%d", height},
+
+		{"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC},
+		{"LCUs/frame", "%d", lcu_per_frame},
+		{"bitrate (Mbit/sec)", "%d", bitrate},
+		{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
+		{"DPB write factor", DUMP_FP_FMT, dpb_write_factor},
+		{"10bpc packing factor", DUMP_FP_FMT,
+			ten_bpc_packing_factor},
+		{"10bpc,BPP factor", DUMP_FP_FMT, ten_bpc_bpp_factor},
+		{"VSP read factor", DUMP_FP_FMT, vsp_read_factor},
+		{"VSP write factor", DUMP_FP_FMT, vsp_write_factor},
+		{"TNBR/LCU_10bpc", "%d", tnbr_per_lcu_10bpc},
+		{"TNBR/LCU_8bpc", "%d", tnbr_per_lcu_8bpc},
+		{"TNBR/LCU", "%d", tnbr_per_lcu},
+		{"colocated bytes/LCU", "%d", colocated_bytes_per_lcu},
+		{"OCMEM usage LCU factor", DUMP_FP_FMT,
+			ocmem_usage_lcu_factor},
+		{"ref OCMEM b/w factor (read)", DUMP_FP_FMT,
+			ref_ocmem_bw_factor_read},
+		{"ref OCMEM b/w factor (write)", DUMP_FP_FMT,
+			ref_ocmem_bw_factor_write},
+		{"B/W for 1x (NV12 8bpc)", DUMP_FP_FMT, bw_for_1x_8bpc},
+		{"DPB B/W For 1x (NV12)", DUMP_FP_FMT, dpb_bw_for_1x},
+
+		{"VMEM", "", DUMP_HEADER_MAGIC},
+		{"line buffer", "%d", vmem_line_buffer},
+		{"chroma cache", "%d", vmem_chroma_cache},
+		{"luma cache", "%d", vmem_luma_cache},
+		{"luma & chroma cache", "%d", vmem_chroma_luma_cache},
+
+		{"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC},
+		{"MV complexity", DUMP_FP_FMT, motion_vector_complexity},
+		{"row cache penalty", DUMP_FP_FMT, row_cache_penalty},
+		{"OPB B/W (single instance)", DUMP_FP_FMT, opb_bw},
+
+		{"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC},
+		{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
+		{"VSP write", DUMP_FP_FMT, ddr.vsp_write},
+		{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
+		{"collocated write", DUMP_FP_FMT, ddr.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
+		{"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
+		{"recon read", DUMP_FP_FMT, ddr.recon_read},
+		{"recon write", DUMP_FP_FMT, ddr.recon_write},
+		{"OPB read", DUMP_FP_FMT, ddr.opb_read},
+		{"OPB write", DUMP_FP_FMT, ddr.opb_write},
+		{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
+		{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+
+		{"INTERMEDIATE VMEM B/W", "", DUMP_HEADER_MAGIC},
+		{"VSP read", "%d", vmem.vsp_read},
+		{"VSP write", DUMP_FP_FMT, vmem.vsp_write},
+		{"collocated read", DUMP_FP_FMT, vmem.collocated_read},
+		{"collocated write", DUMP_FP_FMT, vmem.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_read},
+		{"line buffer write", DUMP_FP_FMT, vmem.line_buffer_write},
+		{"recon read", DUMP_FP_FMT, vmem.recon_read},
+		{"recon write", DUMP_FP_FMT, vmem.recon_write},
+		{"OPB read", DUMP_FP_FMT, vmem.opb_read},
+		{"OPB write", DUMP_FP_FMT, vmem.opb_write},
+		{"DPB read", DUMP_FP_FMT, vmem.dpb_read},
+		{"DPB write", DUMP_FP_FMT, vmem.dpb_write},
+		};
+		__dump(dump, ARRAY_SIZE(dump));
+	}
+
+	switch (gm) {
+	case GOVERNOR_DDR:
+		ret = kbps(fp_round(ddr.total));
+		break;
+	case GOVERNOR_VMEM:
+		ret = kbps(fp_round(vmem.total));
+		break;
+	case GOVERNOR_VMEM_PLUS:
+		ret = __calculate_vmem_plus_ab(d);
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
+	}
+
+	return ret;
+}
+
+
+static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
+		enum governor_mode gm)
+{
+	/*
+	 * XXX: Don't fool around with any of the hardcoded numbers unless you
+	 * know /exactly/ what you're doing.  Many of these numbers are
+	 * measured heuristics and hardcoded numbers taken from the firmware.
+	 */
+	/* Encoder Parameters */
+	enum scenario scenario, bitrate_scenario;
+	enum hal_video_codec standard;
+	int width, height, fps, vmem_size;
+	enum hal_uncompressed_format dpb_color_format;
+	enum hal_uncompressed_format original_color_format;
+	bool dpb_compression_enabled, original_compression_enabled,
+		two_stage_encoding, low_power, rotation, cropping_or_scaling;
+	fp_t dpb_compression_factor, original_compression_factor,
+		qsmmu_bw_overhead_factor;
+	bool b_frames_enabled;
+
+	/* Derived Parameters */
+	int lcu_size;
+	enum gop {
+		GOP_IBBP,
+		GOP_IPPP,
+	} gop;
+	unsigned long bitrate;
+	fp_t bins_to_bit_factor, chroma_luma_factor_dpb, one_frame_bw_dpb,
+		 chroma_luma_factor_original, one_frame_bw_original,
+		 line_buffer_size_per_lcu, line_buffer_size, line_buffer_bw,
+		 original_vmem_requirement, bw_increase_p, bw_increase_b;
+	int collocated_mv_per_lcu, max_transaction_size,
+		search_window_size_vertical_p, search_window_factor_p,
+		search_window_factor_bw_p, vmem_size_p, available_vmem_p,
+		search_window_size_vertical_b, search_window_factor_b,
+		search_window_factor_bw_b, vmem_size_b, available_vmem_b;
+
+	/* Output paramaters */
+	struct {
+		fp_t vsp_read, vsp_write, collocated_read, collocated_write,
+			line_buffer_read, line_buffer_write, original_read,
+			original_write, dpb_read, dpb_write, total;
+	} ddr, vmem;
+
+	unsigned long ret = 0;
+
+	/* Encoder Parameters setup */
+	scenario = SCENARIO_WORST;
+
+	standard = d->codec;
+	width = max(d->width, BASELINE_DIMENSIONS.width);
+	height = max(d->height, BASELINE_DIMENSIONS.height);
+
+	dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC;
+	original_color_format = d->num_formats >= 1 ?
+		d->color_formats[0] : HAL_UNUSED_COLOR;
+
+	fps = d->fps;
+	bitrate_scenario = SCENARIO_WORST;
+
+	dpb_compression_enabled = __ubwc(dpb_color_format);
+	original_compression_enabled = __ubwc(original_color_format);
+
+	two_stage_encoding = false;
+	low_power = d->power_mode == VIDC_POWER_LOW;
+	b_frames_enabled = false;
+
+	dpb_compression_factor = !dpb_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height),
+				__bpp(dpb_color_format), scenario);
+	original_compression_factor = !original_compression_enabled ? FP_ONE :
+		__compression_ratio(__lut(width, height),
+				__bpp(original_color_format), scenario);
+
+	rotation = false;
+	cropping_or_scaling = false;
+	vmem_size = 512; /* in kB */
+
+	/* Derived Parameters */
+	lcu_size = 16;
+	gop = b_frames_enabled ? GOP_IBBP : GOP_IPPP;
+	bitrate = __lut(width, height)->bitrate[bitrate_scenario];
+	bins_to_bit_factor = FP(1, 6, 10);
+
+	/*
+	 * FIXME: Minor color format related hack: a lot of the derived params
+	 * depend on the YUV bitdepth as a variable.  However, we don't have
+	 * appropriate enums defined yet (hence no support).  As a result omit
+	 * a lot of the checks (which should look like the snippet below) in
+	 * favour of hardcoding.
+	 *      dpb_color_format == YUV420 ? 0.5 :
+	 *      dpb_color_format == YUV422 ? 1.0 : 2.0
+	 * Similar hacks are annotated inline in code with the string "CF hack"
+	 * for documentation purposes.
+	 */
+	chroma_luma_factor_dpb = FP(0, 1, 2);
+	one_frame_bw_dpb = fp_mult(FP_ONE + chroma_luma_factor_dpb,
+			fp_div(FP_INT(width * height * fps),
+				FP_INT(1000 * 1000)));
+
+	chroma_luma_factor_original = FP(0, 1, 2); /* XXX: CF hack */
+	one_frame_bw_original = fp_mult(FP_ONE + chroma_luma_factor_original,
+			fp_div(FP_INT(width * height * fps),
+				FP_INT(1000 * 1000)));
+
+	line_buffer_size_per_lcu = FP_ZERO;
+	if (lcu_size == 16)
+		line_buffer_size_per_lcu = FP_INT(128) + fp_mult(FP_INT(256),
+					FP_ONE /*XXX: CF hack */);
+	else
+		line_buffer_size_per_lcu = FP_INT(192) + fp_mult(FP_INT(512),
+					FP_ONE /*XXX: CF hack */);
+
+	line_buffer_size = fp_div(
+			fp_mult(FP_INT(width / lcu_size),
+				line_buffer_size_per_lcu),
+			FP_INT(1024));
+	line_buffer_bw = fp_mult(line_buffer_size,
+			fp_div(FP_INT((height / lcu_size /
+				(two_stage_encoding ? 2 : 1) - 1) * fps),
+				FP_INT(1000)));
+
+	collocated_mv_per_lcu = lcu_size == 16 ? 16 : 64;
+	max_transaction_size = 256;
+
+	original_vmem_requirement = FP_INT(3 *
+			(two_stage_encoding ? 2 : 1) * lcu_size);
+	original_vmem_requirement = fp_mult(original_vmem_requirement,
+			(FP_ONE + chroma_luma_factor_original));
+	original_vmem_requirement += FP_INT((cropping_or_scaling ? 3 : 0) * 2);
+	original_vmem_requirement = fp_mult(original_vmem_requirement,
+			FP_INT(max_transaction_size));
+	original_vmem_requirement = fp_div(original_vmem_requirement,
+			FP_INT(1024));
+
+	search_window_size_vertical_p = low_power ? 32 :
+					b_frames_enabled ? 80 :
+					width > 2048 ? 64 : 48;
+	search_window_factor_p = search_window_size_vertical_p * 2 / lcu_size;
+	search_window_factor_bw_p = !two_stage_encoding ?
+		search_window_size_vertical_p * 2 / lcu_size + 1 :
+		(search_window_size_vertical_p * 2 / lcu_size + 2) / 2;
+	vmem_size_p = (search_window_factor_p * width + 128 * 2) *
+		lcu_size / 2 / 1024; /* XXX: CF hack */
+	bw_increase_p = fp_mult(one_frame_bw_dpb,
+			FP_INT(search_window_factor_bw_p - 1) / 3);
+	available_vmem_p = min_t(int, 3, (vmem_size - fp_int(line_buffer_size) -
+			fp_int(original_vmem_requirement)) / vmem_size_p);
+
+	search_window_size_vertical_b = 48;
+	search_window_factor_b = search_window_size_vertical_b * 2 / lcu_size;
+	search_window_factor_bw_b = !two_stage_encoding ?
+		search_window_size_vertical_b * 2 / lcu_size + 1 :
+		(search_window_size_vertical_b * 2 / lcu_size + 2) / 2;
+	vmem_size_b = (search_window_factor_b * width + 128 * 2) * lcu_size /
+		2 / 1024;
+	bw_increase_b = fp_mult(one_frame_bw_dpb,
+			FP_INT((search_window_factor_bw_b - 1) / 3));
+	available_vmem_b = min_t(int, 6, (vmem_size - fp_int(line_buffer_size) -
+			fp_int(original_vmem_requirement)) / vmem_size_b);
+
+	/* Output parameters for DDR */
+	ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)),
+			bins_to_bit_factor);
+	ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8));
+
+	ddr.collocated_read = fp_div(FP_INT(DIV_ROUND_UP(width, lcu_size) *
+			DIV_ROUND_UP(height, lcu_size) *
+			collocated_mv_per_lcu * fps), FP_INT(1000 * 1000));
+	ddr.collocated_write = ddr.collocated_read;
+
+	ddr.line_buffer_read = (FP_INT(vmem_size) >= line_buffer_size +
+		original_vmem_requirement) ? FP_ZERO : line_buffer_bw;
+	ddr.line_buffer_write = ddr.line_buffer_read;
+
+	ddr.original_read = fp_div(one_frame_bw_original,
+			original_compression_factor);
+	ddr.original_write = FP_ZERO;
+
+	ddr.dpb_read = FP_ZERO;
+	if (gop == GOP_IPPP) {
+		ddr.dpb_read = one_frame_bw_dpb + fp_mult(bw_increase_p,
+			FP_INT(3 - available_vmem_p));
+	} else if (scenario == SCENARIO_WORST ||
+			scenario == SCENARIO_SUSTAINED_WORST) {
+		ddr.dpb_read = fp_mult(one_frame_bw_dpb, FP_INT(2));
+		ddr.dpb_read += fp_mult(FP_INT(6 - available_vmem_b),
+				bw_increase_b);
+	} else {
+		fp_t part_p, part_b;
+
+		part_p = one_frame_bw_dpb + fp_mult(bw_increase_p,
+				FP_INT(3 - available_vmem_p));
+		part_p = fp_div(part_p, FP_INT(3));
+
+		part_b = fp_mult(one_frame_bw_dpb, 2) +
+			fp_mult(FP_INT(6 - available_vmem_b), bw_increase_b);
+		part_b = fp_mult(part_b, FP(0, 2, 3));
+
+		ddr.dpb_read = part_p + part_b;
+	}
+
+	ddr.dpb_read = fp_div(ddr.dpb_read, dpb_compression_factor);
+	ddr.dpb_write = fp_div(one_frame_bw_dpb, dpb_compression_factor);
+
+	ddr.total = ddr.vsp_read + ddr.vsp_write +
+		ddr.collocated_read + ddr.collocated_write +
+		ddr.line_buffer_read + ddr.line_buffer_write +
+		ddr.original_read + ddr.original_write +
+		ddr.dpb_read + ddr.dpb_write;
+
+	qsmmu_bw_overhead_factor = FP(1, 3, 100);
+	ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
+
+	/* ................. for VMEM */
+	vmem.vsp_read = FP_ZERO;
+	vmem.vsp_write = FP_ZERO;
+
+	vmem.collocated_read = FP_ZERO;
+	vmem.collocated_write = FP_ZERO;
+
+	vmem.line_buffer_read = line_buffer_bw - ddr.line_buffer_read;
+	vmem.line_buffer_write = vmem.line_buffer_read;
+
+	vmem.original_read = FP_INT(vmem_size) >= original_vmem_requirement ?
+		ddr.original_read : FP_ZERO;
+	vmem.original_write = vmem.original_read;
+
+	vmem.dpb_read = FP_ZERO;
+	if (gop == GOP_IPPP) {
+		fp_t temp = fp_mult(one_frame_bw_dpb,
+			FP_INT(search_window_factor_bw_p * available_vmem_p));
+		temp = fp_div(temp, FP_INT(3));
+
+		vmem.dpb_read = temp;
+	} else if (scenario != SCENARIO_AVERAGE) {
+		fp_t temp = fp_mult(one_frame_bw_dpb, FP_INT(2));
+
+		temp = fp_mult(temp, FP_INT(search_window_factor_bw_b *
+					available_vmem_b));
+		temp = fp_div(temp, FP_INT(6));
+
+		vmem.dpb_read = temp;
+	} else {
+		fp_t part_p, part_b;
+
+		part_p = fp_mult(one_frame_bw_dpb, FP_INT(
+					search_window_factor_bw_p *
+					available_vmem_p));
+		part_p = fp_div(part_p, FP_INT(3 * 3));
+
+		part_b = fp_mult(one_frame_bw_dpb, FP_INT(2 *
+					search_window_factor_bw_b *
+					available_vmem_b));
+		part_b = fp_div(part_b, FP_INT(6));
+		part_b = fp_mult(part_b, FP(0, 2, 3));
+
+		vmem.dpb_read = part_p + part_b;
+	}
+
+	vmem.dpb_write = FP_ZERO;
+	if (gop == GOP_IPPP) {
+		fp_t temp = fp_mult(one_frame_bw_dpb,
+				FP_INT(available_vmem_p));
+		temp = fp_div(temp, FP_INT(3));
+
+		vmem.dpb_write = temp;
+	} else if (scenario != SCENARIO_AVERAGE) {
+		fp_t temp = fp_mult(one_frame_bw_dpb,
+				FP_INT(2 * available_vmem_b));
+		temp = fp_div(temp, FP_INT(6));
+
+		vmem.dpb_write = temp;
+	} else {
+		fp_t part_b, part_p;
+
+		part_b = fp_mult(one_frame_bw_dpb, FP_INT(available_vmem_p));
+		part_b = fp_div(part_b, FP_INT(9));
+
+		part_p = fp_mult(one_frame_bw_dpb, FP_INT(
+					2 * available_vmem_b));
+		part_p = fp_div(part_p, FP_INT(6));
+		part_b = fp_mult(part_b, FP(0, 2, 3));
+
+		vmem.dpb_write = part_p + part_b;
+	}
+
+	vmem.total = vmem.vsp_read + vmem.vsp_write +
+		vmem.collocated_read + vmem.collocated_write +
+		vmem.line_buffer_read + vmem.line_buffer_write +
+		vmem.original_read + vmem.original_write +
+		vmem.dpb_read + vmem.dpb_write;
+
+	/*
+	 * When in low power mode, attempt to force the VMEM clocks a certain
+	 * frequency that DCVS would prefer
+	 */
+	if (width * height >= 3840 * 2160 && low_power)
+		vmem.total = FP_INT(NOMINAL_BW_MBPS);
+
+	if (debug) {
+		struct dump dump[] = {
+		{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
+		{"scenario", "%d", scenario},
+		{"standard", "%#x", standard},
+		{"width", "%d", width},
+		{"height", "%d", height},
+		{"DPB format", "%#x", dpb_color_format},
+		{"original frame format", "%#x", original_color_format},
+		{"fps", "%d", fps},
+		{"target bitrate", "%d", bitrate_scenario},
+		{"DPB compression enable", "%d", dpb_compression_enabled},
+		{"original compression enable", "%d",
+			original_compression_enabled},
+		{"two stage encoding", "%d", two_stage_encoding},
+		{"low power mode", "%d", low_power},
+		{"DPB compression factor", DUMP_FP_FMT,
+			dpb_compression_factor},
+		{"original compression factor", DUMP_FP_FMT,
+			original_compression_factor},
+		{"rotation", "%d", rotation},
+		{"cropping or scaling", "%d", cropping_or_scaling},
+		{"VMEM size (KB)", "%d", vmem_size},
+
+		{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
+		{"LCU size", "%d", lcu_size},
+		{"GOB pattern", "%d", gop},
+		{"bitrate (Mbit/sec)", "%lu", bitrate},
+		{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
+		{"B-frames enabled", "%d", b_frames_enabled},
+		{"search window size vertical (B)", "%d",
+			search_window_size_vertical_b},
+		{"search window factor (B)", "%d", search_window_factor_b},
+		{"search window factor BW (B)", "%d",
+			search_window_factor_bw_b},
+		{"VMEM size (B)", "%d", vmem_size_b},
+		{"bw increase (MB/s) (B)", DUMP_FP_FMT, bw_increase_b},
+		{"available VMEM (B)", "%d", available_vmem_b},
+		{"search window size vertical (P)", "%d",
+			search_window_size_vertical_p},
+		{"search window factor (P)", "%d", search_window_factor_p},
+		{"search window factor BW (P)", "%d",
+			search_window_factor_bw_p},
+		{"VMEM size (P)", "%d", vmem_size_p},
+		{"bw increase (MB/s) (P)", DUMP_FP_FMT, bw_increase_p},
+		{"available VMEM (P)", "%d", available_vmem_p},
+		{"chroma/luma factor DPB", DUMP_FP_FMT,
+			chroma_luma_factor_dpb},
+		{"one frame BW DPB (MB/s)", DUMP_FP_FMT, one_frame_bw_dpb},
+		{"chroma/Luma factor original", DUMP_FP_FMT,
+			chroma_luma_factor_original},
+		{"one frame BW original (MB/s)", DUMP_FP_FMT,
+			one_frame_bw_original},
+		{"line buffer size per LCU", DUMP_FP_FMT,
+			line_buffer_size_per_lcu},
+		{"line buffer size (KB)", DUMP_FP_FMT, line_buffer_size},
+		{"line buffer BW (MB/s)", DUMP_FP_FMT, line_buffer_bw},
+		{"collocated MVs per LCU", "%d", collocated_mv_per_lcu},
+		{"original VMEM requirement (KB)", DUMP_FP_FMT,
+			original_vmem_requirement},
+
+		{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
+		{"VSP read", DUMP_FP_FMT, ddr.vsp_read},
+		{"VSP read", DUMP_FP_FMT, ddr.vsp_write},
+		{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
+		{"collocated read", DUMP_FP_FMT, ddr.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
+		{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_write},
+		{"original read", DUMP_FP_FMT, ddr.original_read},
+		{"original read", DUMP_FP_FMT, ddr.original_write},
+		{"DPB read", DUMP_FP_FMT, ddr.dpb_read},
+		{"DPB write", DUMP_FP_FMT, ddr.dpb_write},
+
+		{"INTERMEDIATE B/W VMEM", "", DUMP_HEADER_MAGIC},
+		{"VSP read", DUMP_FP_FMT, vmem.vsp_read},
+		{"VSP read", DUMP_FP_FMT, vmem.vsp_write},
+		{"collocated read", DUMP_FP_FMT, vmem.collocated_read},
+		{"collocated read", DUMP_FP_FMT, vmem.collocated_write},
+		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_read},
+		{"line buffer read", DUMP_FP_FMT, vmem.line_buffer_write},
+		{"original read", DUMP_FP_FMT, vmem.original_read},
+		{"original read", DUMP_FP_FMT, vmem.original_write},
+		{"DPB read", DUMP_FP_FMT, vmem.dpb_read},
+		{"DPB write", DUMP_FP_FMT, vmem.dpb_write},
+		};
+		__dump(dump, ARRAY_SIZE(dump));
+	}
+
+	switch (gm) {
+	case GOVERNOR_DDR:
+		ret = kbps(fp_round(ddr.total));
+		break;
+	case GOVERNOR_VMEM:
+		ret = kbps(fp_round(vmem.total));
+		break;
+	case GOVERNOR_VMEM_PLUS:
+		ret = __calculate_vmem_plus_ab(d);
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
+	}
+
+	return ret;
+}
+
+static unsigned long __calculate(struct vidc_bus_vote_data *d,
+		enum governor_mode gm)
+{
+	unsigned long (*calc[])(struct vidc_bus_vote_data *,
+			enum governor_mode) = {
+		[HAL_VIDEO_DOMAIN_VPE] = __calculate_vpe,
+		[HAL_VIDEO_DOMAIN_ENCODER] = __calculate_encoder,
+		[HAL_VIDEO_DOMAIN_DECODER] = __calculate_decoder,
+	};
+
+	return calc[d->domain](d, gm);
+}
+
+static int __get_target_freq(struct devfreq *dev, unsigned long *freq)
+{
+	unsigned long ab_kbps = 0, c = 0;
+	struct devfreq_dev_status stats = {0};
+	struct msm_vidc_gov_data *vidc_data = NULL;
+	struct governor *gov = NULL;
+
+	if (!dev || !freq)
+		return -EINVAL;
+
+	gov = container_of(dev->governor,
+			struct governor, devfreq_gov);
+	dev->profile->get_dev_status(dev->dev.parent, &stats);
+	vidc_data = (struct msm_vidc_gov_data *)stats.private_data;
+
+	for (c = 0; c < vidc_data->data_count; ++c) {
+		if (vidc_data->data->power_mode == VIDC_POWER_TURBO) {
+			*freq = INT_MAX;
+			goto exit;
+		}
+	}
+
+	for (c = 0; c < vidc_data->data_count; ++c)
+		ab_kbps += __calculate(&vidc_data->data[c], gov->mode);
+
+	*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX);
+exit:
+	return 0;
+}
+
+static int __event_handler(struct devfreq *devfreq, unsigned int event,
+		void *data)
+{
+	int rc = 0;
+
+	if (!devfreq)
+		return -EINVAL;
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+	case DEVFREQ_GOV_RESUME:
+		mutex_lock(&devfreq->lock);
+		rc = update_devfreq(devfreq);
+		mutex_unlock(&devfreq->lock);
+		break;
+	}
+
+	return rc;
+}
+
+static struct governor governors[] = {
+	{
+		.mode = GOVERNOR_DDR,
+		.devfreq_gov = {
+			.name = "msm-vidc-ddr",
+			.get_target_freq = __get_target_freq,
+			.event_handler = __event_handler,
+		},
+	},
+	{
+		.mode = GOVERNOR_VMEM,
+		.devfreq_gov = {
+			.name = "msm-vidc-vmem",
+			.get_target_freq = __get_target_freq,
+			.event_handler = __event_handler,
+		},
+	},
+	{
+		.mode = GOVERNOR_VMEM_PLUS,
+		.devfreq_gov = {
+			.name = "msm-vidc-vmem+",
+			.get_target_freq = __get_target_freq,
+			.event_handler = __event_handler,
+		},
+	},
+};
+
+static int __init msm_vidc_bw_gov_init(void)
+{
+	int c = 0, rc = 0;
+
+	for (c = 0; c < ARRAY_SIZE(governors); ++c) {
+		dprintk(VIDC_DBG, "Adding governor %s\n",
+				governors[c].devfreq_gov.name);
+
+		rc = devfreq_add_governor(&governors[c].devfreq_gov);
+		if (rc) {
+			dprintk(VIDC_ERR, "Error adding governor %s: %d\n",
+				governors[c].devfreq_gov.name, rc);
+			break;
+		}
+	}
+
+	return rc;
+}
+module_init(msm_vidc_bw_gov_init);
+
+static void __exit msm_vidc_bw_gov_exit(void)
+{
+	int c = 0;
+
+	for (c = 0; c < ARRAY_SIZE(governors); ++c) {
+		dprintk(VIDC_DBG, "Removing governor %s\n",
+				governors[c].devfreq_gov.name);
+		devfreq_remove_governor(&governors[c].devfreq_gov);
+	}
+}
+module_exit(msm_vidc_bw_gov_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c
new file mode 100644
index 0000000..a702910
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/governors/msm_vidc_table_gov.c
@@ -0,0 +1,379 @@
+/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include "governor.h"
+#include "../msm_vidc_debug.h"
+#include "../msm_vidc_res_parse.h"
+#include "../msm_vidc_internal.h"
+#include "../venus_hfi.h"
+#include "../vidc_hfi_api.h"
+
+
+enum bus_profile {
+	VIDC_BUS_PROFILE_NORMAL			= BIT(0),
+	VIDC_BUS_PROFILE_LOW			= BIT(1),
+	VIDC_BUS_PROFILE_UBWC			= BIT(2),
+};
+
+struct bus_profile_entry {
+	struct {
+		u32 load, freq;
+	} *bus_table;
+	u32 bus_table_size;
+	u32 codec_mask;
+	enum bus_profile profile;
+};
+
+struct msm_vidc_bus_table_gov {
+	struct bus_profile_entry *bus_prof_entries;
+	u32 count;
+	struct devfreq_governor devfreq_gov;
+};
+
+static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov,
+		struct vidc_bus_vote_data *data,
+		enum bus_profile profile)
+{
+	int i = 0, load = 0, freq = 0;
+	enum vidc_vote_data_session sess_type = 0;
+	struct bus_profile_entry *entry = NULL;
+	bool found = false;
+
+	load = NUM_MBS_PER_SEC(data->width, data->height, data->fps);
+	sess_type = VIDC_VOTE_DATA_SESSION_VAL(data->codec, data->domain);
+
+	/* check if ubwc bus profile is present */
+	for (i = 0; i < gov->count; i++) {
+		entry = &gov->bus_prof_entries[i];
+		if (!entry->bus_table || !entry->bus_table_size)
+			continue;
+		if (!venus_hfi_is_session_supported(
+				entry->codec_mask, sess_type))
+			continue;
+		if (entry->profile == profile) {
+			found = true;
+			break;
+		}
+	}
+
+	if (found) {
+		 /* loop over bus table and select frequency */
+		for (i = entry->bus_table_size - 1; i >= 0; --i) {
+			 /*load is arranged in descending order */
+			freq = entry->bus_table[i].freq;
+			if (load <= entry->bus_table[i].load)
+				break;
+		}
+	}
+
+	return freq;
+}
+
+
+static int msm_vidc_table_get_target_freq(struct devfreq *dev,
+		unsigned long *frequency)
+{
+	struct devfreq_dev_status status = {0};
+	struct msm_vidc_gov_data *vidc_data = NULL;
+	struct msm_vidc_bus_table_gov *gov = NULL;
+	enum bus_profile profile = 0;
+	int i = 0;
+
+	if (!dev || !frequency) {
+		dprintk(VIDC_ERR, "%s: Invalid params %pK, %pK\n",
+			__func__, dev, frequency);
+		return -EINVAL;
+	}
+
+	gov = container_of(dev->governor,
+			struct msm_vidc_bus_table_gov, devfreq_gov);
+	if (!gov) {
+		dprintk(VIDC_ERR, "%s: governor not found\n", __func__);
+		return -EINVAL;
+	}
+
+	dev->profile->get_dev_status(dev->dev.parent, &status);
+	vidc_data = (struct msm_vidc_gov_data *)status.private_data;
+
+	*frequency = 0;
+	for (i = 0; i < vidc_data->data_count; i++) {
+		struct vidc_bus_vote_data *data = &vidc_data->data[i];
+		int freq = 0;
+
+		if (data->power_mode == VIDC_POWER_TURBO) {
+			dprintk(VIDC_DBG, "bus: found turbo session[%d] %#x\n",
+				i, VIDC_VOTE_DATA_SESSION_VAL(data->codec,
+					data->domain));
+			*frequency = INT_MAX;
+			goto exit;
+		}
+
+		profile = VIDC_BUS_PROFILE_NORMAL;
+		if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_TP10_UBWC ||
+			data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC)
+			profile = VIDC_BUS_PROFILE_UBWC;
+
+		freq = __get_bus_freq(gov, data, profile);
+
+		/* chose frequency from normal profile
+		 * if specific profile frequency was not found.
+		 */
+		if (!freq)
+			freq = __get_bus_freq(gov, data,
+				VIDC_BUS_PROFILE_NORMAL);
+
+		*frequency += (unsigned long)freq;
+
+		dprintk(VIDC_DBG,
+			"session[%d] %#x: wxh %dx%d, fps %d, bus_profile %#x, freq %d, total_freq %ld KBps\n",
+			i, VIDC_VOTE_DATA_SESSION_VAL(
+			data->codec, data->domain), data->width,
+			data->height, data->fps, profile,
+			freq, *frequency);
+	}
+exit:
+	return 0;
+}
+
+int msm_vidc_table_event_handler(struct devfreq *devfreq,
+		unsigned int event, void *data)
+{
+	int rc = 0;
+
+	if (!devfreq) {
+		dprintk(VIDC_ERR, "%s: NULL devfreq\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+	case DEVFREQ_GOV_RESUME:
+		mutex_lock(&devfreq->lock);
+		rc = update_devfreq(devfreq);
+		mutex_unlock(&devfreq->lock);
+		break;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_free_bus_table(struct platform_device *pdev,
+		struct msm_vidc_bus_table_gov *data)
+{
+	int rc = 0, i = 0;
+
+	if (!pdev || !data) {
+		dprintk(VIDC_ERR, "%s: invalid args %pK %pK\n",
+			__func__, pdev, data);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < data->count; i++)
+		data->bus_prof_entries[i].bus_table = NULL;
+
+	data->bus_prof_entries = NULL;
+	data->count = 0;
+
+	return rc;
+}
+
+static int msm_vidc_load_bus_table(struct platform_device *pdev,
+		struct msm_vidc_bus_table_gov *data)
+{
+	int rc = 0, i = 0, j = 0;
+	const char *name = NULL;
+	struct bus_profile_entry *entry = NULL;
+	struct device_node *parent_node = NULL;
+	struct device_node *child_node = NULL;
+
+	if (!pdev || !data) {
+		dprintk(VIDC_ERR, "%s: invalid args %pK %pK\n",
+			__func__, pdev, data);
+		return -EINVAL;
+	}
+
+	of_property_read_string(pdev->dev.of_node, "name", &name);
+	if (strlen(name) > ARRAY_SIZE(data->devfreq_gov.name) - 1) {
+		dprintk(VIDC_ERR,
+			"%s: name is too long, max should be %zu chars\n",
+			__func__, ARRAY_SIZE(data->devfreq_gov.name) - 1);
+		return -EINVAL;
+	}
+
+	strlcpy((char *)data->devfreq_gov.name, name,
+			ARRAY_SIZE(data->devfreq_gov.name));
+	data->devfreq_gov.get_target_freq = msm_vidc_table_get_target_freq;
+	data->devfreq_gov.event_handler = msm_vidc_table_event_handler;
+
+	parent_node = of_find_node_by_name(pdev->dev.of_node,
+			"qcom,bus-freq-table");
+	if (!parent_node) {
+		dprintk(VIDC_DBG, "Node qcom,bus-freq-table not found.\n");
+		return 0;
+	}
+
+	data->count = of_get_child_count(parent_node);
+	if (!data->count) {
+		dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n");
+		return 0;
+	}
+
+	data->bus_prof_entries = devm_kzalloc(&pdev->dev,
+			sizeof(*data->bus_prof_entries) * data->count,
+			GFP_KERNEL);
+	if (!data->bus_prof_entries) {
+		dprintk(VIDC_DBG, "no memory to allocate bus_prof_entries\n");
+		return -ENOMEM;
+	}
+
+	for_each_child_of_node(parent_node, child_node) {
+
+		if (i >= data->count) {
+			dprintk(VIDC_ERR,
+				"qcom,bus-freq-table: invalid child node %d, max is %d\n",
+				i, data->count);
+			break;
+		}
+		entry = &data->bus_prof_entries[i];
+
+		if (of_find_property(child_node, "qcom,codec-mask", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,codec-mask", &entry->codec_mask);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,codec-mask not found\n");
+				break;
+			}
+		}
+
+		if (of_find_property(child_node, "qcom,low-power-mode", NULL))
+			entry->profile = VIDC_BUS_PROFILE_LOW;
+		else if (of_find_property(child_node, "qcom,ubwc-mode", NULL))
+			entry->profile = VIDC_BUS_PROFILE_UBWC;
+		else
+			entry->profile = VIDC_BUS_PROFILE_NORMAL;
+
+		if (of_find_property(child_node,
+					"qcom,load-busfreq-tbl", NULL)) {
+			rc = msm_vidc_load_u32_table(pdev, child_node,
+						"qcom,load-busfreq-tbl",
+						sizeof(*entry->bus_table),
+						(u32 **)&entry->bus_table,
+						&entry->bus_table_size);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,load-busfreq-tbl failed\n");
+				break;
+			}
+		} else {
+			entry->bus_table = NULL;
+			entry->bus_table_size = 0;
+		}
+
+		dprintk(VIDC_DBG,
+			"qcom,load-busfreq-tbl: size %d, codec_mask %#x, profile %#x\n",
+			entry->bus_table_size, entry->codec_mask,
+			entry->profile);
+		for (j = 0; j < entry->bus_table_size; j++)
+			dprintk(VIDC_DBG, "   load %8d freq %8d\n",
+				entry->bus_table[j].load,
+				entry->bus_table[j].freq);
+
+		i++;
+	}
+
+	return rc;
+}
+
+static int msm_vidc_bus_table_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_bus_table_gov *gov = NULL;
+
+	dprintk(VIDC_DBG, "%s\n", __func__);
+
+	gov = devm_kzalloc(&pdev->dev, sizeof(*gov), GFP_KERNEL);
+	if (!gov) {
+		dprintk(VIDC_ERR, "%s: allocation failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, gov);
+
+	rc = msm_vidc_load_bus_table(pdev, gov);
+	if (rc)
+		return rc;
+
+	rc = devfreq_add_governor(&gov->devfreq_gov);
+	if (rc)
+		dprintk(VIDC_ERR, "%s: add governor failed\n", __func__);
+
+	return rc;
+}
+
+static int msm_vidc_bus_table_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_bus_table_gov *gov = NULL;
+
+	dprintk(VIDC_DBG, "%s\n", __func__);
+
+	gov = platform_get_drvdata(pdev);
+	if (IS_ERR_OR_NULL(gov))
+		return PTR_ERR(gov);
+
+	rc = msm_vidc_free_bus_table(pdev, gov);
+	if (rc)
+		dprintk(VIDC_WARN, "%s: free bus table failed\n", __func__);
+
+	rc = devfreq_remove_governor(&gov->devfreq_gov);
+
+	return rc;
+}
+
+static const struct of_device_id device_id[] = {
+	{.compatible = "qcom,msm-vidc,governor,table"},
+	{}
+};
+
+static struct platform_driver msm_vidc_bus_table_driver = {
+	.probe = msm_vidc_bus_table_probe,
+	.remove = msm_vidc_bus_table_remove,
+	.driver = {
+		.name = "msm_vidc_bus_table_governor",
+		.owner = THIS_MODULE,
+		.of_match_table = device_id,
+	},
+};
+
+static int __init msm_vidc_bus_table_init(void)
+{
+
+	dprintk(VIDC_DBG, "%s\n", __func__);
+
+	return platform_driver_register(&msm_vidc_bus_table_driver);
+}
+
+module_init(msm_vidc_bus_table_init);
+
+static void __exit msm_vidc_bus_table_exit(void)
+{
+	dprintk(VIDC_DBG, "%s\n", __func__);
+	platform_driver_unregister(&msm_vidc_bus_table_driver);
+}
+
+module_exit(msm_vidc_bus_table_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_packetization.c b/drivers/media/platform/msm/vidc_3x/hfi_packetization.c
new file mode 100644
index 0000000..b15baaa
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/hfi_packetization.c
@@ -0,0 +1,2564 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/log2.h>
+#include <linux/hash.h>
+#include "hfi_packetization.h"
+#include "msm_vidc_debug.h"
+
+/* Set up look-up tables to convert HAL_* to HFI_*.
+ *
+ * The tables below mostly take advantage of the fact that most
+ * HAL_* types are defined bitwise. So if we index them normally
+ * when declaring the tables, we end up with huge arrays with wasted
+ * space.  So before indexing them, we apply log2 to use a more
+ * sensible index.
+ */
+static int profile_table[] = {
+	[ilog2(HAL_H264_PROFILE_BASELINE)] = HFI_H264_PROFILE_BASELINE,
+	[ilog2(HAL_H264_PROFILE_MAIN)] = HFI_H264_PROFILE_MAIN,
+	[ilog2(HAL_H264_PROFILE_HIGH)] = HFI_H264_PROFILE_HIGH,
+	[ilog2(HAL_H264_PROFILE_CONSTRAINED_BASE)] =
+		HFI_H264_PROFILE_CONSTRAINED_BASE,
+	[ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
+		HFI_H264_PROFILE_CONSTRAINED_HIGH,
+	[ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
+	[ilog2(HAL_MVC_PROFILE_STEREO_HIGH)] = HFI_H264_PROFILE_STEREO_HIGH,
+};
+
+static int entropy_mode[] = {
+	[ilog2(HAL_H264_ENTROPY_CAVLC)] = HFI_H264_ENTROPY_CAVLC,
+	[ilog2(HAL_H264_ENTROPY_CABAC)] = HFI_H264_ENTROPY_CABAC,
+};
+
+static int cabac_model[] = {
+	[ilog2(HAL_H264_CABAC_MODEL_0)] = HFI_H264_CABAC_MODEL_0,
+	[ilog2(HAL_H264_CABAC_MODEL_1)] = HFI_H264_CABAC_MODEL_1,
+	[ilog2(HAL_H264_CABAC_MODEL_2)] = HFI_H264_CABAC_MODEL_2,
+};
+
+static int statistics_mode[] = {
+	[ilog2(HAL_STATISTICS_MODE_DEFAULT)] = HFI_STATISTICS_MODE_DEFAULT,
+	[ilog2(HAL_STATISTICS_MODE_1)] = HFI_STATISTICS_MODE_1,
+	[ilog2(HAL_STATISTICS_MODE_2)] = HFI_STATISTICS_MODE_2,
+	[ilog2(HAL_STATISTICS_MODE_3)] = HFI_STATISTICS_MODE_3,
+};
+
+static int color_format[] = {
+	[ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME,
+	[ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12,
+	[ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21,
+	[ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE,
+	[ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE,
+	[ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV,
+	[ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU,
+	[ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY,
+	[ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY,
+	[ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565,
+	[ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
+	[ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
+	[ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
+	[ilog2(HAL_COLOR_FORMAT_RGBA8888)] = HFI_COLOR_FORMAT_RGBA8888,
+	/* UBWC Color formats*/
+	[ilog2(HAL_COLOR_FORMAT_NV12_UBWC)] =  HFI_COLOR_FORMAT_NV12_UBWC,
+	[ilog2(HAL_COLOR_FORMAT_NV12_TP10_UBWC)] =
+			HFI_COLOR_FORMAT_YUV420_TP10_UBWC,
+	[ilog2(HAL_COLOR_FORMAT_RGBA8888_UBWC)] =
+			HFI_COLOR_FORMAT_RGBA8888_UBWC,
+};
+
+static int nal_type[] = {
+	[ilog2(HAL_NAL_FORMAT_STARTCODES)] = HFI_NAL_FORMAT_STARTCODES,
+	[ilog2(HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER)] =
+		HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER,
+	[ilog2(HAL_NAL_FORMAT_ONE_BYTE_LENGTH)] =
+		HFI_NAL_FORMAT_ONE_BYTE_LENGTH,
+	[ilog2(HAL_NAL_FORMAT_TWO_BYTE_LENGTH)] =
+		HFI_NAL_FORMAT_TWO_BYTE_LENGTH,
+	[ilog2(HAL_NAL_FORMAT_FOUR_BYTE_LENGTH)] =
+		HFI_NAL_FORMAT_FOUR_BYTE_LENGTH,
+};
+
+static inline int hal_to_hfi_type(int property, int hal_type)
+{
+	if (hal_type <= 0 || roundup_pow_of_two(hal_type) != hal_type) {
+		/* Not a power of 2, it's not going
+		 * to be in any of the tables anyway
+		 */
+		return -EINVAL;
+	}
+
+	if (hal_type)
+		hal_type = ilog2(hal_type);
+
+	switch (property) {
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+		return (hal_type >= ARRAY_SIZE(profile_table)) ?
+			-ENOTSUPP : profile_table[hal_type];
+	case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+		return (hal_type >= ARRAY_SIZE(entropy_mode)) ?
+			-ENOTSUPP : entropy_mode[hal_type];
+	case HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL:
+		return (hal_type >= ARRAY_SIZE(cabac_model)) ?
+			-ENOTSUPP : cabac_model[hal_type];
+	case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+		return (hal_type >= ARRAY_SIZE(color_format)) ?
+			-ENOTSUPP : color_format[hal_type];
+	case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+		return (hal_type >= ARRAY_SIZE(nal_type)) ?
+			-ENOTSUPP : nal_type[hal_type];
+	case HAL_PARAM_VENC_MBI_STATISTICS_MODE:
+		return (hal_type >= ARRAY_SIZE(statistics_mode)) ?
+			-ENOTSUPP : statistics_mode[hal_type];
+	default:
+		return -ENOTSUPP;
+	}
+}
+
+u32 get_hfi_layout(enum hal_buffer_layout_type hal_buf_layout)
+{
+	u32 hfi_layout;
+
+	switch (hal_buf_layout) {
+	case HAL_BUFFER_LAYOUT_TOP_BOTTOM:
+		hfi_layout = HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM;
+		break;
+	case HAL_BUFFER_LAYOUT_SEQ:
+		hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid buffer layout: %#x\n",
+			hal_buf_layout);
+		hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
+		break;
+	}
+	return hfi_layout;
+}
+
+enum hal_domain vidc_get_hal_domain(u32 hfi_domain)
+{
+	enum hal_domain hal_domain = 0;
+
+	switch (hfi_domain) {
+	case HFI_VIDEO_DOMAIN_VPE:
+		hal_domain = HAL_VIDEO_DOMAIN_VPE;
+		break;
+	case HFI_VIDEO_DOMAIN_ENCODER:
+		hal_domain = HAL_VIDEO_DOMAIN_ENCODER;
+		break;
+	case HFI_VIDEO_DOMAIN_DECODER:
+		hal_domain = HAL_VIDEO_DOMAIN_DECODER;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s: invalid domain %x\n",
+			__func__, hfi_domain);
+		hal_domain = 0;
+		break;
+	}
+	return hal_domain;
+}
+
+enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec)
+{
+	enum hal_video_codec hal_codec = 0;
+
+	switch (hfi_codec) {
+	case HFI_VIDEO_CODEC_H264:
+		hal_codec = HAL_VIDEO_CODEC_H264;
+		break;
+	case HFI_VIDEO_CODEC_H263:
+		hal_codec = HAL_VIDEO_CODEC_H263;
+		break;
+	case HFI_VIDEO_CODEC_MPEG1:
+		hal_codec = HAL_VIDEO_CODEC_MPEG1;
+		break;
+	case HFI_VIDEO_CODEC_MPEG2:
+		hal_codec = HAL_VIDEO_CODEC_MPEG2;
+		break;
+	case HFI_VIDEO_CODEC_MPEG4:
+		hal_codec = HAL_VIDEO_CODEC_MPEG4;
+		break;
+	case HFI_VIDEO_CODEC_DIVX_311:
+		hal_codec = HAL_VIDEO_CODEC_DIVX_311;
+		break;
+	case HFI_VIDEO_CODEC_DIVX:
+		hal_codec = HAL_VIDEO_CODEC_DIVX;
+		break;
+	case HFI_VIDEO_CODEC_VC1:
+		hal_codec = HAL_VIDEO_CODEC_VC1;
+		break;
+	case HFI_VIDEO_CODEC_SPARK:
+		hal_codec = HAL_VIDEO_CODEC_SPARK;
+		break;
+	case HFI_VIDEO_CODEC_VP8:
+		hal_codec = HAL_VIDEO_CODEC_VP8;
+		break;
+	case HFI_VIDEO_CODEC_HEVC:
+		hal_codec = HAL_VIDEO_CODEC_HEVC;
+		break;
+	case HFI_VIDEO_CODEC_VP9:
+		hal_codec = HAL_VIDEO_CODEC_VP9;
+		break;
+	case HFI_VIDEO_CODEC_HEVC_HYBRID:
+		hal_codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+		break;
+	default:
+		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
+			__func__, hfi_codec);
+		hal_codec = 0;
+		break;
+	}
+	return hal_codec;
+}
+
+
+u32 vidc_get_hfi_domain(enum hal_domain hal_domain)
+{
+	u32 hfi_domain;
+
+	switch (hal_domain) {
+	case HAL_VIDEO_DOMAIN_VPE:
+		hfi_domain = HFI_VIDEO_DOMAIN_VPE;
+		break;
+	case HAL_VIDEO_DOMAIN_ENCODER:
+		hfi_domain = HFI_VIDEO_DOMAIN_ENCODER;
+		break;
+	case HAL_VIDEO_DOMAIN_DECODER:
+		hfi_domain = HFI_VIDEO_DOMAIN_DECODER;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s: invalid domain 0x%x\n",
+			__func__, hal_domain);
+		hfi_domain = 0;
+		break;
+	}
+	return hfi_domain;
+}
+
+u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec)
+{
+	u32 hfi_codec = 0;
+
+	switch (hal_codec) {
+	case HAL_VIDEO_CODEC_MVC:
+	case HAL_VIDEO_CODEC_H264:
+		hfi_codec = HFI_VIDEO_CODEC_H264;
+		break;
+	case HAL_VIDEO_CODEC_H263:
+		hfi_codec = HFI_VIDEO_CODEC_H263;
+		break;
+	case HAL_VIDEO_CODEC_MPEG1:
+		hfi_codec = HFI_VIDEO_CODEC_MPEG1;
+		break;
+	case HAL_VIDEO_CODEC_MPEG2:
+		hfi_codec = HFI_VIDEO_CODEC_MPEG2;
+		break;
+	case HAL_VIDEO_CODEC_MPEG4:
+		hfi_codec = HFI_VIDEO_CODEC_MPEG4;
+		break;
+	case HAL_VIDEO_CODEC_DIVX_311:
+		hfi_codec = HFI_VIDEO_CODEC_DIVX_311;
+		break;
+	case HAL_VIDEO_CODEC_DIVX:
+		hfi_codec = HFI_VIDEO_CODEC_DIVX;
+		break;
+	case HAL_VIDEO_CODEC_VC1:
+		hfi_codec = HFI_VIDEO_CODEC_VC1;
+		break;
+	case HAL_VIDEO_CODEC_SPARK:
+		hfi_codec = HFI_VIDEO_CODEC_SPARK;
+		break;
+	case HAL_VIDEO_CODEC_VP8:
+		hfi_codec = HFI_VIDEO_CODEC_VP8;
+		break;
+	case HAL_VIDEO_CODEC_HEVC:
+		hfi_codec = HFI_VIDEO_CODEC_HEVC;
+		break;
+	case HAL_VIDEO_CODEC_VP9:
+		hfi_codec = HFI_VIDEO_CODEC_VP9;
+		break;
+	case HAL_VIDEO_CODEC_HEVC_HYBRID:
+		hfi_codec = HFI_VIDEO_CODEC_HEVC_HYBRID;
+		break;
+	default:
+		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
+			__func__, hal_codec);
+		hfi_codec = 0;
+		break;
+	}
+	return hfi_codec;
+}
+
+static void create_pkt_enable(void *pkt, u32 type, bool enable)
+{
+	u32 *pkt_header = pkt;
+	u32 *pkt_type = &pkt_header[0];
+	struct hfi_enable *hfi_enable = (struct hfi_enable *)&pkt_header[1];
+
+	*pkt_type = type;
+	hfi_enable->enable = enable;
+}
+
+int create_pkt_cmd_sys_init(struct hfi_cmd_sys_init_packet *pkt,
+			   u32 arch_type)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SYS_INIT;
+	pkt->size = sizeof(struct hfi_cmd_sys_init_packet);
+	pkt->arch_type = arch_type;
+	return rc;
+}
+
+int create_pkt_cmd_sys_pc_prep(struct hfi_cmd_sys_pc_prep_packet *pkt)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SYS_PC_PREP;
+	pkt->size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
+	return rc;
+}
+
+int create_pkt_cmd_sys_idle_indicator(
+	struct hfi_cmd_sys_set_property_packet *pkt,
+	u32 enable)
+{
+	struct hfi_enable *hfi;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(struct hfi_enable) + sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR;
+	hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+	hfi->enable = enable;
+	return 0;
+}
+
+int create_pkt_cmd_sys_debug_config(
+	struct hfi_cmd_sys_set_property_packet *pkt,
+	u32 mode)
+{
+	struct hfi_debug_config *hfi;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(struct hfi_debug_config) + sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG;
+	hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1];
+	hfi->debug_config = mode;
+	hfi->debug_mode = HFI_DEBUG_MODE_QUEUE;
+	if (msm_vidc_fw_debug_mode
+			<= (HFI_DEBUG_MODE_QUEUE | HFI_DEBUG_MODE_QDSS))
+		hfi->debug_mode = msm_vidc_fw_debug_mode;
+	return 0;
+}
+
+int create_pkt_cmd_sys_coverage_config(
+	struct hfi_cmd_sys_set_property_packet *pkt,
+	u32 mode)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "In %s(), No input packet\n", __func__);
+		return -EINVAL;
+	}
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE;
+	pkt->rg_property_data[1] = mode;
+	dprintk(VIDC_DBG, "Firmware coverage mode %d\n",
+			pkt->rg_property_data[1]);
+	return 0;
+}
+
+int create_pkt_cmd_sys_set_resource(
+		struct hfi_cmd_sys_set_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr,
+		void *resource_value)
+{
+	int rc = 0;
+
+	if (!pkt || !resource_hdr || !resource_value)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SYS_SET_RESOURCE;
+	pkt->size = sizeof(struct hfi_cmd_sys_set_resource_packet);
+	pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle);
+
+	switch (resource_hdr->resource_id) {
+	case VIDC_RESOURCE_OCMEM:
+	case VIDC_RESOURCE_VMEM:
+	{
+		struct hfi_resource_ocmem *hfioc_mem =
+			(struct hfi_resource_ocmem *)
+			&pkt->rg_resource_data[0];
+
+		phys_addr_t imem_addr = (phys_addr_t)resource_value;
+
+		pkt->resource_type = HFI_RESOURCE_OCMEM;
+		pkt->size += sizeof(struct hfi_resource_ocmem) - sizeof(u32);
+		hfioc_mem->size = (u32)resource_hdr->size;
+		hfioc_mem->mem = imem_addr;
+		break;
+	}
+	default:
+		dprintk(VIDC_ERR, "Invalid resource_id %d\n",
+					resource_hdr->resource_id);
+		rc = -ENOTSUPP;
+	}
+
+	return rc;
+}
+
+int create_pkt_cmd_sys_release_resource(
+		struct hfi_cmd_sys_release_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_release_resource_packet);
+	pkt->packet_type = HFI_CMD_SYS_RELEASE_RESOURCE;
+	pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle);
+
+	switch (resource_hdr->resource_id) {
+	case VIDC_RESOURCE_OCMEM:
+	case VIDC_RESOURCE_VMEM:
+		pkt->resource_type = HFI_RESOURCE_OCMEM;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid resource_id %d\n",
+					resource_hdr->resource_id);
+		rc = -ENOTSUPP;
+	}
+
+	return rc;
+}
+
+int create_pkt_cmd_sys_ping(struct hfi_cmd_sys_ping_packet *pkt)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_ping_packet);
+	pkt->packet_type = HFI_CMD_SYS_PING;
+
+	return rc;
+}
+
+inline int create_pkt_cmd_sys_session_init(
+		struct hfi_cmd_sys_session_init_packet *pkt,
+		struct hal_session *session,
+		u32 session_domain, u32 session_codec)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_sys_session_init_packet);
+	pkt->packet_type = HFI_CMD_SYS_SESSION_INIT;
+	pkt->session_id = hash32_ptr(session);
+	pkt->session_domain = vidc_get_hfi_domain(session_domain);
+	pkt->session_codec = vidc_get_hfi_codec(session_codec);
+	if (!pkt->session_codec)
+		return -EINVAL;
+
+	return rc;
+}
+
+int create_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt,
+			int pkt_type, struct hal_session *session)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	/*
+	 * Legacy packetization should skip sending any 3xx specific session
+	 * cmds. Add 3xx specific packetization to the switch case below.
+	 */
+	switch (pkt_type) {
+	case HFI_CMD_SESSION_CONTINUE:
+		dprintk(VIDC_INFO,
+			"%s - skip sending %x for legacy hfi\n",
+			__func__, pkt_type);
+		return -EPERM;
+	default:
+		break;
+	}
+
+	pkt->size = sizeof(struct vidc_hal_session_cmd_pkt);
+	pkt->packet_type = pkt_type;
+	pkt->session_id = hash32_ptr(session);
+
+	return rc;
+}
+
+int create_3x_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt,
+			int pkt_type, struct hal_session *session)
+{
+	int rc = 0;
+
+	if (!pkt)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct vidc_hal_session_cmd_pkt);
+	pkt->packet_type = pkt_type;
+	pkt->session_id = hash32_ptr(session);
+
+	return rc;
+}
+
+int create_pkt_cmd_sys_power_control(
+	struct hfi_cmd_sys_set_property_packet *pkt, u32 enable)
+{
+	struct hfi_enable *hfi;
+
+	if (!pkt) {
+		dprintk(VIDC_ERR, "No input packet\n");
+		return -EINVAL;
+	}
+
+	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
+		sizeof(struct hfi_enable) + sizeof(u32);
+	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
+	hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+	hfi->enable = enable;
+	return 0;
+}
+
+static u32 get_hfi_buffer(int hal_buffer)
+{
+	u32 buffer;
+
+	switch (hal_buffer) {
+	case HAL_BUFFER_INPUT:
+		buffer = HFI_BUFFER_INPUT;
+		break;
+	case HAL_BUFFER_OUTPUT:
+		buffer = HFI_BUFFER_OUTPUT;
+		break;
+	case HAL_BUFFER_OUTPUT2:
+		buffer = HFI_BUFFER_OUTPUT2;
+		break;
+	case HAL_BUFFER_EXTRADATA_INPUT:
+		buffer = HFI_BUFFER_EXTRADATA_INPUT;
+		break;
+	case HAL_BUFFER_EXTRADATA_OUTPUT:
+		buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
+		break;
+	case HAL_BUFFER_EXTRADATA_OUTPUT2:
+		buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_1:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+		break;
+	case HAL_BUFFER_INTERNAL_SCRATCH_2:
+		buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+		break;
+	case HAL_BUFFER_INTERNAL_PERSIST:
+		buffer = HFI_BUFFER_INTERNAL_PERSIST;
+		break;
+	case HAL_BUFFER_INTERNAL_PERSIST_1:
+		buffer = HFI_BUFFER_INTERNAL_PERSIST_1;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid buffer: %#x\n",
+				hal_buffer);
+		buffer = 0;
+		break;
+	}
+	return buffer;
+}
+
+static int get_hfi_extradata_index(enum hal_extradata_id index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case HAL_EXTRADATA_MB_QUANTIZATION:
+		ret = HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION;
+		break;
+	case HAL_EXTRADATA_INTERLACE_VIDEO:
+		ret = HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VC1_FRAMEDISP:
+		ret = HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VC1_SEQDISP:
+		ret = HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_TIMESTAMP:
+		ret = HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_S3D_FRAME_PACKING:
+		ret = HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_FRAME_RATE:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_PANSCAN_WINDOW:
+		ret = HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_RECOVERY_POINT_SEI:
+		ret = HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_MULTISLICE_INFO:
+		ret = HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO;
+		break;
+	case HAL_EXTRADATA_NUM_CONCEALED_MB:
+		ret = HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB;
+		break;
+	case HAL_EXTRADATA_ASPECT_RATIO:
+	case HAL_EXTRADATA_INPUT_CROP:
+	case HAL_EXTRADATA_DIGITAL_ZOOM:
+	case HAL_EXTRADATA_OUTPUT_CROP:
+		ret = HFI_PROPERTY_PARAM_INDEX_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_MPEG2_SEQDISP:
+		ret = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_STREAM_USERDATA:
+		ret = HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_FRAME_QP:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_FRAME_BITS_INFO:
+		ret = HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_LTR_INFO:
+		ret = HFI_PROPERTY_PARAM_VENC_LTR_INFO;
+		break;
+	case HAL_EXTRADATA_METADATA_MBI:
+		ret = HFI_PROPERTY_PARAM_VENC_MBI_DUMPING;
+		break;
+	case HAL_EXTRADATA_VQZIP_SEI:
+		ret = HFI_PROPERTY_PARAM_VDEC_VQZIP_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_YUV_STATS:
+		ret = HFI_PROPERTY_PARAM_VENC_YUVSTAT_INFO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_ROI_QP:
+		ret = HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI:
+		ret =
+		HFI_PROPERTY_PARAM_VDEC_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI:
+		ret = HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VUI_DISPLAY_INFO:
+		ret = HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_VPX_COLORSPACE:
+		ret = HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA;
+		break;
+	case HAL_EXTRADATA_PQ_INFO:
+		ret = HFI_PROPERTY_PARAM_VENC_OVERRIDE_QP_EXTRADATA;
+		break;
+	default:
+		dprintk(VIDC_WARN, "Extradata index not found: %d\n", index);
+		break;
+	}
+	return ret;
+}
+
+static int get_hfi_extradata_id(enum hal_extradata_id index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case HAL_EXTRADATA_ASPECT_RATIO:
+		ret = MSM_VIDC_EXTRADATA_ASPECT_RATIO;
+		break;
+	case HAL_EXTRADATA_INPUT_CROP:
+		ret = MSM_VIDC_EXTRADATA_INPUT_CROP;
+		break;
+	case HAL_EXTRADATA_DIGITAL_ZOOM:
+		ret = MSM_VIDC_EXTRADATA_DIGITAL_ZOOM;
+		break;
+	case HAL_EXTRADATA_OUTPUT_CROP:
+		ret = MSM_VIDC_EXTRADATA_OUTPUT_CROP;
+		break;
+	default:
+		ret = get_hfi_extradata_index(index);
+		break;
+	}
+	return ret;
+}
+
+static u32 get_hfi_buf_mode(enum buffer_mode_type hal_buf_mode)
+{
+	u32 buf_mode;
+
+	switch (hal_buf_mode) {
+	case HAL_BUFFER_MODE_STATIC:
+		buf_mode = HFI_BUFFER_MODE_STATIC;
+		break;
+	case HAL_BUFFER_MODE_RING:
+		buf_mode = HFI_BUFFER_MODE_RING;
+		break;
+	case HAL_BUFFER_MODE_DYNAMIC:
+		buf_mode = HFI_BUFFER_MODE_DYNAMIC;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid buffer mode: %#x\n",
+				hal_buf_mode);
+		buf_mode = 0;
+		break;
+	}
+	return buf_mode;
+}
+
+static u32 get_hfi_ltr_mode(enum ltr_mode ltr_mode_type)
+{
+	u32 ltrmode;
+
+	switch (ltr_mode_type) {
+	case HAL_LTR_MODE_DISABLE:
+		ltrmode = HFI_LTR_MODE_DISABLE;
+		break;
+	case HAL_LTR_MODE_MANUAL:
+		ltrmode = HFI_LTR_MODE_MANUAL;
+		break;
+	case HAL_LTR_MODE_PERIODIC:
+		ltrmode = HFI_LTR_MODE_PERIODIC;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid ltr mode: %#x\n",
+			ltr_mode_type);
+		ltrmode = HFI_LTR_MODE_DISABLE;
+		break;
+	}
+	return ltrmode;
+}
+
+int create_pkt_cmd_session_set_buffers(
+		struct hfi_cmd_session_set_buffers_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info)
+{
+	int rc = 0;
+	int i = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS;
+	pkt->session_id = hash32_ptr(session);
+	pkt->buffer_size = buffer_info->buffer_size;
+	pkt->min_buffer_size = buffer_info->buffer_size;
+	pkt->num_buffers = buffer_info->num_buffers;
+
+	if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
+		buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
+		struct hfi_buffer_info *buff;
+
+		pkt->extra_data_size = buffer_info->extradata_size;
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+				sizeof(u32) + (buffer_info->num_buffers *
+				sizeof(struct hfi_buffer_info));
+		buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+		for (i = 0; i < pkt->num_buffers; i++) {
+			buff->buffer_addr =
+				(u32)buffer_info->align_device_addr;
+			buff->extra_data_addr =
+				(u32)buffer_info->extradata_addr;
+		}
+	} else {
+		pkt->extra_data_size = 0;
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+			((buffer_info->num_buffers - 1) * sizeof(u32));
+		for (i = 0; i < pkt->num_buffers; i++) {
+			pkt->rg_buffer_info[i] =
+				(u32)buffer_info->align_device_addr;
+		}
+	}
+
+	pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
+	if (!pkt->buffer_type)
+		return -EINVAL;
+
+	return rc;
+}
+
+int create_pkt_cmd_session_release_buffers(
+		struct hfi_cmd_session_release_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info)
+{
+	int rc = 0;
+	int i = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
+	pkt->session_id = hash32_ptr(session);
+	pkt->buffer_size = buffer_info->buffer_size;
+	pkt->num_buffers = buffer_info->num_buffers;
+
+	if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
+		buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
+		struct hfi_buffer_info *buff;
+
+		buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+		for (i = 0; i < pkt->num_buffers; i++) {
+			buff->buffer_addr =
+				(u32)buffer_info->align_device_addr;
+			buff->extra_data_addr =
+				(u32)buffer_info->extradata_addr;
+		}
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
+				sizeof(u32) + (buffer_info->num_buffers *
+				sizeof(struct hfi_buffer_info));
+	} else {
+		for (i = 0; i < pkt->num_buffers; i++) {
+			pkt->rg_buffer_info[i] =
+				(u32)buffer_info->align_device_addr;
+		}
+		pkt->extra_data_size = 0;
+		pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
+			((buffer_info->num_buffers - 1) * sizeof(u32));
+	}
+	pkt->response_req = buffer_info->response_required;
+	pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
+	if (!pkt->buffer_type)
+		return -EINVAL;
+	return rc;
+}
+
+int create_pkt_cmd_session_etb_decoder(
+	struct hfi_cmd_session_empty_buffer_compressed_packet *pkt,
+	struct hal_session *session, struct vidc_frame_data *input_frame)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size =
+		sizeof(struct hfi_cmd_session_empty_buffer_compressed_packet);
+	pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp);
+	pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
+	pkt->flags = input_frame->flags;
+	pkt->mark_target = input_frame->mark_target;
+	pkt->mark_data = input_frame->mark_data;
+	pkt->offset = input_frame->offset;
+	pkt->alloc_len = input_frame->alloc_len;
+	pkt->filled_len = input_frame->filled_len;
+	pkt->input_tag = input_frame->clnt_data;
+	pkt->packet_buffer = (u32)input_frame->device_addr;
+
+	trace_msm_v4l2_vidc_buffer_event_start("ETB",
+		input_frame->device_addr, input_frame->timestamp,
+		input_frame->alloc_len, input_frame->filled_len,
+		input_frame->offset);
+
+	if (!pkt->packet_buffer)
+		rc = -EINVAL;
+	return rc;
+}
+
+int create_pkt_cmd_session_etb_encoder(
+	struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet *pkt,
+	struct hal_session *session, struct vidc_frame_data *input_frame)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct
+		hfi_cmd_session_empty_buffer_uncompressed_plane0_packet);
+	pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->view_id = 0;
+	pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp);
+	pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
+	pkt->flags = input_frame->flags;
+	pkt->mark_target = input_frame->mark_target;
+	pkt->mark_data = input_frame->mark_data;
+	pkt->offset = input_frame->offset;
+	pkt->alloc_len = input_frame->alloc_len;
+	pkt->filled_len = input_frame->filled_len;
+	pkt->input_tag = input_frame->clnt_data;
+	pkt->packet_buffer = (u32)input_frame->device_addr;
+	pkt->extra_data_buffer = (u32)input_frame->extradata_addr;
+
+	trace_msm_v4l2_vidc_buffer_event_start("ETB",
+		input_frame->device_addr, input_frame->timestamp,
+		input_frame->alloc_len, input_frame->filled_len,
+		input_frame->offset);
+
+	if (!pkt->packet_buffer)
+		rc = -EINVAL;
+	return rc;
+}
+
+int create_pkt_cmd_session_ftb(struct hfi_cmd_session_fill_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_frame_data *output_frame)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !output_frame)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_fill_buffer_packet);
+	pkt->packet_type = HFI_CMD_SESSION_FILL_BUFFER;
+	pkt->session_id = hash32_ptr(session);
+
+	if (output_frame->buffer_type == HAL_BUFFER_OUTPUT)
+		pkt->stream_id = 0;
+	else if (output_frame->buffer_type == HAL_BUFFER_OUTPUT2)
+		pkt->stream_id = 1;
+
+	if (!output_frame->device_addr)
+		return -EINVAL;
+
+	pkt->packet_buffer = (u32)output_frame->device_addr;
+	pkt->extra_data_buffer = (u32)output_frame->extradata_addr;
+	pkt->alloc_len = output_frame->alloc_len;
+	pkt->filled_len = output_frame->filled_len;
+	pkt->offset = output_frame->offset;
+	pkt->rgData[0] = output_frame->extradata_size;
+
+	trace_msm_v4l2_vidc_buffer_event_start("FTB",
+		output_frame->device_addr, output_frame->timestamp,
+		output_frame->alloc_len, output_frame->filled_len,
+		output_frame->offset);
+	dprintk(VIDC_DBG, "### Q OUTPUT BUFFER ###: %d, %d, %d\n",
+			pkt->alloc_len, pkt->filled_len, pkt->offset);
+
+	return rc;
+}
+
+int create_pkt_cmd_session_parse_seq_header(
+		struct hfi_cmd_session_parse_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !seq_hdr)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_parse_sequence_header_packet);
+	pkt->packet_type = HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->header_len = seq_hdr->seq_hdr_len;
+	if (!seq_hdr->seq_hdr)
+		return -EINVAL;
+	pkt->packet_buffer = (u32)seq_hdr->seq_hdr;
+	return rc;
+}
+
+int create_pkt_cmd_session_get_seq_hdr(
+		struct hfi_cmd_session_get_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !seq_hdr)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_get_sequence_header_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_SEQUENCE_HEADER;
+	pkt->session_id = hash32_ptr(session);
+	pkt->buffer_len = seq_hdr->seq_hdr_len;
+	if (!seq_hdr->seq_hdr)
+		return -EINVAL;
+	pkt->packet_buffer = (u32)seq_hdr->seq_hdr;
+	return rc;
+}
+
+int create_pkt_cmd_session_get_buf_req(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
+
+	return rc;
+}
+
+int create_pkt_cmd_session_flush(struct hfi_cmd_session_flush_packet *pkt,
+			struct hal_session *session, enum hal_flush flush_mode)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_flush_packet);
+	pkt->packet_type = HFI_CMD_SESSION_FLUSH;
+	pkt->session_id = hash32_ptr(session);
+	switch (flush_mode) {
+	case HAL_FLUSH_INPUT:
+		pkt->flush_type = HFI_FLUSH_INPUT;
+		break;
+	case HAL_FLUSH_OUTPUT:
+		pkt->flush_type = HFI_FLUSH_OUTPUT;
+		break;
+	case HAL_FLUSH_ALL:
+		pkt->flush_type = HFI_FLUSH_ALL;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid flush mode: %#x\n", flush_mode);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+int create_pkt_cmd_session_get_property(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session, enum hal_property ptype)
+{
+	int rc = 0;
+
+	if (!pkt || !session) {
+		dprintk(VIDC_ERR, "%s Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+	switch (ptype) {
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__,
+			ptype);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+int create_3x_pkt_cmd_session_get_property(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session, enum hal_property ptype)
+{
+	int rc = 0;
+
+	if (!pkt || !session) {
+		dprintk(VIDC_ERR, "%s Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+	switch (ptype) {
+	case HAL_CONFIG_VDEC_ENTROPY:
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VDEC_ENTROPY;
+		break;
+	default:
+		rc = create_pkt_cmd_session_get_property(pkt,
+				session, ptype);
+	}
+	return rc;
+}
+
+int create_pkt_cmd_session_set_property(
+		struct hfi_cmd_session_set_property_packet *pkt,
+		struct hal_session *session,
+		enum hal_property ptype, void *pdata)
+{
+	int rc = 0;
+
+	if (!pkt || !session)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+
+	switch (ptype) {
+	case HAL_CONFIG_FRAME_RATE:
+	{
+		u32 buffer_type;
+		struct hfi_frame_rate *hfi;
+		struct hal_frame_rate *prop = (struct hal_frame_rate *) pdata;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_FRAME_RATE;
+		hfi = (struct hfi_frame_rate *) &pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		hfi->frame_rate = prop->frame_rate;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_frame_rate);
+		break;
+	}
+	case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+	{
+		u32 buffer_type;
+		struct hfi_uncompressed_format_select *hfi;
+		struct hal_uncompressed_format_select *prop =
+			(struct hal_uncompressed_format_select *) pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT;
+
+		hfi = (struct hfi_uncompressed_format_select *)
+					&pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		hfi->format = hal_to_hfi_type(
+				HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+				prop->format);
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_uncompressed_format_select);
+		break;
+	}
+	case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
+		break;
+	case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
+		break;
+	case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
+		break;
+	case HAL_PARAM_FRAME_SIZE:
+	{
+		struct hfi_frame_size *hfi;
+		struct hal_frame_size *prop = (struct hal_frame_size *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_FRAME_SIZE;
+		hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		hfi->height = prop->height;
+		hfi->width = prop->width;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
+		break;
+	}
+	case HAL_CONFIG_REALTIME:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_REALTIME,
+			(((struct hal_enable *) pdata)->enable));
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_BUFFER_COUNT_ACTUAL:
+	{
+		struct hfi_buffer_count_actual *hfi;
+		struct hal_buffer_count_actual *prop =
+			(struct hal_buffer_count_actual *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL;
+		hfi = (struct hfi_buffer_count_actual *)
+			&pkt->rg_property_data[1];
+		hfi->buffer_count_actual = prop->buffer_count_actual;
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		pkt->size += sizeof(u32) + sizeof(struct
+				hfi_buffer_count_actual);
+
+		break;
+	}
+	case HAL_PARAM_NAL_STREAM_FORMAT_SELECT:
+	{
+		struct hfi_nal_stream_format_select *hfi;
+		struct hal_nal_stream_format_select *prop =
+			(struct hal_nal_stream_format_select *)pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT;
+		hfi = (struct hfi_nal_stream_format_select *)
+			&pkt->rg_property_data[1];
+		dprintk(VIDC_DBG, "data is :%d\n",
+				prop->nal_stream_format_select);
+		hfi->nal_stream_format_select = hal_to_hfi_type(
+				HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+				prop->nal_stream_format_select);
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_nal_stream_format_select);
+		break;
+	}
+	case HAL_PARAM_VDEC_OUTPUT_ORDER:
+	{
+		int *data = (int *) pdata;
+
+		pkt->rg_property_data[0] =
+				HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER;
+		switch (*data) {
+		case HAL_OUTPUT_ORDER_DECODE:
+			pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DECODE;
+			break;
+		case HAL_OUTPUT_ORDER_DISPLAY:
+			pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY;
+			break;
+		default:
+			dprintk(VIDC_ERR, "invalid output order: %#x\n",
+						  *data);
+			break;
+		}
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE:
+	{
+		struct hfi_enable_picture *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
+		hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
+		hfi->picture_type =
+			((struct hfi_enable_picture *)pdata)->picture_type;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_MULTI_STREAM:
+	{
+		struct hfi_multi_stream *hfi;
+		struct hal_multi_stream *prop =
+			(struct hal_multi_stream *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
+		hfi = (struct hfi_multi_stream *) &pkt->rg_property_data[1];
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		hfi->enable = prop->enable;
+		hfi->width = prop->width;
+		hfi->height = prop->height;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_multi_stream);
+		break;
+	}
+	case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT:
+	{
+		struct hfi_display_picture_buffer_count *hfi;
+		struct hal_display_picture_buffer_count *prop =
+			(struct hal_display_picture_buffer_count *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT;
+		hfi = (struct hfi_display_picture_buffer_count *)
+			&pkt->rg_property_data[1];
+		hfi->count = prop->count;
+		hfi->enable = prop->enable;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_display_picture_buffer_count);
+		break;
+	}
+	case HAL_PARAM_DIVX_FORMAT:
+	{
+		int *data = pdata;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_DIVX_FORMAT;
+		switch (*data) {
+		case HAL_DIVX_FORMAT_4:
+			pkt->rg_property_data[1] = HFI_DIVX_FORMAT_4;
+			break;
+		case HAL_DIVX_FORMAT_5:
+			pkt->rg_property_data[1] = HFI_DIVX_FORMAT_5;
+			break;
+		case HAL_DIVX_FORMAT_6:
+			pkt->rg_property_data[1] = HFI_DIVX_FORMAT_6;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid divx format: %#x\n", *data);
+			break;
+		}
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_SYNC_FRAME_DECODE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_REQUEST_IFRAME:
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
+		pkt->size += sizeof(u32);
+		break;
+	case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
+		break;
+	case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
+		break;
+	case HAL_CONFIG_VENC_TARGET_BITRATE:
+	{
+		struct hfi_bitrate *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+		hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
+		hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+		hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+		break;
+	}
+	case HAL_CONFIG_VENC_MAX_BITRATE:
+	{
+		struct hfi_bitrate *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE;
+		hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1];
+		hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate;
+		hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id;
+
+		pkt->size += sizeof(u32) + sizeof(struct hfi_bitrate);
+		break;
+	}
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+	{
+		struct hfi_profile_level *hfi;
+		struct hal_profile_level *prop =
+			(struct hal_profile_level *) pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+		hfi = (struct hfi_profile_level *)
+			&pkt->rg_property_data[1];
+		hfi->level = prop->level;
+		hfi->profile = hal_to_hfi_type(HAL_PARAM_PROFILE_LEVEL_CURRENT,
+				prop->profile);
+		if (hfi->profile <= 0) {
+			hfi->profile = HFI_H264_PROFILE_HIGH;
+			dprintk(VIDC_WARN,
+					"Profile %d not supported, falling back to high\n",
+					prop->profile);
+		}
+
+		if (!hfi->level) {
+			hfi->level = 1;
+			dprintk(VIDC_WARN,
+					"Level %d not supported, falling back to high\n",
+					prop->level);
+		}
+
+		pkt->size += sizeof(u32) + sizeof(struct hfi_profile_level);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_ENTROPY_CONTROL:
+	{
+		struct hfi_h264_entropy_control *hfi;
+		struct hal_h264_entropy_control *prop =
+			(struct hal_h264_entropy_control *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL;
+		hfi = (struct hfi_h264_entropy_control *)
+			&pkt->rg_property_data[1];
+		hfi->entropy_mode = hal_to_hfi_type(
+		   HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
+		   prop->entropy_mode);
+		if (hfi->entropy_mode == HAL_H264_ENTROPY_CABAC)
+			hfi->cabac_model = hal_to_hfi_type(
+			   HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
+			   prop->cabac_model);
+		pkt->size += sizeof(u32) + sizeof(
+			struct hfi_h264_entropy_control);
+		break;
+	}
+	case HAL_PARAM_VENC_RATE_CONTROL:
+	{
+		u32 *rc;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
+		rc = (u32 *)pdata;
+		switch ((enum hal_rate_control) *rc) {
+		case HAL_RATE_CONTROL_OFF:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
+			break;
+		case HAL_RATE_CONTROL_CBR_CFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_CFR;
+			break;
+		case HAL_RATE_CONTROL_CBR_VFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_VFR;
+			break;
+		case HAL_RATE_CONTROL_VBR_CFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR;
+			break;
+		case HAL_RATE_CONTROL_VBR_VFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR;
+			break;
+		case HAL_RATE_CONTROL_MBR_CFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_CFR;
+			break;
+		case HAL_RATE_CONTROL_MBR_VFR:
+			pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_VFR;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+					"Invalid Rate control setting: %pK\n",
+					pdata);
+			break;
+		}
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION:
+	{
+		struct hfi_mpeg4_time_resolution *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION;
+		hfi = (struct hfi_mpeg4_time_resolution *)
+			&pkt->rg_property_data[1];
+		hfi->time_increment_resolution =
+			((struct hal_mpeg4_time_resolution *)pdata)->
+					time_increment_resolution;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION:
+	{
+		struct hfi_mpeg4_header_extension *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION;
+		hfi = (struct hfi_mpeg4_header_extension *)
+			&pkt->rg_property_data[1];
+		hfi->header_extension = (u32)(unsigned long) pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL:
+	{
+		struct hfi_h264_db_control *hfi;
+		struct hal_h264_db_control *prop =
+			(struct hal_h264_db_control *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		hfi = (struct hfi_h264_db_control *) &pkt->rg_property_data[1];
+		switch (prop->mode) {
+		case HAL_H264_DB_MODE_DISABLE:
+			hfi->mode = HFI_H264_DB_MODE_DISABLE;
+			break;
+		case HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY:
+			hfi->mode = HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+			break;
+		case HAL_H264_DB_MODE_ALL_BOUNDARY:
+			hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid deblocking mode: %#x\n",
+						  prop->mode);
+			break;
+		}
+		hfi->slice_alpha_offset = prop->slice_alpha_offset;
+		hfi->slice_beta_offset = prop->slice_beta_offset;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_h264_db_control);
+		break;
+	}
+	case HAL_PARAM_VENC_SESSION_QP:
+	{
+		struct hfi_quantization *hfi;
+		struct hal_quantization *hal_quant =
+			(struct hal_quantization *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SESSION_QP;
+		hfi = (struct hfi_quantization *) &pkt->rg_property_data[1];
+		hfi->qp_i = hal_quant->qpi;
+		hfi->qp_p = hal_quant->qpp;
+		hfi->qp_b = hal_quant->qpb;
+		hfi->layer_id = hal_quant->layer_id;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
+		break;
+	}
+	case HAL_PARAM_VENC_SESSION_QP_RANGE:
+	{
+		struct hfi_quantization_range *hfi;
+		struct hfi_quantization_range *hal_range =
+			(struct hfi_quantization_range *) pdata;
+		u32 min_qp, max_qp;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+		hfi = (struct hfi_quantization_range *)
+				&pkt->rg_property_data[1];
+
+		min_qp = hal_range->min_qp;
+		max_qp = hal_range->max_qp;
+
+		/* We'll be packing in the qp, so make sure we
+		 * won't be losing data when masking
+		 */
+		if (min_qp > 0xff || max_qp > 0xff) {
+			dprintk(VIDC_ERR, "qp value out of range\n");
+			rc = -ERANGE;
+			break;
+		}
+
+		/* When creating the packet, pack the qp value as
+		 * 0xiippbb, where ii = qp range for I-frames,
+		 * pp = qp range for P-frames, etc.
+		 */
+		hfi->min_qp = min_qp | min_qp << 8 | min_qp << 16;
+		hfi->max_qp = max_qp | max_qp << 8 | max_qp << 16;
+		hfi->layer_id = hal_range->layer_id;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_quantization_range);
+		break;
+	}
+	case HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED:
+	{
+		struct hfi_quantization_range *hfi;
+		struct hfi_quantization_range *hal_range =
+			(struct hfi_quantization_range *) pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
+		hfi = (struct hfi_quantization_range *)
+				&pkt->rg_property_data[1];
+
+		hfi->min_qp = hal_range->min_qp;
+		hfi->max_qp = hal_range->max_qp;
+		hfi->layer_id = hal_range->layer_id;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_quantization_range);
+		break;
+	}
+	case HAL_PARAM_VENC_SEARCH_RANGE:
+	{
+		struct hfi_vc1e_perf_cfg_type *hfi;
+		struct hal_vc1e_perf_cfg_type *hal_mv_searchrange =
+			(struct hal_vc1e_perf_cfg_type *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG;
+		hfi = (struct hfi_vc1e_perf_cfg_type *)
+				&pkt->rg_property_data[1];
+		hfi->search_range_x_subsampled[0] =
+			hal_mv_searchrange->i_frame.x_subsampled;
+		hfi->search_range_x_subsampled[1] =
+			hal_mv_searchrange->p_frame.x_subsampled;
+		hfi->search_range_x_subsampled[2] =
+			hal_mv_searchrange->b_frame.x_subsampled;
+		hfi->search_range_y_subsampled[0] =
+			hal_mv_searchrange->i_frame.y_subsampled;
+		hfi->search_range_y_subsampled[1] =
+			hal_mv_searchrange->p_frame.y_subsampled;
+		hfi->search_range_y_subsampled[2] =
+			hal_mv_searchrange->b_frame.y_subsampled;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_vc1e_perf_cfg_type);
+		break;
+	}
+	case HAL_PARAM_VENC_MAX_NUM_B_FRAMES:
+	{
+		struct hfi_max_num_b_frames *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES;
+		hfi = (struct hfi_max_num_b_frames *) &pkt->rg_property_data[1];
+		memcpy(hfi, (struct hfi_max_num_b_frames *) pdata,
+				sizeof(struct hfi_max_num_b_frames));
+		pkt->size += sizeof(u32) + sizeof(struct hfi_max_num_b_frames);
+		break;
+	}
+	case HAL_CONFIG_VENC_INTRA_PERIOD:
+	{
+		struct hfi_intra_period *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD;
+		hfi = (struct hfi_intra_period *) &pkt->rg_property_data[1];
+		memcpy(hfi, (struct hfi_intra_period *) pdata,
+				sizeof(struct hfi_intra_period));
+		pkt->size += sizeof(u32) + sizeof(struct hfi_intra_period);
+		break;
+	}
+	case HAL_CONFIG_VENC_IDR_PERIOD:
+	{
+		struct hfi_idr_period *hfi;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD;
+		hfi = (struct hfi_idr_period *) &pkt->rg_property_data[1];
+		hfi->idr_period = ((struct hfi_idr_period *) pdata)->idr_period;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_CONCEAL_COLOR:
+	{
+		struct hfi_conceal_color *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
+		hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1];
+		if (hfi)
+			hfi->conceal_color =
+				((struct hfi_conceal_color *) pdata)->
+				conceal_color;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VPE_OPERATIONS:
+	{
+		struct hfi_operations_type *hfi;
+
+		struct hal_operations *prop =
+			(struct hal_operations *) pdata;
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VPE_OPERATIONS;
+		hfi = (struct hfi_operations_type *) &pkt->rg_property_data[1];
+		switch (prop->rotate) {
+		case HAL_ROTATE_NONE:
+			hfi->rotation = HFI_ROTATE_NONE;
+			break;
+		case HAL_ROTATE_90:
+			hfi->rotation = HFI_ROTATE_90;
+			break;
+		case HAL_ROTATE_180:
+			hfi->rotation = HFI_ROTATE_180;
+			break;
+		case HAL_ROTATE_270:
+			hfi->rotation = HFI_ROTATE_270;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid rotation setting: %#x\n",
+				prop->rotate);
+			rc = -EINVAL;
+			break;
+		}
+		switch (prop->flip) {
+		case HAL_FLIP_NONE:
+			hfi->flip = HFI_FLIP_NONE;
+			break;
+		case HAL_FLIP_HORIZONTAL:
+			hfi->flip = HFI_FLIP_HORIZONTAL;
+			break;
+		case HAL_FLIP_VERTICAL:
+			hfi->flip = HFI_FLIP_VERTICAL;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid flip setting: %#x\n",
+				prop->flip);
+			rc = -EINVAL;
+			break;
+		}
+		pkt->size += sizeof(u32) + sizeof(struct hfi_operations_type);
+		break;
+	}
+	case HAL_PARAM_VENC_INTRA_REFRESH:
+	{
+		struct hfi_intra_refresh *hfi;
+		struct hal_intra_refresh *prop =
+			(struct hal_intra_refresh *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
+		hfi = (struct hfi_intra_refresh *) &pkt->rg_property_data[1];
+		switch (prop->mode) {
+		case HAL_INTRA_REFRESH_NONE:
+			hfi->mode = HFI_INTRA_REFRESH_NONE;
+			break;
+		case HAL_INTRA_REFRESH_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_ADAPTIVE;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE;
+			break;
+		case HAL_INTRA_REFRESH_RANDOM:
+			hfi->mode = HFI_INTRA_REFRESH_RANDOM;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+					"Invalid intra refresh setting: %#x\n",
+					prop->mode);
+			break;
+		}
+		hfi->air_mbs = prop->air_mbs;
+		hfi->air_ref = prop->air_ref;
+		hfi->cir_mbs = prop->cir_mbs;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_intra_refresh);
+		break;
+	}
+	case HAL_PARAM_VENC_MULTI_SLICE_CONTROL:
+	{
+		struct hfi_multi_slice_control *hfi;
+		struct hal_multi_slice_control *prop =
+			(struct hal_multi_slice_control *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL;
+		hfi = (struct hfi_multi_slice_control *)
+			&pkt->rg_property_data[1];
+		switch (prop->multi_slice) {
+		case HAL_MULTI_SLICE_OFF:
+			hfi->multi_slice = HFI_MULTI_SLICE_OFF;
+			break;
+		case HAL_MULTI_SLICE_GOB:
+			hfi->multi_slice = HFI_MULTI_SLICE_GOB;
+			break;
+		case HAL_MULTI_SLICE_BY_MB_COUNT:
+			hfi->multi_slice = HFI_MULTI_SLICE_BY_MB_COUNT;
+			break;
+		case HAL_MULTI_SLICE_BY_BYTE_COUNT:
+			hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid slice settings: %#x\n",
+				prop->multi_slice);
+			break;
+		}
+		hfi->slice_size = prop->slice_size;
+		pkt->size += sizeof(u32) + sizeof(struct
+					hfi_multi_slice_control);
+		break;
+	}
+	case HAL_PARAM_INDEX_EXTRADATA:
+	{
+		struct hfi_index_extradata_config *hfi;
+		struct hal_extradata_enable *extra = pdata;
+		int id = 0;
+
+		pkt->rg_property_data[0] =
+			get_hfi_extradata_index(extra->index);
+		hfi = (struct hfi_index_extradata_config *)
+			&pkt->rg_property_data[1];
+		hfi->enable = extra->enable;
+		id = get_hfi_extradata_id(extra->index);
+		if (id)
+			hfi->index_extra_data_id = id;
+		else {
+			dprintk(VIDC_WARN,
+				"Failed to find extradata id: %d\n",
+				id);
+			rc = -EINVAL;
+		}
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_index_extradata_config);
+		break;
+	}
+	case HAL_PARAM_VENC_SLICE_DELIVERY_MODE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_VUI_TIMING_INFO:
+	{
+		struct hfi_h264_vui_timing_info *hfi;
+		struct hal_h264_vui_timing_info *timing_info = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO;
+
+		hfi = (struct hfi_h264_vui_timing_info *)&pkt->
+			rg_property_data[1];
+		hfi->enable = timing_info->enable;
+		hfi->fixed_frame_rate = timing_info->fixed_frame_rate;
+		hfi->time_scale = timing_info->time_scale;
+
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_h264_vui_timing_info);
+		break;
+	}
+	case HAL_CONFIG_VPE_DEINTERLACE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_CONFIG_VPE_DEINTERLACE,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_GENERATE_AUDNAL:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_GENERATE_AUDNAL,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_BUFFER_ALLOC_MODE:
+	{
+		u32 buffer_type;
+		u32 buffer_mode;
+		struct hfi_buffer_alloc_mode *hfi;
+		struct hal_buffer_alloc_mode *alloc_info = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE;
+		hfi = (struct hfi_buffer_alloc_mode *)
+			&pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(alloc_info->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		buffer_mode = get_hfi_buf_mode(alloc_info->buffer_mode);
+		if (buffer_mode)
+			hfi->buffer_mode = buffer_mode;
+		else
+			return -EINVAL;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_buffer_alloc_mode);
+		break;
+	}
+	case HAL_PARAM_VDEC_FRAME_ASSEMBLY:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VDEC_SCS_THRESHOLD:
+	{
+		struct hfi_scs_threshold *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD;
+		hfi = (struct hfi_scs_threshold *) &pkt->rg_property_data[1];
+		hfi->threshold_value =
+			((struct hal_scs_threshold *) pdata)->threshold_value;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_scs_threshold);
+		break;
+	}
+	case HAL_PARAM_MVC_BUFFER_LAYOUT:
+	{
+		struct hfi_mvc_buffer_layout_descp_type *hfi;
+		struct hal_mvc_buffer_layout *layout_info = pdata;
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT;
+		hfi = (struct hfi_mvc_buffer_layout_descp_type *)
+			&pkt->rg_property_data[1];
+		hfi->layout_type = get_hfi_layout(layout_info->layout_type);
+		hfi->bright_view_first = layout_info->bright_view_first;
+		hfi->ngap = layout_info->ngap;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_mvc_buffer_layout_descp_type);
+		break;
+	}
+	case HAL_PARAM_VENC_LTRMODE:
+	{
+		struct hfi_ltr_mode *hfi;
+		struct hal_ltr_mode *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_LTRMODE;
+		hfi = (struct hfi_ltr_mode *) &pkt->rg_property_data[1];
+		hfi->ltr_mode = get_hfi_ltr_mode(hal->mode);
+		hfi->ltr_count = hal->count;
+		hfi->trust_mode = hal->trust_mode;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_mode);
+		break;
+	}
+	case HAL_CONFIG_VENC_USELTRFRAME:
+	{
+		struct hfi_ltr_use *hfi;
+		struct hal_ltr_use *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_USELTRFRAME;
+		hfi = (struct hfi_ltr_use *) &pkt->rg_property_data[1];
+		hfi->frames = hal->frames;
+		hfi->ref_ltr = hal->ref_ltr;
+		hfi->use_constrnt = hal->use_constraint;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_use);
+		break;
+	}
+	case HAL_CONFIG_VENC_MARKLTRFRAME:
+	{
+		struct hfi_ltr_mark *hfi;
+		struct hal_ltr_mark *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME;
+		hfi = (struct hfi_ltr_mark *) &pkt->rg_property_data[1];
+		hfi->mark_frame = hal->mark_frame;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_ltr_mark);
+		break;
+	}
+	case HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_HIER_P_NUM_FRAMES:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_ENABLE_INITIAL_QP:
+	{
+		struct hfi_initial_quantization *hfi;
+		struct hal_initial_quantization *quant = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_INITIAL_QP;
+		hfi = (struct hfi_initial_quantization *)
+			&pkt->rg_property_data[1];
+		hfi->init_qp_enable = quant->init_qp_enable;
+		hfi->qp_i = quant->qpi;
+		hfi->qp_p = quant->qpp;
+		hfi->qp_b = quant->qpb;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_initial_quantization);
+		break;
+	}
+	case HAL_PARAM_VPE_COLOR_SPACE_CONVERSION:
+	{
+		struct hfi_vpe_color_space_conversion *hfi = NULL;
+		struct hal_vpe_color_space_conversion *hal = pdata;
+
+		pkt->rg_property_data[0] =
+				HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION;
+		hfi = (struct hfi_vpe_color_space_conversion *)
+			&pkt->rg_property_data[1];
+		memcpy(hfi->csc_matrix, hal->csc_matrix,
+				sizeof(hfi->csc_matrix));
+		memcpy(hfi->csc_bias, hal->csc_bias, sizeof(hfi->csc_bias));
+		memcpy(hfi->csc_limit, hal->csc_limit, sizeof(hfi->csc_limit));
+		pkt->size += sizeof(u32) +
+				sizeof(struct hfi_vpe_color_space_conversion);
+		break;
+	}
+	case HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_NAL_SVC_EXT:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_CONFIG_VENC_PERF_MODE:
+	{
+		u32 hfi_perf_mode = 0;
+		enum hal_perf_mode hal_perf_mode = *(enum hal_perf_mode *)pdata;
+
+		switch (hal_perf_mode) {
+		case HAL_PERF_MODE_POWER_SAVE:
+			hfi_perf_mode = HFI_VENC_PERFMODE_POWER_SAVE;
+			break;
+		case HAL_PERF_MODE_POWER_MAX_QUALITY:
+			hfi_perf_mode = HFI_VENC_PERFMODE_MAX_QUALITY;
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+
+		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_PERF_MODE;
+		pkt->rg_property_data[1] = hfi_perf_mode;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VDEC_NON_SECURE_OUTPUT2:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_HIER_P_HYBRID_MODE:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE;
+		pkt->rg_property_data[1] =
+			((struct hfi_hybrid_hierp *)pdata)->layers;
+		pkt->size += sizeof(u32) +
+			sizeof(struct hfi_hybrid_hierp);
+		break;
+	}
+	case HAL_PARAM_VENC_MBI_STATISTICS_MODE:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_MBI_DUMPING;
+		pkt->rg_property_data[1] = hal_to_hfi_type(
+			HAL_PARAM_VENC_MBI_STATISTICS_MODE,
+				*(u32 *)pdata);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_FRAME_QP:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_FRAME_QP;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_BASELAYER_PRIORITYID:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO:
+	{
+		struct hfi_aspect_ratio *hfi = NULL;
+		struct hal_aspect_ratio *hal = pdata;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO;
+		hfi = (struct hfi_aspect_ratio *)
+			&pkt->rg_property_data[1];
+		memcpy(hfi, hal,
+			sizeof(struct hfi_aspect_ratio));
+		pkt->size += sizeof(u32) +
+				sizeof(struct hfi_aspect_ratio);
+		break;
+	}
+	case HAL_PARAM_VENC_BITRATE_TYPE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_VIDEO_SIGNAL_INFO:
+	{
+		struct hal_video_signal_info *hal = pdata;
+		struct hfi_video_signal_metadata *signal_info =
+			(struct hfi_video_signal_metadata *)
+			&pkt->rg_property_data[1];
+
+		signal_info->enable = true;
+		signal_info->video_format = MSM_VIDC_NTSC;
+		signal_info->video_full_range = hal->full_range;
+		signal_info->color_description = MSM_VIDC_COLOR_DESC_PRESENT;
+		signal_info->color_primaries = hal->color_space;
+		signal_info->transfer_characteristics = hal->transfer_chars;
+		signal_info->matrix_coeffs = hal->matrix_coeffs;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pkt->size += sizeof(u32) + sizeof(*signal_info);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_TRANSFORM_8x8:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			HFI_PROPERTY_PARAM_VENC_H264_8X8_TRANSFORM,
+			((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_IFRAMESIZE_TYPE:
+	{
+		enum hal_iframesize_type hal =
+			*(enum hal_iframesize_type *)pdata;
+		struct hfi_iframe_size *hfi = (struct hfi_iframe_size *)
+			&pkt->rg_property_data[1];
+
+		switch (hal) {
+		case HAL_IFRAMESIZE_TYPE_DEFAULT:
+			hfi->type = HFI_IFRAME_SIZE_DEFAULT;
+			break;
+		case HAL_IFRAMESIZE_TYPE_MEDIUM:
+			hfi->type = HFI_IFRAME_SIZE_MEDIUM;
+			break;
+		case HAL_IFRAMESIZE_TYPE_HUGE:
+			hfi->type = HFI_IFRAME_SIZE_HIGH;
+			break;
+		case HAL_IFRAMESIZE_TYPE_UNLIMITED:
+			hfi->type = HFI_IFRAME_SIZE_UNLIMITED;
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VENC_IFRAMESIZE;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_iframe_size);
+		break;
+	}
+	/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
+	case HAL_CONFIG_BUFFER_REQUIREMENTS:
+	case HAL_CONFIG_PRIORITY:
+	case HAL_CONFIG_BATCH_INFO:
+	case HAL_PARAM_METADATA_PASS_THROUGH:
+	case HAL_SYS_IDLE_INDICATOR:
+	case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+	case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED:
+	case HAL_PARAM_CHROMA_SITE:
+	case HAL_PARAM_PROPERTIES_SUPPORTED:
+	case HAL_PARAM_PROFILE_LEVEL_SUPPORTED:
+	case HAL_PARAM_CAPABILITY_SUPPORTED:
+	case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+	case HAL_PARAM_MULTI_VIEW_FORMAT:
+	case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+	case HAL_PARAM_CODEC_SUPPORTED:
+	case HAL_PARAM_VDEC_MULTI_VIEW_SELECT:
+	case HAL_PARAM_VDEC_MB_QUANTIZATION:
+	case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
+	case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
+	case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
+	case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
+	case HAL_CONFIG_VDEC_MULTI_STREAM:
+	case HAL_PARAM_VENC_MULTI_SLICE_INFO:
+	case HAL_CONFIG_VENC_TIMESTAMP_SCALE:
+	case HAL_PARAM_BUFFER_SIZE_MINIMUM:
+	default:
+		dprintk(VIDC_ERR, "DEFAULT: Calling %#x\n", ptype);
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+static int get_hfi_ssr_type(enum hal_ssr_trigger_type type)
+{
+	int rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+
+	switch (type) {
+	case SSR_ERR_FATAL:
+		rc = HFI_TEST_SSR_SW_ERR_FATAL;
+		break;
+	case SSR_SW_DIV_BY_ZERO:
+		rc = HFI_TEST_SSR_SW_DIV_BY_ZERO;
+		break;
+	case SSR_HW_WDOG_IRQ:
+		rc = HFI_TEST_SSR_HW_WDOG_IRQ;
+		break;
+	default:
+		dprintk(VIDC_WARN,
+			"SSR trigger type not recognized, using WDOG.\n");
+	}
+	return rc;
+}
+
+int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
+		struct hfi_cmd_sys_test_ssr_packet *pkt)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "Invalid params, device: %pK\n", pkt);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_sys_test_ssr_packet);
+	pkt->packet_type = HFI_CMD_SYS_TEST_SSR;
+	pkt->trigger_type = get_hfi_ssr_type(type);
+	return 0;
+}
+
+int create_pkt_cmd_sys_image_version(
+		struct hfi_cmd_sys_get_property_packet *pkt)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "%s invalid param :%pK\n", __func__, pkt);
+		return -EINVAL;
+	}
+	pkt->size = sizeof(struct hfi_cmd_sys_get_property_packet);
+	pkt->packet_type = HFI_CMD_SYS_GET_PROPERTY;
+	pkt->num_properties = 1;
+	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IMAGE_VERSION;
+	return 0;
+}
+
+static int create_3x_pkt_cmd_session_set_property(
+		struct hfi_cmd_session_set_property_packet *pkt,
+		struct hal_session *session,
+		enum hal_property ptype, void *pdata)
+{
+	int rc = 0;
+
+	if (!pkt || !session || !pdata)
+		return -EINVAL;
+
+	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
+	pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
+	pkt->session_id = hash32_ptr(session);
+	pkt->num_properties = 1;
+
+	/*
+	 * Any session set property which is different in 3XX packetization
+	 * should be added as a new case below. All unchanged session set
+	 * properties will be handled in the default case.
+	 */
+	switch (ptype) {
+	case HAL_PARAM_VDEC_MULTI_STREAM:
+	{
+		u32 buffer_type;
+		struct hfi_3x_multi_stream *hfi;
+		struct hal_multi_stream *prop =
+			(struct hal_multi_stream *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM;
+		hfi = (struct hfi_3x_multi_stream *) &pkt->rg_property_data[1];
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+		hfi->enable = prop->enable;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_3x_multi_stream);
+		break;
+	}
+	case HAL_PARAM_VENC_INTRA_REFRESH:
+	{
+		struct hfi_3x_intra_refresh *hfi;
+		struct hal_intra_refresh *prop =
+			(struct hal_intra_refresh *) pdata;
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH;
+		hfi = (struct hfi_3x_intra_refresh *) &pkt->rg_property_data[1];
+		hfi->mbs = 0;
+		switch (prop->mode) {
+		case HAL_INTRA_REFRESH_NONE:
+			hfi->mode = HFI_INTRA_REFRESH_NONE;
+			break;
+		case HAL_INTRA_REFRESH_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_ADAPTIVE;
+			hfi->mbs = prop->air_mbs;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC;
+			hfi->mbs = prop->cir_mbs;
+			break;
+		case HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE:
+			hfi->mode = HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE;
+			hfi->mbs = prop->air_mbs;
+			break;
+		case HAL_INTRA_REFRESH_RANDOM:
+			hfi->mode = HFI_INTRA_REFRESH_RANDOM;
+			hfi->mbs = prop->air_mbs;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"Invalid intra refresh setting: %d\n",
+				prop->mode);
+			break;
+		}
+		pkt->size += sizeof(u32) + sizeof(struct hfi_3x_intra_refresh);
+		break;
+	}
+	case HAL_PARAM_SYNC_BASED_INTERRUPT:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	case HAL_PARAM_VENC_VQZIP_SEI:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+				HFI_PROPERTY_PARAM_VENC_VQZIP_SEI_TYPE,
+				((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
+		break;
+	}
+	/* Deprecated param on Venus 3xx */
+	case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER:
+	{
+		rc = -ENOTSUPP;
+		break;
+	}
+	case HAL_PARAM_BUFFER_SIZE_MINIMUM:
+	{
+		struct hfi_buffer_size_minimum *hfi;
+		struct hal_buffer_size_minimum *prop =
+			(struct hal_buffer_size_minimum *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM;
+
+		hfi = (struct hfi_buffer_size_minimum *)
+			&pkt->rg_property_data[1];
+		hfi->buffer_size = prop->buffer_size;
+
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		pkt->size += sizeof(u32) + sizeof(struct
+				hfi_buffer_count_actual);
+		break;
+	}
+	case HAL_PARAM_VENC_H264_PIC_ORDER_CNT:
+	{
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_H264_PICORDER_CNT_TYPE;
+		pkt->rg_property_data[1] = *(u32 *)pdata;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_PARAM_VENC_LOW_LATENCY:
+	{
+		struct hfi_enable *hfi;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE;
+		hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+		hfi->enable = ((struct hal_enable *) pdata)->enable;
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
+	case HAL_CONFIG_VENC_BLUR_RESOLUTION:
+	{
+		struct hfi_frame_size *hfi;
+		struct hal_frame_size *prop = (struct hal_frame_size *) pdata;
+		u32 buffer_type;
+
+		pkt->rg_property_data[0] =
+			HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE;
+		hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1];
+		buffer_type = get_hfi_buffer(prop->buffer_type);
+		if (buffer_type)
+			hfi->buffer_type = buffer_type;
+		else
+			return -EINVAL;
+
+		hfi->height = prop->height;
+		hfi->width = prop->width;
+		pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
+		break;
+	}
+	default:
+		rc = create_pkt_cmd_session_set_property(pkt,
+				session, ptype, pdata);
+	}
+	return rc;
+}
+
+int create_pkt_cmd_session_sync_process(
+		struct hfi_cmd_session_sync_process_packet *pkt,
+		struct hal_session *session)
+{
+	if (!pkt || !session)
+		return -EINVAL;
+
+	*pkt = (struct hfi_cmd_session_sync_process_packet) {0};
+	pkt->size = sizeof(*pkt);
+	pkt->packet_type = HFI_CMD_SESSION_SYNC;
+	pkt->session_id = hash32_ptr(session);
+	pkt->sync_id = 0;
+
+	return 0;
+}
+
+static struct hfi_packetization_ops hfi_default = {
+	.sys_init = create_pkt_cmd_sys_init,
+	.sys_pc_prep = create_pkt_cmd_sys_pc_prep,
+	.sys_idle_indicator = create_pkt_cmd_sys_idle_indicator,
+	.sys_power_control = create_pkt_cmd_sys_power_control,
+	.sys_set_resource = create_pkt_cmd_sys_set_resource,
+	.sys_debug_config = create_pkt_cmd_sys_debug_config,
+	.sys_coverage_config = create_pkt_cmd_sys_coverage_config,
+	.sys_release_resource = create_pkt_cmd_sys_release_resource,
+	.sys_ping = create_pkt_cmd_sys_ping,
+	.sys_image_version = create_pkt_cmd_sys_image_version,
+	.ssr_cmd = create_pkt_ssr_cmd,
+	.session_init = create_pkt_cmd_sys_session_init,
+	.session_cmd = create_pkt_cmd_session_cmd,
+	.session_set_buffers = create_pkt_cmd_session_set_buffers,
+	.session_release_buffers = create_pkt_cmd_session_release_buffers,
+	.session_etb_decoder = create_pkt_cmd_session_etb_decoder,
+	.session_etb_encoder = create_pkt_cmd_session_etb_encoder,
+	.session_ftb = create_pkt_cmd_session_ftb,
+	.session_parse_seq_header = create_pkt_cmd_session_parse_seq_header,
+	.session_get_seq_hdr = create_pkt_cmd_session_get_seq_hdr,
+	.session_get_buf_req = create_pkt_cmd_session_get_buf_req,
+	.session_flush = create_pkt_cmd_session_flush,
+	.session_get_property = create_pkt_cmd_session_get_property,
+	.session_set_property = create_pkt_cmd_session_set_property,
+};
+
+struct hfi_packetization_ops *get_venus_3x_ops(void)
+{
+	static struct hfi_packetization_ops hfi_venus_3x;
+
+	hfi_venus_3x = hfi_default;
+
+	/* Override new HFI functions for HFI_PACKETIZATION_3XX here. */
+	hfi_venus_3x.session_set_property =
+		create_3x_pkt_cmd_session_set_property;
+	hfi_venus_3x.session_get_property =
+		create_3x_pkt_cmd_session_get_property;
+	hfi_venus_3x.session_cmd = create_3x_pkt_cmd_session_cmd;
+	hfi_venus_3x.session_sync_process = create_pkt_cmd_session_sync_process;
+
+	return &hfi_venus_3x;
+}
+
+struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
+			enum hfi_packetization_type type)
+{
+	dprintk(VIDC_DBG, "%s selected\n",
+		type == HFI_PACKETIZATION_LEGACY ? "legacy packetization" :
+		type == HFI_PACKETIZATION_3XX ? "3xx packetization" :
+		"Unknown hfi");
+
+	switch (type) {
+	case HFI_PACKETIZATION_LEGACY:
+		return &hfi_default;
+	case HFI_PACKETIZATION_3XX:
+		return get_venus_3x_ops();
+	}
+
+	return NULL;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_packetization.h b/drivers/media/platform/msm/vidc_3x/hfi_packetization.h
new file mode 100644
index 0000000..5fcbc5c
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/hfi_packetization.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __HFI_PACKETIZATION__
+#define __HFI_PACKETIZATION__
+
+#include <linux/types.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi.h"
+#include "vidc_hfi_api.h"
+
+#define call_hfi_pkt_op(q, op, args...)			\
+	(((q) && (q)->pkt_ops && (q)->pkt_ops->op) ?	\
+	((q)->pkt_ops->op(args)) : 0)
+
+enum hfi_packetization_type {
+	HFI_PACKETIZATION_LEGACY,
+	HFI_PACKETIZATION_3XX,
+};
+
+struct hfi_packetization_ops {
+	int (*sys_init)(struct hfi_cmd_sys_init_packet *pkt, u32 arch_type);
+	int (*sys_pc_prep)(struct hfi_cmd_sys_pc_prep_packet *pkt);
+	int (*sys_idle_indicator)(struct hfi_cmd_sys_set_property_packet *pkt,
+		u32 enable);
+	int (*sys_power_control)(struct hfi_cmd_sys_set_property_packet *pkt,
+		u32 enable);
+	int (*sys_set_resource)(
+		struct hfi_cmd_sys_set_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr,
+		void *resource_value);
+	int (*sys_debug_config)(struct hfi_cmd_sys_set_property_packet *pkt,
+			u32 mode);
+	int (*sys_coverage_config)(struct hfi_cmd_sys_set_property_packet *pkt,
+			u32 mode);
+	int (*sys_release_resource)(
+		struct hfi_cmd_sys_release_resource_packet *pkt,
+		struct vidc_resource_hdr *resource_hdr);
+	int (*sys_ping)(struct hfi_cmd_sys_ping_packet *pkt);
+	int (*sys_image_version)(struct hfi_cmd_sys_get_property_packet *pkt);
+	int (*ssr_cmd)(enum hal_ssr_trigger_type type,
+		struct hfi_cmd_sys_test_ssr_packet *pkt);
+	int (*session_init)(
+		struct hfi_cmd_sys_session_init_packet *pkt,
+		struct hal_session *session,
+		u32 session_domain, u32 session_codec);
+	int (*session_cmd)(struct vidc_hal_session_cmd_pkt *pkt,
+		int pkt_type, struct hal_session *session);
+	int (*session_set_buffers)(
+		struct hfi_cmd_session_set_buffers_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info);
+	int (*session_release_buffers)(
+		struct hfi_cmd_session_release_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_buffer_addr_info *buffer_info);
+	int (*session_etb_decoder)(
+		struct hfi_cmd_session_empty_buffer_compressed_packet *pkt,
+		struct hal_session *session,
+		struct vidc_frame_data *input_frame);
+	int (*session_etb_encoder)(
+		struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+		*pkt, struct hal_session *session,
+		struct vidc_frame_data *input_frame);
+	int (*session_ftb)(struct hfi_cmd_session_fill_buffer_packet *pkt,
+		struct hal_session *session,
+		struct vidc_frame_data *output_frame);
+	int (*session_parse_seq_header)(
+		struct hfi_cmd_session_parse_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_seq_hdr)(
+		struct hfi_cmd_session_get_sequence_header_packet *pkt,
+		struct hal_session *session, struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_buf_req)(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session);
+	int (*session_flush)(struct hfi_cmd_session_flush_packet *pkt,
+		struct hal_session *session, enum hal_flush flush_mode);
+	int (*session_get_property)(
+		struct hfi_cmd_session_get_property_packet *pkt,
+		struct hal_session *session, enum hal_property ptype);
+	int (*session_set_property)(
+		struct hfi_cmd_session_set_property_packet *pkt,
+		struct hal_session *session,
+		enum hal_property ptype, void *pdata);
+	int (*session_sync_process)(
+		struct hfi_cmd_session_sync_process_packet *pkt,
+		struct hal_session *session);
+};
+
+struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
+		enum hfi_packetization_type);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
new file mode 100644
index 0000000..ffcbdd9
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c
@@ -0,0 +1,1958 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/hash.h>
+#include <soc/qcom/smem.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_io.h"
+#include "msm_vidc_debug.h"
+#include "vidc_hfi.h"
+
+static enum vidc_status hfi_parse_init_done_properties(
+		struct msm_vidc_capability *capability,
+		u32 num_sessions, u8 *data_ptr, u32 num_properties,
+		u32 rem_bytes, u32 codec, u32 domain);
+
+static enum vidc_status hfi_map_err_status(u32 hfi_err)
+{
+	enum vidc_status vidc_err;
+
+	switch (hfi_err) {
+	case HFI_ERR_NONE:
+	case HFI_ERR_SESSION_SAME_STATE_OPERATION:
+		vidc_err = VIDC_ERR_NONE;
+		break;
+	case HFI_ERR_SYS_FATAL:
+		vidc_err = VIDC_ERR_HW_FATAL;
+		break;
+	case HFI_ERR_SYS_VERSION_MISMATCH:
+	case HFI_ERR_SYS_INVALID_PARAMETER:
+	case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE:
+	case HFI_ERR_SESSION_INVALID_PARAMETER:
+	case HFI_ERR_SESSION_INVALID_SESSION_ID:
+	case HFI_ERR_SESSION_INVALID_STREAM_ID:
+		vidc_err = VIDC_ERR_BAD_PARAM;
+		break;
+	case HFI_ERR_SYS_INSUFFICIENT_RESOURCES:
+	case HFI_ERR_SYS_UNSUPPORTED_DOMAIN:
+	case HFI_ERR_SYS_UNSUPPORTED_CODEC:
+	case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY:
+	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+	case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES:
+	case HFI_ERR_SESSION_UNSUPPORTED_STREAM:
+		vidc_err = VIDC_ERR_NOT_SUPPORTED;
+		break;
+	case HFI_ERR_SYS_MAX_SESSIONS_REACHED:
+		vidc_err = VIDC_ERR_MAX_CLIENTS;
+		break;
+	case HFI_ERR_SYS_SESSION_IN_USE:
+		vidc_err = VIDC_ERR_CLIENT_PRESENT;
+		break;
+	case HFI_ERR_SESSION_FATAL:
+		vidc_err = VIDC_ERR_CLIENT_FATAL;
+		break;
+	case HFI_ERR_SESSION_BAD_POINTER:
+		vidc_err = VIDC_ERR_BAD_PARAM;
+		break;
+	case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION:
+		vidc_err = VIDC_ERR_BAD_STATE;
+		break;
+	case HFI_ERR_SESSION_STREAM_CORRUPT:
+	case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED:
+		vidc_err = VIDC_ERR_BITSTREAM_ERR;
+		break;
+	case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED:
+		vidc_err = VIDC_ERR_IFRAME_EXPECTED;
+		break;
+	case HFI_ERR_SESSION_START_CODE_NOT_FOUND:
+		vidc_err = VIDC_ERR_START_CODE_NOT_FOUND;
+		break;
+	case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING:
+	default:
+		vidc_err = VIDC_ERR_FAIL;
+		break;
+	}
+	return vidc_err;
+}
+
+static enum msm_vidc_pixel_depth get_hal_pixel_depth(u32 hfi_bit_depth)
+{
+	switch (hfi_bit_depth) {
+	case HFI_BITDEPTH_8: return MSM_VIDC_BIT_DEPTH_8;
+	case HFI_BITDEPTH_9:
+	case HFI_BITDEPTH_10: return MSM_VIDC_BIT_DEPTH_10;
+	}
+	dprintk(VIDC_ERR, "Unsupported bit depth: %d\n", hfi_bit_depth);
+	return MSM_VIDC_BIT_DEPTH_UNSUPPORTED;
+}
+
+static int hfi_process_sess_evt_seq_changed(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_event event_notify = {0};
+	int num_properties_changed;
+	struct hfi_frame_size *frame_sz;
+	struct hfi_profile_level *profile_level;
+	struct hfi_bit_depth *pixel_depth;
+	struct hfi_pic_struct *pic_struct;
+	u8 *data_ptr;
+	int prop_id;
+	enum msm_vidc_pixel_depth luma_bit_depth, chroma_bit_depth;
+	struct hfi_colour_space *colour_info;
+
+	 /* Initialize pic_struct to unknown as default */
+	//event_notify.pic_struct = MSM_VIDC_PIC_STRUCT_UNKNOWN;
+
+	if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_init_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	event_notify.device_id = device_id;
+	event_notify.session_id = (void *)(uintptr_t)pkt->session_id;
+	event_notify.status = VIDC_ERR_NONE;
+	num_properties_changed = pkt->event_data2;
+	switch (pkt->event_data1) {
+	case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES:
+		event_notify.hal_event_type =
+			HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES;
+		break;
+	case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES:
+		event_notify.hal_event_type =
+			HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES;
+		break;
+	default:
+		break;
+	}
+
+	if (num_properties_changed) {
+		data_ptr = (u8 *) &pkt->rg_ext_event_data[0];
+		do {
+			prop_id = (int) *((u32 *)data_ptr);
+			switch (prop_id) {
+			case HFI_PROPERTY_PARAM_FRAME_SIZE:
+				data_ptr = data_ptr + sizeof(u32);
+				frame_sz =
+					(struct hfi_frame_size *) data_ptr;
+				event_notify.width = frame_sz->width;
+				event_notify.height = frame_sz->height;
+				dprintk(VIDC_DBG, "height: %d width: %d\n",
+					frame_sz->height, frame_sz->width);
+				data_ptr +=
+					sizeof(struct hfi_frame_size);
+				break;
+			case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
+				data_ptr = data_ptr + sizeof(u32);
+				profile_level =
+					(struct hfi_profile_level *) data_ptr;
+				dprintk(VIDC_DBG, "profile: %d level: %d\n",
+					profile_level->profile,
+					profile_level->level);
+				data_ptr +=
+					sizeof(struct hfi_profile_level);
+				break;
+			case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH:
+				data_ptr = data_ptr + sizeof(u32);
+				pixel_depth = (struct hfi_bit_depth *) data_ptr;
+				/*
+				 * Luma and chroma can have different bitdepths.
+				 * Driver should rely on luma and chroma
+				 * bitdepth for determining output bitdepth
+				 * type.
+				 *
+				 * pixel_depth->bitdepth will include luma
+				 * bitdepth info in bits 0..15 and chroma
+				 * bitdept in bits 16..31.
+				 */
+				luma_bit_depth = get_hal_pixel_depth(
+					pixel_depth->bit_depth &
+					GENMASK(15, 0));
+				chroma_bit_depth = get_hal_pixel_depth(
+					(pixel_depth->bit_depth &
+					GENMASK(31, 16)) >> 16);
+				if (luma_bit_depth == MSM_VIDC_BIT_DEPTH_10 ||
+					chroma_bit_depth ==
+						MSM_VIDC_BIT_DEPTH_10)
+					event_notify.bit_depth =
+						MSM_VIDC_BIT_DEPTH_10;
+				else
+					event_notify.bit_depth = luma_bit_depth;
+				dprintk(VIDC_DBG,
+					"bitdepth(%d), luma_bit_depth(%d), chroma_bit_depth(%d)\n",
+					event_notify.bit_depth, luma_bit_depth,
+					chroma_bit_depth);
+				data_ptr += sizeof(struct hfi_bit_depth);
+				break;
+			case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT:
+				data_ptr = data_ptr + sizeof(u32);
+				pic_struct = (struct hfi_pic_struct *) data_ptr;
+				event_notify.pic_struct =
+					pic_struct->progressive_only;
+				dprintk(VIDC_DBG,
+					"Progressive only flag: %d\n",
+						pic_struct->progressive_only);
+				data_ptr +=
+					sizeof(struct hfi_pic_struct);
+				break;
+			case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE:
+				data_ptr = data_ptr + sizeof(u32);
+				colour_info =
+					(struct hfi_colour_space *) data_ptr;
+				event_notify.colour_space =
+					colour_info->colour_space;
+				dprintk(VIDC_DBG,
+					"Colour space value is: %d\n",
+						colour_info->colour_space);
+				data_ptr +=
+					sizeof(struct hfi_colour_space);
+				break;
+			default:
+				dprintk(VIDC_ERR,
+					"%s cmd: %#x not supported\n",
+					__func__, prop_id);
+				break;
+			}
+			num_properties_changed--;
+		} while (num_properties_changed > 0);
+	}
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_EVENT_CHANGE,
+		.response.event = event_notify,
+	};
+
+	return 0;
+}
+
+static int hfi_process_evt_release_buffer_ref(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_event event_notify = {0};
+	struct hfi_msg_release_buffer_ref_event_packet *data;
+
+	dprintk(VIDC_DBG,
+			"RECEIVED: EVENT_NOTIFY - release_buffer_reference\n");
+	if (sizeof(struct hfi_msg_event_notify_packet)
+		> pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_init_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	data = (struct hfi_msg_release_buffer_ref_event_packet *)
+				pkt->rg_ext_event_data;
+
+	event_notify.device_id = device_id;
+	event_notify.session_id = (void *)(uintptr_t)pkt->session_id;
+	event_notify.status = VIDC_ERR_NONE;
+	event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE;
+	event_notify.packet_buffer = data->packet_buffer;
+	event_notify.extra_data_buffer = data->extra_data_buffer;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_EVENT_CHANGE,
+		.response.event = event_notify,
+	};
+
+	return 0;
+}
+
+static int hfi_process_sys_error(u32 device_id, struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	cmd_done.device_id = device_id;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SYS_ERROR,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_error(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->event_data1);
+	dprintk(VIDC_INFO, "Received: SESSION_ERROR with event id : %d\n",
+		pkt->event_data1);
+	switch (pkt->event_data1) {
+	case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
+	case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
+	case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+	case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
+		cmd_done.status = VIDC_ERR_NONE;
+		dprintk(VIDC_INFO, "Non Fatal: HFI_EVENT_SESSION_ERROR\n");
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_RESPONSE_UNUSED,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	default:
+		dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR\n");
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_ERROR,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	}
+}
+
+static int hfi_process_event_notify(u32 device_id,
+		struct hfi_msg_event_notify_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n");
+
+	if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -E2BIG;
+	}
+
+	switch (pkt->event_id) {
+	case HFI_EVENT_SYS_ERROR:
+		dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d, %#x\n",
+			pkt->event_data1, pkt->event_data2);
+		return hfi_process_sys_error(device_id, info);
+	case HFI_EVENT_SESSION_ERROR:
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR[%#x]\n",
+				pkt->session_id);
+		return hfi_process_session_error(device_id, pkt, info);
+
+	case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
+		dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED[%#x]\n",
+			pkt->session_id);
+		return hfi_process_sess_evt_seq_changed(device_id, pkt, info);
+
+	case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
+		dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE[%#x]\n",
+			pkt->session_id);
+		return hfi_process_evt_release_buffer_ref(device_id, pkt, info);
+
+	case HFI_EVENT_SESSION_PROPERTY_CHANGED:
+	default:
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_RESPONSE_UNUSED,
+		};
+
+		return 0;
+	}
+}
+
+static int hfi_process_sys_init_done(u32 device_id,
+		struct hfi_msg_sys_init_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	enum vidc_status status = VIDC_ERR_NONE;
+
+	dprintk(VIDC_DBG, "RECEIVED: SYS_INIT_DONE\n");
+	if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) {
+		dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", __func__,
+				pkt->size);
+		return -E2BIG;
+	}
+	if (!pkt->num_properties) {
+		dprintk(VIDC_ERR,
+				"hal_process_sys_init_done: no_properties\n");
+		status = VIDC_ERR_FAIL;
+		goto err_no_prop;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: status %#x\n",
+			__func__, status);
+		goto err_no_prop;
+	}
+
+err_no_prop:
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = NULL;
+	cmd_done.status = (u32)status;
+	cmd_done.size = sizeof(struct vidc_hal_sys_init_done);
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SYS_INIT_DONE,
+		.response.cmd = cmd_done,
+	};
+	return 0;
+}
+
+static int hfi_process_sys_rel_resource_done(u32 device_id,
+		struct hfi_msg_sys_release_resource_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	enum vidc_status status = VIDC_ERR_NONE;
+	u32 pkt_size;
+
+	dprintk(VIDC_DBG, "RECEIVED: SYS_RELEASE_RESOURCE_DONE\n");
+	pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet);
+	if (pkt_size > pkt->size) {
+		dprintk(VIDC_ERR,
+			"hal_process_sys_rel_resource_done: bad size: %d\n",
+			pkt->size);
+		return -E2BIG;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = NULL;
+	cmd_done.status = (u32) status;
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SYS_RELEASE_RESOURCE_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+enum hal_capability get_hal_cap_type(u32 capability_type)
+{
+	enum hal_capability hal_cap = 0;
+
+	switch (capability_type) {
+	case HFI_CAPABILITY_FRAME_WIDTH:
+		hal_cap = HAL_CAPABILITY_FRAME_WIDTH;
+		break;
+	case HFI_CAPABILITY_FRAME_HEIGHT:
+		hal_cap = HAL_CAPABILITY_FRAME_HEIGHT;
+		break;
+	case HFI_CAPABILITY_MBS_PER_FRAME:
+		hal_cap = HAL_CAPABILITY_MBS_PER_FRAME;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND:
+		hal_cap = HAL_CAPABILITY_MBS_PER_SECOND;
+		break;
+	case HFI_CAPABILITY_FRAMERATE:
+		hal_cap = HAL_CAPABILITY_FRAMERATE;
+		break;
+	case HFI_CAPABILITY_SCALE_X:
+		hal_cap = HAL_CAPABILITY_SCALE_X;
+		break;
+	case HFI_CAPABILITY_SCALE_Y:
+		hal_cap = HAL_CAPABILITY_SCALE_Y;
+		break;
+	case HFI_CAPABILITY_BITRATE:
+		hal_cap = HAL_CAPABILITY_BITRATE;
+		break;
+	case HFI_CAPABILITY_BFRAME:
+		hal_cap = HAL_CAPABILITY_BFRAME;
+		break;
+	case HFI_CAPABILITY_PEAKBITRATE:
+		hal_cap = HAL_CAPABILITY_PEAKBITRATE;
+		break;
+	case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
+		hal_cap = HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS;
+		break;
+	case HFI_CAPABILITY_ENC_LTR_COUNT:
+		hal_cap = HAL_CAPABILITY_ENC_LTR_COUNT;
+		break;
+	case HFI_CAPABILITY_CP_OUTPUT2_THRESH:
+		hal_cap = HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD;
+		break;
+	case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS:
+		hal_cap = HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS;
+		break;
+	case HFI_CAPABILITY_LCU_SIZE:
+		hal_cap = HAL_CAPABILITY_LCU_SIZE;
+		break;
+	case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS:
+		hal_cap = HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE:
+		hal_cap = HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE;
+		break;
+	default:
+		dprintk(VIDC_DBG, "%s: unknown capablity %#x\n",
+			__func__, capability_type);
+		break;
+	}
+
+	return hal_cap;
+}
+
+static inline void copy_cap_prop(
+		struct hfi_capability_supported *in,
+		struct msm_vidc_capability *capability)
+{
+	struct hal_capability_supported *out = NULL;
+
+	if (!in || !capability) {
+		dprintk(VIDC_ERR, "%s Invalid input parameters\n",
+			__func__);
+		return;
+	}
+
+	switch (in->capability_type) {
+	case HFI_CAPABILITY_FRAME_WIDTH:
+		out = &capability->width;
+		break;
+	case HFI_CAPABILITY_FRAME_HEIGHT:
+		out = &capability->height;
+		break;
+	case HFI_CAPABILITY_MBS_PER_FRAME:
+		out = &capability->mbs_per_frame;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND:
+		out = &capability->mbs_per_sec;
+		break;
+	case HFI_CAPABILITY_FRAMERATE:
+		out = &capability->frame_rate;
+		break;
+	case HFI_CAPABILITY_SCALE_X:
+		out = &capability->scale_x;
+		break;
+	case HFI_CAPABILITY_SCALE_Y:
+		out = &capability->scale_y;
+		break;
+	case HFI_CAPABILITY_BITRATE:
+		out = &capability->bitrate;
+		break;
+	case HFI_CAPABILITY_BFRAME:
+		out = &capability->bframe;
+		break;
+	case HFI_CAPABILITY_PEAKBITRATE:
+		out = &capability->peakbitrate;
+		break;
+	case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS:
+		out = &capability->hier_p;
+		break;
+	case HFI_CAPABILITY_ENC_LTR_COUNT:
+		out = &capability->ltr_count;
+		break;
+	case HFI_CAPABILITY_CP_OUTPUT2_THRESH:
+		out = &capability->secure_output2_threshold;
+		break;
+	case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS:
+		out = &capability->hier_b;
+		break;
+	case HFI_CAPABILITY_LCU_SIZE:
+		out = &capability->lcu_size;
+		break;
+	case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS:
+		out = &capability->hier_p_hybrid;
+		break;
+	case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE:
+		out = &capability->mbs_per_sec_power_save;
+		break;
+	default:
+		dprintk(VIDC_DBG, "%s: unknown capablity %#x\n",
+			__func__, in->capability_type);
+		break;
+	}
+
+	if (out) {
+		out->capability_type = get_hal_cap_type(in->capability_type);
+		out->min = in->min;
+		out->max = in->max;
+		out->step_size = in->step_size;
+	}
+}
+
+static int hfi_fill_codec_info(u8 *data_ptr,
+		struct vidc_hal_sys_init_done *sys_init_done) {
+	u32 i;
+	u32 codecs = 0, codec_count = 0, size = 0;
+	struct msm_vidc_capability *capability;
+	u32 prop_id = *((u32 *)data_ptr);
+	u8 *orig_data_ptr = data_ptr;
+
+	if (prop_id ==  HFI_PROPERTY_PARAM_CODEC_SUPPORTED) {
+		struct hfi_codec_supported *prop;
+
+		data_ptr = data_ptr + sizeof(u32);
+		prop = (struct hfi_codec_supported *) data_ptr;
+		sys_init_done->dec_codec_supported =
+			prop->decoder_codec_supported;
+		sys_init_done->enc_codec_supported =
+			prop->encoder_codec_supported;
+		size = sizeof(struct hfi_codec_supported) + sizeof(u32);
+	} else {
+		dprintk(VIDC_WARN,
+			"%s: prop_id %#x, expected codec_supported property\n",
+			__func__, prop_id);
+	}
+
+	codecs = sys_init_done->dec_codec_supported;
+	for (i = 0; i < 8 * sizeof(codecs); i++) {
+		if ((1 << i) & codecs) {
+			capability =
+				&sys_init_done->capabilities[codec_count++];
+			capability->codec =
+				vidc_get_hal_codec((1 << i) & codecs);
+			capability->domain =
+				vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER);
+		}
+	}
+	codecs = sys_init_done->enc_codec_supported;
+	for (i = 0; i < 8 * sizeof(codecs); i++) {
+		if ((1 << i) & codecs) {
+			capability =
+				&sys_init_done->capabilities[codec_count++];
+			capability->codec =
+				vidc_get_hal_codec((1 << i) & codecs);
+			capability->domain =
+				vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER);
+		}
+	}
+	sys_init_done->codec_count = codec_count;
+
+	prop_id = *((u32 *)(orig_data_ptr + size));
+	if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) {
+		struct hfi_max_sessions_supported *prop =
+			(struct hfi_max_sessions_supported *)
+			(orig_data_ptr + size + sizeof(u32));
+
+		sys_init_done->max_sessions_supported = prop->max_sessions;
+		size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32);
+		dprintk(VIDC_DBG, "max_sessions_supported %d\n",
+				prop->max_sessions);
+	}
+	return size;
+}
+
+enum vidc_status hfi_process_session_init_done_prop_read(
+		struct hfi_msg_sys_session_init_done_packet *pkt,
+		struct vidc_hal_session_init_done *session_init_done)
+{
+	enum vidc_status status = VIDC_ERR_NONE;
+	struct msm_vidc_capability *capability = NULL;
+	u32 rem_bytes, num_properties;
+	u8 *data_ptr;
+
+	rem_bytes = pkt->size - sizeof(struct
+			hfi_msg_sys_session_init_done_packet) + sizeof(u32);
+	if (!rem_bytes) {
+		dprintk(VIDC_ERR, "%s: invalid property info\n", __func__);
+		return VIDC_ERR_FAIL;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: error status 0x%x\n", __func__, status);
+		return status;
+	}
+
+	data_ptr = (u8 *)&pkt->rg_property_data[0];
+	num_properties = pkt->num_properties;
+
+	capability = &session_init_done->capability;
+	status = hfi_parse_init_done_properties(
+			capability, 1, data_ptr, num_properties, rem_bytes,
+			vidc_get_hfi_codec(capability->codec),
+			vidc_get_hfi_domain(capability->domain));
+	if (status) {
+		dprintk(VIDC_ERR, "%s: parse status 0x%x\n", __func__, status);
+		return status;
+	}
+
+	return status;
+}
+
+static int copy_caps_to_sessions(struct hfi_capability_supported *cap,
+		u32 num_caps, struct msm_vidc_capability *capabilities,
+		u32 num_sessions, u32 codecs, u32 domain)
+{
+	u32 i = 0, j = 0;
+	struct msm_vidc_capability *capability;
+	u32 sess_codec;
+	u32 sess_domain;
+
+	/*
+	 * iterate over num_sessions and copy all the capabilities
+	 * to matching sessions.
+	 */
+	for (i = 0; i < num_sessions; i++) {
+		sess_codec = 0;
+		sess_domain = 0;
+		capability = &capabilities[i];
+
+		if (capability->codec)
+			sess_codec =
+				vidc_get_hfi_codec(capability->codec);
+		if (capability->domain)
+			sess_domain =
+				vidc_get_hfi_domain(capability->domain);
+
+		if (!(sess_codec & codecs && sess_domain & domain))
+			continue;
+
+		for (j = 0; j < num_caps; j++)
+			copy_cap_prop(&cap[j], capability);
+	}
+
+	return 0;
+}
+
+static int copy_alloc_mode_to_sessions(
+		struct hfi_buffer_alloc_mode_supported *prop,
+		struct msm_vidc_capability *capabilities,
+		u32 num_sessions, u32 codecs, u32 domain)
+{
+	u32 i = 0, j = 0;
+	struct msm_vidc_capability *capability;
+	u32 sess_codec;
+	u32 sess_domain;
+
+	/*
+	 * iterate over num_sessions and copy all the entries
+	 * to matching sessions.
+	 */
+	for (i = 0; i < num_sessions; i++) {
+		sess_codec = 0;
+		sess_domain = 0;
+		capability = &capabilities[i];
+
+		if (capability->codec)
+			sess_codec =
+				vidc_get_hfi_codec(capability->codec);
+		if (capability->domain)
+			sess_domain =
+				vidc_get_hfi_domain(capability->domain);
+
+		if (!(sess_codec & codecs && sess_domain & domain))
+			continue;
+
+		for (j = 0; j < prop->num_entries; j++) {
+			if (prop->buffer_type == HFI_BUFFER_OUTPUT ||
+				prop->buffer_type == HFI_BUFFER_OUTPUT2) {
+				switch (prop->rg_data[j]) {
+				case HFI_BUFFER_MODE_STATIC:
+					capability->alloc_mode_out |=
+						HAL_BUFFER_MODE_STATIC;
+					break;
+				case HFI_BUFFER_MODE_RING:
+					capability->alloc_mode_out |=
+						HAL_BUFFER_MODE_RING;
+					break;
+				case HFI_BUFFER_MODE_DYNAMIC:
+					capability->alloc_mode_out |=
+						HAL_BUFFER_MODE_DYNAMIC;
+					break;
+				}
+			} else if (prop->buffer_type == HFI_BUFFER_INPUT) {
+				switch (prop->rg_data[j]) {
+				case HFI_BUFFER_MODE_STATIC:
+					capability->alloc_mode_in |=
+						HAL_BUFFER_MODE_STATIC;
+					break;
+				case HFI_BUFFER_MODE_RING:
+					capability->alloc_mode_in |=
+						HAL_BUFFER_MODE_RING;
+					break;
+				case HFI_BUFFER_MODE_DYNAMIC:
+					capability->alloc_mode_in |=
+						HAL_BUFFER_MODE_DYNAMIC;
+					break;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static enum vidc_status hfi_parse_init_done_properties(
+		struct msm_vidc_capability *capabilities,
+		u32 num_sessions, u8 *data_ptr, u32 num_properties,
+		u32 rem_bytes, u32 codecs, u32 domain)
+{
+	enum vidc_status status = VIDC_ERR_NONE;
+	u32 prop_id, next_offset;
+
+	while (status == VIDC_ERR_NONE && num_properties &&
+			rem_bytes >= sizeof(u32)) {
+
+		prop_id = *((u32 *)data_ptr);
+		next_offset = sizeof(u32);
+
+		switch (prop_id) {
+		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
+		{
+			struct hfi_codec_mask_supported *prop =
+				(struct hfi_codec_mask_supported *)
+				(data_ptr + next_offset);
+
+			codecs = prop->codecs;
+			domain = prop->video_domains;
+			next_offset += sizeof(struct hfi_codec_mask_supported);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
+		{
+			struct hfi_capability_supported_info *prop =
+				(struct hfi_capability_supported_info *)
+				(data_ptr + next_offset);
+
+			if ((rem_bytes - next_offset) < prop->num_capabilities *
+				sizeof(struct hfi_capability_supported)) {
+				status = VIDC_ERR_BAD_PARAM;
+				break;
+			}
+			next_offset += sizeof(u32) +
+				prop->num_capabilities *
+				sizeof(struct hfi_capability_supported);
+
+			copy_caps_to_sessions(&prop->rg_data[0],
+					prop->num_capabilities,
+					capabilities, num_sessions,
+					codecs, domain);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+		{
+			struct hfi_uncompressed_format_supported *prop =
+				(struct hfi_uncompressed_format_supported *)
+				(data_ptr + next_offset);
+			u32 num_format_entries;
+			char *fmt_ptr;
+			struct hfi_uncompressed_plane_info *plane_info;
+
+			if ((rem_bytes - next_offset) < sizeof(*prop)) {
+				status = VIDC_ERR_BAD_PARAM;
+				break;
+			}
+			num_format_entries = prop->format_entries;
+			next_offset = sizeof(*prop);
+			fmt_ptr = (char *)&prop->rg_format_info[0];
+
+			while (num_format_entries) {
+				u32 bytes_to_skip;
+
+				plane_info =
+				(struct hfi_uncompressed_plane_info *) fmt_ptr;
+
+				if ((rem_bytes - next_offset) <
+						sizeof(*plane_info)) {
+					status = VIDC_ERR_BAD_PARAM;
+					break;
+				}
+				bytes_to_skip = sizeof(*plane_info) -
+					sizeof(struct
+					hfi_uncompressed_plane_constraints) +
+					plane_info->num_planes *
+					sizeof(struct
+					hfi_uncompressed_plane_constraints);
+
+				fmt_ptr += bytes_to_skip;
+				next_offset += bytes_to_skip;
+				num_format_entries--;
+			}
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED:
+		{
+			struct hfi_properties_supported *prop =
+				(struct hfi_properties_supported *)
+				(data_ptr + next_offset);
+			next_offset += sizeof(*prop) - sizeof(u32)
+				+ prop->num_properties * sizeof(u32);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
+		{
+			struct msm_vidc_capability capability;
+			char *ptr = NULL;
+			u32 count = 0;
+			u32 prof_count = 0;
+			struct hfi_profile_level *prof_level;
+			struct hfi_profile_level_supported *prop =
+				(struct hfi_profile_level_supported *)
+				(data_ptr + next_offset);
+
+			ptr = (char *) &prop->rg_profile_level[0];
+			prof_count = prop->profile_count;
+			next_offset += sizeof(u32);
+
+			if (prof_count > MAX_PROFILE_COUNT) {
+				prof_count = MAX_PROFILE_COUNT;
+				dprintk(VIDC_WARN,
+					"prop count exceeds max profile count\n");
+				break;
+			}
+			while (prof_count) {
+				prof_level = (struct hfi_profile_level *)ptr;
+				capability.
+				profile_level.profile_level[count].profile
+					= prof_level->profile;
+				capability.
+				profile_level.profile_level[count].level
+					= prof_level->level;
+				prof_count--;
+				count++;
+				ptr += sizeof(struct hfi_profile_level);
+				next_offset += sizeof(struct hfi_profile_level);
+			}
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED:
+		{
+			next_offset +=
+				sizeof(struct hfi_interlace_format_supported);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED:
+		{
+			next_offset +=
+				sizeof(struct hfi_nal_stream_format_supported);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT:
+		{
+			next_offset += sizeof(u32);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE:
+		{
+			next_offset += sizeof(u32);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH:
+		{
+			next_offset +=
+				sizeof(struct hfi_intra_refresh);
+			num_properties--;
+			break;
+		}
+		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
+		{
+			struct hfi_buffer_alloc_mode_supported *prop =
+				(struct hfi_buffer_alloc_mode_supported *)
+				(data_ptr + next_offset);
+
+			if (prop->num_entries >= 32) {
+				dprintk(VIDC_ERR,
+					"%s - num_entries: %d from f/w seems suspect\n",
+					__func__, prop->num_entries);
+				break;
+			}
+			next_offset +=
+				sizeof(struct hfi_buffer_alloc_mode_supported) -
+				sizeof(u32) + prop->num_entries * sizeof(u32);
+
+			copy_alloc_mode_to_sessions(prop,
+					capabilities, num_sessions,
+					codecs, domain);
+
+			num_properties--;
+			break;
+		}
+		default:
+			dprintk(VIDC_DBG,
+				"%s: default case - data_ptr %pK, prop_id 0x%x\n",
+				__func__, data_ptr, prop_id);
+			break;
+		}
+		rem_bytes -= next_offset;
+		data_ptr += next_offset;
+	}
+
+	return status;
+}
+
+enum vidc_status hfi_process_sys_init_done_prop_read(
+	struct hfi_msg_sys_init_done_packet *pkt,
+	struct vidc_hal_sys_init_done *sys_init_done)
+{
+	enum vidc_status status = VIDC_ERR_NONE;
+	u32 rem_bytes, bytes_read, num_properties;
+	u8 *data_ptr;
+	u32 codecs = 0, domain = 0;
+
+	if (!pkt || !sys_init_done) {
+		dprintk(VIDC_ERR,
+			"hfi_msg_sys_init_done: Invalid input\n");
+		return VIDC_ERR_FAIL;
+	}
+
+	rem_bytes = pkt->size - sizeof(struct
+			hfi_msg_sys_init_done_packet) + sizeof(u32);
+
+	if (!rem_bytes) {
+		dprintk(VIDC_ERR,
+			"hfi_msg_sys_init_done: missing_prop_info\n");
+		return VIDC_ERR_FAIL;
+	}
+
+	status = hfi_map_err_status(pkt->error_type);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: status %#x\n", __func__, status);
+		return status;
+	}
+
+	data_ptr = (u8 *) &pkt->rg_property_data[0];
+	num_properties = pkt->num_properties;
+	dprintk(VIDC_DBG,
+		"%s: data_start %pK, num_properties %#x\n",
+		__func__, data_ptr, num_properties);
+	if (!num_properties) {
+		sys_init_done->capabilities = NULL;
+		dprintk(VIDC_DBG,
+			"Venus didn't set any properties in SYS_INIT_DONE");
+		return status;
+	}
+	bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done);
+	data_ptr += bytes_read;
+	rem_bytes -= bytes_read;
+	num_properties--;
+
+	status = hfi_parse_init_done_properties(
+			sys_init_done->capabilities,
+			VIDC_MAX_SESSIONS, data_ptr, num_properties,
+			rem_bytes, codecs, domain);
+	if (status) {
+		dprintk(VIDC_ERR, "%s: parse status %#x\n",
+			__func__, status);
+		return status;
+	}
+
+	return status;
+}
+
+static void hfi_process_sess_get_prop_dec_entropy(
+	struct hfi_msg_session_property_info_packet *prop,
+	enum hal_h264_entropy *entropy)
+{
+	u32 req_bytes, hfi_entropy;
+
+	req_bytes = prop->size - sizeof(
+			struct hfi_msg_session_property_info_packet);
+
+	if (!req_bytes || req_bytes % sizeof(hfi_entropy)) {
+		dprintk(VIDC_ERR, "%s: bad packet: %d\n", __func__, req_bytes);
+		return;
+	}
+
+	hfi_entropy = prop->rg_property_data[1];
+	*entropy =
+		hfi_entropy == HFI_H264_ENTROPY_CAVLC ? HAL_H264_ENTROPY_CAVLC :
+		hfi_entropy == HFI_H264_ENTROPY_CABAC ? HAL_H264_ENTROPY_CABAC :
+							HAL_UNUSED_ENTROPY;
+}
+
+static void hfi_process_sess_get_prop_profile_level(
+	struct hfi_msg_session_property_info_packet *prop,
+	struct hfi_profile_level *profile_level)
+{
+	struct hfi_profile_level *hfi_profile_level;
+	u32 req_bytes;
+
+	dprintk(VIDC_DBG, "Entered %s\n", __func__);
+	if (!prop) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_profile_level: bad_prop: %pK\n",
+			prop);
+		return;
+	}
+	req_bytes = prop->size - sizeof(
+			struct hfi_msg_session_property_info_packet);
+
+	if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level)) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_profile_level: bad_pkt: %d\n",
+			req_bytes);
+		return;
+	}
+	hfi_profile_level = (struct hfi_profile_level *)
+				&prop->rg_property_data[1];
+	profile_level->profile = hfi_profile_level->profile;
+	profile_level->level = hfi_profile_level->level;
+	dprintk(VIDC_DBG, "%s profile: %d level: %d\n",
+		__func__, profile_level->profile,
+		profile_level->level);
+}
+
+static void hfi_process_sess_get_prop_buf_req(
+	struct hfi_msg_session_property_info_packet *prop,
+	struct buffer_requirements *buffreq)
+{
+	struct hfi_buffer_requirements *hfi_buf_req;
+	u32 req_bytes;
+
+	if (!prop) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req: bad_prop: %pK\n",
+			prop);
+		return;
+	}
+
+	req_bytes = prop->size - sizeof(
+			struct hfi_msg_session_property_info_packet);
+	if (!req_bytes || req_bytes % sizeof(struct hfi_buffer_requirements) ||
+		!prop->rg_property_data[1]) {
+		dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req: bad_pkt: %d\n",
+			req_bytes);
+		return;
+	}
+
+	hfi_buf_req = (struct hfi_buffer_requirements *)
+		&prop->rg_property_data[1];
+
+	if (!hfi_buf_req) {
+		dprintk(VIDC_ERR, "%s - invalid buffer req pointer\n",
+			__func__);
+		return;
+	}
+
+	while (req_bytes) {
+		if (hfi_buf_req->buffer_size &&
+			hfi_buf_req->buffer_count_min > hfi_buf_req->
+			buffer_count_actual)
+			dprintk(VIDC_WARN,
+				"Bad buffer requirements for %#x: min %d, actual %d\n",
+				hfi_buf_req->buffer_type,
+				hfi_buf_req->buffer_count_min,
+				hfi_buf_req->buffer_count_actual);
+
+		dprintk(VIDC_DBG, "got buffer requirements for: %d\n",
+					hfi_buf_req->buffer_type);
+		switch (hfi_buf_req->buffer_type) {
+		case HFI_BUFFER_INPUT:
+			memcpy(&buffreq->buffer[0], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[0].buffer_type = HAL_BUFFER_INPUT;
+			break;
+		case HFI_BUFFER_OUTPUT:
+			memcpy(&buffreq->buffer[1], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[1].buffer_type = HAL_BUFFER_OUTPUT;
+			break;
+		case HFI_BUFFER_OUTPUT2:
+			memcpy(&buffreq->buffer[2], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[2].buffer_type = HAL_BUFFER_OUTPUT2;
+			break;
+		case HFI_BUFFER_EXTRADATA_INPUT:
+			memcpy(&buffreq->buffer[3], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[3].buffer_type =
+				HAL_BUFFER_EXTRADATA_INPUT;
+			break;
+		case HFI_BUFFER_EXTRADATA_OUTPUT:
+			memcpy(&buffreq->buffer[4], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[4].buffer_type =
+				HAL_BUFFER_EXTRADATA_OUTPUT;
+			break;
+		case HFI_BUFFER_EXTRADATA_OUTPUT2:
+			memcpy(&buffreq->buffer[5], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[5].buffer_type =
+				HAL_BUFFER_EXTRADATA_OUTPUT2;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH:
+			memcpy(&buffreq->buffer[6], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[6].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH_1:
+			memcpy(&buffreq->buffer[7], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[7].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_1;
+			break;
+		case HFI_BUFFER_INTERNAL_SCRATCH_2:
+			memcpy(&buffreq->buffer[8], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[8].buffer_type =
+				HAL_BUFFER_INTERNAL_SCRATCH_2;
+			break;
+		case HFI_BUFFER_INTERNAL_PERSIST:
+			memcpy(&buffreq->buffer[9], hfi_buf_req,
+			sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[9].buffer_type =
+				HAL_BUFFER_INTERNAL_PERSIST;
+			break;
+		case HFI_BUFFER_INTERNAL_PERSIST_1:
+			memcpy(&buffreq->buffer[10], hfi_buf_req,
+				sizeof(struct hfi_buffer_requirements));
+			buffreq->buffer[10].buffer_type =
+				HAL_BUFFER_INTERNAL_PERSIST_1;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+			"hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n",
+			hfi_buf_req->buffer_type);
+			break;
+		}
+		req_bytes -= sizeof(struct hfi_buffer_requirements);
+		hfi_buf_req++;
+	}
+}
+
+static int hfi_process_session_prop_info(u32 device_id,
+		struct hfi_msg_session_property_info_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	struct hfi_profile_level profile_level = {0};
+	enum hal_h264_entropy entropy = HAL_UNUSED_ENTROPY;
+	struct buffer_requirements buff_req = { { {0} } };
+
+	dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO[%#x]\n",
+			pkt->session_id);
+
+	if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_prop_info: bad_pkt_size\n");
+		return -E2BIG;
+	} else if (!pkt->num_properties) {
+		dprintk(VIDC_ERR,
+			"hal_process_session_prop_info: no_properties\n");
+		return -EINVAL;
+	}
+
+	switch (pkt->rg_property_data[0]) {
+	case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
+		hfi_process_sess_get_prop_buf_req(pkt, &buff_req);
+		cmd_done.device_id = device_id;
+		cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		cmd_done.status = VIDC_ERR_NONE;
+		cmd_done.data.property.buf_req = buff_req;
+		cmd_done.size = sizeof(buff_req);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_PROPERTY_INFO,
+			.response.cmd = cmd_done,
+		};
+
+		return 0;
+	case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
+		hfi_process_sess_get_prop_profile_level(pkt, &profile_level);
+		cmd_done.device_id = device_id;
+		cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		cmd_done.status = VIDC_ERR_NONE;
+		cmd_done.data.property.profile_level =
+			(struct hal_profile_level) {
+				.profile = profile_level.profile,
+				.level = profile_level.level,
+			};
+		cmd_done.size = sizeof(struct hal_profile_level);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_PROPERTY_INFO,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
+		hfi_process_sess_get_prop_dec_entropy(pkt, &entropy);
+		cmd_done.device_id = device_id;
+		cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		cmd_done.status = VIDC_ERR_NONE;
+		cmd_done.data.property.h264_entropy = entropy;
+		cmd_done.size = sizeof(enum hal_h264_entropy);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_SESSION_PROPERTY_INFO,
+			.response.cmd = cmd_done,
+		};
+		return 0;
+	default:
+		dprintk(VIDC_DBG,
+				"hal_process_session_prop_info: unknown_prop_id: %x\n",
+				pkt->rg_property_data[0]);
+		return -ENOTSUPP;
+	}
+}
+
+static int hfi_process_session_init_done(u32 device_id,
+		struct hfi_msg_sys_session_init_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+	struct vidc_hal_session_init_done session_init_done = { {0} };
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_INIT_DONE[%x]\n", pkt->session_id);
+
+	if (sizeof(struct hfi_msg_sys_session_init_done_packet) > pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_init_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	if (!cmd_done.status) {
+		cmd_done.status = hfi_process_session_init_done_prop_read(
+			pkt, &session_init_done);
+	}
+
+	cmd_done.data.session_init_done = session_init_done;
+	cmd_done.size = sizeof(struct vidc_hal_session_init_done);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_INIT_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_load_res_done(u32 device_id,
+		struct hfi_msg_session_load_resources_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%#x]\n",
+		pkt->session_id);
+
+	if (sizeof(struct hfi_msg_session_load_resources_done_packet) !=
+		pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_load_res_done: bad packet size: %d\n",
+				pkt->size);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_LOAD_RESOURCE_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_flush_done(u32 device_id,
+		struct hfi_msg_session_flush_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_flush_done: bad packet size: %d\n",
+				pkt->size);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = sizeof(u32);
+
+	switch (pkt->flush_type) {
+	case HFI_FLUSH_OUTPUT:
+		cmd_done.data.flush_type = HAL_FLUSH_OUTPUT;
+		break;
+	case HFI_FLUSH_INPUT:
+		cmd_done.data.flush_type = HAL_FLUSH_INPUT;
+		break;
+	case HFI_FLUSH_ALL:
+		cmd_done.data.flush_type = HAL_FLUSH_ALL;
+		break;
+	default:
+		dprintk(VIDC_ERR,
+				"%s: invalid flush type!", __func__);
+		return -EINVAL;
+	}
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_FLUSH_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_etb_done(u32 device_id,
+		struct hfi_msg_session_empty_buffer_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_data_done data_done = {0};
+	struct hfi_picture_type *hfi_picture_type = NULL;
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id);
+
+	if (!pkt || pkt->size <
+		sizeof(struct hfi_msg_session_empty_buffer_done_packet)) {
+		dprintk(VIDC_ERR,
+				"hal_process_session_etb_done: bad_pkt_size\n");
+		return -E2BIG;
+	}
+
+	data_done.device_id = device_id;
+	data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	data_done.status = hfi_map_err_status(pkt->error_type);
+	data_done.size = sizeof(struct msm_vidc_cb_data_done);
+	data_done.clnt_data = pkt->input_tag;
+	data_done.input_done.offset = pkt->offset;
+	data_done.input_done.filled_len = pkt->filled_len;
+	data_done.input_done.packet_buffer =
+		(ion_phys_addr_t)pkt->packet_buffer;
+	data_done.input_done.extra_data_buffer =
+		(ion_phys_addr_t)pkt->extra_data_buffer;
+	data_done.input_done.status =
+		hfi_map_err_status(pkt->error_type);
+	hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[0];
+	if (hfi_picture_type->is_sync_frame) {
+		if (hfi_picture_type->picture_type)
+			data_done.input_done.flags =
+				hfi_picture_type->picture_type;
+		else
+			dprintk(VIDC_DBG,
+				"Non-Sync frame sent for H264/HEVC\n");
+	}
+
+	trace_msm_v4l2_vidc_buffer_event_end("ETB",
+		(u32)pkt->packet_buffer, -1, -1,
+		pkt->filled_len, pkt->offset);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_ETB_DONE,
+		.response.data = data_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_ftb_done(
+		u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_data_done data_done = {0};
+	bool is_decoder = false, is_encoder = false;
+
+	if (!msg_hdr) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	is_encoder = msg_hdr->size == sizeof(struct
+			hfi_msg_session_fill_buffer_done_compressed_packet) + 4;
+	is_decoder = msg_hdr->size == sizeof(struct
+			hfi_msg_session_fbd_uncompressed_plane0_packet) + 4;
+
+	if (!(is_encoder ^ is_decoder)) {
+		dprintk(VIDC_ERR, "Ambiguous packet (%#x) received (size %d)\n",
+				msg_hdr->packet, msg_hdr->size);
+		return -EBADHANDLE;
+	}
+
+	if (is_encoder) {
+		struct hfi_msg_session_fill_buffer_done_compressed_packet *pkt =
+		(struct hfi_msg_session_fill_buffer_done_compressed_packet *)
+		msg_hdr;
+		dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n",
+				pkt->session_id);
+		if (sizeof(struct
+			hfi_msg_session_fill_buffer_done_compressed_packet)
+			> pkt->size) {
+			dprintk(VIDC_ERR,
+				"hal_process_session_ftb_done: bad_pkt_size\n");
+			return -E2BIG;
+		} else if (pkt->error_type != HFI_ERR_NONE) {
+			dprintk(VIDC_ERR,
+				"got buffer back with error %x\n",
+				pkt->error_type);
+			/* Proceed with the FBD */
+		}
+
+		data_done.device_id = device_id;
+		data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		data_done.status = hfi_map_err_status(pkt->error_type);
+		data_done.size = sizeof(struct msm_vidc_cb_data_done);
+		data_done.clnt_data = 0;
+
+		data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+		data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
+		data_done.output_done.flags1 = pkt->flags;
+		data_done.output_done.mark_target = pkt->mark_target;
+		data_done.output_done.mark_data = pkt->mark_data;
+		data_done.output_done.stats = pkt->stats;
+		data_done.output_done.offset1 = pkt->offset;
+		data_done.output_done.alloc_len1 = pkt->alloc_len;
+		data_done.output_done.filled_len1 = pkt->filled_len;
+		data_done.output_done.picture_type = pkt->picture_type;
+		data_done.output_done.packet_buffer1 =
+			(ion_phys_addr_t)pkt->packet_buffer;
+		data_done.output_done.extra_data_buffer =
+			(ion_phys_addr_t)pkt->extra_data_buffer;
+		data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
+	} else /* if (is_decoder) */ {
+		struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt =
+		(struct	hfi_msg_session_fbd_uncompressed_plane0_packet *)
+		msg_hdr;
+
+		dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n",
+				pkt->session_id);
+		if (sizeof(
+			struct hfi_msg_session_fbd_uncompressed_plane0_packet) >
+			pkt->size) {
+			dprintk(VIDC_ERR,
+					"hal_process_session_ftb_done: bad_pkt_size\n");
+			return -E2BIG;
+		}
+
+		data_done.device_id = device_id;
+		data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+		data_done.status = hfi_map_err_status(pkt->error_type);
+		data_done.size = sizeof(struct msm_vidc_cb_data_done);
+		data_done.clnt_data = 0;
+
+		data_done.output_done.stream_id = pkt->stream_id;
+		data_done.output_done.view_id = pkt->view_id;
+		data_done.output_done.timestamp_hi = pkt->time_stamp_hi;
+		data_done.output_done.timestamp_lo = pkt->time_stamp_lo;
+		data_done.output_done.flags1 = pkt->flags;
+		data_done.output_done.mark_target = pkt->mark_target;
+		data_done.output_done.mark_data = pkt->mark_data;
+		data_done.output_done.stats = pkt->stats;
+		data_done.output_done.alloc_len1 = pkt->alloc_len;
+		data_done.output_done.filled_len1 = pkt->filled_len;
+		data_done.output_done.offset1 = pkt->offset;
+		data_done.output_done.frame_width = pkt->frame_width;
+		data_done.output_done.frame_height = pkt->frame_height;
+		data_done.output_done.start_x_coord = pkt->start_x_coord;
+		data_done.output_done.start_y_coord = pkt->start_y_coord;
+		data_done.output_done.input_tag1 = pkt->input_tag;
+		data_done.output_done.picture_type = pkt->picture_type;
+		data_done.output_done.packet_buffer1 = pkt->packet_buffer;
+		data_done.output_done.extra_data_buffer =
+			pkt->extra_data_buffer;
+
+		if (!pkt->stream_id)
+			data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT;
+		else if (pkt->stream_id == 1)
+			data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT2;
+	}
+
+	trace_msm_v4l2_vidc_buffer_event_end("FTB",
+		(u32)data_done.output_done.packet_buffer1,
+		(((u64)data_done.output_done.timestamp_hi) << 32)
+		+ ((u64)data_done.output_done.timestamp_lo),
+		data_done.output_done.alloc_len1,
+		data_done.output_done.filled_len1,
+		data_done.output_done.offset1);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_FTB_DONE,
+		.response.data = data_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_start_done(u32 device_id,
+		struct hfi_msg_session_start_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_session_start_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_START_DONE,
+		.response.cmd = cmd_done,
+	};
+	return 0;
+}
+
+static int hfi_process_session_stop_done(u32 device_id,
+		struct hfi_msg_session_stop_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_session_stop_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_STOP_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_rel_res_done(u32 device_id,
+		struct hfi_msg_session_release_resources_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%#x]\n",
+		pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_session_release_resources_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_RELEASE_RESOURCE_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_rel_buf_done(u32 device_id,
+		struct hfi_msg_session_release_buffers_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	if (!pkt || pkt->size <
+		sizeof(struct hfi_msg_session_release_buffers_done_packet)) {
+		dprintk(VIDC_ERR, "bad packet/packet size %d\n",
+			pkt ? pkt->size : 0);
+		return -E2BIG;
+	}
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_BUFFER_DONE[%#x]\n",
+			pkt->session_id);
+
+	cmd_done.device_id = device_id;
+	cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done);
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	if (pkt->rg_buffer_info) {
+		cmd_done.data.buffer_info =
+			*(struct hal_buffer_info *)pkt->rg_buffer_info;
+		cmd_done.size = sizeof(struct hal_buffer_info);
+	} else {
+		dprintk(VIDC_ERR, "invalid payload in rel_buff_done\n");
+	}
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_RELEASE_BUFFER_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_end_done(u32 device_id,
+		struct hfi_msg_sys_session_end_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_sys_session_end_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n", __func__);
+		return -E2BIG;
+	}
+
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_END_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_abort_done(u32 device_id,
+	struct hfi_msg_sys_session_abort_done_packet *pkt,
+	struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n",
+			pkt->session_id);
+
+	if (!pkt || pkt->size !=
+		sizeof(struct hfi_msg_sys_session_abort_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size: %d\n",
+				__func__, pkt ? pkt->size : 0);
+		return -E2BIG;
+	}
+	cmd_done.device_id = device_id;
+	cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	cmd_done.status = hfi_map_err_status(pkt->error_type);
+	cmd_done.size = 0;
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_ABORT_DONE,
+		.response.cmd = cmd_done,
+	};
+
+	return 0;
+}
+
+static int hfi_process_session_get_seq_hdr_done(
+		u32 device_id,
+		struct hfi_msg_session_get_sequence_header_done_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	struct msm_vidc_cb_data_done data_done = {0};
+
+	if (!pkt || pkt->size !=
+			sizeof(struct
+			hfi_msg_session_get_sequence_header_done_packet)) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -E2BIG;
+	}
+
+	dprintk(VIDC_DBG, "RECEIVED:SESSION_GET_SEQ_HDR_DONE[%#x]\n",
+			pkt->session_id);
+
+	data_done.device_id = device_id;
+	data_done.size = sizeof(struct msm_vidc_cb_data_done);
+	data_done.session_id = (void *)(uintptr_t)pkt->session_id;
+	data_done.status = hfi_map_err_status(pkt->error_type);
+	data_done.output_done.packet_buffer1 =
+		(ion_phys_addr_t)pkt->sequence_header;
+	data_done.output_done.filled_len1 = pkt->header_len;
+	dprintk(VIDC_INFO, "seq_hdr: %#x, Length: %d\n",
+			pkt->sequence_header, pkt->header_len);
+
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_SESSION_GET_SEQ_HDR_DONE,
+		.response.data = data_done,
+	};
+
+	return 0;
+}
+
+static void hfi_process_sys_get_prop_image_version(
+		struct hfi_msg_sys_property_info_packet *pkt)
+{
+	int i = 0;
+	u32 smem_block_size = 0;
+	u8 *smem_table_ptr;
+	char version[256];
+	const u32 version_string_size = 128;
+	const u32 smem_image_index_venus = 14 * 128;
+	u8 *str_image_version;
+	int req_bytes;
+
+	req_bytes = pkt->size - sizeof(*pkt);
+	if (req_bytes < version_string_size ||
+			!pkt->rg_property_data[1] ||
+			pkt->num_properties > 1) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_get_prop_image_version: bad_pkt: %d\n",
+				req_bytes);
+		return;
+	}
+	str_image_version = (u8 *)&pkt->rg_property_data[1];
+	/*
+	 * The version string returned by firmware includes null
+	 * characters at the start and in between. Replace the null
+	 * characters with space, to print the version info.
+	 */
+	for (i = 0; i < version_string_size; i++) {
+		if (str_image_version[i] != '\0')
+			version[i] = str_image_version[i];
+		else
+			version[i] = ' ';
+	}
+	version[i] = '\0';
+	dprintk(VIDC_DBG, "F/W version: %s\n", version);
+
+	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+			&smem_block_size, 0, SMEM_ANY_HOST_FLAG);
+	if ((smem_image_index_venus + version_string_size) <= smem_block_size &&
+			smem_table_ptr)
+		memcpy(smem_table_ptr + smem_image_index_venus,
+				str_image_version, version_string_size);
+}
+
+static int hfi_process_sys_property_info(u32 device_id,
+		struct hfi_msg_sys_property_info_packet *pkt,
+		struct msm_vidc_cb_info *info)
+{
+	if (!pkt) {
+		dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+		return -EINVAL;
+	} else if (pkt->size < sizeof(*pkt)) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_property_info: bad_pkt_size\n");
+		return -E2BIG;
+	} else if (!pkt->num_properties) {
+		dprintk(VIDC_ERR,
+				"hfi_process_sys_property_info: no_properties\n");
+		return -EINVAL;
+	}
+
+	switch (pkt->rg_property_data[0]) {
+	case HFI_PROPERTY_SYS_IMAGE_VERSION:
+		hfi_process_sys_get_prop_image_version(pkt);
+
+		*info = (struct msm_vidc_cb_info) {
+			.response_type =  HAL_RESPONSE_UNUSED,
+		};
+		return 0;
+	default:
+		dprintk(VIDC_DBG,
+				"hfi_process_sys_property_info: unknown_prop_id: %x\n",
+				pkt->rg_property_data[0]);
+		return -ENOTSUPP;
+	}
+
+}
+
+static int hfi_process_ignore(u32 device_id,
+		struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info)
+{
+	*info = (struct msm_vidc_cb_info) {
+		.response_type =  HAL_RESPONSE_UNUSED,
+	};
+
+	return 0;
+}
+
+int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info)
+{
+	typedef int (*pkt_func_def)(u32, void *, struct msm_vidc_cb_info *info);
+	pkt_func_def pkt_func = NULL;
+
+	if (!info || !msg_hdr || msg_hdr->size < VIDC_IFACEQ_MIN_PKT_SIZE) {
+		dprintk(VIDC_ERR, "%s: bad packet/packet size\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	dprintk(VIDC_DBG, "Parse response %#x\n", msg_hdr->packet);
+	switch (msg_hdr->packet) {
+	case HFI_MSG_EVENT_NOTIFY:
+		pkt_func = (pkt_func_def)hfi_process_event_notify;
+		break;
+	case  HFI_MSG_SYS_INIT_DONE:
+		pkt_func = (pkt_func_def)hfi_process_sys_init_done;
+		break;
+	case HFI_MSG_SYS_SESSION_INIT_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_init_done;
+		break;
+	case HFI_MSG_SYS_PROPERTY_INFO:
+		pkt_func = (pkt_func_def)hfi_process_sys_property_info;
+		break;
+	case HFI_MSG_SYS_SESSION_END_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_end_done;
+		break;
+	case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_load_res_done;
+		break;
+	case HFI_MSG_SESSION_START_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_start_done;
+		break;
+	case HFI_MSG_SESSION_STOP_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_stop_done;
+		break;
+	case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_etb_done;
+		break;
+	case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_ftb_done;
+		break;
+	case HFI_MSG_SESSION_FLUSH_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_flush_done;
+		break;
+	case HFI_MSG_SESSION_PROPERTY_INFO:
+		pkt_func = (pkt_func_def)hfi_process_session_prop_info;
+		break;
+	case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_rel_res_done;
+		break;
+	case HFI_MSG_SYS_RELEASE_RESOURCE:
+		pkt_func = (pkt_func_def)hfi_process_sys_rel_resource_done;
+		break;
+	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+		pkt_func = (pkt_func_def) hfi_process_session_get_seq_hdr_done;
+		break;
+	case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_rel_buf_done;
+		break;
+	case HFI_MSG_SYS_SESSION_ABORT_DONE:
+		pkt_func = (pkt_func_def)hfi_process_session_abort_done;
+		break;
+	case HFI_MSG_SESSION_SYNC_DONE:
+		pkt_func = (pkt_func_def)hfi_process_ignore;
+		break;
+	default:
+		dprintk(VIDC_DBG, "Unable to parse message: %#x\n",
+				msg_hdr->packet);
+		break;
+	}
+
+	return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_smem.c b/drivers/media/platform/msm/vidc_3x/msm_smem.c
new file mode 100644
index 0000000..a6d5476
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_smem.c
@@ -0,0 +1,701 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <asm/dma-iommu.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-direction.h>
+#include <linux/iommu.h>
+#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/msm_ion.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "media/msm_vidc.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_resources.h"
+
+struct smem_client {
+	int mem_type;
+	void *clnt;
+	struct msm_vidc_platform_resources *res;
+	enum session_type session_type;
+};
+
+static int get_device_address(struct smem_client *smem_client,
+		struct ion_handle *hndl, unsigned long align,
+		ion_phys_addr_t *iova, unsigned long *buffer_size,
+		unsigned long flags, enum hal_buffer buffer_type,
+		struct dma_mapping_info *mapping_info)
+{
+	int rc = 0;
+	struct ion_client *clnt = NULL;
+	struct dma_buf *buf = NULL;
+	struct dma_buf_attachment *attach;
+	struct sg_table *table = NULL;
+	struct context_bank_info *cb = NULL;
+
+	if (!iova || !buffer_size || !hndl || !smem_client || !mapping_info) {
+		dprintk(VIDC_ERR, "Invalid params: %pK, %pK, %pK, %pK\n",
+				smem_client, hndl, iova, buffer_size);
+		return -EINVAL;
+	}
+
+	clnt = smem_client->clnt;
+	if (!clnt) {
+		dprintk(VIDC_ERR, "Invalid client\n");
+		return -EINVAL;
+	}
+
+	if (is_iommu_present(smem_client->res)) {
+		cb = msm_smem_get_context_bank(smem_client, flags & SMEM_SECURE,
+				buffer_type);
+		if (!cb) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to get context bank device\n",
+				 __func__);
+			rc = -EIO;
+			goto mem_map_failed;
+		}
+
+		/* Convert an Ion handle to a dma buf */
+		buf = ion_share_dma_buf(clnt, hndl);
+		if (IS_ERR_OR_NULL(buf)) {
+			rc = PTR_ERR(buf) ?: -ENOMEM;
+			dprintk(VIDC_ERR, "Share ION buf to DMA failed\n");
+			goto mem_map_failed;
+		}
+
+		/* Prepare a dma buf for dma on the given device */
+		attach = dma_buf_attach(buf, cb->dev);
+		if (IS_ERR_OR_NULL(attach)) {
+			rc = PTR_ERR(attach) ?: -ENOMEM;
+			dprintk(VIDC_ERR, "Failed to attach dmabuf\n");
+			goto mem_buf_attach_failed;
+		}
+
+		/* Get the scatterlist for the given attachment */
+		table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+		if (IS_ERR_OR_NULL(table)) {
+			rc = PTR_ERR(table) ?: -ENOMEM;
+			dprintk(VIDC_ERR, "Failed to map table\n");
+			goto mem_map_table_failed;
+		}
+
+		/* debug trace's need to be updated later */
+		trace_msm_smem_buffer_iommu_op_start("MAP", 0, 0,
+			align, *iova, *buffer_size);
+
+		/* Map a scatterlist into an SMMU */
+		rc = msm_dma_map_sg_lazy(cb->dev, table->sgl, table->nents,
+				DMA_BIDIRECTIONAL, buf);
+		if (rc != table->nents) {
+			dprintk(VIDC_ERR,
+				"Mapping failed with rc(%d), expected rc(%d)\n",
+				rc, table->nents);
+			rc = -ENOMEM;
+			goto mem_map_sg_failed;
+		}
+		if (table->sgl) {
+			dprintk(VIDC_DBG,
+				"%s: CB : %s, DMA buf: %pK, device: %pK, attach: %pK, table: %pK, table sgl: %pK, rc: %d, dma_address: %pa\n",
+				__func__, cb->name, buf, cb->dev, attach,
+				table, table->sgl, rc,
+				&table->sgl->dma_address);
+
+			*iova = table->sgl->dma_address;
+			*buffer_size = table->sgl->dma_length;
+		} else {
+			dprintk(VIDC_ERR, "sgl is NULL\n");
+			rc = -ENOMEM;
+			goto mem_map_sg_failed;
+		}
+
+		mapping_info->dev = cb->dev;
+		mapping_info->mapping = cb->mapping;
+		mapping_info->table = table;
+		mapping_info->attach = attach;
+		mapping_info->buf = buf;
+
+		trace_msm_smem_buffer_iommu_op_end("MAP", 0, 0,
+			align, *iova, *buffer_size);
+	} else {
+		dprintk(VIDC_DBG, "Using physical memory address\n");
+		rc = ion_phys(clnt, hndl, iova, (size_t *)buffer_size);
+		if (rc) {
+			dprintk(VIDC_ERR, "ion memory map failed - %d\n", rc);
+			goto mem_map_failed;
+		}
+	}
+
+	dprintk(VIDC_DBG, "mapped ion handle %pK to %pa\n", hndl, iova);
+	return 0;
+mem_map_sg_failed:
+	dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
+mem_map_table_failed:
+	dma_buf_detach(buf, attach);
+mem_buf_attach_failed:
+	dma_buf_put(buf);
+mem_map_failed:
+	return rc;
+}
+
+static void put_device_address(struct smem_client *smem_client,
+	struct ion_handle *hndl, u32 flags,
+	struct dma_mapping_info *mapping_info,
+	enum hal_buffer buffer_type)
+{
+	struct ion_client *clnt = NULL;
+
+	if (!hndl || !smem_client || !mapping_info) {
+		dprintk(VIDC_WARN, "Invalid params: %pK, %pK\n",
+				smem_client, hndl);
+		return;
+	}
+
+	if (!mapping_info->dev || !mapping_info->table ||
+		!mapping_info->buf || !mapping_info->attach) {
+		dprintk(VIDC_WARN, "Invalid params:\n");
+		return;
+	}
+
+	clnt = smem_client->clnt;
+	if (!clnt) {
+		dprintk(VIDC_WARN, "Invalid client\n");
+		return;
+	}
+	if (is_iommu_present(smem_client->res)) {
+		dprintk(VIDC_DBG,
+			"Calling dma_unmap_sg - device: %pK, address: %pa, buf: %pK, table: %pK, attach: %pK\n",
+			mapping_info->dev,
+			&mapping_info->table->sgl->dma_address,
+			mapping_info->buf, mapping_info->table,
+			mapping_info->attach);
+
+		trace_msm_smem_buffer_iommu_op_start("UNMAP", 0, 0, 0, 0, 0);
+		msm_dma_unmap_sg(mapping_info->dev, mapping_info->table->sgl,
+			mapping_info->table->nents, DMA_BIDIRECTIONAL,
+			mapping_info->buf);
+		dma_buf_unmap_attachment(mapping_info->attach,
+			mapping_info->table, DMA_BIDIRECTIONAL);
+		dma_buf_detach(mapping_info->buf, mapping_info->attach);
+		dma_buf_put(mapping_info->buf);
+		trace_msm_smem_buffer_iommu_op_end("UNMAP", 0, 0, 0, 0, 0);
+	}
+}
+
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+		struct msm_smem *mem, enum hal_buffer buffer_type)
+{
+	struct ion_handle *hndl;
+	ion_phys_addr_t iova = 0;
+	unsigned long buffer_size = 0;
+	int rc = 0;
+	unsigned long align = SZ_4K;
+	unsigned long ion_flags = 0;
+
+	hndl = ion_import_dma_buf_fd(client->clnt, fd);
+	dprintk(VIDC_DBG, "%s ion handle: %pK\n", __func__, hndl);
+	if (IS_ERR_OR_NULL(hndl)) {
+		dprintk(VIDC_ERR, "Failed to get handle: %pK, %d, %d, %pK\n",
+				client, fd, offset, hndl);
+		rc = -ENOMEM;
+		goto fail_import_fd;
+	}
+	mem->kvaddr = NULL;
+	rc = ion_handle_get_flags(client->clnt, hndl, &ion_flags);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+		goto fail_device_address;
+	}
+
+	mem->buffer_type = buffer_type;
+	if (ion_flags & ION_FLAG_CACHED)
+		mem->flags |= SMEM_CACHED;
+
+	if (ion_flags & ION_FLAG_SECURE)
+		mem->flags |= SMEM_SECURE;
+
+	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+				mem->flags, buffer_type, &mem->mapping_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
+		goto fail_device_address;
+	}
+
+	mem->mem_type = client->mem_type;
+	mem->smem_priv = hndl;
+	mem->device_addr = iova;
+	mem->size = buffer_size;
+	if ((u32)mem->device_addr != iova) {
+		dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
+			&iova, (u32)mem->device_addr);
+		goto fail_device_address;
+	}
+	dprintk(VIDC_DBG,
+		"%s: ion_handle = %pK, fd = %d, device_addr = %pa, size = %u, kvaddr = %pK, buffer_type = %d, flags = %#lx\n",
+		__func__, mem->smem_priv, fd, &mem->device_addr, mem->size,
+		mem->kvaddr, mem->buffer_type, mem->flags);
+	return rc;
+fail_device_address:
+	ion_free(client->clnt, hndl);
+fail_import_fd:
+	return rc;
+}
+
+static int get_secure_flag_for_buffer_type(
+		struct smem_client *client, enum hal_buffer buffer_type)
+{
+
+	if (!client) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (buffer_type) {
+	case HAL_BUFFER_INPUT:
+		if (client->session_type == MSM_VIDC_ENCODER)
+			return ION_FLAG_CP_PIXEL;
+		else
+			return ION_FLAG_CP_BITSTREAM;
+	case HAL_BUFFER_OUTPUT:
+	case HAL_BUFFER_OUTPUT2:
+		if (client->session_type == MSM_VIDC_ENCODER)
+			return ION_FLAG_CP_BITSTREAM;
+		else
+			return ION_FLAG_CP_PIXEL;
+	case HAL_BUFFER_INTERNAL_SCRATCH:
+		return ION_FLAG_CP_BITSTREAM;
+	case HAL_BUFFER_INTERNAL_SCRATCH_1:
+		return ION_FLAG_CP_NON_PIXEL;
+	case HAL_BUFFER_INTERNAL_SCRATCH_2:
+		return ION_FLAG_CP_PIXEL;
+	case HAL_BUFFER_INTERNAL_PERSIST:
+		return ION_FLAG_CP_BITSTREAM;
+	case HAL_BUFFER_INTERNAL_PERSIST_1:
+		return ION_FLAG_CP_NON_PIXEL;
+	default:
+		WARN(1, "No matching secure flag for buffer type : %x\n",
+				buffer_type);
+		return -EINVAL;
+	}
+}
+
+static int alloc_ion_mem(struct smem_client *client, size_t size, u32 align,
+	u32 flags, enum hal_buffer buffer_type, struct msm_smem *mem,
+	int map_kernel)
+{
+	struct ion_handle *hndl;
+	ion_phys_addr_t iova = 0;
+	unsigned long buffer_size = 0;
+	unsigned long heap_mask = 0;
+	int rc = 0;
+	int ion_flags = 0;
+
+	align = ALIGN(align, SZ_4K);
+	size = ALIGN(size, SZ_4K);
+
+	if (is_iommu_present(client->res)) {
+		heap_mask = ION_HEAP(ION_IOMMU_HEAP_ID);
+	} else {
+		dprintk(VIDC_DBG,
+			"allocate shared memory from adsp heap size %zx align %d\n",
+			size, align);
+		heap_mask = ION_HEAP(ION_ADSP_HEAP_ID);
+	}
+
+	if (flags & SMEM_CACHED)
+		ion_flags |= ION_FLAG_CACHED;
+
+	if (flags & SMEM_SECURE) {
+		int secure_flag =
+			get_secure_flag_for_buffer_type(client, buffer_type);
+		if (secure_flag < 0) {
+			rc = secure_flag;
+			goto fail_shared_mem_alloc;
+		}
+
+		ion_flags |= ION_FLAG_SECURE | secure_flag;
+		heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
+
+		if (client->res->slave_side_cp) {
+			heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
+			size = ALIGN(size, SZ_1M);
+			align = ALIGN(size, SZ_1M);
+		}
+	}
+
+	trace_msm_smem_buffer_ion_op_start("ALLOC", (u32)buffer_type,
+		heap_mask, size, align, flags, map_kernel);
+	hndl = ion_alloc(client->clnt, size, align, heap_mask, ion_flags);
+	if (IS_ERR_OR_NULL(hndl)) {
+		dprintk(VIDC_ERR,
+		"Failed to allocate shared memory = %pK, %zx, %d, %#x\n",
+		client, size, align, flags);
+		rc = -ENOMEM;
+		goto fail_shared_mem_alloc;
+	}
+	trace_msm_smem_buffer_ion_op_end("ALLOC", (u32)buffer_type,
+		heap_mask, size, align, flags, map_kernel);
+	mem->mem_type = client->mem_type;
+	mem->smem_priv = hndl;
+	mem->flags = flags;
+	mem->buffer_type = buffer_type;
+	if (map_kernel) {
+		mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+		if (IS_ERR_OR_NULL(mem->kvaddr)) {
+			dprintk(VIDC_ERR,
+				"Failed to map shared mem in kernel\n");
+			rc = -EIO;
+			goto fail_map;
+		}
+	} else {
+		mem->kvaddr = NULL;
+	}
+
+	rc = get_device_address(client, hndl, align, &iova, &buffer_size,
+				flags, buffer_type, &mem->mapping_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get device address: %d\n",
+			rc);
+		goto fail_device_address;
+	}
+	mem->device_addr = iova;
+	if ((u32)mem->device_addr != iova) {
+		dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
+			&iova, (u32)mem->device_addr);
+		goto fail_device_address;
+	}
+	mem->size = size;
+	dprintk(VIDC_DBG,
+		"%s: ion_handle = %pK, device_addr = %pa, size = %u, kvaddr = %pK, buffer_type = %#x, flags = %#lx\n",
+		__func__, mem->smem_priv, &mem->device_addr,
+		mem->size, mem->kvaddr, mem->buffer_type, mem->flags);
+	return rc;
+fail_device_address:
+	if (mem->kvaddr)
+		ion_unmap_kernel(client->clnt, hndl);
+fail_map:
+	ion_free(client->clnt, hndl);
+fail_shared_mem_alloc:
+	return rc;
+}
+
+static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+{
+	dprintk(VIDC_DBG,
+		"%s: ion_handle = %pK, device_addr = %pa, size = %u, kvaddr = %pK, buffer_type = %#x\n",
+		__func__, mem->smem_priv, &mem->device_addr,
+		mem->size, mem->kvaddr, mem->buffer_type);
+
+	if (mem->device_addr)
+		put_device_address(client, mem->smem_priv, mem->flags,
+			&mem->mapping_info, mem->buffer_type);
+
+	if (mem->kvaddr)
+		ion_unmap_kernel(client->clnt, mem->smem_priv);
+	if (mem->smem_priv) {
+		trace_msm_smem_buffer_ion_op_start("FREE",
+				(u32)mem->buffer_type, -1, mem->size, -1,
+				mem->flags, -1);
+		dprintk(VIDC_DBG,
+			"%s: Freeing handle %pK, client: %pK\n",
+			__func__, mem->smem_priv, client->clnt);
+		ion_free(client->clnt, mem->smem_priv);
+		trace_msm_smem_buffer_ion_op_end("FREE", (u32)mem->buffer_type,
+			-1, mem->size, -1, mem->flags, -1);
+	}
+}
+
+static void *ion_new_client(void)
+{
+	struct ion_client *client = NULL;
+
+	client = msm_ion_client_create("video_client");
+	if (!client)
+		dprintk(VIDC_ERR, "Failed to create smem client\n");
+	return client;
+};
+
+static void ion_delete_client(struct smem_client *client)
+{
+	ion_client_destroy(client->clnt);
+}
+
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+		enum hal_buffer buffer_type)
+{
+	struct smem_client *client = clt;
+	int rc = 0;
+	struct msm_smem *mem;
+
+	if (fd < 0) {
+		dprintk(VIDC_ERR, "Invalid fd: %d\n", fd);
+		return NULL;
+	}
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem) {
+		dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
+		return NULL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		rc = -EINVAL;
+		break;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
+		kfree(mem);
+		mem = NULL;
+	}
+	return mem;
+}
+
+bool msm_smem_compare_buffers(void *clt, int fd, void *priv)
+{
+	struct smem_client *client = clt;
+	struct ion_handle *handle = NULL;
+	bool ret = false;
+
+	if (!clt || !priv) {
+		dprintk(VIDC_ERR, "Invalid params: %pK, %pK\n",
+			clt, priv);
+		return false;
+	}
+	handle = ion_import_dma_buf_fd(client->clnt, fd);
+	ret = handle == priv;
+	handle ? ion_free(client->clnt, handle) : 0;
+	return ret;
+}
+
+static int ion_cache_operations(struct smem_client *client,
+	struct msm_smem *mem, enum smem_cache_ops cache_op)
+{
+	unsigned long ionflag = 0;
+	int rc = 0;
+	int msm_cache_ops = 0;
+
+	if (!mem || !client) {
+		dprintk(VIDC_ERR, "Invalid params: %pK, %pK\n",
+			mem, client);
+		return -EINVAL;
+	}
+	rc = ion_handle_get_flags(client->clnt,	mem->smem_priv,
+		&ionflag);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"ion_handle_get_flags failed: %d\n", rc);
+		goto cache_op_failed;
+	}
+	if (ION_IS_CACHED(ionflag)) {
+		switch (cache_op) {
+		case SMEM_CACHE_CLEAN:
+			msm_cache_ops = ION_IOC_CLEAN_CACHES;
+			break;
+		case SMEM_CACHE_INVALIDATE:
+			msm_cache_ops = ION_IOC_INV_CACHES;
+			break;
+		case SMEM_CACHE_CLEAN_INVALIDATE:
+			msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+			break;
+		default:
+			dprintk(VIDC_ERR, "cache operation not supported\n");
+			rc = -EINVAL;
+			goto cache_op_failed;
+		}
+		rc = msm_ion_do_cache_op(client->clnt,
+				(struct ion_handle *)mem->smem_priv,
+				0, (unsigned long)mem->size,
+				msm_cache_ops);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"cache operation failed %d\n", rc);
+			goto cache_op_failed;
+		}
+	}
+cache_op_failed:
+	return rc;
+}
+
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops cache_op)
+{
+	struct smem_client *client = clt;
+	int rc = 0;
+
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n",
+			client);
+		return -EINVAL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = ion_cache_operations(client, mem, cache_op);
+		if (rc)
+			dprintk(VIDC_ERR,
+			"Failed cache operations: %d\n", rc);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	return rc;
+}
+
+void *msm_smem_new_client(enum smem_type mtype,
+		void *platform_resources, enum session_type stype)
+{
+	struct smem_client *client = NULL;
+	void *clnt = NULL;
+	struct msm_vidc_platform_resources *res = platform_resources;
+
+	switch (mtype) {
+	case SMEM_ION:
+		clnt = ion_new_client();
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	if (clnt) {
+		client = kzalloc(sizeof(*client), GFP_KERNEL);
+		if (client) {
+			client->mem_type = mtype;
+			client->clnt = clnt;
+			client->res = res;
+			client->session_type = stype;
+		}
+	} else {
+		dprintk(VIDC_ERR, "Failed to create new client: mtype = %d\n",
+			mtype);
+	}
+	return client;
+}
+
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+		enum hal_buffer buffer_type, int map_kernel)
+{
+	struct smem_client *client;
+	int rc = 0;
+	struct msm_smem *mem;
+
+	client = clt;
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid  client passed\n");
+		return NULL;
+	}
+	if (!size) {
+		dprintk(VIDC_ERR, "No need to allocate memory of size: %zx\n",
+			size);
+		return NULL;
+	}
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem) {
+		dprintk(VIDC_ERR, "Failed to allocate shared mem\n");
+		return NULL;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		rc = alloc_ion_mem(client, size, align, flags, buffer_type,
+					mem, map_kernel);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		rc = -EINVAL;
+		break;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to allocate shared memory\n");
+		kfree(mem);
+		mem = NULL;
+	}
+	return mem;
+}
+
+void msm_smem_free(void *clt, struct msm_smem *mem)
+{
+	struct smem_client *client = clt;
+
+	if (!client || !mem) {
+		dprintk(VIDC_ERR, "Invalid  client/handle passed\n");
+		return;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		free_ion_mem(client, mem);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	kfree(mem);
+};
+
+void msm_smem_delete_client(void *clt)
+{
+	struct smem_client *client = clt;
+
+	if (!client) {
+		dprintk(VIDC_ERR, "Invalid  client passed\n");
+		return;
+	}
+	switch (client->mem_type) {
+	case SMEM_ION:
+		ion_delete_client(client);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Mem type not supported\n");
+		break;
+	}
+	kfree(client);
+}
+
+struct context_bank_info *msm_smem_get_context_bank(void *clt,
+			bool is_secure, enum hal_buffer buffer_type)
+{
+	struct smem_client *client = clt;
+	struct context_bank_info *cb = NULL, *match = NULL;
+
+	if (!clt) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return NULL;
+	}
+
+	/*
+	 * HAL_BUFFER_INPUT is directly mapped to bitstream CB in DT
+	 * as the buffer type structure was initially designed
+	 * just for decoder. For Encoder, input should be mapped to
+	 * pixel_CB. So swap the buffer types just in this local scope.
+	 */
+	if (is_secure && client->session_type == MSM_VIDC_ENCODER) {
+		if (buffer_type == HAL_BUFFER_INPUT)
+			buffer_type = HAL_BUFFER_OUTPUT;
+		else if (buffer_type == HAL_BUFFER_OUTPUT)
+			buffer_type = HAL_BUFFER_INPUT;
+	}
+
+	list_for_each_entry(cb, &client->res->context_banks, list) {
+		if (cb->is_secure == is_secure &&
+				cb->buffer_type & buffer_type) {
+			match = cb;
+			dprintk(VIDC_DBG,
+				"context bank found for CB : %s, device: %pK mapping: %pK\n",
+				match->name, match->dev, match->mapping);
+			break;
+		}
+	}
+
+	return match;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c
new file mode 100644
index 0000000..9d5f255
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_v4l2_vidc.c
@@ -0,0 +1,829 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/io.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_common.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_internal.h"
+#include "msm_vidc_res_parse.h"
+#include "msm_vidc_resources.h"
+#include "venus_boot.h"
+#include "vidc_hfi_api.h"
+
+#define BASE_DEVICE_NUMBER 32
+
+struct msm_vidc_drv *vidc_driver;
+
+uint32_t msm_vidc_pwr_collapse_delay = 2000;
+
+static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
+{
+	return container_of(filp->private_data,
+					struct msm_vidc_inst, event_handler);
+}
+
+static int msm_v4l2_open(struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+	struct msm_video_device *vid_dev =
+		container_of(vdev, struct msm_video_device, vdev);
+	struct msm_vidc_core *core = video_drvdata(filp);
+	struct msm_vidc_inst *vidc_inst;
+
+	trace_msm_v4l2_vidc_open_start("msm_v4l2_open start");
+	vidc_inst = msm_vidc_open(core->id, vid_dev->type);
+	if (!vidc_inst) {
+		dprintk(VIDC_ERR,
+		"Failed to create video instance, core: %d, type = %d\n",
+		core->id, vid_dev->type);
+		return -ENOMEM;
+	}
+	clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
+	filp->private_data = &(vidc_inst->event_handler);
+	trace_msm_v4l2_vidc_open_end("msm_v4l2_open end");
+	return 0;
+}
+
+static int msm_v4l2_close(struct file *filp)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst;
+
+	trace_msm_v4l2_vidc_close_start("msm_v4l2_close start");
+	vidc_inst = get_vidc_inst(filp, NULL);
+	rc = msm_vidc_release_buffers(vidc_inst,
+			V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"Failed in %s for release output buffers\n", __func__);
+
+	rc = msm_vidc_close(vidc_inst);
+	trace_msm_v4l2_vidc_close_end("msm_v4l2_close end");
+	return rc;
+}
+
+static int msm_v4l2_querycap(struct file *filp, void *fh,
+			struct v4l2_capability *cap)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
+
+	return msm_vidc_querycap((void *)vidc_inst, cap);
+}
+
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+					struct v4l2_fmtdesc *f)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_enum_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_s_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+					struct v4l2_format *f)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_g_fmt((void *)vidc_inst, f);
+}
+
+int msm_v4l2_s_ctrl(struct file *file, void *fh,
+					struct v4l2_control *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_s_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_g_ctrl(struct file *file, void *fh,
+					struct v4l2_control *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_g_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_s_ext_ctrl(struct file *file, void *fh,
+					struct v4l2_ext_controls *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_s_ext_ctrl((void *)vidc_inst, a);
+}
+
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+				struct v4l2_requestbuffers *b)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+	int rc = 0;
+
+	if (!b->count)
+		rc = msm_vidc_release_buffers(vidc_inst, b->type);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"Failed in %s for release output buffers\n", __func__);
+	return msm_vidc_reqbufs((void *)vidc_inst, b);
+}
+
+int msm_v4l2_prepare_buf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	return msm_vidc_prepare_buf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_qbuf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	return msm_vidc_qbuf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+				struct v4l2_buffer *b)
+{
+	return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
+}
+
+int msm_v4l2_streamon(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_streamon((void *)vidc_inst, i);
+}
+
+int msm_v4l2_streamoff(struct file *file, void *fh,
+				enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_streamoff((void *)vidc_inst, i);
+}
+
+static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
+	struct msm_vidc_inst *vidc_inst = container_of(fh,
+			struct msm_vidc_inst, event_handler);
+
+	return msm_vidc_subscribe_event((void *)vidc_inst, sub);
+}
+
+static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
+				const struct v4l2_event_subscription *sub)
+{
+	struct msm_vidc_inst *vidc_inst = container_of(fh,
+			struct msm_vidc_inst, event_handler);
+
+	return msm_vidc_unsubscribe_event((void *)vidc_inst, sub);
+}
+
+static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
+				struct v4l2_decoder_cmd *dec)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)dec);
+}
+
+static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+				struct v4l2_encoder_cmd *enc)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)enc);
+}
+static int msm_v4l2_s_parm(struct file *file, void *fh,
+			struct v4l2_streamparm *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_comm_s_parm(vidc_inst, a);
+}
+static int msm_v4l2_g_parm(struct file *file, void *fh,
+		struct v4l2_streamparm *a)
+{
+	return 0;
+}
+
+static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
+				struct v4l2_frmsizeenum *fsize)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_enum_framesizes((void *)vidc_inst, fsize);
+}
+
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+	.vidioc_querycap = msm_v4l2_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
+	.vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
+	.vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
+	.vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
+	.vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
+	.vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
+	.vidioc_reqbufs = msm_v4l2_reqbufs,
+	.vidioc_prepare_buf = msm_v4l2_prepare_buf,
+	.vidioc_qbuf = msm_v4l2_qbuf,
+	.vidioc_dqbuf = msm_v4l2_dqbuf,
+	.vidioc_streamon = msm_v4l2_streamon,
+	.vidioc_streamoff = msm_v4l2_streamoff,
+	.vidioc_s_ctrl = msm_v4l2_s_ctrl,
+	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
+	.vidioc_s_ext_ctrls = msm_v4l2_s_ext_ctrl,
+	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
+	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
+	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+	.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
+	.vidioc_s_parm = msm_v4l2_s_parm,
+	.vidioc_g_parm = msm_v4l2_g_parm,
+	.vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
+};
+
+static unsigned int msm_v4l2_poll(struct file *filp,
+	struct poll_table_struct *pt)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
+
+	return msm_vidc_poll((void *)vidc_inst, filp, pt);
+}
+
+static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
+	.owner = THIS_MODULE,
+	.open = msm_v4l2_open,
+	.release = msm_v4l2_close,
+	.unlocked_ioctl = video_ioctl2,
+	.poll = msm_v4l2_poll,
+};
+
+void msm_vidc_release_video_device(struct video_device *pvdev)
+{
+}
+
+static int read_platform_resources(struct msm_vidc_core *core,
+		struct platform_device *pdev)
+{
+	if (!core || !pdev) {
+		dprintk(VIDC_ERR, "%s: Invalid params %pK %pK\n",
+			__func__, core, pdev);
+		return -EINVAL;
+	}
+
+	core->hfi_type = VIDC_HFI_VENUS;
+	core->resources.pdev = pdev;
+	if (pdev->dev.of_node) {
+		/* Target supports DT, parse from it */
+		return read_platform_resources_from_dt(&core->resources);
+	}
+	dprintk(VIDC_ERR, "pdev node is NULL\n");
+	return -EINVAL;
+}
+
+static int msm_vidc_initialize_core(struct platform_device *pdev,
+				struct msm_vidc_core *core)
+{
+	int i = 0;
+	int rc = 0;
+
+	if (!core)
+		return -EINVAL;
+	rc = read_platform_resources(core, pdev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get platform resources\n");
+		return rc;
+	}
+
+	INIT_LIST_HEAD(&core->instances);
+	mutex_init(&core->lock);
+
+	core->state = VIDC_CORE_UNINIT;
+	for (i = SYS_MSG_INDEX(SYS_MSG_START);
+		i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
+		init_completion(&core->completions[i]);
+	}
+
+	INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
+	return rc;
+}
+
+static ssize_t msm_vidc_link_name_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct msm_vidc_core *core = dev_get_drvdata(dev);
+
+	if (core)
+		if (dev == &core->vdev[MSM_VIDC_DECODER].vdev.dev)
+			return snprintf(buf, PAGE_SIZE, "venus_dec");
+		else if (dev == &core->vdev[MSM_VIDC_ENCODER].vdev.dev)
+			return snprintf(buf, PAGE_SIZE, "venus_enc");
+		else
+			return 0;
+	else
+		return 0;
+}
+
+static DEVICE_ATTR(link_name, 0444, msm_vidc_link_name_show, NULL);
+
+static ssize_t store_pwr_collapse_delay(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long val = 0;
+	int rc = 0;
+
+	rc = kstrtoul(buf, 0, &val);
+	if (rc)
+		return rc;
+	else if (!val)
+		return -EINVAL;
+	msm_vidc_pwr_collapse_delay = val;
+	return count;
+}
+
+static ssize_t show_pwr_collapse_delay(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", msm_vidc_pwr_collapse_delay);
+}
+
+static DEVICE_ATTR(pwr_collapse_delay, 0644, show_pwr_collapse_delay,
+		store_pwr_collapse_delay);
+
+static ssize_t show_thermal_level(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level);
+}
+
+static ssize_t store_thermal_level(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	int rc = 0, val = 0;
+
+	rc = kstrtoint(buf, 0, &val);
+	if (rc || val < 0) {
+		dprintk(VIDC_WARN,
+			"Invalid thermal level value: %s\n", buf);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Thermal level old %d new %d\n",
+			vidc_driver->thermal_level, val);
+
+	if (val == vidc_driver->thermal_level)
+		return count;
+	vidc_driver->thermal_level = val;
+
+	msm_comm_handle_thermal_event();
+	return count;
+}
+
+static DEVICE_ATTR(thermal_level, 0644, show_thermal_level,
+		store_thermal_level);
+
+static ssize_t show_platform_version(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d",
+			vidc_driver->platform_version);
+}
+
+static ssize_t store_platform_version(struct device *dev,
+		struct device_attribute *attr, const char *buf,
+		size_t count)
+{
+	dprintk(VIDC_WARN, "store platform version is not allowed\n");
+	return count;
+}
+
+static DEVICE_ATTR(platform_version, 0444, show_platform_version,
+		store_platform_version);
+
+static ssize_t show_capability_version(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	return scnprintf(buf, PAGE_SIZE, "%d",
+			vidc_driver->capability_version);
+}
+
+static ssize_t store_capability_version(struct device *dev,
+		struct device_attribute *attr, const char *buf,
+		size_t count)
+{
+	dprintk(VIDC_WARN, "store capability version is not allowed\n");
+	return count;
+}
+
+static DEVICE_ATTR(capability_version, 0444, show_capability_version,
+		store_capability_version);
+
+static struct attribute *msm_vidc_core_attrs[] = {
+		&dev_attr_pwr_collapse_delay.attr,
+		&dev_attr_thermal_level.attr,
+		&dev_attr_platform_version.attr,
+		&dev_attr_capability_version.attr,
+		NULL
+};
+
+static struct attribute_group msm_vidc_core_attr_group = {
+		.attrs = msm_vidc_core_attrs,
+};
+
+static const struct of_device_id msm_vidc_dt_match[] = {
+	{.compatible = "qcom,msm-vidc"},
+	{.compatible = "qcom,msm-vidc,context-bank"},
+	{.compatible = "qcom,msm-vidc,bus"},
+	{}
+};
+
+static u32 msm_vidc_read_efuse_version(struct platform_device *pdev,
+	struct version_table *table, const char *fuse_name)
+{
+	void __iomem *base;
+	struct resource *res;
+	u32 ret = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, fuse_name);
+	if (!res) {
+		dprintk(VIDC_DBG, "Failed to get resource %s\n", fuse_name);
+		goto exit;
+	}
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dprintk(VIDC_ERR,
+			"failed ioremap: res->start %#x, size %d\n",
+			(u32)res->start, (u32)resource_size(res));
+		goto exit;
+	} else {
+		ret = readl_relaxed(base);
+		ret = (ret & table->version_mask) >>
+			table->version_shift;
+
+		devm_iounmap(&pdev->dev, base);
+	}
+exit:
+	return ret;
+}
+
+static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct device *dev;
+	int nr = BASE_DEVICE_NUMBER;
+
+	if (!vidc_driver) {
+		dprintk(VIDC_ERR, "Invalid vidc driver\n");
+		return -EINVAL;
+	}
+
+	core = kzalloc(sizeof(*core), GFP_KERNEL);
+	if (!core) {
+		dprintk(VIDC_ERR,
+			"Failed to allocate memory for device core\n");
+		return -ENOMEM;
+	}
+
+	dev_set_drvdata(&pdev->dev, core);
+	rc = msm_vidc_initialize_core(pdev, core);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init core\n");
+		goto err_core_init;
+	}
+	rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to create attributes\n");
+		goto err_core_init;
+	}
+
+	core->id = MSM_VIDC_CORE_VENUS;
+
+	rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to register v4l2 device\n");
+		goto err_v4l2_register;
+	}
+
+	/* setup the decoder device */
+	core->vdev[MSM_VIDC_DECODER].vdev.release =
+		msm_vidc_release_video_device;
+	core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops;
+	core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+	core->vdev[MSM_VIDC_DECODER].vdev.vfl_dir = VFL_DIR_M2M;
+	core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER;
+	core->vdev[MSM_VIDC_DECODER].vdev.v4l2_dev = &core->v4l2_dev;
+	rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
+					VFL_TYPE_GRABBER, nr);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to register video decoder device");
+		goto err_dec_register;
+	}
+
+	video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
+	dev = &core->vdev[MSM_VIDC_DECODER].vdev.dev;
+	rc = device_create_file(dev, &dev_attr_link_name);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to create link name sysfs for decoder");
+		goto err_dec_attr_link_name;
+	}
+
+	/* setup the encoder device */
+	core->vdev[MSM_VIDC_ENCODER].vdev.release =
+		msm_vidc_release_video_device;
+	core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops;
+	core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+	core->vdev[MSM_VIDC_ENCODER].vdev.vfl_dir = VFL_DIR_M2M;
+	core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER;
+	core->vdev[MSM_VIDC_ENCODER].vdev.v4l2_dev = &core->v4l2_dev;
+	rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
+				VFL_TYPE_GRABBER, nr + 1);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to register video encoder device");
+		goto err_enc_register;
+	}
+
+	video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
+	dev = &core->vdev[MSM_VIDC_ENCODER].vdev.dev;
+	rc = device_create_file(dev, &dev_attr_link_name);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to create link name sysfs for encoder");
+		goto err_enc_attr_link_name;
+	}
+
+	/* finish setting up the 'core' */
+	mutex_lock(&vidc_driver->lock);
+	if (vidc_driver->num_cores  + 1 > MSM_VIDC_CORES_MAX) {
+		mutex_unlock(&vidc_driver->lock);
+		dprintk(VIDC_ERR, "Maximum cores already exist, core_no = %d\n",
+				vidc_driver->num_cores);
+		goto err_cores_exceeded;
+	}
+	vidc_driver->num_cores++;
+	mutex_unlock(&vidc_driver->lock);
+
+	core->device = vidc_hfi_initialize(core->hfi_type, core->id,
+				&core->resources, &handle_cmd_response);
+	if (IS_ERR_OR_NULL(core->device)) {
+		mutex_lock(&vidc_driver->lock);
+		vidc_driver->num_cores--;
+		mutex_unlock(&vidc_driver->lock);
+
+		rc = PTR_ERR(core->device) ?: -EBADHANDLE;
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "Failed to create HFI device\n");
+		else
+			dprintk(VIDC_DBG, "msm_vidc: request probe defer\n");
+		goto err_cores_exceeded;
+	}
+
+	mutex_lock(&vidc_driver->lock);
+	list_add_tail(&core->list, &vidc_driver->cores);
+	mutex_unlock(&vidc_driver->lock);
+
+	core->debugfs_root = msm_vidc_debugfs_init_core(
+		core, vidc_driver->debugfs_root);
+
+	vidc_driver->platform_version =
+		msm_vidc_read_efuse_version(pdev,
+			core->resources.pf_ver_tbl, "efuse");
+
+	vidc_driver->capability_version =
+		msm_vidc_read_efuse_version(
+			pdev, core->resources.pf_cap_tbl, "efuse2");
+
+	dprintk(VIDC_DBG, "populating sub devices\n");
+	/*
+	 * Trigger probe for each sub-device i.e. qcom,msm-vidc,context-bank.
+	 * When msm_vidc_probe is called for each sub-device, parse the
+	 * context-bank details and store it in core->resources.context_banks
+	 * list.
+	 */
+	rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
+			&pdev->dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to trigger probe for sub-devices\n");
+		goto err_fail_sub_device_probe;
+	}
+
+	return rc;
+
+err_fail_sub_device_probe:
+	vidc_hfi_deinitialize(core->hfi_type, core->device);
+err_cores_exceeded:
+	device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
+			&dev_attr_link_name);
+err_enc_attr_link_name:
+	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+err_enc_register:
+	device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
+			&dev_attr_link_name);
+err_dec_attr_link_name:
+	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+err_dec_register:
+	v4l2_device_unregister(&core->v4l2_dev);
+err_v4l2_register:
+	sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+err_core_init:
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(core);
+	return rc;
+}
+
+static int msm_vidc_probe_context_bank(struct platform_device *pdev)
+{
+	return read_context_bank_resources_from_dt(pdev);
+}
+
+static int msm_vidc_probe_bus(struct platform_device *pdev)
+{
+	return read_bus_resources_from_dt(pdev);
+}
+
+static int msm_vidc_probe(struct platform_device *pdev)
+{
+	/*
+	 * Sub devices probe will be triggered by of_platform_populate() towards
+	 * the end of the probe function after msm-vidc device probe is
+	 * completed. Return immediately after completing sub-device probe.
+	 */
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) {
+		return msm_vidc_probe_vidc_device(pdev);
+	} else if (of_device_is_compatible(pdev->dev.of_node,
+		"qcom,msm-vidc,bus")) {
+		return msm_vidc_probe_bus(pdev);
+	} else if (of_device_is_compatible(pdev->dev.of_node,
+		"qcom,msm-vidc,context-bank")) {
+		return msm_vidc_probe_context_bank(pdev);
+	}
+	/* How did we end up here? */
+	WARN_ON(VIDC_DBG_WARN_ENABLE);
+	return -EINVAL;
+}
+
+static int msm_vidc_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	if (!pdev) {
+		dprintk(VIDC_ERR, "%s invalid input %pK", __func__, pdev);
+		return -EINVAL;
+	}
+
+	core = dev_get_drvdata(&pdev->dev);
+	if (!core) {
+		dprintk(VIDC_ERR, "%s invalid core", __func__);
+		return -EINVAL;
+	}
+
+	if (core->resources.use_non_secure_pil)
+		venus_boot_deinit();
+
+	vidc_hfi_deinitialize(core->hfi_type, core->device);
+	device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
+				&dev_attr_link_name);
+	video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+	device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
+				&dev_attr_link_name);
+	video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+	v4l2_device_unregister(&core->v4l2_dev);
+
+	msm_vidc_free_platform_resources(&core->resources);
+	sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
+	dev_set_drvdata(&pdev->dev, NULL);
+	kfree(core);
+	return rc;
+}
+
+static int msm_vidc_pm_suspend(struct device *dev)
+{
+	int rc = 0;
+	struct msm_vidc_core *core;
+
+	/*
+	 * Bail out if
+	 * - driver possibly not probed yet
+	 * - not the main device. We don't support power management on
+	 *   subdevices (e.g. context banks)
+	 */
+	if (!dev || !dev->driver ||
+		!of_device_is_compatible(dev->of_node, "qcom,msm-vidc"))
+		return 0;
+
+	core = dev_get_drvdata(dev);
+	if (!core) {
+		dprintk(VIDC_ERR, "%s invalid core\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_vidc_suspend(core->id);
+	if (rc == -ENOTSUPP)
+		rc = 0;
+	else if (rc)
+		dprintk(VIDC_WARN, "Failed to suspend: %d\n", rc);
+
+
+	return rc;
+}
+
+static int msm_vidc_pm_resume(struct device *dev)
+{
+	dprintk(VIDC_INFO, "%s\n", __func__);
+	return 0;
+}
+
+static const struct dev_pm_ops msm_vidc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume)
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static struct platform_driver msm_vidc_driver = {
+	.probe = msm_vidc_probe,
+	.remove = msm_vidc_remove,
+	.driver = {
+		.name = "msm_vidc_v4l2",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_vidc_dt_match,
+		.pm = &msm_vidc_pm_ops,
+	},
+};
+
+static int __init msm_vidc_init(void)
+{
+	int rc = 0;
+
+	vidc_driver = kzalloc(sizeof(*vidc_driver),
+						GFP_KERNEL);
+	if (!vidc_driver) {
+		dprintk(VIDC_ERR,
+			"Failed to allocate memroy for msm_vidc_drv\n");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&vidc_driver->cores);
+	mutex_init(&vidc_driver->lock);
+	vidc_driver->debugfs_root = msm_vidc_debugfs_init_drv();
+	if (!vidc_driver->debugfs_root)
+		dprintk(VIDC_ERR,
+			"Failed to create debugfs for msm_vidc\n");
+
+	rc = platform_driver_register(&msm_vidc_driver);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to register platform driver\n");
+		debugfs_remove_recursive(vidc_driver->debugfs_root);
+		kfree(vidc_driver);
+		vidc_driver = NULL;
+	}
+
+	return rc;
+}
+
+static void __exit msm_vidc_exit(void)
+{
+	platform_driver_unregister(&msm_vidc_driver);
+	debugfs_remove_recursive(vidc_driver->debugfs_root);
+	kfree(vidc_driver);
+	vidc_driver = NULL;
+}
+
+module_init(msm_vidc_init);
+module_exit(msm_vidc_exit);
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vdec.c b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
new file mode 100644
index 0000000..b0f639a
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vdec.c
@@ -0,0 +1,2741 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <soc/qcom/scm.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MIN_NUM_OUTPUT_BUFFERS 4
+#define MIN_NUM_OUTPUT_BUFFERS_VP9 6
+#define MIN_NUM_CAPTURE_BUFFERS 6
+#define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS 1
+#define MAX_NUM_OUTPUT_BUFFERS VB2_MAX_FRAME
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
+#define MB_SIZE_IN_PIXEL (16 * 16)
+#define MAX_OPERATING_FRAME_RATE (300 << 16)
+#define OPERATING_FRAME_RATE_STEP (1 << 16)
+#define SLAVE_SIDE_CP_ALIGNMENT 0x100000
+#define MASTER_SIDE_CP_ALIGNMENT 0x1000
+
+static const char *const mpeg_video_vidc_divx_format[] = {
+	"DIVX Format 3",
+	"DIVX Format 4",
+	"DIVX Format 5",
+	"DIVX Format 6",
+	NULL
+};
+static const char *const mpeg_video_stream_format[] = {
+	"NAL Format Start Codes",
+	"NAL Format One NAL Per Buffer",
+	"NAL Format One Byte Length",
+	"NAL Format Two Byte Length",
+	"NAL Format Four Byte Length",
+	NULL
+};
+static const char *const mpeg_video_output_order[] = {
+	"Display Order",
+	"Decode Order",
+	NULL
+};
+static const char *const mpeg_vidc_video_alloc_mode_type[] = {
+	"Buffer Allocation Static",
+	"Buffer Allocation Ring Buffer",
+	"Buffer Allocation Dynamic Buffer"
+};
+
+static const char *const perf_level[] = {
+	"Nominal",
+	"Performance",
+	"Turbo"
+};
+
+static const char *const h263_level[] = {
+	"1.0",
+	"2.0",
+	"3.0",
+	"4.0",
+	"4.5",
+	"5.0",
+	"6.0",
+	"7.0",
+};
+
+static const char *const h263_profile[] = {
+	"Baseline",
+	"H320 Coding",
+	"Backward Compatible",
+	"ISWV2",
+	"ISWV3",
+	"High Compression",
+	"Internet",
+	"Interlace",
+	"High Latency",
+};
+
+static const char *const vp8_profile_level[] = {
+	"Unused",
+	"0.0",
+	"1.0",
+	"2.0",
+	"3.0",
+};
+
+static const char *const mpeg2_profile[] = {
+	"Simple",
+	"Main",
+	"422",
+	"Snr Scalable",
+	"Spatial Scalable",
+	"High",
+};
+
+static const char *const mpeg2_level[] = {
+	"0",
+	"1",
+	"2",
+	"3",
+};
+static const char *const mpeg_vidc_video_entropy_mode[] = {
+	"CAVLC Entropy Mode",
+	"CABAC Entropy Mode",
+};
+
+static const char *const mpeg_vidc_video_h264_mvc_layout[] = {
+	"Frame packing arrangement sequential",
+	"Frame packing arrangement top-bottom",
+};
+
+static const char *const mpeg_vidc_video_dpb_color_format[] = {
+	"DPB Color Format None",
+	"DPB Color Format UBWC",
+	"DPB Color Format UBWC TP10",
+};
+
+static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+		.name = "NAL Format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+		),
+		.qmenu = mpeg_video_stream_format,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
+		.name = "Output Order",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
+			),
+		.qmenu = mpeg_video_output_order,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE,
+		.name = "Picture Type Decoding",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
+		.name = "Keep Aspect Ratio",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
+		.name = "Deblocker Mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
+		.name = "Divx Format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
+			),
+		.qmenu = mpeg_video_vidc_divx_format,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
+		.name = "MB Error Map Reporting",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
+		.name = "control",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
+		.name = "Sync Frame Decode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+		.name = "Secure mode",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+		.name = "Extradata Type",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE,
+		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI) |
+			(1 <<
+			V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE)
+			),
+		.qmenu = mpeg_video_vidc_extradata,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+		.name = "Decoder Performance Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+		.default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+		.qmenu = perf_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT,
+		.name = "Buffer allocation mode for input",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+			),
+		.qmenu = mpeg_vidc_video_alloc_mode_type,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
+		.name = "Buffer allocation mode for output",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+			),
+		.qmenu = mpeg_vidc_video_alloc_mode_type,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY,
+		.name = "Video frame assembly",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE,
+		.default_value =  V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
+		.name = "Video decoder multi stream",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+		.maximum =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY,
+		.default_value =
+			V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+		.menu_skip_mask = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+		.name = "MPEG4 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.maximum =
+		V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+		.name = "MPEG4 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+		.name = "H264 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+		.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+		.name = "H264 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_VOLATILE,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+		.name = "H263 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+		),
+		.qmenu = h263_profile,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+		.name = "H263 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+		),
+		.qmenu = h263_level,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+		.name = "VP8 Profile Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+		),
+		.qmenu = vp8_profile_level,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE,
+		.name = "MPEG2 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_422) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SNR_SCALABLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SPATIAL_SCALABLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH)
+		),
+		.qmenu = mpeg2_profile,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL,
+		.name = "MPEG2 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3)
+		),
+		.qmenu = mpeg2_level,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD,
+		.name = "Video start code search threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = INT_MAX,
+		.default_value = INT_MAX,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT,
+		.name = "MVC buffer layout",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM)
+			),
+		.qmenu = mpeg_vidc_video_h264_mvc_layout,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
+		.name = "Picture concealed color",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0x0,
+		.maximum = 0xffffff,
+		.default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT,
+		.name = "Buffer size limit",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD,
+		.name = "Secure scaling output2 threshold",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2,
+		.name = "Non-Secure output2",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT,
+		.name = "Video decoder dpb color format",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC) |
+			(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC)
+			),
+		.qmenu = mpeg_vidc_video_dpb_color_format,
+	},
+	{
+		.id = V4L2_CID_VIDC_QBUF_MODE,
+		.name = "Allows batching of buffers for power savings",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_VIDC_QBUF_STANDARD,
+		.maximum = V4L2_VIDC_QBUF_BATCHED,
+		.default_value = V4L2_VIDC_QBUF_STANDARD,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+		.name = "Entropy Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		.default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.step = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+		),
+		.qmenu = mpeg_vidc_video_entropy_mode,
+		.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY,
+		.name = "Session Priority",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE,
+		.name = "Set Decoder Operating rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_OPERATING_FRAME_RATE,
+		.default_value = 0,
+		.step = OPERATING_FRAME_RATE_STEP,
+	},
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
+
+static int vdec_hal_to_v4l2(int id, int value);
+
+static u32 get_frame_size_nv12(int plane,
+					u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+static u32 get_frame_size_compressed(int plane,
+					u32 max_mbs_per_frame, u32 size_per_mb)
+{
+	return (max_mbs_per_frame * size_per_mb * 3/2)/2;
+}
+
+static u32 get_frame_size_nv12_ubwc_10bit(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
+}
+
+static u32 get_frame_size(struct msm_vidc_inst *inst,
+					const struct msm_vidc_format *fmt,
+					int fmt_type, int plane)
+{
+	u32 frame_size = 0;
+
+	if (fmt_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		frame_size = fmt->get_frame_size(plane,
+					inst->capability.mbs_per_frame.max,
+					MB_SIZE_IN_PIXEL);
+		if (inst->buffer_size_limit &&
+			(inst->buffer_size_limit < frame_size)) {
+			frame_size = inst->buffer_size_limit;
+			dprintk(VIDC_DBG, "input buffer size limited to %d\n",
+				frame_size);
+		} else {
+			dprintk(VIDC_DBG, "set input buffer size to %d\n",
+				frame_size);
+		}
+	} else if (fmt_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		frame_size = fmt->get_frame_size(plane,
+					inst->capability.height.max,
+					inst->capability.width.max);
+		dprintk(VIDC_DBG, "set output buffer size to %d\n",
+			frame_size);
+	} else {
+		dprintk(VIDC_WARN, "Wrong format type\n");
+	}
+	return frame_size;
+}
+
+static u32 get_output_frame_size(struct msm_vidc_inst *inst,
+					const struct msm_vidc_format *fmt,
+					u32 height, u32 width, int plane)
+{
+	u32 frame_size = fmt->get_frame_size(plane,
+					height, width);
+
+	if (inst->flags & VIDC_SECURE) {
+		u32 alignment = inst->core->resources.slave_side_cp ?
+			SLAVE_SIDE_CP_ALIGNMENT : MASTER_SIDE_CP_ALIGNMENT;
+		frame_size = MSM_MEDIA_ALIGN(frame_size, alignment);
+	}
+	return frame_size;
+}
+
+static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
+					struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
+		if (inst->fmts[OUTPUT_PORT].fourcc != V4L2_PIX_FMT_H264_MVC) {
+			dprintk(VIDC_ERR, "Control %#x only valid for MVC\n",
+					ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
+			ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) {
+			dprintk(VIDC_ERR,
+					"Profile %#x not supported for MVC\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
+			ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) {
+			dprintk(VIDC_ERR, "Level %#x not supported for MVC\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+struct msm_vidc_format vdec_formats[] = {
+	{
+		.name = "YCbCr Semiplanar 4:2:0",
+		.description = "Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.num_planes = 2,
+		.get_frame_size = get_frame_size_nv12,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "UBWC YCbCr Semiplanar 4:2:0",
+		.description = "UBWC Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12_UBWC,
+		.num_planes = 2,
+		.get_frame_size = get_frame_size_nv12_ubwc,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "UBWC YCbCr Semiplanar 4:2:0 10bit",
+		.description = "UBWC Y/CbCr 4:2:0 10bit",
+		.fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
+		.num_planes = 2,
+		.get_frame_size = get_frame_size_nv12_ubwc_10bit,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "Mpeg4",
+		.description = "Mpeg4 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "Mpeg2",
+		.description = "Mpeg2 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG2,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H263",
+		.description = "H263 compressed format",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VC1",
+		.description = "VC-1 compressed format",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VC1 SP",
+		.description = "VC-1 compressed format G",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H264",
+		.description = "H264 compressed format",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "H264_MVC",
+		.description = "H264_MVC compressed format",
+		.fourcc = V4L2_PIX_FMT_H264_MVC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "HEVC",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "HEVC_HYBRID",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VP8",
+		.description = "VP8 compressed format",
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "VP9",
+		.description = "VP9 compressed format",
+		.fourcc = V4L2_PIX_FMT_VP9,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "DIVX 311",
+		.description = "DIVX 311 compressed format",
+		.fourcc = V4L2_PIX_FMT_DIVX_311,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "DIVX",
+		.description = "DIVX 4/5/6 compressed format",
+		.fourcc = V4L2_PIX_FMT_DIVX,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	}
+};
+
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamon\n");
+	mutex_lock(&q->lock);
+	rc = vb2_streamon(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamoff\n");
+	mutex_lock(&q->lock);
+	rc = vb2_streamoff(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct vidc_buffer_addr_info buffer_info;
+	int extra_idx = 0;
+	int i;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			inst->core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+			"Core %pK in bad state, ignoring prepare buf\n",
+				inst->core);
+		goto exit;
+	}
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+			"Planes mismatch: needed: %d, allocated: %d\n",
+			inst->fmts[CAPTURE_PORT].num_planes,
+			b->length);
+			rc = -EINVAL;
+			break;
+		}
+		for (i = 0; i < min_t(int, b->length, VIDEO_MAX_PLANES); ++i) {
+			dprintk(VIDC_DBG,
+			"prepare plane: %d, device_addr = %#lx, size = %d\n",
+			i, b->m.planes[i].m.userptr,
+			b->m.planes[i].length);
+		}
+
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = b->m.planes[0].m.userptr;
+
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
+			b->m.planes[extra_idx].m.userptr) {
+			buffer_info.extradata_addr =
+				b->m.planes[extra_idx].m.userptr;
+			buffer_info.extradata_size =
+				b->m.planes[extra_idx].length;
+			dprintk(VIDC_DBG, "extradata: %pa, length = %d\n",
+				&buffer_info.extradata_addr,
+				buffer_info.extradata_size);
+		} else {
+			buffer_info.extradata_addr = 0;
+			buffer_info.extradata_size = 0;
+		}
+
+		rc = call_hfi_op(hdev, session_set_buffers,
+				(void *)inst->session, &buffer_info);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"vidc_hal_session_set_buffers failed\n");
+		}
+		break;
+	default:
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_vdec_release_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	struct vidc_buffer_addr_info buffer_info;
+	struct msm_vidc_core *core;
+	int extra_idx = 0;
+	int i;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	hdev = inst->core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+			"Core %pK in bad state, ignoring release output buf\n",
+				core);
+		goto exit;
+	}
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+			"Planes mismatch: needed: %d, to release: %d\n",
+			inst->fmts[CAPTURE_PORT].num_planes, b->length);
+			rc = -EINVAL;
+			break;
+		}
+
+		for (i = 0; i < b->length; ++i) {
+			dprintk(VIDC_DBG,
+			"Release plane: %d device_addr = %#lx, size = %d\n",
+			i, b->m.planes[i].m.userptr,
+			b->m.planes[i].length);
+		}
+
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = b->m.planes[0].m.userptr;
+		buffer_info.response_required = false;
+
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES
+			&& b->m.planes[extra_idx].m.userptr)
+			buffer_info.extradata_addr =
+				b->m.planes[extra_idx].m.userptr;
+		else
+			buffer_info.extradata_addr = 0;
+
+		rc = call_hfi_op(hdev, session_release_buffers,
+			(void *)inst->session, &buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+			"vidc_hal_session_release_buffers failed\n");
+		break;
+	default:
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->lock);
+	rc = vb2_qbuf(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
+		return -EINVAL;
+	}
+	mutex_lock(&q->lock);
+	rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	if (!inst || !b) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, buffer = %pK\n", inst, b);
+		return -EINVAL;
+	}
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
+			, b->type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->lock);
+	rc = vb2_reqbufs(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
+	return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	struct hfi_device *hdev;
+	int rc = 0, i = 0, stride = 0, scanlines = 0, color_format = 0;
+	unsigned int *plane_sizes = NULL, extra_idx = 0;
+
+	if (!inst || !f || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, format = %pK\n", inst, f);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		fmt = &inst->fmts[CAPTURE_PORT];
+	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		fmt = &inst->fmts[OUTPUT_PORT];
+	else
+		return -ENOTSUPP;
+
+	f->fmt.pix_mp.pixelformat = fmt->fourcc;
+	f->fmt.pix_mp.num_planes = fmt->num_planes;
+	if (inst->in_reconfig) {
+		inst->prop.height[OUTPUT_PORT] = inst->reconfig_height;
+		inst->prop.width[OUTPUT_PORT] = inst->reconfig_width;
+
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"%s: unsupported session\n", __func__);
+			goto exit;
+		}
+	}
+
+	f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+	f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+	stride = inst->prop.width[CAPTURE_PORT];
+	scanlines = inst->prop.height[CAPTURE_PORT];
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		plane_sizes = &inst->bufq[OUTPUT_PORT].plane_sizes[0];
+		for (i = 0; i < fmt->num_planes; ++i) {
+			if (!plane_sizes[i]) {
+				f->fmt.pix_mp.plane_fmt[i].sizeimage =
+					get_frame_size(inst, fmt, f->type, i);
+				plane_sizes[i] = f->fmt.pix_mp.plane_fmt[i].
+					sizeimage;
+			} else
+				f->fmt.pix_mp.plane_fmt[i].sizeimage =
+					plane_sizes[i];
+		}
+		f->fmt.pix_mp.height = inst->prop.height[OUTPUT_PORT];
+		f->fmt.pix_mp.width = inst->prop.width[OUTPUT_PORT];
+		f->fmt.pix_mp.plane_fmt[0].bytesperline =
+			(__u16)inst->prop.width[OUTPUT_PORT];
+		f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+			(__u16)inst->prop.height[OUTPUT_PORT];
+	} else {
+		switch (fmt->fourcc) {
+		case V4L2_PIX_FMT_NV12:
+			color_format = COLOR_FMT_NV12;
+			break;
+		case V4L2_PIX_FMT_NV12_UBWC:
+			color_format = COLOR_FMT_NV12_UBWC;
+			break;
+		case V4L2_PIX_FMT_NV12_TP10_UBWC:
+			color_format = COLOR_FMT_NV12_BPP10_UBWC;
+			break;
+		default:
+			dprintk(VIDC_WARN, "Color format not recognized\n");
+			rc = -ENOTSUPP;
+			goto exit;
+		}
+
+		stride = VENUS_Y_STRIDE(color_format,
+				inst->prop.width[CAPTURE_PORT]);
+		scanlines = VENUS_Y_SCANLINES(color_format,
+				inst->prop.height[CAPTURE_PORT]);
+
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			get_output_frame_size(inst, fmt,
+			f->fmt.pix_mp.height, f->fmt.pix_mp.width, 0);
+
+		extra_idx = EXTRADATA_IDX(fmt->num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+				VENUS_EXTRADATA_SIZE(
+					inst->prop.height[CAPTURE_PORT],
+					inst->prop.width[CAPTURE_PORT]);
+		}
+
+		for (i = 0; i < fmt->num_planes; ++i)
+			inst->bufq[CAPTURE_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+
+		f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
+		f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
+		f->fmt.pix_mp.plane_fmt[0].bytesperline =
+			(__u16)stride;
+		f->fmt.pix_mp.plane_fmt[0].reserved[0] =
+			(__u16)scanlines;
+	}
+
+exit:
+	return rc;
+}
+
+static int set_default_properties(struct msm_vidc_inst *inst)
+{
+	struct hfi_device *hdev;
+	struct v4l2_control ctrl = {0};
+	enum hal_default_properties defaults;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	defaults = call_hfi_op(hdev, get_default_properties,
+					hdev->hfi_device_data);
+
+	if (defaults & HAL_VIDEO_DYNAMIC_BUF_MODE) {
+		dprintk(VIDC_DBG, "Enable dynamic buffer mode\n");
+		ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT;
+		ctrl.value = V4L2_MPEG_VIDC_VIDEO_DYNAMIC;
+		rc = msm_comm_s_ctrl(inst, &ctrl);
+		if (rc)
+			dprintk(VIDC_ERR,
+				"Failed to enable dynamic buffer mode by default: %d\n",
+				rc);
+	}
+
+	return rc;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	struct msm_vidc_format *fmt = NULL;
+	struct hal_frame_size frame_sz;
+	unsigned int extra_idx = 0;
+	int rc = 0;
+	int ret = 0;
+	int i;
+	int max_input_size = 0;
+
+	if (!inst || !inst->core || !f) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+			CAPTURE_PORT);
+		if (!fmt || fmt->type != CAPTURE_PORT) {
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on CAPTURE port\n",
+				f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+			frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+			frame_sz.width = inst->prop.width[CAPTURE_PORT];
+			frame_sz.height = inst->prop.height[CAPTURE_PORT];
+			msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT2,
+				f->fmt.pix_mp.pixelformat);
+			dprintk(VIDC_DBG,
+				"buffer type = %d width = %d, height = %d\n",
+				frame_sz.buffer_type, frame_sz.width,
+				frame_sz.height);
+			ret = msm_comm_try_set_prop(inst,
+				HAL_PARAM_FRAME_SIZE, &frame_sz);
+		} else {
+			msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT,
+				f->fmt.pix_mp.pixelformat);
+		}
+
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			get_output_frame_size(inst, &inst->fmts[fmt->type],
+			f->fmt.pix_mp.height, f->fmt.pix_mp.width, 0);
+
+		extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+				VENUS_EXTRADATA_SIZE(
+					inst->prop.height[CAPTURE_PORT],
+					inst->prop.width[CAPTURE_PORT]);
+		}
+
+		f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
+		for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+			inst->bufq[CAPTURE_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+
+		fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+				ARRAY_SIZE(vdec_formats),
+				f->fmt.pix_mp.pixelformat,
+				OUTPUT_PORT);
+		if (!fmt || fmt->type != OUTPUT_PORT) {
+			dprintk(VIDC_ERR,
+			"Format: %d not supported on OUTPUT port\n",
+			f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to initialize instance\n");
+			goto err_invalid_fmt;
+		}
+
+		if (!(get_hal_codec(inst->fmts[fmt->type].fourcc) &
+			inst->core->dec_codec_supported)) {
+			dprintk(VIDC_ERR,
+				"Codec(%#x) is not present in the supported codecs list(%#x)\n",
+				get_hal_codec(inst->fmts[fmt->type].fourcc),
+				inst->core->dec_codec_supported);
+			rc = -EINVAL;
+			goto err_invalid_fmt;
+		}
+
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to open instance\n");
+			goto err_invalid_fmt;
+		}
+
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto err_invalid_fmt;
+		}
+
+		frame_sz.buffer_type = HAL_BUFFER_INPUT;
+		frame_sz.width = inst->prop.width[OUTPUT_PORT];
+		frame_sz.height = inst->prop.height[OUTPUT_PORT];
+		dprintk(VIDC_DBG,
+			"buffer type = %d width = %d, height = %d\n",
+			frame_sz.buffer_type, frame_sz.width,
+			frame_sz.height);
+		msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+
+		max_input_size = get_frame_size(inst,
+					&inst->fmts[fmt->type], f->type, 0);
+		if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
+			!f->fmt.pix_mp.plane_fmt[0].sizeimage) {
+			f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
+		}
+
+		f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
+		for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+			inst->bufq[OUTPUT_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
+
+		set_default_properties(inst);
+	}
+err_invalid_fmt:
+	return rc;
+}
+
+int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+	if (!inst || !cap) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, cap = %pK\n", inst, cap);
+		return -EINVAL;
+	}
+	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
+	cap->bus_info[0] = 0;
+	cap->version = MSM_VIDC_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+						V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+						V4L2_CAP_STREAMING;
+	memset(cap->reserved, 0, sizeof(cap->reserved));
+	return 0;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, f = %pK\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+			ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	}
+
+	memset(f->reserved, 0, sizeof(f->reserved));
+	if (fmt) {
+		strlcpy(f->description, fmt->description,
+				sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+	} else {
+		dprintk(VIDC_DBG, "No more formats found\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int set_actual_buffer_count(struct msm_vidc_inst *inst,
+			int count, enum hal_buffer type)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct hal_buffer_count_actual buf_count;
+
+	hdev = inst->core->device;
+
+	buf_count.buffer_type = type;
+	buf_count.buffer_count_actual = count;
+	rc = call_hfi_op(hdev, session_set_property,
+		inst->session, HAL_PARAM_BUFFER_COUNT_ACTUAL, &buf_count);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to set actual buffer count %d for buffer type %d\n",
+			count, type);
+	return rc;
+}
+
+static int msm_vdec_queue_setup(struct vb2_queue *q,
+				unsigned int *num_buffers,
+				unsigned int *num_planes, unsigned int sizes[],
+				struct device *alloc_ctxs[])
+{
+	int i, rc = 0;
+	struct msm_vidc_inst *inst;
+	struct hal_buffer_requirements *bufreq;
+	int extra_idx = 0;
+	int min_buff_count = 0;
+
+	if (!q || !num_buffers || !num_planes
+		|| !sizes || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK, %pK, %pK\n",
+			q, num_buffers, num_planes);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"%s: Failed : Buffer requirements\n", __func__);
+		goto exit;
+	}
+
+
+
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		*num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+		if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+				*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+			*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+		/*
+		 * Increase input buffer count to 6 as for some
+		 * vp9 clips which have superframes with more
+		 * than 4 subframes requires more than 4
+		 * reference frames to decode.
+		 */
+		if (inst->fmts[OUTPUT_PORT].fourcc ==
+				V4L2_PIX_FMT_VP9 &&
+				*num_buffers < MIN_NUM_OUTPUT_BUFFERS_VP9)
+			*num_buffers = MIN_NUM_OUTPUT_BUFFERS_VP9;
+
+		for (i = 0; i < *num_planes; i++) {
+			sizes[i] = get_frame_size(inst,
+					&inst->fmts[OUTPUT_PORT], q->type, i);
+		}
+		rc = set_actual_buffer_count(inst, *num_buffers,
+			HAL_BUFFER_INPUT);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
+		*num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to open instance\n");
+			break;
+		}
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to get buffer requirements: %d\n", rc);
+			break;
+		}
+
+		bufreq = get_buff_req_buffer(inst,
+			msm_comm_get_hal_output_buffer(inst));
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"No buffer requirement for buffer type %x\n",
+				HAL_BUFFER_OUTPUT);
+			rc = -EINVAL;
+			break;
+		}
+
+		/* Pretend as if FW itself is asking for
+		 * additional buffers.
+		 * *num_buffers += MSM_VIDC_ADDITIONAL_BUFS_FOR_DCVS
+		 * is wrong since it will end up increasing the count
+		 * on every call to reqbufs if *num_bufs is larger
+		 * than min requirement.
+		 */
+		*num_buffers = max(*num_buffers, bufreq->buffer_count_min
+			+ msm_dcvs_get_extra_buff_count(inst));
+
+		min_buff_count = (!!(inst->flags & VIDC_THUMBNAIL)) ?
+			MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS :
+				MIN_NUM_CAPTURE_BUFFERS;
+
+		*num_buffers = clamp_val(*num_buffers,
+			min_buff_count, VB2_MAX_FRAME);
+
+		dprintk(VIDC_DBG, "Set actual output buffer count: %d\n",
+				*num_buffers);
+		rc = set_actual_buffer_count(inst, *num_buffers,
+					msm_comm_get_hal_output_buffer(inst));
+		if (rc)
+			break;
+
+		if (*num_buffers != bufreq->buffer_count_actual) {
+			rc = msm_comm_try_get_bufreqs(inst);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Failed to get buf req, %d\n", rc);
+				break;
+			}
+		}
+		dprintk(VIDC_DBG, "count =  %d, size = %d, alignment = %d\n",
+				inst->buff_req.buffer[1].buffer_count_actual,
+				inst->buff_req.buffer[1].buffer_size,
+				inst->buff_req.buffer[1].buffer_alignment);
+		sizes[0] = inst->bufq[CAPTURE_PORT].plane_sizes[0];
+
+
+		/* Set actual buffer count to firmware for DPB buffers.
+		 * Firmware mandates setting of minimum buffer size
+		 * and actual buffer count for both OUTPUT and OUTPUT2.
+		 * Hence we are setting back the same buffer size
+		 * information back to firmware.
+		 */
+		if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_OUTPUT);
+			if (!bufreq) {
+				rc = -EINVAL;
+				break;
+			}
+
+			rc = set_actual_buffer_count(inst,
+				bufreq->buffer_count_actual,
+				HAL_BUFFER_OUTPUT);
+			if (rc)
+				break;
+		}
+
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			sizes[extra_idx] =
+				VENUS_EXTRADATA_SIZE(
+					inst->prop.height[CAPTURE_PORT],
+					inst->prop.width[CAPTURE_PORT]);
+		}
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+exit:
+	return rc;
+}
+
+static inline int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct {
+		enum hal_buffer type;
+		struct hal_buffer_requirements *req;
+		size_t size;
+	} internal_buffers[] = {
+		{ HAL_BUFFER_INTERNAL_SCRATCH, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_SCRATCH_1, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_SCRATCH_2, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_PERSIST, NULL, 0},
+		{ HAL_BUFFER_INTERNAL_PERSIST_1, NULL, 0},
+	};
+
+	struct hal_frame_size frame_sz;
+	int i;
+
+	frame_sz.buffer_type = HAL_BUFFER_INPUT;
+	frame_sz.width = inst->capability.width.max;
+	frame_sz.height =
+		(inst->capability.mbs_per_frame.max * 256) /
+		inst->capability.width.max;
+
+	dprintk(VIDC_DBG,
+		"Max buffer reqs, buffer type = %d width = %d, height = %d, max_mbs_per_frame = %d\n",
+		frame_sz.buffer_type, frame_sz.width,
+		frame_sz.height, inst->capability.mbs_per_frame.max);
+
+	msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s Failed to get max buf req, %d\n", __func__, rc);
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) {
+		internal_buffers[i].req =
+			get_buff_req_buffer(inst, internal_buffers[i].type);
+		internal_buffers[i].size = internal_buffers[i].req ?
+			internal_buffers[i].req->buffer_size : 0;
+	}
+
+	frame_sz.buffer_type = HAL_BUFFER_INPUT;
+	frame_sz.width = inst->prop.width[OUTPUT_PORT];
+	frame_sz.height = inst->prop.height[OUTPUT_PORT];
+
+	msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s Failed to get back old buf req, %d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	dprintk(VIDC_DBG,
+			"Old buffer reqs, buffer type = %d width = %d, height = %d\n",
+			frame_sz.buffer_type, frame_sz.width,
+			frame_sz.height);
+
+	for (i = 0; i < ARRAY_SIZE(internal_buffers); i++) {
+		if (internal_buffers[i].req) {
+			internal_buffers[i].req->buffer_size =
+				internal_buffers[i].size;
+			dprintk(VIDC_DBG,
+				"Changing buffer type : %d size to : %zd\n",
+				internal_buffers[i].type,
+				internal_buffers[i].size);
+		}
+	}
+	return 0;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	bool slave_side_cp = inst->core->resources.slave_side_cp;
+	struct hal_buffer_size_minimum b;
+	unsigned int buffer_size;
+	struct msm_vidc_format *fmt = NULL;
+
+	fmt = &inst->fmts[CAPTURE_PORT];
+	buffer_size = get_output_frame_size(inst, fmt,
+		inst->prop.height[CAPTURE_PORT],
+		inst->prop.width[CAPTURE_PORT], 0);
+	hdev = inst->core->device;
+
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_vidc_check_scaling_supported(inst);
+		b.buffer_type = HAL_BUFFER_OUTPUT2;
+	} else {
+		b.buffer_type = HAL_BUFFER_OUTPUT;
+	}
+
+	b.buffer_size = buffer_size;
+	rc = call_hfi_op(hdev, session_set_property,
+		 inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
+		 &b);
+	if (rc) {
+		dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
+		return -EINVAL;
+	}
+	if ((inst->flags & VIDC_SECURE) && !inst->in_reconfig &&
+		!slave_side_cp) {
+		rc = set_max_internal_buffers_size(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set max scratch buffer size: %d\n",
+				rc);
+			goto fail_start;
+		}
+	}
+	rc = msm_comm_set_scratch_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to set scratch buffers: %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
+
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_comm_set_output_buffers(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set output buffers: %d\n", rc);
+			goto fail_start;
+		}
+	}
+
+	/*
+	 * For seq_changed_insufficient, driver should set session_continue
+	 * to firmware after the following sequence
+	 * - driver raises insufficient event to v4l2 client
+	 * - all output buffers have been flushed and freed
+	 * - v4l2 client queries buffer requirements and splits/combines OPB-DPB
+	 * - v4l2 client sets new set of buffers to firmware
+	 * - v4l2 client issues CONTINUE to firmware to resume decoding of
+	 *   submitted ETBs.
+	 */
+	if (inst->in_reconfig) {
+		dprintk(VIDC_DBG, "send session_continue after reconfig\n");
+		rc = call_hfi_op(hdev, session_continue,
+			(void *) inst->session);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s - failed to send session_continue\n",
+				__func__);
+			goto fail_start;
+		}
+	}
+	inst->in_reconfig = false;
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto fail_start;
+	}
+	msm_dcvs_init_load(inst);
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY) {
+		rc = msm_comm_queue_output_buffers(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to queue output buffers: %d\n", rc);
+			goto fail_start;
+		}
+	}
+
+fail_start:
+	return rc;
+}
+
+static inline int stop_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+	return rc;
+}
+
+
+static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+	dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n",
+		q->type, inst);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		goto stream_start_failed;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Streamon failed on: %d capability for inst: %pK\n",
+			q->type, inst);
+		goto stream_start_failed;
+	}
+
+	rc = msm_comm_qbuf(inst, NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to commit buffers queued before STREAM_ON to hardware: %d\n",
+				rc);
+		goto stream_start_failed;
+	}
+
+stream_start_failed:
+	return rc;
+}
+
+static void msm_vdec_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
+		return;
+	}
+
+	inst = q->drv_priv;
+	dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+			rc = stop_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+			rc = stop_streaming(inst);
+		break;
+	default:
+		dprintk(VIDC_ERR,
+			"Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK, cap = %d to state: %d\n",
+			inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
+}
+
+static void msm_vdec_buf_queue(struct vb2_buffer *vb)
+{
+	int rc = msm_comm_qbuf(vb2_get_drv_priv(vb->vb2_queue), vb);
+
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_vdec_vb2q_ops = {
+	.queue_setup = msm_vdec_queue_setup,
+	.start_streaming = msm_vdec_start_streaming,
+	.buf_queue = msm_vdec_buf_queue,
+	.stop_streaming = msm_vdec_stop_streaming,
+};
+
+const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
+{
+	return &msm_vdec_vb2q_ops;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid input = %pK\n", inst);
+		return -EINVAL;
+	}
+	inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+	inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+	inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
+	inst->capability.height.max = DEFAULT_HEIGHT;
+	inst->capability.width.min = MIN_SUPPORTED_WIDTH;
+	inst->capability.width.max = DEFAULT_WIDTH;
+	inst->capability.alloc_mode_in = HAL_BUFFER_MODE_STATIC;
+	inst->capability.alloc_mode_out = HAL_BUFFER_MODE_STATIC;
+	inst->capability.secure_output2_threshold.min = 0;
+	inst->capability.secure_output2_threshold.max = 0;
+	inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->prop.fps = DEFAULT_FPS;
+	memcpy(&inst->fmts[OUTPUT_PORT], &vdec_formats[2],
+						sizeof(struct msm_vidc_format));
+	memcpy(&inst->fmts[CAPTURE_PORT], &vdec_formats[0],
+						sizeof(struct msm_vidc_format));
+	return rc;
+}
+
+static inline enum buffer_mode_type get_buf_type(int val)
+{
+	switch (val) {
+	case V4L2_MPEG_VIDC_VIDEO_STATIC:
+		return HAL_BUFFER_MODE_STATIC;
+	case V4L2_MPEG_VIDC_VIDEO_RING:
+		return HAL_BUFFER_MODE_RING;
+	case V4L2_MPEG_VIDC_VIDEO_DYNAMIC:
+		return HAL_BUFFER_MODE_DYNAMIC;
+	default:
+		dprintk(VIDC_ERR, "%s: invalid buf type: %d\n", __func__, val);
+	}
+	return 0;
+}
+
+static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	union hal_get_property hprop;
+
+	if (!inst || !inst->core || !inst->core->device || !ctrl) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	/*
+	 * HACK: unlock the control prior to querying the hardware.  Otherwise
+	 * lower level code that attempts to do g_ctrl() will end up deadlocking
+	 * us.
+	 */
+	v4l2_ctrl_unlock(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+		rc = msm_comm_try_get_prop(inst,
+				HAL_PARAM_PROFILE_LEVEL_CURRENT, &hprop);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: Failed getting profile: %d",
+					__func__, rc);
+			break;
+		}
+		ctrl->val = vdec_hal_to_v4l2(ctrl->id,
+				hprop.profile_level.profile);
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+		rc = msm_comm_try_get_prop(inst,
+				HAL_PARAM_PROFILE_LEVEL_CURRENT, &hprop);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: Failed getting level: %d",
+					__func__, rc);
+			break;
+		}
+
+		ctrl->val = vdec_hal_to_v4l2(ctrl->id,
+				hprop.profile_level.level);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD:
+		dprintk(VIDC_DBG, "Secure scaling threshold is: %d",
+				inst->capability.secure_output2_threshold.max);
+		ctrl->val = inst->capability.secure_output2_threshold.max;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		rc = msm_comm_try_get_prop(inst,
+				HAL_CONFIG_VDEC_ENTROPY, &hprop);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: Failed getting entropy type: %d",
+					__func__, rc);
+			break;
+		}
+		switch (hprop.h264_entropy) {
+		case HAL_H264_ENTROPY_CAVLC:
+			ctrl->val = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC;
+			break;
+		case HAL_H264_ENTROPY_CABAC:
+			ctrl->val = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC;
+			break;
+		case HAL_UNUSED_ENTROPY:
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	default:
+		/* Other controls aren't really volatile, shouldn't need to
+		 * modify ctrl->value
+		 */
+		break;
+	}
+	v4l2_ctrl_lock(ctrl);
+
+	return rc;
+}
+
+static int vdec_v4l2_to_hal(int id, int value)
+{
+	switch (id) {
+		/* H264 */
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+			return HAL_H264_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+			return HAL_H264_PROFILE_CONSTRAINED_BASE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
+			return HAL_H264_PROFILE_CONSTRAINED_HIGH;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+			return HAL_H264_PROFILE_MAIN;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+			return HAL_H264_PROFILE_EXTENDED;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+			return HAL_H264_PROFILE_HIGH;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+			return HAL_H264_PROFILE_HIGH10;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+			return HAL_H264_PROFILE_HIGH422;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+			return HAL_H264_PROFILE_HIGH444;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+			return HAL_H264_LEVEL_1;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+			return HAL_H264_LEVEL_1b;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+			return HAL_H264_LEVEL_11;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+			return HAL_H264_LEVEL_12;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+			return HAL_H264_LEVEL_13;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+			return HAL_H264_LEVEL_2;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+			return HAL_H264_LEVEL_21;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+			return HAL_H264_LEVEL_22;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+			return HAL_H264_LEVEL_3;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+			return HAL_H264_LEVEL_31;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+			return HAL_H264_LEVEL_32;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+			return HAL_H264_LEVEL_4;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+			return HAL_H264_LEVEL_41;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+			return HAL_H264_LEVEL_42;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+			return HAL_H264_LEVEL_5;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+			return HAL_H264_LEVEL_51;
+		default:
+			goto unknown_value;
+		}
+	}
+unknown_value:
+	dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
+	return -EINVAL;
+}
+
+static int vdec_hal_to_v4l2(int id, int value)
+{
+	switch (id) {
+		/* H264 */
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (value) {
+		case HAL_H264_PROFILE_BASELINE:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+		case HAL_H264_PROFILE_CONSTRAINED_BASE:
+			return
+			V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
+		case HAL_H264_PROFILE_MAIN:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
+		case HAL_H264_PROFILE_EXTENDED:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
+		case HAL_H264_PROFILE_HIGH:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+		case HAL_H264_PROFILE_HIGH10:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
+		case HAL_H264_PROFILE_HIGH422:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
+		case HAL_H264_PROFILE_HIGH444:
+			return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		switch (value) {
+		case HAL_H264_LEVEL_1:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
+		case HAL_H264_LEVEL_1b:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
+		case HAL_H264_LEVEL_11:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
+		case HAL_H264_LEVEL_12:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
+		case HAL_H264_LEVEL_13:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
+		case HAL_H264_LEVEL_2:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
+		case HAL_H264_LEVEL_21:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
+		case HAL_H264_LEVEL_22:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
+		case HAL_H264_LEVEL_3:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
+		case HAL_H264_LEVEL_31:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
+		case HAL_H264_LEVEL_32:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
+		case HAL_H264_LEVEL_4:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+		case HAL_H264_LEVEL_41:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
+		case HAL_H264_LEVEL_42:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+		case HAL_H264_LEVEL_5:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
+		case HAL_H264_LEVEL_51:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+		/*
+		 * Extremely dirty hack: we haven't implemented g_ctrl of
+		 * any of these controls and have no intention of doing
+		 * so in the near future.  So just return 0 so that we
+		 * don't see the annoying "Unknown control" errors at the
+		 * bottom of this function.
+		 */
+		return 0;
+	}
+
+unknown_value:
+	dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
+	return -EINVAL;
+}
+
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+		struct v4l2_ctrl **cluster, int ncontrols)
+{
+	int c;
+
+	for (c = 0; c < ncontrols; ++c)
+		if (cluster[c]->id == id)
+			return cluster[c];
+	return NULL;
+}
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct hal_nal_stream_format_supported stream_format;
+	struct hal_enable_picture enable_picture;
+	struct hal_enable hal_property;
+	enum hal_property property_id = 0;
+	u32 property_val = 0;
+	void *pdata = NULL;
+	struct hfi_device *hdev;
+	struct hal_extradata_enable extra;
+	struct hal_buffer_alloc_mode alloc_mode;
+	struct hal_multi_stream multi_stream;
+	struct hal_scs_threshold scs_threshold;
+	struct hal_mvc_buffer_layout layout;
+	struct v4l2_ctrl *temp_ctrl = NULL;
+	struct hal_profile_level profile_level;
+	struct hal_frame_size frame_sz;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	rc = is_ctrl_valid_for_codec(inst, ctrl);
+	if (rc)
+		return rc;
+
+	/* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+		struct v4l2_ctrl *__temp; \
+		__temp = get_ctrl_from_cluster( \
+			__ctrl_id, \
+			ctrl->cluster, ctrl->ncontrols); \
+		if (!__temp) { \
+			dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \
+				#__ctrl_id, __ctrl_id); \
+			/* Clusters are hardcoded, if we can't find */ \
+			/* something then things are massively screwed up */ \
+			WARN_ON(VIDC_DBG_WARN_ENABLE); \
+		} \
+		__temp; \
+	})
+
+	v4l2_ctrl_unlock(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+		property_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+		stream_format.nal_stream_format_supported = BIT(ctrl->val);
+		pdata = &stream_format;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+		property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+		property_val = ctrl->val;
+		pdata = &property_val;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE:
+		property_id = HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+		if (ctrl->val ==
+			V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_ON)
+			enable_picture.picture_type = HAL_PICTURE_I;
+		else
+			enable_picture.picture_type = HAL_PICTURE_I |
+				HAL_PICTURE_P | HAL_PICTURE_B |
+				HAL_PICTURE_IDR;
+		pdata = &enable_picture;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+		property_id = HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+		property_id = HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+		property_id = HAL_PARAM_DIVX_FORMAT;
+		property_val = ctrl->val;
+		pdata = &property_val;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+		property_id = HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+		property_id = HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE:
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE:
+			inst->flags &= ~VIDC_THUMBNAIL;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE:
+			inst->flags |= VIDC_THUMBNAIL;
+			break;
+		}
+
+		property_id = HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+		inst->flags |= VIDC_SECURE;
+		dprintk(VIDC_DBG, "Setting secure mode to: %d\n",
+				!!(inst->flags & VIDC_SECURE));
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+		property_id = HAL_PARAM_INDEX_EXTRADATA;
+		extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+		extra.enable = 1;
+		pdata = &extra;
+		break;
+	case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+			inst->flags &= ~VIDC_TURBO;
+			break;
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+			inst->flags |= VIDC_TURBO;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Perf mode %x not supported\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		msm_comm_scale_clocks_and_bus(inst);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT:
+		if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) {
+			rc = -ENOTSUPP;
+			break;
+		}
+		property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+		alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+		alloc_mode.buffer_type = HAL_BUFFER_INPUT;
+		inst->buffer_mode_set[OUTPUT_PORT] = alloc_mode.buffer_mode;
+		pdata = &alloc_mode;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
+		property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
+		hal_property.enable = ctrl->val;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT:
+		property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+		alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+
+		if (!(alloc_mode.buffer_mode &
+			inst->capability.alloc_mode_out)) {
+			dprintk(VIDC_WARN,
+				"buffer mode[%d] not supported for capture port[0x%x]\n",
+				ctrl->val, inst->capability.alloc_mode_out);
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		alloc_mode.buffer_type = HAL_BUFFER_OUTPUT;
+		pdata = &alloc_mode;
+		inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+		if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
+				HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Downscaling not supported: %#x\n",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+			multi_stream.enable = true;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed : Enabling OUTPUT port : %d\n",
+					rc);
+				break;
+			}
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+			multi_stream.enable = false;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed:Disabling OUTPUT2 port : %d\n",
+					rc);
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
+			multi_stream.enable = true;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed :Enabling OUTPUT2 port : %d\n",
+					rc);
+					break;
+			}
+			multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
+			multi_stream.enable = false;
+			pdata = &multi_stream;
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
+				pdata);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed disabling OUTPUT port : %d\n",
+					rc);
+				break;
+			}
+
+			frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+			frame_sz.width = inst->prop.width[CAPTURE_PORT];
+			frame_sz.height = inst->prop.height[CAPTURE_PORT];
+			pdata = &frame_sz;
+			dprintk(VIDC_DBG,
+				"buffer type = %d width = %d, height = %d\n",
+				frame_sz.buffer_type, frame_sz.width,
+				frame_sz.height);
+			rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_FRAME_SIZE, pdata);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed setting OUTPUT2 size : %d\n",
+					rc);
+
+			alloc_mode.buffer_mode =
+				inst->buffer_mode_set[CAPTURE_PORT];
+			alloc_mode.buffer_type = HAL_BUFFER_OUTPUT2;
+			rc = call_hfi_op(hdev, session_set_property,
+				inst->session, HAL_PARAM_BUFFER_ALLOC_MODE,
+				&alloc_mode);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Failed to set alloc_mode on OUTPUT2: %d\n",
+					rc);
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"Failed : Unsupported multi stream setting\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD:
+		property_id = HAL_PARAM_VDEC_SCS_THRESHOLD;
+		scs_threshold.threshold_value = ctrl->val;
+		pdata = &scs_threshold;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
+		property_id = HAL_PARAM_MVC_BUFFER_LAYOUT;
+		layout.layout_type = msm_comm_get_hal_buffer_layout(ctrl->val);
+		layout.bright_view_first = 0;
+		layout.ngap = 0;
+		pdata = &layout;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
+		property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
+		property_val = ctrl->val;
+		pdata = &property_val;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = vdec_v4l2_to_hal(ctrl->id,
+				ctrl->val);
+		profile_level.level = vdec_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = vdec_v4l2_to_hal(ctrl->id,
+				ctrl->val);
+		profile_level.profile = vdec_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT:
+		dprintk(VIDC_DBG,
+			"Limiting input buffer size from %u to %u\n",
+			inst->buffer_size_limit, ctrl->val);
+		inst->buffer_size_limit = ctrl->val;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2:
+		property_id = HAL_PARAM_VDEC_NON_SECURE_OUTPUT2;
+		hal_property.enable = ctrl->val;
+		dprintk(VIDC_DBG, "%s non_secure output2\n",
+			ctrl->val ? "Enabling" : "Disabling");
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_VIDC_QBUF_MODE:
+		property_id = HAL_PARAM_SYNC_BASED_INTERRUPT;
+		hal_property.enable = ctrl->val == V4L2_VIDC_QBUF_BATCHED;
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY:
+		property_id = HAL_CONFIG_REALTIME;
+		/* firmware has inverted values for realtime and
+		 * non-realtime priority
+		 */
+		hal_property.enable = !(ctrl->val);
+		pdata = &hal_property;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+		break;
+	default:
+		break;
+	}
+
+	v4l2_ctrl_lock(ctrl);
+#undef TRY_GET_CTRL
+
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG,
+			"Control: HAL property=%#x,ctrl: id=%#x,value=%#x\n",
+			property_id, ctrl->id, ctrl->val);
+		rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, property_id, pdata);
+	}
+
+	return rc;
+}
+
+static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0, i = 0, fourcc = 0;
+	struct v4l2_ext_control *ext_control;
+	struct v4l2_control control;
+
+	if (!inst || !inst->core || !ctrl) {
+		dprintk(VIDC_ERR,
+			"%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	ext_control = ctrl->controls;
+	control.id =
+		V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
+
+	for (i = 0; i < ctrl->count; i++) {
+		switch (ext_control[i].id) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
+			control.value = ext_control[i].value;
+
+			rc = msm_comm_s_ctrl(inst, &control);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"%s Failed setting stream output mode : %d\n",
+					__func__, rc);
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT:
+			switch (ext_control[i].value) {
+			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE:
+				if (!msm_comm_g_ctrl_for_id(inst, control.id)) {
+					rc = msm_comm_release_output_buffers(
+						inst);
+					if (rc)
+						dprintk(VIDC_ERR,
+							"%s Release output buffers failed\n",
+							__func__);
+				}
+				break;
+			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC:
+			case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC:
+				if (ext_control[i].value ==
+					V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC)
+					fourcc = V4L2_PIX_FMT_NV12_UBWC;
+				else
+					fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC;
+				if (msm_comm_g_ctrl_for_id(inst, control.id)) {
+					rc = msm_comm_set_color_format(inst,
+						HAL_BUFFER_OUTPUT, fourcc);
+					if (rc) {
+						dprintk(VIDC_ERR,
+							"%s Failed setting output color format : %d\n",
+							__func__, rc);
+						break;
+					}
+					rc = msm_comm_try_get_bufreqs(inst);
+					if (rc)
+						dprintk(VIDC_ERR,
+							"%s Failed to get buffer requirements : %d\n",
+							__func__, rc);
+				}
+				break;
+			default:
+				dprintk(VIDC_ERR,
+					"%s Unsupported output color format\n",
+					__func__);
+				rc = -ENOTSUPP;
+				break;
+			}
+			break;
+		default:
+			dprintk(VIDC_ERR
+				, "%s Unsupported set control %d",
+				__func__, ext_control[i].id);
+			rc = -ENOTSUPP;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0, c = 0;
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+				struct msm_vidc_inst, ctrl_handler);
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto failed_open_done;
+	}
+
+	for (c = 0; c < ctrl->ncontrols; ++c) {
+		if (ctrl->cluster[c]->is_new) {
+			rc = try_set_ctrl(inst, ctrl->cluster[c]);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed setting %x\n",
+						ctrl->cluster[c]->id);
+				break;
+			}
+		}
+	}
+
+failed_open_done:
+	return rc;
+}
+
+static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	int rc = 0, c = 0;
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+				struct msm_vidc_inst, ctrl_handler);
+	struct v4l2_ctrl *master = ctrl->cluster[0];
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto failed_open_done;
+	}
+	for (c = 0; c < master->ncontrols; ++c) {
+		int d = 0;
+
+		for (d = 0; d < NUM_CTRLS; ++d) {
+			if (master->cluster[c]->id == inst->ctrls[d]->id &&
+				inst->ctrls[d]->flags &
+				V4L2_CTRL_FLAG_VOLATILE) {
+				rc = try_get_ctrl(inst, master->cluster[c]);
+				if (rc) {
+					dprintk(VIDC_ERR, "Failed getting %x\n",
+							master->cluster[c]->id);
+					return rc;
+				}
+				break;
+			}
+		}
+	}
+	return rc;
+
+failed_open_done:
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to get hal property\n");
+	return rc;
+}
+
+static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
+
+	.s_ctrl = msm_vdec_op_s_ctrl,
+	.g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
+{
+	return &msm_vdec_ctrl_ops;
+}
+
+int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0;
+
+	rc = try_set_ext_ctrl(inst, ctrl);
+	if (rc) {
+		dprintk(VIDC_ERR, "Error setting extended control\n");
+		return rc;
+	}
+	return rc;
+}
+
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
+{
+	return msm_comm_ctrl_init(inst, msm_vdec_ctrls,
+		ARRAY_SIZE(msm_vdec_ctrls), &msm_vdec_ctrl_ops);
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vdec.h b/drivers/media/platform/msm/vidc_3x/msm_vdec.h
new file mode 100644
index 0000000..065f02a
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vdec.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2012, 2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _MSM_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
+int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
+int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+struct vb2_ops *msm_vdec_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.c b/drivers/media/platform/msm/vidc_3x/msm_venc.c
new file mode 100644
index 0000000..50ec4bd
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_venc.c
@@ -0,0 +1,4584 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define MSM_VENC_DVC_NAME "msm_venc_8974"
+#define MIN_NUM_OUTPUT_BUFFERS 4
+#define MIN_NUM_CAPTURE_BUFFERS 4
+#define MIN_BIT_RATE 32000
+#define MAX_BIT_RATE 300000000
+#define DEFAULT_BIT_RATE 64000
+#define BIT_RATE_STEP 100
+#define DEFAULT_FRAME_RATE 15
+#define MAX_OPERATING_FRAME_RATE (300 << 16)
+#define OPERATING_FRAME_RATE_STEP (1 << 16)
+#define MAX_SLICE_BYTE_SIZE ((MAX_BIT_RATE)>>3)
+#define MIN_SLICE_BYTE_SIZE 512
+#define MAX_SLICE_MB_SIZE ((4096 * 2304) >> 8)
+#define I_FRAME_QP 26
+#define P_FRAME_QP 28
+#define B_FRAME_QP 30
+#define MAX_INTRA_REFRESH_MBS ((4096 * 2304) >> 8)
+#define MAX_NUM_B_FRAMES 4
+#define MAX_LTR_FRAME_COUNT 10
+#define MAX_HYBRID_HIER_P_LAYERS 6
+
+#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+#define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
+#define BITSTREAM_RESTRICT_ENABLED \
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED
+#define BITSTREAM_RESTRICT_DISABLED \
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED
+#define MIN_TIME_RESOLUTION 1
+#define MAX_TIME_RESOLUTION 0xFFFFFF
+#define DEFAULT_TIME_RESOLUTION 0x7530
+
+/*
+ * Default 601 to 709 conversion coefficients for resolution: 176x144 negative
+ * coeffs are converted to s4.9 format (e.g. -22 converted to ((1 << 13) - 22)
+ * 3x3 transformation matrix coefficients in s4.9 fixed point format
+ */
+static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
+	470, 8170, 8148, 0, 490, 50, 0, 34, 483
+};
+
+/* offset coefficients in s9 fixed point format */
+static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
+	34, 0, 4
+};
+
+/* clamping value for Y/U/V([min,max] for Y/U/V) */
+static u32 vpe_csc_601_to_709_limit_coeff[HAL_MAX_LIMIT_COEFFS] = {
+	16, 235, 16, 240, 16, 240
+};
+
+static const char *const mpeg_video_rate_control[] = {
+	"No Rate Control",
+	"VBR VFR",
+	"VBR CFR",
+	"CBR VFR",
+	"CBR CFR",
+	"MBR CFR",
+	"MBR VFR",
+	NULL
+};
+
+static const char *const mpeg_video_rotation[] = {
+	"No Rotation",
+	"90 Degree Rotation",
+	"180 Degree Rotation",
+	"270 Degree Rotation",
+	NULL
+};
+
+static const char *const h264_video_entropy_cabac_model[] = {
+	"Model 0",
+	"Model 1",
+	"Model 2",
+	NULL
+};
+
+static const char *const h263_level[] = {
+	"1.0",
+	"2.0",
+	"3.0",
+	"4.0",
+	"4.5",
+	"5.0",
+	"6.0",
+	"7.0",
+};
+
+static const char *const h263_profile[] = {
+	"Baseline",
+	"H320 Coding",
+	"Backward Compatible",
+	"ISWV2",
+	"ISWV3",
+	"High Compression",
+	"Internet",
+	"Interlace",
+	"High Latency",
+};
+
+static const char *const hevc_tier_level[] = {
+	"Main Tier Level 1",
+	"Main Tier Level 2",
+	"Main Tier Level 2.1",
+	"Main Tier Level 3",
+	"Main Tier Level 3.1",
+	"Main Tier Level 4",
+	"Main Tier Level 4.1",
+	"Main Tier Level 5",
+	"Main Tier Level 5.1",
+	"Main Tier Level 5.2",
+	"Main Tier Level 6",
+	"Main Tier Level 6.1",
+	"Main Tier Level 6.2",
+	"High Tier Level 1",
+	"High Tier Level 2",
+	"High Tier Level 2.1",
+	"High Tier Level 3",
+	"High Tier Level 3.1",
+	"High Tier Level 4",
+	"High Tier Level 4.1",
+	"High Tier Level 5",
+	"High Tier Level 5.1",
+	"High Tier Level 5.2",
+	"High Tier Level 6",
+	"High Tier Level 6.1",
+	"High Tier Level 6.2",
+};
+
+static const char *const hevc_profile[] = {
+	"Main",
+	"Main10",
+	"Main Still Pic",
+};
+
+static const char *const vp8_profile_level[] = {
+	"Unused",
+	"0.0",
+	"1.0",
+	"2.0",
+	"3.0",
+};
+
+static const char *const perf_level[] = {
+	"Nominal",
+	"Performance",
+	"Turbo"
+};
+
+static const char *const mbi_statistics[] = {
+	"Camcorder Default",
+	"Mode 1",
+	"Mode 2",
+	"Mode 3"
+};
+
+static const char *const intra_refresh_modes[] = {
+	"None",
+	"Cyclic",
+	"Adaptive",
+	"Cyclic Adaptive",
+	"Random"
+};
+
+static const char *const timestamp_mode[] = {
+	"Honor",
+	"Ignore",
+};
+
+static const char *const iframe_sizes[] = {
+	"Default",
+	"Medium",
+	"Huge",
+	"Unlimited"
+};
+
+static struct msm_vidc_ctrl msm_venc_ctrls[] = {
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD,
+		.name = "IDR Period",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = INT_MAX,
+		.default_value = DEFAULT_FRAME_RATE,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES,
+		.name = "Intra Period for P frames",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 2*DEFAULT_FRAME_RATE-1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
+		.name = "Intra Period for B frames",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = INT_MAX,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME,
+		.name = "Request I Frame",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL,
+		.name = "Video Framerate and Bitrate Control",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF,
+		.step = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR)
+		),
+		.qmenu = mpeg_video_rate_control,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+		.name = "Bitrate Control",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		.maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+		.default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+		.step = 0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
+		(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+		),
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE,
+		.name = "Bit Rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_BIT_RATE,
+		.maximum = MAX_BIT_RATE,
+		.default_value = DEFAULT_BIT_RATE,
+		.step = BIT_RATE_STEP,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+		.name = "Peak Bit Rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_BIT_RATE,
+		.maximum = MAX_BIT_RATE,
+		.default_value = DEFAULT_BIT_RATE,
+		.step = BIT_RATE_STEP,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+		.name = "Entropy Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+		.default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
+		(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+		.name = "CABAC Model",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)
+		),
+		.qmenu = h264_video_entropy_cabac_model,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+		.name = "MPEG4 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.maximum = CODING,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+		.name = "MPEG4 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+		.name = "H264 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
+		.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+		.name = "H264 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
+		.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+		.name = "H263 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
+		),
+		.qmenu = h263_profile,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+		.name = "H263 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
+		),
+		.qmenu = h263_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+		.name = "VP8 Profile Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+		),
+		.qmenu = vp8_profile_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+		.name = "HEVC Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN,
+		.menu_skip_mask =  ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC)
+		),
+		.qmenu = hevc_profile,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+		.name = "HEVC Tier and Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1)
+		),
+		.qmenu = hevc_tier_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+		.name = "Rotation",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)
+		),
+		.qmenu = mpeg_video_rotation,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+		.name = "H264 I Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = I_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+		.name = "H264 P Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = P_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+		.name = "H264 B Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = B_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+		.name = "H263 I Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = I_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+		.name = "H263 P Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = P_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
+		.name = "H263 B Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = B_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP,
+		.name = "VPX I Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = I_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP,
+		.name = "VPX P Frame Quantization",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = P_FRAME_QP,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+		.name = "H264 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+		.name = "H264 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 51,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP,
+		.name = "VPX Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = 0,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP,
+		.name = "VPX Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 127,
+		.default_value = 127,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP,
+		.name = "VP8 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 128,
+		.default_value = 1,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP,
+		.name = "VP8 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 128,
+		.default_value = 128,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+		.name = "MPEG4 Minimum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = 1,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+		.name = "MPEG4 Maximum QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 31,
+		.default_value = 31,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED,
+		.name = "H264 Minimum QP PACKED",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0x00010101,
+		.maximum = 0x00333333,
+		.default_value = 0x00010101,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED,
+		.name = "H264 Maximum QP PACKED",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0x00010101,
+		.maximum = 0x00333333,
+		.default_value = 0x00333333,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+		.name = "Slice Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		.maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_GOB,
+		.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) |
+		(1 << V4L2_MPEG_VIDEO_MULTI_SLICE_GOB)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+		.name = "Slice Byte Size",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_SLICE_BYTE_SIZE,
+		.maximum = MAX_SLICE_BYTE_SIZE,
+		.default_value = MIN_SLICE_BYTE_SIZE,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+		.name = "Slice MB Size",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = MAX_SLICE_MB_SIZE,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB,
+		.name = "Slice GOB",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = MAX_SLICE_MB_SIZE,
+		.default_value = 1,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE,
+		.name = "Slice delivery mode",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE,
+		.name = "Intra Refresh Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE,
+		.menu_skip_mask = ~(
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
+		(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
+		),
+		.qmenu = intra_refresh_modes,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS,
+		.name = "Intra Refresh AIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF,
+		.name = "Intra Refresh AIR REF",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS,
+		.name = "Intra Refresh CIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+		.name = "H.264 Loop Filter Alpha Offset",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = -6,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+		.name = "H.264 Loop Filter Beta Offset",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = -6,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+		.name = "H.264 Loop Filter Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+		.maximum = L_MODE,
+		.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) |
+		(1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) |
+		(1 << L_MODE)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+		.name = "Sequence Header Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+		.maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+		.default_value =
+			V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
+		(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)
+		),
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
+		.name = "Secure mode",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
+		.name = "Extradata Type",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.maximum = V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO,
+		.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
+		.menu_skip_mask = ~(
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS)|
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP) |
+			(1 << V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO)
+			),
+		.qmenu = mpeg_video_vidc_extradata,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO,
+		.name = "H264 VUI Timing Info",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER,
+		.name = "H264 AU Delimiter",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_ENABLED,
+		.step = 1,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_DISABLED,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
+		.name = "Encoder Performance Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
+		.default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
+			(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
+		.qmenu = perf_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+		.name = "Intra Refresh CIR MBS",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_INTRA_REFRESH_MBS,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT,
+		.name = "H264 VUI Timing Info",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = BITSTREAM_RESTRICT_DISABLED,
+		.maximum = BITSTREAM_RESTRICT_ENABLED,
+		.default_value = BITSTREAM_RESTRICT_ENABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY,
+		.name = "Preserve Text Qualty",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE,
+		.name = "Deinterlace for encoder",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION,
+		.name = "Vop time increment resolution",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_TIME_RESOLUTION,
+		.maximum = MAX_TIME_RESOLUTION,
+		.default_value = DEFAULT_TIME_RESOLUTION,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER,
+		.name = "Request Seq Header",
+		.type = V4L2_CTRL_TYPE_BUTTON,
+		.minimum = 0,
+		.maximum = 0,
+		.default_value = 0,
+		.step = 0,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME,
+		.name = "H264 Use LTR",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (MAX_LTR_FRAME_COUNT - 1),
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT,
+		.name = "Ltr Count",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_LTR_FRAME_COUNT,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE,
+		.name = "Ltr Mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_MANUAL,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME,
+		.name = "H264 Mark LTR",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = (MAX_LTR_FRAME_COUNT - 1),
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS,
+		.name = "Set Hier P num layers",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE,
+		.name = "Encoder Timestamp Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum =
+			V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR,
+		.maximum =
+			V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE)),
+		.qmenu = timestamp_mode,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE,
+		.name = "VP8 Error Resilience mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_ENABLED,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP,
+		.name = "Enable setting initial QP",
+		.type = V4L2_CTRL_TYPE_BITMASK,
+		.minimum = 0,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME |
+			V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME |
+			V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME,
+		.default_value = 0,
+		.step = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP,
+		.name = "Iframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP,
+		.name = "Pframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP,
+		.name = "Bframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP,
+		.name = "Iframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP,
+		.name = "Pframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP,
+		.name = "Bframe initial QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 51,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE,
+		.name = "I-Frame X coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE,
+		.name = "I-Frame Y coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE,
+		.name = "P-Frame X coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE,
+		.name = "P-Frame Y coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE,
+		.name = "B-Frame X coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE,
+		.name = "B-Frame Y coordinate search range",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 4,
+		.maximum = 128,
+		.default_value = 4,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC,
+		.name = "Enable H264 SVC NAL",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE,
+		.name = "Set Encoder performance mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS,
+		.name = "Set Hier B num layers",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 3,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE,
+		.name = "Set Hybrid Hier P mode",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 5,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE,
+		.name = "MBI Statistics Mode",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_2) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3)),
+		.qmenu = mbi_statistics,
+	},
+	{
+		.id = V4L2_CID_VIDC_QBUF_MODE,
+		.name = "Allows batching of buffers for power savings",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_VIDC_QBUF_STANDARD,
+		.maximum = V4L2_VIDC_QBUF_BATCHED,
+		.default_value = V4L2_VIDC_QBUF_STANDARD,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS,
+		.name = "Set Max Hier P num layers sessions",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID,
+		.name = "Set Base Layer ID for Hier-P",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 6,
+		.default_value = 0,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP,
+		.name = "Set frame level QP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 127,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH,
+		.name = "SAR Width",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 4096,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT,
+		.name = "SAR Height",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 2160,
+		.default_value = 1,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY,
+		.name = "Session Priority",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI,
+		.name = "VQZIP SEI",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE,
+		.name = "Layer wise bitrate for H264/H265 Hybrid HP",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MIN_BIT_RATE,
+		.maximum = MAX_BIT_RATE,
+		.default_value = DEFAULT_BIT_RATE,
+		.step = BIT_RATE_STEP,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE,
+		.name = "Set Encoder Operating rate",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = MAX_OPERATING_FRAME_RATE,
+		.default_value = 0,
+		.step = OPERATING_FRAME_RATE_STEP,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE,
+		.name = "BITRATE TYPE",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_PIC_ORDER_CNT,
+		.name = "Set H264 Picture Order Count",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2,
+		.default_value = 0,
+		.step = 2,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC,
+		.name = "Set VPE Color space conversion coefficients",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
+		.name = "Low Latency Mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH,
+		.name = "Set Blur width",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2048,
+		.default_value = 0,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT,
+		.name = "Set Blur height",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 2048,
+		.default_value = 0,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE,
+		.name = "Set Color space",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MSM_VIDC_BT709_5,
+		.maximum = MSM_VIDC_BT2020,
+		.default_value = MSM_VIDC_BT601_6_625,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE,
+		.name = "Set Color space range",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS,
+		.name = "Set Color space transfer characterstics",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MSM_VIDC_TRANSFER_BT709_5,
+		.maximum = MSM_VIDC_TRANSFER_BT_2020_12,
+		.default_value = MSM_VIDC_TRANSFER_601_6_625,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS,
+		.name = "Set Color space matrix coefficients",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = MSM_VIDC_MATRIX_BT_709_5,
+		.maximum = MSM_VIDC_MATRIX_BT_2020_CONST,
+		.default_value = MSM_VIDC_MATRIX_601_6_625,
+		.step = 1,
+		.qmenu = NULL,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8,
+		.name = "Transform 8x8",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_DISABLE,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE,
+		.step = 1,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE,
+		.name = "Bounds of I-frame size",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT,
+		.menu_skip_mask = ~(
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_MEDIUM) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_HUGE) |
+			(1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED)),
+		.qmenu = iframe_sizes,
+	},
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
+
+static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+static u32 get_frame_size_rgba(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888, width, height);
+}
+
+static u32 get_frame_size_rgba_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888_UBWC, width, height);
+}
+
+static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
+}
+
+static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
+{
+	int sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2;
+
+	return ALIGN(sz, SZ_4K);
+}
+
+static struct msm_vidc_format venc_formats[] = {
+	{
+		.name = "YCbCr Semiplanar 4:2:0",
+		.description = "Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv12,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "UBWC YCbCr Semiplanar 4:2:0",
+		.description = "UBWC Y/CbCr 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12_UBWC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv12_ubwc,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "RGBA 8:8:8:8",
+		.description = "RGBA 8:8:8:8",
+		.fourcc = V4L2_PIX_FMT_RGB32,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_rgba,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "UBWC RGBA 8:8:8:8",
+		.description = "UBWC RGBA 8:8:8:8",
+		.fourcc = V4L2_PIX_FMT_RGBA8888_UBWC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_rgba_ubwc,
+		.type = OUTPUT_PORT,
+	},
+	{
+		.name = "Mpeg4",
+		.description = "Mpeg4 compressed format",
+		.fourcc = V4L2_PIX_FMT_MPEG4,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "H263",
+		.description = "H263 compressed format",
+		.fourcc = V4L2_PIX_FMT_H263,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "H264",
+		.description = "H264 compressed format",
+		.fourcc = V4L2_PIX_FMT_H264,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "VP8",
+		.description = "VP8 compressed format",
+		.fourcc = V4L2_PIX_FMT_VP8,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "HEVC",
+		.description = "HEVC compressed format",
+		.fourcc = V4L2_PIX_FMT_HEVC,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
+	{
+		.name = "YCrCb Semiplanar 4:2:0",
+		.description = "Y/CrCb 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_nv21,
+		.type = OUTPUT_PORT,
+	},
+};
+
+static void msm_venc_update_plane_count(struct msm_vidc_inst *inst, int type)
+{
+	struct v4l2_ctrl *ctrl = NULL;
+	u32 extradata = 0;
+
+	if (!inst)
+		return;
+
+	inst->fmts[type].num_planes = 1;
+
+	ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+		V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
+
+	if (ctrl)
+		extradata = v4l2_ctrl_g_ctrl(ctrl);
+
+	if (type == CAPTURE_PORT) {
+		switch (extradata) {
+		case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
+		case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB:
+		case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER:
+		case V4L2_MPEG_VIDC_EXTRADATA_LTR:
+		case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
+			inst->fmts[CAPTURE_PORT].num_planes = 2;
+		default:
+			break;
+		}
+	} else if (type == OUTPUT_PORT) {
+		switch (extradata) {
+		case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP:
+		case V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM:
+		case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO:
+		case V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS:
+		case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP:
+		case V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO:
+			inst->fmts[OUTPUT_PORT].num_planes = 2;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static int msm_venc_set_csc(struct msm_vidc_inst *inst);
+
+static int msm_venc_queue_setup(struct vb2_queue *q,
+				unsigned int *num_buffers,
+				unsigned int *num_planes, unsigned int sizes[],
+				struct device *alloc_ctxs[])
+{
+	int i, temp, rc = 0;
+	struct msm_vidc_inst *inst;
+	struct hal_buffer_count_actual new_buf_count;
+	enum hal_property property_id;
+	struct hfi_device *hdev;
+	struct hal_buffer_requirements *buff_req;
+	u32 extra_idx = 0;
+	struct hal_buffer_requirements *buff_req_buffer = NULL;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to open instance\n");
+		return rc;
+	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to get buffer requirements: %d\n", rc);
+		return rc;
+	}
+
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		*num_planes = 1;
+
+		buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+		if (buff_req) {
+
+			/* Pretend as if the FW itself is asking for additional
+			 * buffers, which are required for DCVS
+			 */
+			unsigned int min_req_buffers =
+				buff_req->buffer_count_min +
+				msm_dcvs_get_extra_buff_count(inst);
+			*num_buffers = max(*num_buffers, min_req_buffers);
+		}
+
+		if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS ||
+				*num_buffers > VB2_MAX_FRAME) {
+			int temp = *num_buffers;
+
+			*num_buffers = clamp_val(*num_buffers,
+					MIN_NUM_CAPTURE_BUFFERS,
+					VB2_MAX_FRAME);
+			dprintk(VIDC_INFO,
+				"Changing buffer count on CAPTURE_MPLANE from %d to %d for best effort encoding\n",
+				temp, *num_buffers);
+		}
+
+		msm_venc_update_plane_count(inst, CAPTURE_PORT);
+		*num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+
+		for (i = 0; i < *num_planes; i++) {
+			int extra_idx = EXTRADATA_IDX(*num_planes);
+
+			buff_req_buffer = get_buff_req_buffer(inst,
+					HAL_BUFFER_OUTPUT);
+
+			sizes[i] = buff_req_buffer ?
+				buff_req_buffer->buffer_size : 0;
+
+			if (extra_idx && i == extra_idx &&
+					extra_idx < VIDEO_MAX_PLANES) {
+				buff_req_buffer = get_buff_req_buffer(inst,
+						HAL_BUFFER_EXTRADATA_OUTPUT);
+				if (!buff_req_buffer) {
+					dprintk(VIDC_ERR,
+						"%s: failed - invalid buffer req\n",
+						__func__);
+					return -EINVAL;
+				}
+
+				sizes[i] = buff_req_buffer->buffer_size;
+			}
+		}
+
+		dprintk(VIDC_DBG, "actual output buffer count set to fw = %d\n",
+				*num_buffers);
+		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+		new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+		new_buf_count.buffer_count_actual = *num_buffers;
+		rc = call_hfi_op(hdev, session_set_property, inst->session,
+			property_id, &new_buf_count);
+
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		*num_planes = 1;
+
+		*num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
+			max(*num_buffers, inst->buff_req.buffer[0].
+				buffer_count_min);
+
+		temp = *num_buffers;
+
+		*num_buffers = clamp_val(*num_buffers,
+				MIN_NUM_OUTPUT_BUFFERS,
+				VB2_MAX_FRAME);
+		dprintk(VIDC_INFO,
+			"Changing buffer count on OUTPUT_MPLANE from %d to %d for best effort encoding\n",
+			temp, *num_buffers);
+
+		property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL;
+		new_buf_count.buffer_type = HAL_BUFFER_INPUT;
+		new_buf_count.buffer_count_actual = *num_buffers;
+
+		dprintk(VIDC_DBG, "actual input buffer count set to fw = %d\n",
+				*num_buffers);
+		msm_venc_update_plane_count(inst, OUTPUT_PORT);
+		*num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+
+		rc = call_hfi_op(hdev, session_set_property, inst->session,
+					property_id, &new_buf_count);
+		if (rc)
+			dprintk(VIDC_ERR, "failed to set count to fw\n");
+
+		dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
+				inst->buff_req.buffer[0].buffer_size,
+				inst->buff_req.buffer[0].buffer_alignment,
+				inst->buff_req.buffer[0].buffer_count_actual);
+		sizes[0] = inst->fmts[OUTPUT_PORT].get_frame_size(
+				0, inst->prop.height[OUTPUT_PORT],
+				inst->prop.width[OUTPUT_PORT]);
+
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[OUTPUT_PORT].num_planes);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			buff_req_buffer = get_buff_req_buffer(inst,
+				HAL_BUFFER_EXTRADATA_INPUT);
+			if (!buff_req_buffer) {
+				dprintk(VIDC_ERR,
+					"%s: failed - invalid buffer req\n",
+					__func__);
+				return -EINVAL;
+			}
+
+			sizes[extra_idx] = buff_req_buffer->buffer_size;
+		}
+
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers)
+{
+	int num_enh_layers = 0;
+	u32 property_id = 0;
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_VP8)
+		return 0;
+
+	num_enh_layers = layers ? : 0;
+	dprintk(VIDC_DBG, "%s Hier-P in firmware\n",
+			num_enh_layers ? "Enable" : "Disable");
+
+	hdev = inst->core->device;
+	property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
+	rc = call_hfi_op(hdev, session_set_property,
+			(void *)inst->session, property_id,
+			(void *)&num_enh_layers);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed with error = %d\n", __func__, rc);
+	}
+	return rc;
+}
+
+static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst)
+{
+	u32 rc = 0;
+	u32 prop_id = 0, power_save_min = 0, power_save_max = 0, inst_load = 0;
+	void *pdata = NULL;
+	struct hfi_device *hdev = NULL;
+	enum hal_perf_mode venc_mode;
+	enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+		LOAD_CALC_IGNORE_THUMBNAIL_LOAD;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	inst_load = msm_comm_get_inst_load(inst, quirks);
+	power_save_min = inst->capability.mbs_per_sec_power_save.min;
+	power_save_max = inst->capability.mbs_per_sec_power_save.max;
+
+	dprintk(VIDC_DBG,
+		"Power Save Mode min mb's %d max mb's %d inst load %d\n",
+		power_save_min, power_save_max, inst_load);
+
+	if (!power_save_min || !power_save_max)
+		return rc;
+
+	hdev = inst->core->device;
+	if (inst_load >= power_save_min) {
+		prop_id = HAL_CONFIG_VENC_PERF_MODE;
+		venc_mode = HAL_PERF_MODE_POWER_SAVE;
+		pdata = &venc_mode;
+		rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, prop_id, pdata);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to set power save mode for inst: %pK\n",
+				__func__, inst);
+			goto fail_power_mode_set;
+		}
+		inst->flags |= VIDC_LOW_POWER;
+		msm_dcvs_enc_set_power_save_mode(inst, true);
+		dprintk(VIDC_INFO, "Power Save Mode set for inst: %pK\n", inst);
+	}
+
+fail_power_mode_set:
+	return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	msm_venc_power_save_mode_enable(inst);
+	if (inst->capability.pixelprocess_capabilities &
+		HAL_VIDEO_ENCODER_SCALING_CAPABILITY)
+		rc = msm_vidc_check_scaling_supported(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
+		return -EINVAL;
+	}
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to get Buffer Requirements : %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_set_scratch_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set scratch buffers: %d\n", rc);
+		goto fail_start;
+	}
+	rc = msm_comm_set_persist_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set persist buffers: %d\n", rc);
+		goto fail_start;
+	}
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto fail_start;
+	}
+	msm_dcvs_init_load(inst);
+
+fail_start:
+	return rc;
+}
+
+static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
+		return -EINVAL;
+	}
+	inst = q->drv_priv;
+	dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n",
+		q->type, inst);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
+			rc = start_streaming(inst);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		goto stream_start_failed;
+	}
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Streamon failed on: %d capability for inst: %pK\n",
+			q->type, inst);
+		goto stream_start_failed;
+	}
+
+	rc = msm_comm_qbuf(inst, NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to commit buffers queued before STREAM_ON to hardware: %d\n",
+				rc);
+		goto stream_start_failed;
+	}
+
+stream_start_failed:
+	return rc;
+}
+
+static void msm_venc_stop_streaming(struct vb2_queue *q)
+{
+	struct msm_vidc_inst *inst;
+	int rc = 0;
+
+	if (!q || !q->drv_priv) {
+		dprintk(VIDC_ERR, "%s - Invalid input, q = %pK\n", __func__, q);
+		return;
+	}
+
+	inst = q->drv_priv;
+	dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
+	switch (q->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Q-type is not supported: %d\n", q->type);
+		rc = -EINVAL;
+		break;
+	}
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK, cap = %d to state: %d\n",
+			inst, q->type, MSM_VIDC_CLOSE_DONE);
+}
+
+static void msm_venc_buf_queue(struct vb2_buffer *vb)
+{
+	int rc = msm_comm_qbuf(vb2_get_drv_priv(vb->vb2_queue), vb);
+
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_venc_vb2q_ops = {
+	.queue_setup = msm_venc_queue_setup,
+	.start_streaming = msm_venc_start_streaming,
+	.buf_queue = msm_venc_buf_queue,
+	.stop_streaming = msm_venc_stop_streaming,
+};
+
+const struct vb2_ops *msm_venc_get_vb2q_ops(void)
+{
+	return &msm_venc_vb2q_ops;
+}
+
+static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
+		struct v4l2_ctrl **cluster, int ncontrols)
+{
+	int c;
+
+	for (c = 0; c < ncontrols; ++c)
+		if (cluster[c]->id == id)
+			return cluster[c];
+	return NULL;
+}
+
+/* Helper function to translate V4L2_* to HAL_* */
+static inline int venc_v4l2_to_hal(int id, int value)
+{
+	switch (id) {
+	/* MPEG4 */
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+			return HAL_MPEG4_LEVEL_0;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+			return HAL_MPEG4_LEVEL_0b;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+			return HAL_MPEG4_LEVEL_1;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+			return HAL_MPEG4_LEVEL_2;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+			return HAL_MPEG4_LEVEL_3;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+			return HAL_MPEG4_LEVEL_4;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+			return HAL_MPEG4_LEVEL_5;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+			return HAL_MPEG4_PROFILE_SIMPLE;
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+			return HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
+		default:
+			goto unknown_value;
+		}
+	/* H264 */
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+			return HAL_H264_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+			return HAL_H264_PROFILE_CONSTRAINED_BASE;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+			return HAL_H264_PROFILE_MAIN;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+			return HAL_H264_PROFILE_EXTENDED;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+			return HAL_H264_PROFILE_HIGH;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+			return HAL_H264_PROFILE_HIGH10;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+			return HAL_H264_PROFILE_HIGH422;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+			return HAL_H264_PROFILE_HIGH444;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
+			return HAL_H264_PROFILE_CONSTRAINED_HIGH;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+			return HAL_H264_LEVEL_1;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+			return HAL_H264_LEVEL_1b;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+			return HAL_H264_LEVEL_11;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+			return HAL_H264_LEVEL_12;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+			return HAL_H264_LEVEL_13;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+			return HAL_H264_LEVEL_2;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+			return HAL_H264_LEVEL_21;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+			return HAL_H264_LEVEL_22;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+			return HAL_H264_LEVEL_3;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+			return HAL_H264_LEVEL_31;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+			return HAL_H264_LEVEL_32;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+			return HAL_H264_LEVEL_4;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+			return HAL_H264_LEVEL_41;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+			return HAL_H264_LEVEL_42;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+			return HAL_H264_LEVEL_5;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+			return HAL_H264_LEVEL_51;
+		case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
+			return HAL_H264_LEVEL_52;
+		default:
+			goto unknown_value;
+		}
+	/* H263 */
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE:
+			return HAL_H263_PROFILE_BASELINE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING:
+			return HAL_H263_PROFILE_H320CODING;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE:
+			return HAL_H263_PROFILE_BACKWARDCOMPATIBLE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2:
+			return HAL_H263_PROFILE_ISWV2;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3:
+			return HAL_H263_PROFILE_ISWV3;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION:
+			return HAL_H263_PROFILE_HIGHCOMPRESSION;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET:
+			return HAL_H263_PROFILE_INTERNET;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE:
+			return HAL_H263_PROFILE_INTERLACE;
+		case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY:
+			return HAL_H263_PROFILE_HIGHLATENCY;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC:
+			return HAL_H264_ENTROPY_CAVLC;
+		case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC:
+			return HAL_H264_ENTROPY_CABAC;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0:
+			return HAL_H264_CABAC_MODEL_0;
+		case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1:
+			return HAL_H264_CABAC_MODEL_1;
+		case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2:
+			return HAL_H264_CABAC_MODEL_2;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0:
+			return HAL_H263_LEVEL_10;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0:
+			return HAL_H263_LEVEL_20;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0:
+			return HAL_H263_LEVEL_30;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0:
+			return HAL_H263_LEVEL_40;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5:
+			return HAL_H263_LEVEL_45;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0:
+			return HAL_H263_LEVEL_50;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0:
+			return HAL_H263_LEVEL_60;
+		case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0:
+			return HAL_H263_LEVEL_70;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0:
+			return HAL_VPX_PROFILE_VERSION_0;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1:
+			return HAL_VPX_PROFILE_VERSION_1;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2:
+			return HAL_VPX_PROFILE_VERSION_2;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3:
+			return HAL_VPX_PROFILE_VERSION_3;
+		case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED:
+			return HAL_VPX_PROFILE_UNUSED;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN:
+			return HAL_HEVC_PROFILE_MAIN;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10:
+			return HAL_HEVC_PROFILE_MAIN10;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC:
+			return HAL_HEVC_PROFILE_MAIN_STILL_PIC;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2:
+			return HAL_HEVC_MAIN_TIER_LEVEL_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_2_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3:
+			return HAL_HEVC_MAIN_TIER_LEVEL_3;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_3_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4:
+			return HAL_HEVC_MAIN_TIER_LEVEL_4;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_4_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5:
+			return HAL_HEVC_MAIN_TIER_LEVEL_5;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_5_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2:
+			return HAL_HEVC_MAIN_TIER_LEVEL_5_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6:
+			return HAL_HEVC_MAIN_TIER_LEVEL_6;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1:
+			return HAL_HEVC_MAIN_TIER_LEVEL_6_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2:
+			return HAL_HEVC_MAIN_TIER_LEVEL_6_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2:
+			return HAL_HEVC_HIGH_TIER_LEVEL_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_2_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3:
+			return HAL_HEVC_HIGH_TIER_LEVEL_3;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_3_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4:
+			return HAL_HEVC_HIGH_TIER_LEVEL_4;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_4_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5:
+			return HAL_HEVC_HIGH_TIER_LEVEL_5;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_5_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2:
+			return HAL_HEVC_HIGH_TIER_LEVEL_5_2;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6:
+			return HAL_HEVC_HIGH_TIER_LEVEL_6;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1:
+			return HAL_HEVC_HIGH_TIER_LEVEL_6_1;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE:
+			return HAL_ROTATE_NONE;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90:
+			return HAL_ROTATE_90;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180:
+			return HAL_ROTATE_180;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270:
+			return HAL_ROTATE_270;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+		switch (value) {
+		case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+			return HAL_H264_DB_MODE_DISABLE;
+		case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+			return HAL_H264_DB_MODE_ALL_BOUNDARY;
+		case L_MODE:
+			return HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT:
+			return HAL_STATISTICS_MODE_DEFAULT;
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1:
+			return HAL_STATISTICS_MODE_1;
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_2:
+			return HAL_STATISTICS_MODE_2;
+		case V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3:
+			return HAL_STATISTICS_MODE_3;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE:
+		switch (value) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT:
+			return HAL_IFRAMESIZE_TYPE_DEFAULT;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_MEDIUM:
+			return HAL_IFRAMESIZE_TYPE_MEDIUM;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_HUGE:
+			return HAL_IFRAMESIZE_TYPE_HUGE;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED:
+			return HAL_IFRAMESIZE_TYPE_UNLIMITED;
+		default:
+			goto unknown_value;
+		}
+	}
+
+unknown_value:
+	dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
+	return -EINVAL;
+}
+
+/* Small helper macro for quickly getting a control and err checking */
+#define TRY_GET_CTRL(__ctrl_id) ({ \
+		struct v4l2_ctrl *__temp; \
+		__temp = get_ctrl_from_cluster( \
+			__ctrl_id, \
+			ctrl->cluster, ctrl->ncontrols); \
+		if (!__temp) { \
+			dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \
+				#__ctrl_id, __ctrl_id); \
+			/* Clusters are hardcoded, if we can't find */ \
+			/* something then things are massively screwed up */ \
+			WARN_ON(VIDC_DBG_WARN_ENABLE); \
+		} \
+		__temp; \
+	})
+
+static int msm_venc_validate_qp_value(struct msm_vidc_inst *inst,
+					struct v4l2_ctrl *ctrl)
+{
+	int rc = 0, min, max;
+	struct v4l2_ctrl *temp_ctrl = NULL;
+	int qp_value = ctrl->val;
+
+#define VALIDATE_BOUNDARIES(__min, __max, __val) ({\
+	int __rc = __val >= __min && \
+			__val <= __max; \
+	if (!__rc) \
+		dprintk(VIDC_ERR, "QP beyond range: min(%d) max(%d) val(%d)", \
+				__min, __max, __val); \
+	__rc; \
+})
+
+	switch (inst->fmts[CAPTURE_PORT].fourcc) {
+	case V4L2_PIX_FMT_VP8:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MAX_QP);
+		max = temp_ctrl->maximum;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MIN_QP);
+		min = temp_ctrl->minimum;
+		if (!VALIDATE_BOUNDARIES(min, max, qp_value))
+			rc = -EINVAL;
+		break;
+	case V4L2_PIX_FMT_H263:
+	case V4L2_PIX_FMT_MPEG4:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP);
+		max = temp_ctrl->maximum;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP);
+		min = temp_ctrl->minimum;
+		if (!VALIDATE_BOUNDARIES(min, max, qp_value))
+			rc = -EINVAL;
+		break;
+	case V4L2_PIX_FMT_H264:
+	case V4L2_PIX_FMT_HEVC:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP);
+		max = temp_ctrl->maximum;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP);
+		min = temp_ctrl->minimum;
+		if (!VALIDATE_BOUNDARIES(min, max, qp_value))
+			rc = -EINVAL;
+		break;
+	default:
+		dprintk(VIDC_ERR, "%s Invalid Codec\n", __func__);
+		return -EINVAL;
+	}
+	return rc;
+#undef VALIDATE_BOUNDARIES
+}
+
+
+static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
+{
+	int rc = 0;
+	struct hal_request_iframe request_iframe;
+	struct hal_bitrate bitrate;
+	struct hal_profile_level profile_level;
+	struct hal_h264_entropy_control h264_entropy_control;
+	struct hal_quantization quantization;
+	struct hal_intra_period intra_period;
+	struct hal_idr_period idr_period;
+	struct hal_operations operations;
+	struct hal_intra_refresh intra_refresh;
+	struct hal_multi_slice_control multi_slice_control;
+	struct hal_h264_db_control h264_db_control;
+	struct hal_enable enable;
+	struct hal_h264_vui_timing_info vui_timing_info;
+	struct hal_quantization_range qp_range;
+	struct hal_h264_vui_bitstream_restrc vui_bitstream_restrict;
+	struct hal_preserve_text_quality preserve_text_quality;
+	u32 property_id = 0, property_val = 0;
+	void *pdata = NULL;
+	struct v4l2_ctrl *temp_ctrl = NULL;
+	struct hfi_device *hdev;
+	struct hal_extradata_enable extra;
+	struct hal_mpeg4_time_resolution time_res;
+	struct hal_ltr_use use_ltr;
+	struct hal_ltr_mark mark_ltr;
+	struct hal_hybrid_hierp hyb_hierp;
+	u32 hier_p_layers = 0, hier_b_layers = 0, mbi_statistics_mode = 0;
+	enum hal_perf_mode venc_mode;
+	int max_hierp_layers;
+	int baselayerid = 0;
+	int frameqp = 0;
+	int pic_order_cnt = 0;
+	struct hal_video_signal_info signal_info = {0};
+	enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	/*
+	 * Unlock the control prior to setting to the hardware. Otherwise
+	 * lower level code that attempts to do a get_ctrl() will end up
+	 * deadlocking.
+	 */
+	v4l2_ctrl_unlock(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD:
+		if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_H264 &&
+			inst->fmts[CAPTURE_PORT].fourcc !=
+				V4L2_PIX_FMT_H264_NO_SC &&
+			inst->fmts[CAPTURE_PORT].fourcc !=
+				V4L2_PIX_FMT_HEVC) {
+			dprintk(VIDC_ERR,
+				"Control %#x only valid for H264 and HEVC\n",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		property_id = HAL_CONFIG_VENC_IDR_PERIOD;
+		idr_period.idr_period = ctrl->val;
+		pdata = &idr_period;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES:
+	case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
+	{
+		int num_p, num_b;
+		u32 max_num_b_frames;
+
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
+		num_b = temp_ctrl->val;
+
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
+		num_p = temp_ctrl->val;
+
+		if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES)
+			num_p = ctrl->val;
+		else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES)
+			num_b = ctrl->val;
+
+		max_num_b_frames = num_b ? MAX_NUM_B_FRAMES : 0;
+		property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES;
+		pdata = &max_num_b_frames;
+		rc = call_hfi_op(hdev, session_set_property,
+			(void *)inst->session, property_id, pdata);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed : Setprop MAX_NUM_B_FRAMES %d\n",
+				rc);
+			break;
+		}
+
+		property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
+		intra_period.pframes = num_p;
+		intra_period.bframes = num_b;
+
+		/*
+		 *Incase firmware does not have B-Frame support,
+		 *offload the b-frame count to p-frame to make up
+		 *for the requested Intraperiod
+		 */
+		if (!inst->capability.bframe.max) {
+			intra_period.pframes = num_p + num_b;
+			intra_period.bframes = 0;
+			dprintk(VIDC_DBG,
+				"No bframe support, changing pframe from %d to %d\n",
+				num_p, intra_period.pframes);
+		}
+		pdata = &intra_period;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME:
+		property_id = HAL_CONFIG_VENC_REQUEST_IFRAME;
+		request_iframe.enable = true;
+		pdata = &request_iframe;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL:
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+	{
+		int final_mode = 0;
+		struct v4l2_ctrl update_ctrl = {.id = 0};
+
+		/* V4L2_CID_MPEG_VIDEO_BITRATE_MODE and _RATE_CONTROL
+		 * manipulate the same thing.  If one control's state
+		 * changes, try to mirror the state in the other control's
+		 * value
+		 */
+		if (ctrl->id == V4L2_CID_MPEG_VIDEO_BITRATE_MODE) {
+			if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+				final_mode = HAL_RATE_CONTROL_VBR_CFR;
+				update_ctrl.val =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR;
+			} else {/* ...if (ctrl->val == _BITRATE_MODE_CBR) */
+				final_mode = HAL_RATE_CONTROL_CBR_CFR;
+				update_ctrl.val =
+				V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR;
+			}
+
+			update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
+
+		} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL) {
+			switch (ctrl->val) {
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+				update_ctrl.val =
+					V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR:
+			case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR:
+				update_ctrl.val =
+					V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+				break;
+			}
+
+			final_mode = ctrl->val;
+			update_ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
+		}
+
+		if (update_ctrl.id) {
+			temp_ctrl = TRY_GET_CTRL(update_ctrl.id);
+			temp_ctrl->val = update_ctrl.val;
+		}
+
+		property_id = HAL_PARAM_VENC_RATE_CONTROL;
+		property_val = final_mode;
+		pdata = &property_val;
+
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+	{
+		property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
+		bitrate.bit_rate = ctrl->val;
+		bitrate.layer_id = 0;
+		pdata = &bitrate;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+	{
+		struct v4l2_ctrl *avg_bitrate = TRY_GET_CTRL(
+			V4L2_CID_MPEG_VIDEO_BITRATE);
+
+		if (ctrl->val < avg_bitrate->val) {
+			dprintk(VIDC_ERR,
+				"Peak bitrate (%d) is lower than average bitrate (%d)\n",
+				ctrl->val, avg_bitrate->val);
+			rc = -EINVAL;
+			break;
+		} else if (ctrl->val < avg_bitrate->val * 2) {
+			dprintk(VIDC_WARN,
+				"Peak bitrate (%d) ideally should be twice the average bitrate (%d)\n",
+				ctrl->val, avg_bitrate->val);
+		}
+
+		property_id = HAL_CONFIG_VENC_MAX_BITRATE;
+		bitrate.bit_rate = ctrl->val;
+		bitrate.layer_id = 0;
+		pdata = &bitrate;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+		temp_ctrl = TRY_GET_CTRL(
+			V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL);
+
+		property_id = HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+		h264_entropy_control.entropy_mode = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val);
+		h264_entropy_control.cabac_model = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+			temp_ctrl->val);
+		pdata = &h264_entropy_control;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE);
+
+		property_id = HAL_PARAM_VENC_H264_ENTROPY_CONTROL;
+		h264_entropy_control.cabac_model = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val);
+		h264_entropy_control.entropy_mode = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL,
+			temp_ctrl->val);
+		pdata = &h264_entropy_control;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+						ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		dprintk(VIDC_DBG, "\nprofile: %d\n",
+			   profile_level.profile);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		dprintk(VIDC_DBG, "\nLevel: %d\n",
+			   profile_level.level);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
+				ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+				ctrl->val);
+		profile_level.level = HAL_VPX_PROFILE_UNUSED;
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = venc_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
+	{
+		struct v4l2_ctrl *deinterlace = NULL;
+
+		if (!(inst->capability.pixelprocess_capabilities &
+			HAL_VIDEO_ENCODER_ROTATION_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Rotation not supported: %#x\n",
+				ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		deinterlace =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE);
+		if (ctrl->val && deinterlace && deinterlace->val !=
+				V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED) {
+			dprintk(VIDC_ERR,
+				"Rotation not supported with deinterlacing\n");
+			rc = -EINVAL;
+			break;
+		}
+		property_id = HAL_CONFIG_VPE_OPERATIONS;
+		operations.rotate = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
+				ctrl->val);
+		operations.flip = HAL_FLIP_NONE;
+		pdata = &operations;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: {
+		struct v4l2_ctrl *qpp, *qpb;
+
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc)
+			break;
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpi = ctrl->val;
+		quantization.qpp = qpp->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpb;
+
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc)
+			break;
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpp = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpp;
+
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc)
+			break;
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP);
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpb = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpp = qpp->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: {
+		struct v4l2_ctrl *qpp, *qpb;
+
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpi = ctrl->val;
+		quantization.qpp = qpp->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpb;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpp = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpb = qpb->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: {
+		struct v4l2_ctrl *qpi, *qpp;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP);
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpb = ctrl->val;
+		quantization.qpi = qpi->val;
+		quantization.qpp = qpp->val;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: {
+		struct v4l2_ctrl *qpp;
+
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpi = ctrl->val;
+		quantization.qpp = qpp->val;
+		/* Bframes are not supported for VPX */
+		quantization.qpb = 0;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: {
+		struct v4l2_ctrl *qpi;
+
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP);
+
+		property_id = HAL_PARAM_VENC_SESSION_QP;
+		quantization.qpp = ctrl->val;
+		quantization.qpi = qpi->val;
+		/* Bframes are not supported for VPX */
+		quantization.qpb = 0;
+		quantization.layer_id = 0;
+
+		pdata = &quantization;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP (%d) > Max QP(%d)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP (%d) < Min QP(%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP (%d) > Max QP(%d)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP (%d) < Min QP(%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MAX_QP);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP (%d) > Max QP(%d)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_VPX_MIN_QP);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP (%d) < Min QP(%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP);
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP);
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED: {
+		struct v4l2_ctrl *qp_max;
+
+		qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED);
+		if (ctrl->val >= qp_max->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Min QP PACKED (0x%x) > Max QP PACKED (0x%x)\n",
+					ctrl->val, qp_max->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = qp_max->val;
+		qp_range.min_qp = ctrl->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED: {
+		struct v4l2_ctrl *qp_min;
+
+		qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED);
+		if (ctrl->val <= qp_min->val) {
+			dprintk(VIDC_ERR,
+					"Bad range: Max QP PACKED (%d) < Min QP PACKED (%d)\n",
+					ctrl->val, qp_min->val);
+			rc = -ERANGE;
+			break;
+		}
+
+		property_id = HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED;
+		qp_range.layer_id = 0;
+		qp_range.max_qp = ctrl->val;
+		qp_range.min_qp = qp_min->val;
+
+		pdata = &qp_range;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
+		int temp = 0;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SLICE_GOB:
+			temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB;
+			break;
+		case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+		default:
+			temp = 0;
+			break;
+		}
+
+		if (temp)
+			temp_ctrl = TRY_GET_CTRL(temp);
+
+		property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+		multi_slice_control.multi_slice = ctrl->val;
+		multi_slice_control.slice_size = temp ? temp_ctrl->val : 0;
+
+		pdata = &multi_slice_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+
+		property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL;
+		multi_slice_control.multi_slice = temp_ctrl->val;
+		multi_slice_control.slice_size = ctrl->val;
+		pdata = &multi_slice_control;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: {
+		bool codec_avc =
+			inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264 ||
+			inst->fmts[CAPTURE_PORT].fourcc ==
+							V4L2_PIX_FMT_H264_NO_SC;
+
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE);
+		if (codec_avc && temp_ctrl->val ==
+				V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+			property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE;
+			enable.enable = true;
+		} else {
+			dprintk(VIDC_WARN,
+			"Failed : slice delivery mode is not supported\n");
+			enable.enable = false;
+		}
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: {
+		struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs;
+		bool is_cont_intra_supported = false;
+
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+		is_cont_intra_supported =
+		(inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264) ||
+		(inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_HEVC);
+
+		if (is_cont_intra_supported) {
+			if (ctrl->val != HAL_INTRA_REFRESH_NONE)
+				enable.enable = true;
+			else
+				enable.enable = false;
+
+			rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session,
+				HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED, &enable);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to set constrained intra\n");
+				rc = -EINVAL;
+				break;
+			}
+		}
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.mode = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: {
+		struct v4l2_ctrl *ir_mode, *air_ref, *cir_mbs;
+
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.air_mbs = ctrl->val;
+		intra_refresh.mode = ir_mode->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: {
+		struct v4l2_ctrl *ir_mode, *air_mbs, *cir_mbs;
+
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.air_ref = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.mode = ir_mode->val;
+		intra_refresh.cir_mbs = cir_mbs->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: {
+		struct v4l2_ctrl *ir_mode, *air_mbs, *air_ref;
+
+		ir_mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE);
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.cir_mbs = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.mode = ir_mode->val;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: {
+		struct v4l2_ctrl *air_mbs, *air_ref;
+
+		air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+		air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+		property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+		intra_refresh.cir_mbs = ctrl->val;
+		intra_refresh.air_mbs = air_mbs->val;
+		intra_refresh.air_ref = air_ref->val;
+		intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC;
+
+		pdata = &intra_refresh;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+	{
+		struct v4l2_ctrl *alpha, *beta;
+
+		alpha = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+		beta = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+		property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		h264_db_control.slice_alpha_offset = alpha->val;
+		h264_db_control.slice_beta_offset = beta->val;
+		h264_db_control.mode = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+				ctrl->val);
+		pdata = &h264_db_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+	{
+		struct v4l2_ctrl *mode, *beta;
+
+		mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+		beta = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA);
+
+		property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		h264_db_control.slice_alpha_offset = ctrl->val;
+		h264_db_control.slice_beta_offset = beta->val;
+		h264_db_control.mode = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+				mode->val);
+		pdata = &h264_db_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+	{
+		struct v4l2_ctrl *mode, *alpha;
+
+		mode = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE);
+		alpha = TRY_GET_CTRL(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA);
+		property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
+		h264_db_control.slice_alpha_offset = alpha->val;
+		h264_db_control.slice_beta_offset = ctrl->val;
+		h264_db_control.mode = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+				mode->val);
+		pdata = &h264_db_control;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+		property_id = HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE:
+			enable.enable = 0;
+			break;
+		case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME:
+			enable.enable = 1;
+			break;
+		case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+		default:
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+		inst->flags |= VIDC_SECURE;
+		dprintk(VIDC_INFO, "Setting secure mode to: %d\n",
+				!!(inst->flags & VIDC_SECURE));
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+		property_id = HAL_PARAM_INDEX_EXTRADATA;
+		extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
+		extra.enable = 1;
+		pdata = &extra;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO:
+	{
+		struct v4l2_ctrl *rc_mode;
+		bool cfr = false;
+
+		property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO;
+		rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
+
+		switch (rc_mode->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
+		case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
+			cfr = true;
+			break;
+		default:
+			cfr = false;
+			break;
+		}
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED:
+			vui_timing_info.enable = 0;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED:
+			vui_timing_info.enable = 1;
+			vui_timing_info.fixed_frame_rate = cfr;
+			vui_timing_info.time_scale = NSEC_PER_SEC;
+		}
+
+		pdata = &vui_timing_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER:
+		property_id = HAL_PARAM_VENC_GENERATE_AUDNAL;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_DISABLED:
+			enable.enable = 0;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_AU_DELIMITER_ENABLED:
+			enable.enable = 1;
+			break;
+		default:
+			rc = -ENOTSUPP;
+			break;
+		}
+
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
+			if (inst->flags & VIDC_TURBO) {
+				inst->flags &= ~VIDC_TURBO;
+				msm_dcvs_init_load(inst);
+			}
+			break;
+		case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
+			inst->flags |= VIDC_TURBO;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Perf mode %x not supported\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		msm_comm_scale_clocks_and_bus(inst);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT:
+		property_id = HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC;
+		vui_bitstream_restrict.enable = ctrl->val;
+		pdata = &vui_bitstream_restrict;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY:
+		property_id = HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY;
+		preserve_text_quality.enable = ctrl->val;
+		pdata = &preserve_text_quality;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION:
+		property_id = HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION;
+		time_res.time_increment_resolution = ctrl->val;
+		pdata = &time_res;
+		break;
+
+	case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE:
+	{
+		struct v4l2_ctrl *rotation = NULL;
+
+		if (!(inst->capability.pixelprocess_capabilities &
+			HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY)) {
+			dprintk(VIDC_ERR, "Deinterlace not supported: %#x\n",
+					ctrl->id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		rotation = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+		if (ctrl->val && rotation && rotation->val !=
+			V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) {
+			dprintk(VIDC_ERR,
+				"Deinterlacing not supported with rotation");
+			rc = -EINVAL;
+			break;
+		}
+		property_id = HAL_CONFIG_VPE_DEINTERLACE;
+		switch (ctrl->val) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED:
+			enable.enable = 1;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED:
+		default:
+			enable.enable = 0;
+			break;
+		}
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER:
+		atomic_inc(&inst->seq_hdr_reqs);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME:
+		property_id = HAL_CONFIG_VENC_USELTRFRAME;
+		use_ltr.ref_ltr = ctrl->val;
+		use_ltr.use_constraint = false;
+		use_ltr.frames = 0;
+		pdata = &use_ltr;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME:
+		if (ctrl->val < inst->capability.ltr_count.min ||
+			ctrl->val >= inst->capability.ltr_count.max) {
+			dprintk(VIDC_ERR,
+				"Error setting markltr %d range: [%d,%d)\n",
+				ctrl->val, inst->capability.ltr_count.min,
+				inst->capability.ltr_count.max);
+			rc = -ENOTSUPP;
+			break;
+		}
+		property_id = HAL_CONFIG_VENC_MARKLTRFRAME;
+		mark_ltr.mark_frame = ctrl->val;
+		pdata = &mark_ltr;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS:
+		property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES;
+		hier_p_layers = ctrl->val;
+		if (hier_p_layers > inst->capability.hier_p.max) {
+			dprintk(VIDC_ERR,
+				"Error setting hier p num layers %d max supported is %d\n",
+				hier_p_layers, inst->capability.hier_p.max);
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &hier_p_layers;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE:
+		property_id = HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP;
+		enable.enable = (ctrl->val ==
+		V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE);
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE:
+		property_id = HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC:
+		property_id = HAL_PARAM_VENC_H264_NAL_SVC_EXT;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE:
+		property_id = HAL_CONFIG_VENC_PERF_MODE;
+
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE:
+			inst->flags |= VIDC_LOW_POWER;
+			venc_mode = HAL_PERF_MODE_POWER_SAVE;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY:
+			inst->flags &= ~VIDC_LOW_POWER;
+			venc_mode = HAL_PERF_MODE_POWER_MAX_QUALITY;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Power save mode %x not supported\n",
+					ctrl->val);
+			rc = -ENOTSUPP;
+			property_id = 0;
+			break;
+		}
+		pdata = &venc_mode;
+
+		msm_dcvs_enc_set_power_save_mode(inst,
+			ctrl->val == V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS:
+		if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) {
+			dprintk(VIDC_ERR, "Hier B supported for HEVC only\n");
+			rc = -ENOTSUPP;
+			break;
+		}
+		property_id = HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS;
+		hier_b_layers = ctrl->val;
+		pdata = &hier_b_layers;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE:
+		property_id = HAL_PARAM_VENC_HIER_P_HYBRID_MODE;
+		hyb_hierp.layers = ctrl->val;
+		pdata = &hyb_hierp;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE:
+		property_id = HAL_PARAM_VENC_MBI_STATISTICS_MODE;
+		mbi_statistics_mode = venc_v4l2_to_hal(
+			V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE,
+			ctrl->val);
+		pdata = &mbi_statistics_mode;
+		break;
+	case V4L2_CID_VIDC_QBUF_MODE:
+		property_id = HAL_PARAM_SYNC_BASED_INTERRUPT;
+		enable.enable = ctrl->val == V4L2_VIDC_QBUF_BATCHED;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS:
+		property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS;
+		max_hierp_layers = ctrl->val;
+		if (max_hierp_layers > inst->capability.hier_p.max) {
+			dprintk(VIDC_ERR,
+				"Error max HP layers(%d)>max supported(%d)\n",
+				max_hierp_layers, inst->capability.hier_p.max);
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &max_hierp_layers;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID:
+		property_id = HAL_CONFIG_VENC_BASELAYER_PRIORITYID;
+		baselayerid = ctrl->val;
+		pdata = &baselayerid;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP:
+		/* Sanity check for the QP boundaries as we are using
+		 * same control to set dynamic QP for all the codecs
+		 */
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid QP Config QP Range\n");
+			break;
+		}
+		property_id = HAL_CONFIG_VENC_FRAME_QP;
+		frameqp = ctrl->val;
+		pdata = &frameqp;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP:
+	{
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid Initial I QP\n");
+			break;
+		}
+		/*
+		 * Defer sending property from here, set_ext_ctrl
+		 * will send it based on the rc value.
+		 */
+		property_id = 0;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP:
+	{
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid Initial B QP\n");
+			break;
+		}
+		/*
+		 * Defer sending property from here, set_ext_ctrl
+		 * will send it based on the rc value.
+		 */
+		property_id = 0;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP:
+	{
+		rc = msm_venc_validate_qp_value(inst, ctrl);
+		if (rc) {
+			dprintk(VIDC_ERR, "Invalid Initial P QP\n");
+			break;
+		}
+		/*
+		 * Defer sending property from here, set_ext_ctrl
+		 * will send it based on the rc value.
+		 */
+		property_id = 0;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI:
+		property_id = HAL_PARAM_VENC_VQZIP_SEI;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY:
+		property_id = HAL_CONFIG_REALTIME;
+		/* firmware has inverted values for realtime and
+		 * non-realtime priority
+		 */
+		enable.enable = !(ctrl->val);
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
+	{
+		property_id = HAL_PARAM_VENC_BITRATE_TYPE;
+		enable.enable = ctrl->val;
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_PIC_ORDER_CNT:
+	{
+		property_id = HAL_PARAM_VENC_H264_PIC_ORDER_CNT;
+		pic_order_cnt = ctrl->val;
+		pdata = &pic_order_cnt;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE:
+	{
+		signal_info.color_space = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE);
+		signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS);
+		signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS);
+		signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE:
+	{
+		signal_info.full_range = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS);
+		signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS);
+		signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS:
+	{
+		signal_info.transfer_chars = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE);
+		signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS);
+		signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS:
+	{
+		signal_info.matrix_coeffs = ctrl->val;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE);
+		signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS);
+		signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0;
+		property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO;
+		pdata = &signal_info;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC:
+		if (ctrl->val == V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE) {
+			rc = msm_venc_set_csc(inst);
+			if (rc)
+				dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
+		}
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
+	{
+		property_id = HAL_PARAM_VENC_LOW_LATENCY;
+		if (ctrl->val ==
+			V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE)
+			enable.enable = 1;
+		else
+			enable.enable = 0;
+		pdata = &enable;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8:
+		property_id = HAL_PARAM_VENC_H264_TRANSFORM_8x8;
+		switch (ctrl->val) {
+		case V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE:
+			enable.enable = 1;
+			break;
+		case V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_DISABLE:
+			enable.enable = 0;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"Invalid H264 8x8 transform control value %d\n",
+				ctrl->val);
+			rc = -ENOTSUPP;
+			break;
+		}
+		pdata = &enable;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE:
+		property_id = HAL_PARAM_VENC_IFRAMESIZE_TYPE;
+		iframesize_type = venc_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE,
+				ctrl->val);
+		pdata = &iframesize_type;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Unsupported index: %x\n", ctrl->id);
+		rc = -ENOTSUPP;
+		break;
+	}
+
+	v4l2_ctrl_lock(ctrl);
+
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG, "Control: HAL property=%x,ctrl_value=%d\n",
+				property_id,
+				ctrl->val);
+		rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, property_id, pdata);
+	}
+
+	return rc;
+}
+#undef TRY_GET_CTRL
+
+static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0, i;
+	struct v4l2_ext_control *control;
+	struct hfi_device *hdev;
+	struct hal_ltr_mode ltr_mode;
+	struct hal_vc1e_perf_cfg_type search_range = { {0} };
+	u32 property_id = 0;
+	void *pdata = NULL;
+	struct msm_vidc_capability *cap = NULL;
+	struct hal_initial_quantization quant;
+	struct hal_aspect_ratio sar;
+	struct hal_bitrate bitrate;
+	struct hal_frame_size blur_res;
+	struct v4l2_control temp_ctrl;
+
+	if (!inst || !inst->core || !inst->core->device || !ctrl) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	cap = &inst->capability;
+
+	control = ctrl->controls;
+	for (i = 0; i < ctrl->count; i++) {
+		switch (control[i].id) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
+			if (control[i].value !=
+				V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE) {
+				rc = msm_venc_toggle_hier_p(inst, false);
+				if (rc)
+					break;
+			}
+			ltr_mode.mode = control[i].value;
+			ltr_mode.trust_mode = 1;
+			property_id = HAL_PARAM_VENC_LTRMODE;
+			pdata = &ltr_mode;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT:
+			ltr_mode.count =  control[i].value;
+			if (ltr_mode.count > cap->ltr_count.max) {
+				dprintk(VIDC_ERR,
+					"Invalid LTR count %d. Supported max: %d\n",
+					ltr_mode.count,
+					cap->ltr_count.max);
+				/*
+				 * FIXME: Return an error (-EINVALID)
+				 * here once VP8 supports LTR count
+				 * capability
+				 */
+				ltr_mode.count = 1;
+			}
+			ltr_mode.trust_mode = 1;
+			property_id = HAL_PARAM_VENC_LTRMODE;
+			pdata = &ltr_mode;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP:
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			quant.init_qp_enable = control[i].value;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP:
+			quant.qpi = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP:
+			quant.qpp = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP:
+			quant.qpb = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP:
+			/* Sanity check for the QP boundaries as we are using
+			 * same control to set Initial QP for all the codecs
+			 */
+			temp_ctrl.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP;
+			temp_ctrl.value = control[i].value;
+
+			rc = msm_comm_s_ctrl(inst, &temp_ctrl);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s Failed setting Initial I Frame QP : %d\n",
+					__func__, rc);
+				break;
+			}
+			quant.qpi = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP:
+			temp_ctrl.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP;
+			temp_ctrl.value = control[i].value;
+			rc = msm_comm_s_ctrl(inst, &temp_ctrl);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s Failed setting Initial P Frame QP : %d\n",
+					__func__, rc);
+				break;
+			}
+			quant.qpp = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP:
+			temp_ctrl.id =
+				V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP;
+			temp_ctrl.value = control[i].value;
+			rc = msm_comm_s_ctrl(inst, &temp_ctrl);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s Failed setting Initial B Frame QP : %d\n",
+					__func__, rc);
+				break;
+			}
+			quant.qpb = control[i].value;
+			property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP;
+			pdata = &quant;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE:
+			search_range.i_frame.x_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE:
+			search_range.i_frame.y_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE:
+			search_range.p_frame.x_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE:
+			search_range.p_frame.y_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE:
+			search_range.b_frame.x_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE:
+			search_range.b_frame.y_subsampled = control[i].value;
+			property_id = HAL_PARAM_VENC_SEARCH_RANGE;
+			pdata = &search_range;
+			break;
+		case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH:
+			sar.aspect_width = control[i].value;
+			property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO;
+			pdata = &sar;
+			break;
+		case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT:
+			sar.aspect_height = control[i].value;
+			property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO;
+			pdata = &sar;
+			break;
+		case V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE:
+		{
+			if (control[i].value) {
+				bitrate.layer_id = i;
+				bitrate.bit_rate = control[i].value;
+				property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
+				pdata = &bitrate;
+				dprintk(VIDC_DBG, "bitrate for layer(%d)=%d\n",
+					i, bitrate.bit_rate);
+				rc = call_hfi_op(hdev, session_set_property,
+					(void *)inst->session, property_id,
+					 pdata);
+				if (rc) {
+					dprintk(VIDC_DBG, "prop %x failed\n",
+						property_id);
+					return rc;
+				}
+				if (i == MAX_HYBRID_HIER_P_LAYERS - 1) {
+					dprintk(VIDC_DBG, "HAL property=%x\n",
+						property_id);
+					property_id = 0;
+					rc = 0;
+				}
+			}
+			break;
+		}
+		case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH:
+			property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION;
+			blur_res.width = control[i].value;
+			blur_res.buffer_type = HAL_BUFFER_INPUT;
+			property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION;
+			pdata = &blur_res;
+			break;
+		case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT:
+			blur_res.height = control[i].value;
+			blur_res.buffer_type = HAL_BUFFER_INPUT;
+			property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION;
+			pdata = &blur_res;
+			break;
+		default:
+			dprintk(VIDC_ERR, "Invalid id set: %d\n",
+				control[i].id);
+			rc = -ENOTSUPP;
+			break;
+		}
+		if (rc)
+			break;
+	}
+
+	if (!rc && property_id) {
+		dprintk(VIDC_DBG, "Control: HAL property=%x\n", property_id);
+		rc = call_hfi_op(hdev, session_set_property,
+				(void *)inst->session, property_id, pdata);
+	}
+	return rc;
+}
+
+static int msm_venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+
+	int rc = 0, c = 0;
+
+	struct msm_vidc_inst *inst = container_of(ctrl->handler,
+					struct msm_vidc_inst, ctrl_handler);
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to start done state\n", inst);
+		goto failed_open_done;
+	}
+
+	for (c = 0; c < ctrl->ncontrols; ++c) {
+		if (ctrl->cluster[c]->is_new) {
+			struct v4l2_ctrl *temp = ctrl->cluster[c];
+
+			rc = try_set_ctrl(inst, temp);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed setting %s (%x)\n",
+						v4l2_ctrl_get_name(temp->id),
+						temp->id);
+				break;
+			}
+		}
+	}
+failed_open_done:
+	if (rc)
+		dprintk(VIDC_ERR, "Failed setting control: %x (%s)",
+				ctrl->id, v4l2_ctrl_get_name(ctrl->id));
+	return rc;
+}
+
+static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_venc_ctrl_ops = {
+
+	.s_ctrl = msm_venc_op_s_ctrl,
+	.g_volatile_ctrl = msm_venc_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_venc_get_ctrl_ops(void)
+{
+	return &msm_venc_ctrl_ops;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid input = %pK\n", inst);
+		return -EINVAL;
+	}
+	inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+	inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
+	inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+	inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
+	inst->capability.height.max = DEFAULT_HEIGHT;
+	inst->capability.width.min = MIN_SUPPORTED_WIDTH;
+	inst->capability.width.max = DEFAULT_WIDTH;
+	inst->capability.alloc_mode_in = HAL_BUFFER_MODE_STATIC;
+	inst->capability.alloc_mode_out = HAL_BUFFER_MODE_STATIC;
+	inst->capability.secure_output2_threshold.min = 0;
+	inst->capability.secure_output2_threshold.max = 0;
+	inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+	inst->prop.fps = DEFAULT_FPS;
+	inst->capability.pixelprocess_capabilities = 0;
+	memcpy(&inst->fmts[CAPTURE_PORT], &venc_formats[4],
+						sizeof(struct msm_vidc_format));
+	memcpy(&inst->fmts[OUTPUT_PORT], &venc_formats[0],
+						sizeof(struct msm_vidc_format));
+	return rc;
+}
+
+int msm_venc_s_ext_ctrl(struct msm_vidc_inst *inst,
+	struct v4l2_ext_controls *ctrl)
+{
+	int rc = 0;
+
+	rc = try_set_ext_ctrl(inst, ctrl);
+	if (rc) {
+		dprintk(VIDC_ERR, "Error setting extended control\n");
+		return rc;
+	}
+	return rc;
+}
+
+int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+	if (!inst || !cap) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, cap = %pK\n", inst, cap);
+		return -EINVAL;
+	}
+	strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card));
+	cap->bus_info[0] = 0;
+	cap->version = MSM_VIDC_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+						V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+						V4L2_CAP_STREAMING;
+	memset(cap->reserved, 0, sizeof(cap->reserved));
+	return 0;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, f = %pK\n", inst, f);
+		return -EINVAL;
+	}
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+			ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT);
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+			ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT);
+		f->flags = V4L2_FMT_FLAG_COMPRESSED;
+	}
+
+	memset(f->reserved, 0, sizeof(f->reserved));
+	if (fmt) {
+		strlcpy(f->description, fmt->description,
+				sizeof(f->description));
+		f->pixelformat = fmt->fourcc;
+	} else {
+		dprintk(VIDC_DBG, "No more formats found\n");
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int msm_venc_set_csc(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int count = 0;
+	struct hal_vpe_color_space_conversion vpe_csc;
+
+	while (count < HAL_MAX_MATRIX_COEFFS) {
+		if (count < HAL_MAX_BIAS_COEFFS)
+			vpe_csc.csc_bias[count] =
+				vpe_csc_601_to_709_bias_coeff[count];
+		if (count < HAL_MAX_LIMIT_COEFFS)
+			vpe_csc.csc_limit[count] =
+				vpe_csc_601_to_709_limit_coeff[count];
+		vpe_csc.csc_matrix[count] =
+			vpe_csc_601_to_709_matrix_coeff[count];
+		count = count + 1;
+	}
+	rc = msm_comm_try_set_prop(inst,
+			HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc);
+	if (rc)
+		dprintk(VIDC_ERR, "Setting VPE coefficients failed\n");
+
+	return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	struct hfi_device *hdev;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, format = %pK\n", inst, f);
+		return -EINVAL;
+	}
+
+	if (!inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+			CAPTURE_PORT);
+		if (!fmt || fmt->type != CAPTURE_PORT) {
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on CAPTURE port\n",
+				f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto exit;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		msm_venc_update_plane_count(inst, CAPTURE_PORT);
+		fmt->num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+
+		rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to open instance\n");
+			goto exit;
+		}
+
+		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto exit;
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		struct hal_frame_size frame_sz;
+
+		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
+		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto exit;
+		}
+
+		frame_sz.buffer_type = HAL_BUFFER_INPUT;
+		frame_sz.width = inst->prop.width[OUTPUT_PORT];
+		frame_sz.height = inst->prop.height[OUTPUT_PORT];
+		dprintk(VIDC_DBG, "width = %d, height = %d\n",
+				frame_sz.width, frame_sz.height);
+		rc = call_hfi_op(hdev, session_set_property, (void *)
+			inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set framesize for Output port\n");
+			goto exit;
+		}
+
+		fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+			ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+			OUTPUT_PORT);
+		if (!fmt || fmt->type != OUTPUT_PORT) {
+			dprintk(VIDC_ERR,
+				"Format: %d not supported on OUTPUT port\n",
+				f->fmt.pix_mp.pixelformat);
+			rc = -EINVAL;
+			goto exit;
+		}
+		memcpy(&inst->fmts[fmt->type], fmt,
+						sizeof(struct msm_vidc_format));
+
+		msm_venc_update_plane_count(inst, OUTPUT_PORT);
+		fmt->num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+
+		msm_comm_set_color_format(inst, HAL_BUFFER_INPUT, fmt->fourcc);
+	} else {
+		dprintk(VIDC_ERR, "%s - Unsupported buf type: %d\n",
+			__func__, f->type);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	f->fmt.pix_mp.num_planes = fmt->num_planes;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		struct hal_frame_size frame_sz = {0};
+		struct hal_buffer_requirements *bufreq = NULL;
+
+		frame_sz.width = inst->prop.width[CAPTURE_PORT];
+		frame_sz.height = inst->prop.height[CAPTURE_PORT];
+		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+		rc = call_hfi_op(hdev, session_set_property, (void *)
+				inst->session, HAL_PARAM_FRAME_SIZE,
+				&frame_sz);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to set OUTPUT framesize\n");
+			goto exit;
+		}
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			dprintk(VIDC_WARN,
+				"%s : Getting buffer reqs failed: %d\n",
+					__func__, rc);
+			goto exit;
+		}
+		bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			bufreq ? bufreq->buffer_size : 0;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		struct hal_buffer_requirements *bufreq = NULL;
+		int extra_idx = 0;
+
+		for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+				inst->fmts[fmt->type].get_frame_size(i,
+				f->fmt.pix_mp.height, f->fmt.pix_mp.width);
+		}
+		extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			bufreq = get_buff_req_buffer(inst,
+					HAL_BUFFER_EXTRADATA_INPUT);
+			f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+				bufreq ? bufreq->buffer_size : 0;
+		}
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+	const struct msm_vidc_format *fmt = NULL;
+	int rc = 0;
+	int i;
+	u32 height, width, num_planes;
+	unsigned int extra_idx = 0;
+	struct hal_buffer_requirements *bufreq = NULL;
+
+	if (!inst || !f) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, format = %pK\n", inst, f);
+		return -EINVAL;
+	}
+
+	rc = msm_comm_try_get_bufreqs(inst);
+	if (rc) {
+		dprintk(VIDC_WARN, "Getting buffer requirements failed: %d\n",
+				rc);
+		return rc;
+	}
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		fmt = &inst->fmts[CAPTURE_PORT];
+		height = inst->prop.height[CAPTURE_PORT];
+		width = inst->prop.width[CAPTURE_PORT];
+		msm_venc_update_plane_count(inst, CAPTURE_PORT);
+		num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		fmt = &inst->fmts[OUTPUT_PORT];
+		height = inst->prop.height[OUTPUT_PORT];
+		width = inst->prop.width[OUTPUT_PORT];
+		msm_venc_update_plane_count(inst, OUTPUT_PORT);
+		num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+	} else {
+		dprintk(VIDC_ERR, "Invalid type: %x\n", f->type);
+		return -ENOTSUPP;
+	}
+
+	f->fmt.pix_mp.pixelformat = fmt->fourcc;
+	f->fmt.pix_mp.height = height;
+	f->fmt.pix_mp.width = width;
+	f->fmt.pix_mp.num_planes = num_planes;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		for (i = 0; i < num_planes; ++i) {
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+				fmt->get_frame_size(i, height, width);
+		}
+	} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		bufreq = get_buff_req_buffer(inst,
+				HAL_BUFFER_OUTPUT);
+
+		f->fmt.pix_mp.plane_fmt[0].sizeimage =
+			bufreq ? bufreq->buffer_size : 0;
+	}
+	extra_idx = EXTRADATA_IDX(num_planes);
+	if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+		if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+			bufreq = get_buff_req_buffer(inst,
+						HAL_BUFFER_EXTRADATA_OUTPUT);
+		else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			bufreq = get_buff_req_buffer(inst,
+						HAL_BUFFER_EXTRADATA_INPUT);
+
+		f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+			bufreq ? bufreq->buffer_size : 0;
+	}
+
+	for (i = 0; i < num_planes; ++i) {
+		if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			inst->bufq[OUTPUT_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			inst->bufq[CAPTURE_PORT].plane_sizes[i] =
+				f->fmt.pix_mp.plane_fmt[i].sizeimage;
+		}
+	}
+	return rc;
+}
+
+int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	if (!inst || !b) {
+		dprintk(VIDC_ERR,
+			"Invalid input, inst = %pK, buffer = %pK\n", inst, b);
+		return -EINVAL;
+	}
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR,
+		"Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->lock);
+	rc = vb2_reqbufs(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int rc = 0;
+	int i;
+	struct vidc_buffer_addr_info buffer_info = {0};
+	struct hfi_device *hdev;
+	int extra_idx = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			inst->core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+			"Core %pK in bad state, ignoring prepare buf\n",
+				inst->core);
+		goto exit;
+	}
+
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+				"Planes mismatch: needed: %d, allocated: %d\n",
+				inst->fmts[CAPTURE_PORT].num_planes,
+				b->length);
+			rc = -EINVAL;
+			break;
+		}
+
+		for (i = 0; i < min_t(int, b->length, VIDEO_MAX_PLANES); i++) {
+			dprintk(VIDC_DBG, "device_addr = %#lx, size = %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length);
+		}
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr =
+			b->m.planes[0].m.userptr;
+
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+			buffer_info.extradata_addr =
+				b->m.planes[extra_idx].m.userptr;
+			dprintk(VIDC_DBG, "extradata: %#lx\n",
+					b->m.planes[extra_idx].m.userptr);
+			buffer_info.extradata_size =
+				b->m.planes[extra_idx].length;
+		}
+
+		rc = call_hfi_op(hdev, session_set_buffers,
+				(void *)inst->session, &buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+					"vidc_hal_session_set_buffers failed\n");
+		break;
+	default:
+		dprintk(VIDC_ERR,
+			"Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_release_buf(struct msm_vidc_inst *inst,
+					struct v4l2_buffer *b)
+{
+	int i, rc = 0, extra_idx = 0;
+	struct vidc_buffer_addr_info buffer_info = {0};
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move inst: %pK to release res done state\n",
+			inst);
+		goto exit;
+	}
+	switch (b->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+		if (b->length !=
+			inst->fmts[CAPTURE_PORT].num_planes) {
+			dprintk(VIDC_ERR,
+					"Planes mismatch: needed: %d, to release: %d\n",
+					inst->fmts[CAPTURE_PORT].num_planes,
+					b->length);
+			rc = -EINVAL;
+			break;
+		}
+		for (i = 0; i < b->length; i++) {
+			dprintk(VIDC_DBG,
+				"Release device_addr = %#lx, size = %d, %d\n",
+				b->m.planes[i].m.userptr,
+				b->m.planes[i].length, inst->state);
+		}
+		buffer_info.buffer_size = b->m.planes[0].length;
+		buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr =
+			b->m.planes[0].m.userptr;
+		extra_idx = EXTRADATA_IDX(b->length);
+		if (extra_idx && (extra_idx < VIDEO_MAX_PLANES))
+			buffer_info.extradata_addr =
+			b->m.planes[extra_idx].m.userptr;
+		buffer_info.response_required = false;
+		rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+					"vidc_hal_session_release_buffers failed\n");
+		}
+		break;
+	default:
+		dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
+		break;
+	}
+exit:
+	return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	mutex_lock(&q->lock);
+	rc = vb2_qbuf(&q->vb2_bufq, b);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buf_queue *q = NULL;
+	int rc = 0;
+
+	q = msm_comm_get_vb2q(inst, b->type);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", b->type);
+		return -EINVAL;
+	}
+	mutex_lock(&q->lock);
+	rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
+	return rc;
+}
+
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamon\n");
+	mutex_lock(&q->lock);
+	rc = vb2_streamon(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+	int rc = 0;
+	struct buf_queue *q;
+
+	q = msm_comm_get_vb2q(inst, i);
+	if (!q) {
+		dprintk(VIDC_ERR,
+			"Failed to find buffer queue for type = %d\n", i);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
+	mutex_lock(&q->lock);
+	rc = vb2_streamoff(&q->vb2_bufq, i);
+	mutex_unlock(&q->lock);
+	if (rc)
+		dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
+	return rc;
+}
+
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
+{
+	return msm_comm_ctrl_init(inst, msm_venc_ctrls,
+			ARRAY_SIZE(msm_venc_ctrls), &msm_venc_ctrl_ops);
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.h b/drivers/media/platform/msm/vidc_3x/msm_venc.h
new file mode 100644
index 0000000..e357304
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_venc.h
@@ -0,0 +1,37 @@
+/*Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _MSM_VENC_H_
+#define _MSM_VENC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
+int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_release_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
+int msm_venc_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+struct vb2_ops *msm_venc_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_vidc.c
new file mode 100644
index 0000000..7b22511
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc.c
@@ -0,0 +1,1420 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "msm_vidc_debug.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_common.h"
+#include <linux/delay.h>
+#include "vidc_hfi_api.h"
+#include "msm_vidc_dcvs.h"
+
+#define MAX_EVENTS 30
+
+static int get_poll_flags(void *instance)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+	struct vb2_buffer *out_vb = NULL;
+	struct vb2_buffer *cap_vb = NULL;
+	unsigned long flags;
+	int rc = 0;
+
+	if (v4l2_event_pending(&inst->event_handler))
+		rc |= POLLPRI;
+
+	spin_lock_irqsave(&capq->done_lock, flags);
+	if (!list_empty(&capq->done_list))
+		cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
+								done_entry);
+	if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
+				|| cap_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLIN | POLLRDNORM;
+	spin_unlock_irqrestore(&capq->done_lock, flags);
+
+	spin_lock_irqsave(&outq->done_lock, flags);
+	if (!list_empty(&outq->done_list))
+		out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
+								done_entry);
+	if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
+				|| out_vb->state == VB2_BUF_STATE_ERROR))
+		rc |= POLLOUT | POLLWRNORM;
+	spin_unlock_irqrestore(&outq->done_lock, flags);
+
+	return rc;
+}
+
+int msm_vidc_poll(void *instance, struct file *filp,
+		struct poll_table_struct *wait)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct vb2_queue *outq = NULL;
+	struct vb2_queue *capq = NULL;
+
+	if (!inst)
+		return -EINVAL;
+
+	outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+
+	poll_wait(filp, &inst->event_handler.wait, wait);
+	poll_wait(filp, &capq->done_wq, wait);
+	poll_wait(filp, &outq->done_wq, wait);
+	return get_poll_flags(inst);
+}
+EXPORT_SYMBOL(msm_vidc_poll);
+
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !cap)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_querycap(instance, cap);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_querycap(instance, cap);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_querycap);
+
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_enum_fmt(instance, f);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_enum_fmt(instance, f);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_enum_fmt);
+
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_s_fmt(instance, f);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_s_fmt(instance, f);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_fmt);
+
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !f)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_g_fmt(instance, f);
+	else if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_g_fmt(instance, f);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_g_fmt);
+
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
+	return msm_comm_s_ctrl(instance, control);
+}
+EXPORT_SYMBOL(msm_vidc_s_ctrl);
+
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
+	return msm_comm_g_ctrl(instance, control);
+}
+EXPORT_SYMBOL(msm_vidc_g_ctrl);
+
+int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *control)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !control)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_s_ext_ctrl(instance, control);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_s_ext_ctrl(instance, control);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_s_ext_ctrl);
+
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !b)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_reqbufs(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_reqbufs(instance, b);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_reqbufs);
+
+struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
+		struct v4l2_buffer *b, int idx, int *plane)
+{
+	struct buffer_info *temp;
+	struct buffer_info *ret = NULL;
+	int i;
+	int fd = b->m.planes[idx].reserved[0];
+	u32 buff_off = b->m.planes[idx].reserved[1];
+	u32 size = b->m.planes[idx].length;
+	ion_phys_addr_t device_addr = b->m.planes[idx].m.userptr;
+
+	if (fd < 0 || !plane) {
+		dprintk(VIDC_ERR, "Invalid input\n");
+		goto err_invalid_input;
+	}
+
+	WARN(!mutex_is_locked(&inst->registeredbufs.lock),
+		"Registered buf lock is not acquired for %s", __func__);
+
+	*plane = 0;
+	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+			bool ion_hndl_matches = temp->handle[i] ?
+				msm_smem_compare_buffers(inst->mem_client, fd,
+				temp->handle[i]->smem_priv) : false;
+			bool device_addr_matches = device_addr ==
+						temp->device_addr[i];
+			bool contains_within = CONTAINS(temp->buff_off[i],
+					temp->size[i], buff_off) ||
+				CONTAINS(buff_off, size, temp->buff_off[i]);
+			bool overlaps = OVERLAPS(buff_off, size,
+					temp->buff_off[i], temp->size[i]);
+
+			if (!temp->inactive &&
+				(ion_hndl_matches || device_addr_matches) &&
+				(contains_within || overlaps)) {
+				dprintk(VIDC_DBG,
+						"This memory region is already mapped\n");
+				ret = temp;
+				*plane = i;
+				break;
+			}
+		}
+		if (ret)
+			break;
+	}
+
+err_invalid_input:
+	return ret;
+}
+
+static struct msm_smem *get_same_fd_buffer(struct msm_vidc_inst *inst, int fd)
+{
+	struct buffer_info *temp;
+	struct msm_smem *same_fd_handle = NULL;
+
+	int i;
+
+	if (!fd)
+		return NULL;
+
+	if (!inst || fd < 0) {
+		dprintk(VIDC_ERR, "%s: Invalid input\n", __func__);
+		goto err_invalid_input;
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+			bool ion_hndl_matches = temp->handle[i] ?
+				msm_smem_compare_buffers(inst->mem_client, fd,
+				temp->handle[i]->smem_priv) : false;
+			if (ion_hndl_matches && temp->mapped[i])  {
+				temp->same_fd_ref[i]++;
+				dprintk(VIDC_INFO,
+				"Found same fd buffer\n");
+				same_fd_handle = temp->handle[i];
+				break;
+			}
+		}
+		if (same_fd_handle)
+			break;
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+
+err_invalid_input:
+	return same_fd_handle;
+}
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
+				ion_phys_addr_t device_addr)
+{
+	struct buffer_info *temp = NULL;
+	bool found = false;
+	int i;
+
+	if (!buf_list || !device_addr) {
+		dprintk(VIDC_ERR,
+			"Invalid input- device_addr: %pa buf_list: %pK\n",
+			&device_addr, buf_list);
+		goto err_invalid_input;
+	}
+
+	mutex_lock(&buf_list->lock);
+	list_for_each_entry(temp, &buf_list->list, list) {
+		for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
+			if (!temp->inactive &&
+				temp->device_addr[i] == device_addr)  {
+				dprintk(VIDC_INFO,
+				"Found same fd buffer\n");
+				found = true;
+				break;
+			}
+		}
+
+		if (found)
+			break;
+	}
+	mutex_unlock(&buf_list->lock);
+
+err_invalid_input:
+	return temp;
+}
+
+static inline void populate_buf_info(struct buffer_info *binfo,
+			struct v4l2_buffer *b, u32 i)
+{
+	if (i >= VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "%s: Invalid input\n", __func__);
+		return;
+	}
+	binfo->type = b->type;
+	binfo->fd[i] = b->m.planes[i].reserved[0];
+	binfo->buff_off[i] = b->m.planes[i].reserved[1];
+	binfo->size[i] = b->m.planes[i].length;
+	binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+	binfo->num_planes = b->length;
+	binfo->memory = b->memory;
+	binfo->v4l2_index = b->index;
+	binfo->timestamp.tv_sec = b->timestamp.tv_sec;
+	binfo->timestamp.tv_usec = b->timestamp.tv_usec;
+	dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
+			__func__, i, binfo->fd[0], b->index);
+}
+
+static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b,
+					struct buffer_info *binfo)
+{
+	int i = 0;
+
+	b->type = binfo->type;
+	b->length = binfo->num_planes;
+	b->memory = binfo->memory;
+	b->index = binfo->v4l2_index;
+	b->timestamp.tv_sec = binfo->timestamp.tv_sec;
+	b->timestamp.tv_usec = binfo->timestamp.tv_usec;
+	binfo->dequeued = false;
+	for (i = 0; i < binfo->num_planes; ++i) {
+		b->m.planes[i].reserved[0] = binfo->fd[i];
+		b->m.planes[i].reserved[1] = binfo->buff_off[i];
+		b->m.planes[i].length = binfo->size[i];
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
+		dprintk(VIDC_DBG, "%s %d %d %d %pa\n", __func__, binfo->fd[i],
+				binfo->buff_off[i], binfo->size[i],
+				&binfo->device_addr[i]);
+	}
+}
+
+static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
+		struct v4l2_plane *p, enum hal_buffer buffer_type)
+{
+	struct msm_smem *handle = NULL;
+
+	handle = msm_comm_smem_user_to_kernel(inst,
+				p->reserved[0],
+				p->reserved[1],
+				buffer_type);
+	if (!handle) {
+		dprintk(VIDC_ERR,
+			"%s: Failed to get device buffer address\n", __func__);
+		return NULL;
+	}
+	return handle;
+}
+
+static inline enum hal_buffer get_hal_buffer_type(
+		struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return HAL_BUFFER_INPUT;
+	else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return HAL_BUFFER_OUTPUT;
+	else
+		return -EINVAL;
+}
+
+static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b,
+				struct msm_vidc_inst *inst)
+{
+	return b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+		inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC;
+}
+
+
+static inline bool is_encoder_input_buffer(struct v4l2_buffer *b,
+				struct msm_vidc_inst *inst)
+{
+	return b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+			inst->session_type == MSM_VIDC_ENCODER;
+}
+
+static inline void save_v4l2_buffer(struct v4l2_buffer *b,
+						struct buffer_info *binfo)
+{
+	int i = 0;
+
+	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			continue;
+		}
+		populate_buf_info(binfo, b, i);
+	}
+}
+
+int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+	struct buffer_info *binfo = NULL;
+	struct buffer_info *temp = NULL, *iterator = NULL;
+	int plane = 0;
+	int i = 0, rc = 0;
+	struct msm_smem *same_fd_handle = NULL;
+
+	if (!b || !inst) {
+		dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+	if (!binfo) {
+		dprintk(VIDC_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+	if (b->length > VIDEO_MAX_PLANES) {
+		dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+			b->length, VIDEO_MAX_PLANES);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	dprintk(VIDC_DBG, "[MAP] Create binfo = %pK fd = %d type = %d\n",
+			binfo, b->m.planes[0].reserved[0], b->type);
+
+	for (i = 0; i < b->length; ++i) {
+		rc = 0;
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			continue;
+		}
+		mutex_lock(&inst->registeredbufs.lock);
+		temp = get_registered_buf(inst, b, i, &plane);
+		if (temp && !is_dynamic_output_buffer_mode(b, inst)) {
+			dprintk(VIDC_DBG,
+				"This memory region has already been prepared\n");
+			rc = 0;
+			mutex_unlock(&inst->registeredbufs.lock);
+			goto exit;
+		}
+
+		if (temp && is_dynamic_output_buffer_mode(b, inst) && !i) {
+			/*
+			 * Buffer is already present in registered list
+			 * increment ref_count, populate new values of v4l2
+			 * buffer in existing buffer_info struct.
+			 *
+			 * We will use the saved buffer info and queue it when
+			 * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w.
+			 */
+			dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
+			temp->inactive = false;
+			list_for_each_entry(iterator,
+				&inst->registeredbufs.list, list) {
+				if (iterator == temp) {
+					rc = buf_ref_get(inst, temp);
+					save_v4l2_buffer(b, temp);
+					break;
+				}
+			}
+		}
+		mutex_unlock(&inst->registeredbufs.lock);
+		/*
+		 * rc == 1,
+		 * buffer is mapped, fw has released all reference, so skip
+		 * mapping and queue it immediately.
+		 *
+		 * rc == 2,
+		 * buffer is mapped and fw is holding a reference, hold it in
+		 * the driver and queue it later when fw has released
+		 */
+		if (rc == 1) {
+			rc = 0;
+			goto exit;
+		} else if (rc == 2) {
+			rc = -EEXIST;
+			goto exit;
+		}
+
+		same_fd_handle = get_same_fd_buffer(
+				inst, b->m.planes[i].reserved[0]);
+
+		populate_buf_info(binfo, b, i);
+		if (same_fd_handle) {
+			binfo->device_addr[i] =
+			same_fd_handle->device_addr + binfo->buff_off[i];
+			b->m.planes[i].m.userptr = binfo->device_addr[i];
+			binfo->mapped[i] = false;
+			binfo->handle[i] = same_fd_handle;
+		} else {
+			binfo->handle[i] = map_buffer(inst, &b->m.planes[i],
+					get_hal_buffer_type(inst, b));
+			if (!binfo->handle[i]) {
+				rc = -EINVAL;
+				goto exit;
+			}
+
+			binfo->mapped[i] = true;
+			binfo->device_addr[i] = binfo->handle[i]->device_addr +
+				binfo->buff_off[i];
+			b->m.planes[i].m.userptr = binfo->device_addr[i];
+		}
+
+		/* We maintain one ref count for all planes*/
+		if (!i && is_dynamic_output_buffer_mode(b, inst)) {
+			rc = buf_ref_get(inst, binfo);
+			if (rc < 0)
+				goto exit;
+		}
+		dprintk(VIDC_DBG,
+			"%s: [MAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+			__func__, binfo, i, binfo->handle[i],
+			&binfo->device_addr[i], binfo->fd[i],
+			binfo->buff_off[i], binfo->mapped[i]);
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_add_tail(&binfo->list, &inst->registeredbufs.list);
+	mutex_unlock(&inst->registeredbufs.lock);
+	return 0;
+
+exit:
+	kfree(binfo);
+	return rc;
+}
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo)
+{
+	int i = 0;
+	struct buffer_info *temp = NULL;
+	bool found = false, keep_node = false;
+
+	if (!inst || !binfo) {
+		dprintk(VIDC_ERR, "%s invalid param: %pK %pK\n",
+			__func__, inst, binfo);
+		return -EINVAL;
+	}
+
+	WARN(!mutex_is_locked(&inst->registeredbufs.lock),
+		"Registered buf lock is not acquired for %s", __func__);
+
+	/*
+	 * Make sure the buffer to be unmapped and deleted
+	 * from the registered list is present in the list.
+	 */
+	list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+		if (temp == binfo) {
+			found = true;
+			break;
+		}
+	}
+
+	/*
+	 * Free the buffer info only if
+	 * - buffer info has not been deleted from registered list
+	 * - vidc client has called dqbuf on the buffer
+	 * - no references are held on the buffer
+	 */
+	if (!found || !temp || !temp->pending_deletion || !temp->dequeued)
+		goto exit;
+
+	for (i = 0; i < temp->num_planes; i++) {
+		dprintk(VIDC_DBG,
+			"%s: [UNMAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+			__func__, temp, i, temp->handle[i],
+			&temp->device_addr[i], temp->fd[i],
+			temp->buff_off[i], temp->mapped[i]);
+		/*
+		 * Unmap the handle only if the buffer has been mapped and no
+		 * other buffer has a reference to this buffer.
+		 * In case of buffers with same fd, we will map the buffer only
+		 * once and subsequent buffers will refer to the mapped buffer's
+		 * device address.
+		 * For buffers which share the same fd, do not unmap and keep
+		 * the buffer info in registered list.
+		 */
+		if (temp->handle[i] && temp->mapped[i] &&
+			!temp->same_fd_ref[i]) {
+			msm_comm_smem_free(inst,
+				temp->handle[i]);
+		}
+
+		if (temp->same_fd_ref[i])
+			keep_node = true;
+		else {
+			temp->fd[i] = 0;
+			temp->handle[i] = 0;
+			temp->device_addr[i] = 0;
+			temp->uvaddr[i] = 0;
+		}
+	}
+	if (!keep_node) {
+		dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %pK\n", temp);
+		list_del(&temp->list);
+		kfree(temp);
+	} else {
+		temp->inactive = true;
+		dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %pK\n", temp);
+	}
+exit:
+	return 0;
+}
+
+
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo)
+{
+	struct v4l2_buffer b = {0};
+	struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} };
+
+	if (!binfo) {
+		dprintk(VIDC_ERR, "%s invalid param: %pK\n", __func__, binfo);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]);
+
+	b.m.planes = plane;
+	repopulate_v4l2_buffer(&b, binfo);
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_qbuf(inst, &b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_qbuf(inst, &b);
+
+	return -EINVAL;
+}
+
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+				struct buffer_info *binfo)
+{
+	int i = 0;
+	int rc = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
+		return -EINVAL;
+	}
+
+	if (!binfo) {
+		dprintk(VIDC_ERR, "%s: invalid buffer info: %pK\n",
+			__func__, inst);
+		return -EINVAL;
+	}
+
+	if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return 0;
+
+
+	for (i = 0; i < binfo->num_planes; i++) {
+		if (binfo->handle[i]) {
+			rc = msm_comm_smem_cache_operations(inst,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s: Failed to clean caches: %d\n",
+					__func__, rc);
+				return -EINVAL;
+			}
+		} else
+			dprintk(VIDC_DBG, "%s: NULL handle for plane %d\n",
+					__func__, i);
+	}
+	return 0;
+}
+
+static bool valid_v4l2_buffer(struct v4l2_buffer *b,
+		struct msm_vidc_inst *inst) {
+	enum vidc_ports port =
+		!V4L2_TYPE_IS_MULTIPLANAR(b->type) ? MAX_PORT_NUM :
+		b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT :
+		b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? OUTPUT_PORT :
+								MAX_PORT_NUM;
+
+	return port != MAX_PORT_NUM &&
+		inst->fmts[port].num_planes == b->length;
+}
+
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst))
+		return -EINVAL;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+		inst->core->state == VIDC_CORE_INVALID)
+		return -EINVAL;
+
+	if (is_dynamic_output_buffer_mode(b, inst))
+		return 0;
+
+	if (map_and_register_buf(inst, b))
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_prepare_buf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_prepare_buf(instance, b);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_prepare_buf);
+
+int msm_vidc_release_buffers(void *instance, int buffer_type)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *bi, *dummy;
+	struct v4l2_buffer buffer_info;
+	struct v4l2_plane plane[VIDEO_MAX_PLANES];
+	int i, rc = 0;
+
+	if (!inst)
+		return -EINVAL;
+
+	if (!inst->in_reconfig &&
+		inst->state > MSM_VIDC_LOAD_RESOURCES &&
+		inst->state < MSM_VIDC_RELEASE_RESOURCES_DONE) {
+		rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to move inst: %pK to release res done\n",
+					inst);
+		}
+	}
+
+	/*
+	 * In dynamic buffer mode, driver needs to release resources,
+	 * but not call release buffers on firmware, as the buffers
+	 * were never registered with firmware.
+	 */
+	if (buffer_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+		inst->buffer_mode_set[CAPTURE_PORT] ==
+				HAL_BUFFER_MODE_DYNAMIC) {
+		goto free_and_unmap;
+	}
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(bi, &inst->registeredbufs.list, list) {
+		bool release_buf = false;
+
+		if (bi->type == buffer_type) {
+			buffer_info.type = bi->type;
+			for (i = 0; i < min(bi->num_planes, VIDEO_MAX_PLANES);
+						i++) {
+				plane[i].reserved[0] = bi->fd[i];
+				plane[i].reserved[1] = bi->buff_off[i];
+				plane[i].length = bi->size[i];
+				plane[i].m.userptr = bi->device_addr[i];
+				buffer_info.m.planes = plane;
+				dprintk(VIDC_DBG,
+					"Releasing buffer: %d, %d, %d\n",
+					buffer_info.m.planes[i].reserved[0],
+					buffer_info.m.planes[i].reserved[1],
+					buffer_info.m.planes[i].length);
+			}
+			buffer_info.length = bi->num_planes;
+			release_buf = true;
+		}
+
+		if (!release_buf)
+			continue;
+		if (inst->session_type == MSM_VIDC_DECODER)
+			rc = msm_vdec_release_buf(instance,
+				&buffer_info);
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			rc = msm_venc_release_buf(instance,
+				&buffer_info);
+		if (rc)
+			dprintk(VIDC_ERR,
+				"Failed Release buffer: %d, %d, %d\n",
+				buffer_info.m.planes[0].reserved[0],
+				buffer_info.m.planes[0].reserved[1],
+				buffer_info.m.planes[0].length);
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+
+free_and_unmap:
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
+		if (bi->type == buffer_type) {
+			list_del(&bi->list);
+			for (i = 0; i < bi->num_planes; i++) {
+				if (bi->handle[i] && bi->mapped[i]) {
+					dprintk(VIDC_DBG,
+						"%s: [UNMAP] binfo = %pK, handle[%d] = %pK, device_addr = %pa, fd = %d, offset = %d, mapped = %d\n",
+						__func__, bi, i, bi->handle[i],
+						&bi->device_addr[i], bi->fd[i],
+						bi->buff_off[i], bi->mapped[i]);
+					msm_comm_smem_free(inst,
+							bi->handle[i]);
+				}
+			}
+			kfree(bi);
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_release_buffers);
+
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *binfo;
+	int plane = 0;
+	int rc = 0;
+	int i;
+
+	if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst))
+		return -EINVAL;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+		inst->core->state == VIDC_CORE_INVALID)
+		return -EINVAL;
+
+	rc = map_and_register_buf(inst, b);
+	if (rc == -EEXIST) {
+		if (atomic_read(&inst->in_flush) &&
+			is_dynamic_output_buffer_mode(b, inst)) {
+			dprintk(VIDC_ERR,
+				"Flush in progress, do not hold any buffers in driver\n");
+			msm_comm_flush_dynamic_buffers(inst);
+		}
+		return 0;
+	}
+	if (rc)
+		return rc;
+
+	for (i = 0; i < b->length; ++i) {
+		if (EXTRADATA_IDX(b->length) &&
+			(i == EXTRADATA_IDX(b->length)) &&
+			!b->m.planes[i].length) {
+			b->m.planes[i].m.userptr = 0;
+			continue;
+		}
+		mutex_lock(&inst->registeredbufs.lock);
+		binfo = get_registered_buf(inst, b, i, &plane);
+		mutex_unlock(&inst->registeredbufs.lock);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+				"This buffer is not registered: %d, %d, %d\n",
+				b->m.planes[i].reserved[0],
+				b->m.planes[i].reserved[1],
+				b->m.planes[i].length);
+			goto err_invalid_buff;
+		}
+		b->m.planes[i].m.userptr = binfo->device_addr[i];
+		dprintk(VIDC_DBG, "Queueing device address = %pa\n",
+				&binfo->device_addr[i]);
+
+		if (inst->fmts[OUTPUT_PORT].fourcc ==
+			V4L2_PIX_FMT_HEVC_HYBRID && binfo->handle[i] &&
+			b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			rc = msm_comm_smem_cache_operations(inst,
+				binfo->handle[i], SMEM_CACHE_INVALIDATE);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to inv caches: %d\n", rc);
+				goto err_invalid_buff;
+			}
+		}
+
+		if (binfo->handle[i] &&
+			(b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+			rc = msm_comm_smem_cache_operations(inst,
+					binfo->handle[i], SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to clean caches: %d\n", rc);
+				goto err_invalid_buff;
+			}
+		}
+	}
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_qbuf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_qbuf(instance, b);
+
+err_invalid_buff:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_qbuf);
+
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *buffer_info = NULL;
+	int i = 0, rc = 0;
+
+	if (!inst || !b || !valid_v4l2_buffer(b, inst))
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		rc = msm_vdec_dqbuf(instance, b);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		rc = msm_venc_dqbuf(instance, b);
+
+	if (rc)
+		return rc;
+
+	for (i = b->length - 1; i >= 0 ; i--) {
+		if (EXTRADATA_IDX(b->length) &&
+			i == EXTRADATA_IDX(b->length)) {
+			continue;
+		}
+		buffer_info = device_to_uvaddr(&inst->registeredbufs,
+			b->m.planes[i].m.userptr);
+
+		if (!buffer_info) {
+			dprintk(VIDC_ERR,
+				"%s no buffer info registered for buffer addr: %#lx\n",
+				__func__, b->m.planes[i].m.userptr);
+			return -EINVAL;
+		}
+
+		b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
+		b->m.planes[i].reserved[0] = buffer_info->fd[i];
+		b->m.planes[i].reserved[1] = buffer_info->buff_off[i];
+		if (!(inst->flags & VIDC_SECURE) && !b->m.planes[i].m.userptr) {
+			dprintk(VIDC_ERR,
+			"%s: Failed to find user virtual address, %#lx, %d, %d\n",
+			__func__, b->m.planes[i].m.userptr, b->type, i);
+			return -EINVAL;
+		}
+	}
+
+	if (!buffer_info) {
+		dprintk(VIDC_ERR,
+			"%s: error - no buffer info found in registered list\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = output_buffer_cache_invalidate(inst, buffer_info);
+	if (rc)
+		return rc;
+
+	if (is_dynamic_output_buffer_mode(b, inst)) {
+		buffer_info->dequeued = true;
+
+		dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
+			buffer_info->fd[0]);
+		mutex_lock(&inst->registeredbufs.lock);
+		rc = unmap_and_deregister_buf(inst, buffer_info);
+		mutex_unlock(&inst->registeredbufs.lock);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_dqbuf);
+
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_streamon(instance, i);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_streamon(instance, i);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_streamon);
+
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		return msm_vdec_streamoff(instance, i);
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		return msm_venc_streamoff(instance, i);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(msm_vidc_streamoff);
+
+int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct msm_vidc_capability *capability = NULL;
+
+	if (!inst || !fsize) {
+		dprintk(VIDC_ERR, "%s: invalid parameter: %pK %pK\n",
+				__func__, inst, fsize);
+		return -EINVAL;
+	}
+	if (!inst->core)
+		return -EINVAL;
+
+	capability = &inst->capability;
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = capability->width.min;
+	fsize->stepwise.max_width = capability->width.max;
+	fsize->stepwise.step_width = capability->width.step_size;
+	fsize->stepwise.min_height = capability->height.min;
+	fsize->stepwise.max_height = capability->height.max;
+	fsize->stepwise.step_height = capability->height.step_size;
+	return 0;
+}
+EXPORT_SYMBOL(msm_vidc_enum_framesizes);
+
+static void *vidc_get_userptr(struct device *dev, unsigned long vaddr,
+			unsigned long size, enum dma_data_direction dma_dir)
+{
+	return (void *)0xdeadbeef;
+}
+
+static void vidc_put_userptr(void *buf_priv)
+{
+
+}
+static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
+	.get_userptr = vidc_get_userptr,
+	.put_userptr = vidc_put_userptr,
+};
+
+static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
+		enum v4l2_buf_type type, enum session_type sess)
+{
+	struct vb2_queue *q = NULL;
+
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		q = &inst->bufq[CAPTURE_PORT].vb2_bufq;
+	} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		q = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+	} else {
+		dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type);
+		return -EINVAL;
+	}
+
+	q->type = type;
+	q->io_modes = VB2_MMAP | VB2_USERPTR;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+
+	if (sess == MSM_VIDC_DECODER)
+		q->ops = msm_vdec_get_vb2q_ops();
+	else if (sess == MSM_VIDC_ENCODER)
+		q->ops = msm_venc_get_vb2q_ops();
+	q->mem_ops = &msm_vidc_vb2_mem_ops;
+	q->drv_priv = inst;
+	return vb2_queue_init(q);
+}
+
+static int setup_event_queue(void *inst,
+				struct video_device *pvdev)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	v4l2_fh_init(&vidc_inst->event_handler, pvdev);
+	v4l2_fh_add(&vidc_inst->event_handler);
+
+	return rc;
+}
+
+int msm_vidc_subscribe_event(void *inst,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !sub)
+		return -EINVAL;
+
+	rc = v4l2_event_subscribe(&vidc_inst->event_handler,
+		sub, MAX_EVENTS, NULL);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_subscribe_event);
+
+int msm_vidc_unsubscribe_event(void *inst,
+	const struct v4l2_event_subscription *sub)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !sub)
+		return -EINVAL;
+
+	rc = v4l2_event_unsubscribe(&vidc_inst->event_handler, sub);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_unsubscribe_event);
+
+int msm_vidc_dqevent(void *inst, struct v4l2_event *event)
+{
+	int rc = 0;
+	struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
+
+	if (!inst || !event)
+		return -EINVAL;
+
+	rc = v4l2_event_dequeue(&vidc_inst->event_handler, event, false);
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_dqevent);
+
+static bool msm_vidc_check_for_inst_overload(struct msm_vidc_core *core)
+{
+	u32 instance_count = 0;
+	u32 secure_instance_count = 0;
+	struct msm_vidc_inst *inst = NULL;
+	bool overload = false;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		instance_count++;
+		/* This flag is not updated yet for the current instance */
+		if (inst->flags & VIDC_SECURE)
+			secure_instance_count++;
+	}
+	mutex_unlock(&core->lock);
+
+	/* Instance count includes current instance as well. */
+
+	if ((instance_count > core->resources.max_inst_count) ||
+		(secure_instance_count > core->resources.max_secure_inst_count))
+		overload = true;
+	return overload;
+}
+
+void *msm_vidc_open(int core_id, int session_type)
+{
+	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_core *core = NULL;
+	int rc = 0;
+	int i = 0;
+
+	if (core_id >= MSM_VIDC_CORES_MAX ||
+			session_type >= MSM_VIDC_MAX_DEVICES) {
+		dprintk(VIDC_ERR, "Invalid input, core_id = %d, session = %d\n",
+			core_id, session_type);
+		goto err_invalid_core;
+	}
+	core = get_vidc_core(core_id);
+	if (!core) {
+		dprintk(VIDC_ERR,
+			"Failed to find core for core_id = %d\n", core_id);
+		goto err_invalid_core;
+	}
+
+	inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+	if (!inst) {
+		dprintk(VIDC_ERR, "Failed to allocate memory\n");
+		rc = -ENOMEM;
+		goto err_invalid_core;
+	}
+
+	pr_info(VIDC_DBG_TAG "Opening video instance: %pK, %d\n",
+		VIDC_MSG_PRIO2STRING(VIDC_INFO), inst, session_type);
+	mutex_init(&inst->sync_lock);
+	mutex_init(&inst->bufq[CAPTURE_PORT].lock);
+	mutex_init(&inst->bufq[OUTPUT_PORT].lock);
+	mutex_init(&inst->lock);
+
+	INIT_MSM_VIDC_LIST(&inst->pendingq);
+	INIT_MSM_VIDC_LIST(&inst->scratchbufs);
+	INIT_MSM_VIDC_LIST(&inst->persistbufs);
+	INIT_MSM_VIDC_LIST(&inst->pending_getpropq);
+	INIT_MSM_VIDC_LIST(&inst->outputbufs);
+	INIT_MSM_VIDC_LIST(&inst->registeredbufs);
+
+	kref_init(&inst->kref);
+
+	inst->session_type = session_type;
+	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
+	inst->core = core;
+	inst->bit_depth = MSM_VIDC_BIT_DEPTH_8;
+	inst->instant_bitrate = 0;
+	inst->pic_struct = MSM_VIDC_PIC_STRUCT_PROGRESSIVE;
+	inst->colour_space = MSM_VIDC_BT601_6_525;
+
+	for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
+		i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
+		init_completion(&inst->completions[i]);
+	}
+	inst->mem_client = msm_smem_new_client(SMEM_ION,
+					&inst->core->resources, session_type);
+	if (!inst->mem_client) {
+		dprintk(VIDC_ERR, "Failed to create memory client\n");
+		goto fail_mem_client;
+	}
+	if (session_type == MSM_VIDC_DECODER) {
+		msm_vdec_inst_init(inst);
+		rc = msm_vdec_ctrl_init(inst);
+	} else if (session_type == MSM_VIDC_ENCODER) {
+		msm_venc_inst_init(inst);
+		rc = msm_venc_ctrl_init(inst);
+	}
+
+	if (rc)
+		goto fail_bufq_capture;
+
+	msm_dcvs_init(inst);
+	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+			session_type);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to initialize vb2 queue on capture port\n");
+		goto fail_bufq_capture;
+	}
+	rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+			session_type);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to initialize vb2 queue on capture port\n");
+		goto fail_bufq_output;
+	}
+
+	setup_event_queue(inst, &core->vdev[session_type].vdev);
+
+	mutex_lock(&core->lock);
+	list_add_tail(&inst->list, &core->instances);
+	mutex_unlock(&core->lock);
+
+	rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to move video instance to init state\n");
+		goto fail_init;
+	}
+
+	if (msm_vidc_check_for_inst_overload(core)) {
+		dprintk(VIDC_ERR,
+			"Instance count reached Max limit, rejecting session");
+		goto fail_init;
+	}
+
+	inst->debugfs_root =
+		msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
+
+	return inst;
+fail_init:
+	v4l2_fh_del(&inst->event_handler);
+	v4l2_fh_exit(&inst->event_handler);
+	vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq);
+
+	mutex_lock(&core->lock);
+	list_del(&inst->list);
+	mutex_unlock(&core->lock);
+
+fail_bufq_output:
+	vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq);
+fail_bufq_capture:
+	msm_comm_ctrl_deinit(inst);
+	msm_smem_delete_client(inst->mem_client);
+fail_mem_client:
+	kfree(inst);
+	inst = NULL;
+err_invalid_core:
+	return inst;
+}
+EXPORT_SYMBOL(msm_vidc_open);
+
+static void cleanup_instance(struct msm_vidc_inst *inst)
+{
+	struct vb2_buf_entry *entry, *dummy;
+
+	if (inst) {
+
+		mutex_lock(&inst->pendingq.lock);
+		list_for_each_entry_safe(entry, dummy, &inst->pendingq.list,
+				list) {
+			list_del(&entry->list);
+			kfree(entry);
+		}
+		mutex_unlock(&inst->pendingq.lock);
+
+		if (msm_comm_release_scratch_buffers(inst, false)) {
+			dprintk(VIDC_ERR,
+				"Failed to release scratch buffers\n");
+		}
+
+		if (msm_comm_release_persist_buffers(inst)) {
+			dprintk(VIDC_ERR,
+				"Failed to release persist buffers\n");
+		}
+
+		if (msm_comm_release_output_buffers(inst)) {
+			dprintk(VIDC_ERR,
+				"Failed to release output buffers\n");
+		}
+
+		if (inst->extradata_handle)
+			msm_comm_smem_free(inst, inst->extradata_handle);
+
+		mutex_lock(&inst->pending_getpropq.lock);
+		if (!list_empty(&inst->pending_getpropq.list)) {
+			dprintk(VIDC_ERR,
+				"pending_getpropq not empty\n");
+			WARN_ON(VIDC_DBG_WARN_ENABLE);
+		}
+		mutex_unlock(&inst->pending_getpropq.lock);
+	}
+}
+
+int msm_vidc_destroy(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	int i = 0;
+
+	if (!inst || !inst->core)
+		return -EINVAL;
+
+	core = inst->core;
+
+	mutex_lock(&core->lock);
+	/* inst->list lives in core->instances */
+	list_del(&inst->list);
+	mutex_unlock(&core->lock);
+
+	msm_comm_ctrl_deinit(inst);
+
+	v4l2_fh_del(&inst->event_handler);
+	v4l2_fh_exit(&inst->event_handler);
+
+	for (i = 0; i < MAX_PORT_NUM; i++)
+		vb2_queue_release(&inst->bufq[i].vb2_bufq);
+
+	mutex_destroy(&inst->sync_lock);
+	mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
+	mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
+	mutex_destroy(&inst->lock);
+
+	msm_vidc_debugfs_deinit_inst(inst);
+	pr_info(VIDC_DBG_TAG "Closed video instance: %pK\n",
+			VIDC_MSG_PRIO2STRING(VIDC_INFO), inst);
+	kfree(inst);
+	return 0;
+}
+
+int msm_vidc_close(void *instance)
+{
+	void close_helper(struct kref *kref)
+	{
+		struct msm_vidc_inst *inst = container_of(kref,
+				struct msm_vidc_inst, kref);
+
+		msm_vidc_destroy(inst);
+	}
+
+	struct msm_vidc_inst *inst = instance;
+	struct buffer_info *bi, *dummy;
+	int rc = 0;
+
+	if (!inst || !inst->core)
+		return -EINVAL;
+
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry_safe(bi, dummy, &inst->registeredbufs.list, list) {
+		if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			int i = 0;
+
+			list_del(&bi->list);
+
+			for (i = 0; i < min(bi->num_planes, VIDEO_MAX_PLANES);
+					i++) {
+				if (bi->handle[i] && bi->mapped[i])
+					msm_comm_smem_free(inst, bi->handle[i]);
+			}
+
+			kfree(bi);
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+
+	cleanup_instance(inst);
+	if (inst->state != MSM_VIDC_CORE_INVALID &&
+		inst->core->state != VIDC_CORE_INVALID)
+		rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+	else
+		rc = msm_comm_force_cleanup(inst);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to move video instance to uninit state\n");
+
+	msm_comm_session_clean(inst);
+	msm_smem_delete_client(inst->mem_client);
+
+	kref_put(&inst->kref, close_helper);
+	return 0;
+}
+EXPORT_SYMBOL(msm_vidc_close);
+
+int msm_vidc_suspend(int core_id)
+{
+	return msm_comm_suspend(core_id);
+}
+EXPORT_SYMBOL(msm_vidc_suspend);
+
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
new file mode 100644
index 0000000..395ea58
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c
@@ -0,0 +1,5262 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/boot_stats.h>
+#include <asm/div64.h>
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define IS_ALREADY_IN_STATE(__p, __d) ({\
+	int __rc = (__p >= __d);\
+	__rc; \
+})
+
+#define SUM_ARRAY(__arr, __start, __end) ({\
+		int __index;\
+		typeof((__arr)[0]) __sum = 0;\
+		for (__index = (__start); __index <= (__end); __index++) {\
+			if (__index >= 0 && __index < ARRAY_SIZE(__arr))\
+				__sum += __arr[__index];\
+		} \
+		__sum;\
+})
+
+#define V4L2_EVENT_SEQ_CHANGED_SUFFICIENT \
+		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
+#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
+		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+#define V4L2_EVENT_RELEASE_BUFFER_REFERENCE \
+		V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE
+
+#define MAX_SUPPORTED_INSTANCES 16
+
+const char *const mpeg_video_vidc_extradata[] = {
+	"Extradata none",
+	"Extradata MB Quantization",
+	"Extradata Interlace Video",
+	"Extradata VC1 Framedisp",
+	"Extradata VC1 Seqdisp",
+	"Extradata timestamp",
+	"Extradata S3D Frame Packing",
+	"Extradata Frame Rate",
+	"Extradata Panscan Window",
+	"Extradata Recovery point SEI",
+	"Extradata Multislice info",
+	"Extradata number of concealed MB",
+	"Extradata metadata filler",
+	"Extradata input crop",
+	"Extradata digital zoom",
+	"Extradata aspect ratio",
+	"Extradata mpeg2 seqdisp",
+	"Extradata stream userdata",
+	"Extradata frame QP",
+	"Extradata frame bits info",
+	"Extradata LTR",
+	"Extradata macroblock metadata",
+	"Extradata VQZip SEI",
+	"Extradata YUV Stats",
+	"Extradata ROI QP",
+	"Extradata output crop",
+	"Extradata display colour SEI",
+	"Extradata light level SEI",
+	"Extradata display VUI",
+	"Extradata vpx color space",
+	"Extradata PQ Info",
+};
+
+struct getprop_buf {
+	struct list_head list;
+	void *data;
+};
+
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst);
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
+static void handle_session_error(enum hal_command_response cmd, void *data);
+
+bool msm_comm_turbo_session(struct msm_vidc_inst *inst)
+{
+	return !!(inst->flags & VIDC_TURBO);
+}
+
+static inline bool is_thumbnail_session(struct msm_vidc_inst *inst)
+{
+	return !!(inst->flags & VIDC_THUMBNAIL);
+}
+
+static inline bool is_low_power_session(struct msm_vidc_inst *inst)
+{
+	return !!(inst->flags & VIDC_LOW_POWER);
+}
+
+int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+	return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+
+int msm_comm_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+	return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl);
+}
+
+int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id)
+{
+	int rc = 0;
+	struct v4l2_control ctrl = {
+		.id = id,
+	};
+
+	rc = msm_comm_g_ctrl(inst, &ctrl);
+	return rc ?: ctrl.value;
+}
+
+static struct v4l2_ctrl **get_super_cluster(struct msm_vidc_inst *inst,
+				int num_ctrls)
+{
+	int c = 0;
+	struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) *
+			num_ctrls, GFP_KERNEL);
+
+	if (!cluster || !inst)
+		return NULL;
+
+	for (c = 0; c < num_ctrls; c++)
+		cluster[c] =  inst->ctrls[c];
+
+	return cluster;
+}
+
+int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
+		struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
+		const struct v4l2_ctrl_ops *ctrl_ops)
+{
+	int idx = 0;
+	struct v4l2_ctrl_config ctrl_cfg = {0};
+	int ret_val = 0;
+
+	if (!inst || !drv_ctrls || !ctrl_ops || !num_ctrls) {
+		dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	inst->ctrls = kcalloc(num_ctrls, sizeof(struct v4l2_ctrl *),
+				GFP_KERNEL);
+	if (!inst->ctrls) {
+		dprintk(VIDC_ERR, "%s - failed to allocate ctrl\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls);
+
+	if (ret_val) {
+		dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n",
+				inst->ctrl_handler.error);
+		return ret_val;
+	}
+
+	for (; idx < num_ctrls; idx++) {
+		struct v4l2_ctrl *ctrl = NULL;
+
+		if (IS_PRIV_CTRL(drv_ctrls[idx].id)) {
+			/*add private control*/
+			ctrl_cfg.def = drv_ctrls[idx].default_value;
+			ctrl_cfg.flags = 0;
+			ctrl_cfg.id = drv_ctrls[idx].id;
+			ctrl_cfg.max = drv_ctrls[idx].maximum;
+			ctrl_cfg.min = drv_ctrls[idx].minimum;
+			ctrl_cfg.menu_skip_mask =
+				drv_ctrls[idx].menu_skip_mask;
+			ctrl_cfg.name = drv_ctrls[idx].name;
+			ctrl_cfg.ops = ctrl_ops;
+			ctrl_cfg.step = drv_ctrls[idx].step;
+			ctrl_cfg.type = drv_ctrls[idx].type;
+			ctrl_cfg.qmenu = drv_ctrls[idx].qmenu;
+
+			ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler,
+					&ctrl_cfg, NULL);
+		} else {
+			if (drv_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+				ctrl = v4l2_ctrl_new_std_menu(
+					&inst->ctrl_handler,
+					ctrl_ops,
+					drv_ctrls[idx].id,
+					drv_ctrls[idx].maximum,
+					drv_ctrls[idx].menu_skip_mask,
+					drv_ctrls[idx].default_value);
+			} else {
+				ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler,
+					ctrl_ops,
+					drv_ctrls[idx].id,
+					drv_ctrls[idx].minimum,
+					drv_ctrls[idx].maximum,
+					drv_ctrls[idx].step,
+					drv_ctrls[idx].default_value);
+			}
+		}
+
+		if (!ctrl) {
+			dprintk(VIDC_ERR, "%s - invalid ctrl %s\n", __func__,
+				 drv_ctrls[idx].name);
+			return -EINVAL;
+		}
+
+		ret_val = inst->ctrl_handler.error;
+		if (ret_val) {
+			dprintk(VIDC_ERR,
+				"Error adding ctrl (%s) to ctrl handle, %d\n",
+				drv_ctrls[idx].name, inst->ctrl_handler.error);
+			return ret_val;
+		}
+
+		ctrl->flags |= drv_ctrls[idx].flags;
+		inst->ctrls[idx] = ctrl;
+	}
+
+	/* Construct a super cluster of all controls */
+	inst->cluster = get_super_cluster(inst, num_ctrls);
+	if (!inst->cluster) {
+		dprintk(VIDC_WARN,
+			"Failed to setup super cluster\n");
+		return -EINVAL;
+	}
+
+	v4l2_ctrl_cluster(num_ctrls, inst->cluster);
+
+	return ret_val;
+}
+
+int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	kfree(inst->ctrls);
+	kfree(inst->cluster);
+	v4l2_ctrl_handler_free(&inst->ctrl_handler);
+
+	return 0;
+}
+
+static inline bool is_non_realtime_session(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct v4l2_control ctrl = {
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY
+	};
+	rc = msm_comm_g_ctrl(inst, &ctrl);
+	return (!rc && ctrl.value);
+}
+
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst)
+{
+	switch (msm_comm_g_ctrl_for_id(inst,
+				V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE)) {
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
+			return HAL_VIDEO_DECODER_SECONDARY;
+		case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
+		default:
+			return HAL_VIDEO_DECODER_PRIMARY;
+	}
+}
+
+static int msm_comm_get_mbs_per_frame(struct msm_vidc_inst *inst)
+{
+	int output_port_mbs, capture_port_mbs;
+
+	output_port_mbs = inst->in_reconfig ?
+			NUM_MBS_PER_FRAME(inst->reconfig_width,
+				inst->reconfig_height) :
+			NUM_MBS_PER_FRAME(inst->prop.width[OUTPUT_PORT],
+				inst->prop.height[OUTPUT_PORT]);
+	capture_port_mbs = NUM_MBS_PER_FRAME(inst->prop.width[CAPTURE_PORT],
+		inst->prop.height[CAPTURE_PORT]);
+
+	return max(output_port_mbs, capture_port_mbs);
+}
+
+static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
+{
+	int rc;
+	u32 fps;
+	struct v4l2_control ctrl;
+	int mb_per_frame;
+
+	mb_per_frame = msm_comm_get_mbs_per_frame(inst);
+
+	ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE;
+	rc = msm_comm_g_ctrl(inst, &ctrl);
+	if (!rc && ctrl.value) {
+		fps = (ctrl.value >> 16) ? ctrl.value >> 16 : 1;
+		/*
+		 * Check if operating rate is less than fps.
+		 * If Yes, then use fps to scale the clocks
+		 */
+		fps = fps > inst->prop.fps ? fps : inst->prop.fps;
+		return (mb_per_frame * fps);
+	} else
+		return (mb_per_frame * inst->prop.fps);
+}
+
+int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
+		enum load_calc_quirks quirks)
+{
+	int load = 0;
+
+	mutex_lock(&inst->lock);
+
+	if (!(inst->state >= MSM_VIDC_OPEN_DONE &&
+		inst->state < MSM_VIDC_STOP_DONE))
+		goto exit;
+
+	load = msm_comm_get_mbs_per_sec(inst);
+
+	if (is_thumbnail_session(inst)) {
+		if (quirks & LOAD_CALC_IGNORE_THUMBNAIL_LOAD)
+			load = 0;
+	}
+
+	if (msm_comm_turbo_session(inst)) {
+		if (!(quirks & LOAD_CALC_IGNORE_TURBO_LOAD))
+			load = inst->core->resources.max_load;
+	}
+
+	/*  Clock and Load calculations for REALTIME/NON-REALTIME
+	 *                        OPERATING RATE SET/NO OPERATING RATE SET
+	 *
+	 *                 | OPERATING RATE SET   | OPERATING RATE NOT SET |
+	 * ----------------|--------------------- |------------------------|
+	 * REALTIME        | load = res * op_rate |  load = res * fps      |
+	 *                 | clk  = res * op_rate |  clk  = res * fps      |
+	 * ----------------|----------------------|------------------------|
+	 * NON-REALTIME    | load = res * 1 fps   |  load = res * 1 fps    |
+	 *                 | clk  = res * op_rate |  clk  = res * fps      |
+	 * ----------------|----------------------|------------------------|
+	 */
+
+	if (is_non_realtime_session(inst) &&
+		(quirks & LOAD_CALC_IGNORE_NON_REALTIME_LOAD)) {
+		if (!inst->prop.fps) {
+			dprintk(VIDC_INFO, "instance:%pK fps = 0\n", inst);
+			load = 0;
+		} else {
+			load = msm_comm_get_mbs_per_sec(inst) / inst->prop.fps;
+		}
+	}
+
+exit:
+	mutex_unlock(&inst->lock);
+	return load;
+}
+
+int msm_comm_get_load(struct msm_vidc_core *core,
+	enum session_type type, enum load_calc_quirks quirks)
+{
+	struct msm_vidc_inst *inst = NULL;
+	int num_mbs_per_sec = 0;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "Invalid args: %pK\n", core);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst->session_type != type)
+			continue;
+
+		num_mbs_per_sec += msm_comm_get_inst_load(inst, quirks);
+	}
+	mutex_unlock(&core->lock);
+
+	return num_mbs_per_sec;
+}
+
+enum hal_domain get_hal_domain(int session_type)
+{
+	enum hal_domain domain;
+
+	switch (session_type) {
+	case MSM_VIDC_ENCODER:
+		domain = HAL_VIDEO_DOMAIN_ENCODER;
+		break;
+	case MSM_VIDC_DECODER:
+		domain = HAL_VIDEO_DOMAIN_DECODER;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Wrong domain\n");
+		domain = HAL_UNUSED_DOMAIN;
+		break;
+	}
+
+	return domain;
+}
+
+enum hal_video_codec get_hal_codec(int fourcc)
+{
+	enum hal_video_codec codec;
+
+	switch (fourcc) {
+	case V4L2_PIX_FMT_H264:
+	case V4L2_PIX_FMT_H264_NO_SC:
+		codec = HAL_VIDEO_CODEC_H264;
+		break;
+	case V4L2_PIX_FMT_H264_MVC:
+		codec = HAL_VIDEO_CODEC_MVC;
+		break;
+	case V4L2_PIX_FMT_H263:
+		codec = HAL_VIDEO_CODEC_H263;
+		break;
+	case V4L2_PIX_FMT_MPEG1:
+		codec = HAL_VIDEO_CODEC_MPEG1;
+		break;
+	case V4L2_PIX_FMT_MPEG2:
+		codec = HAL_VIDEO_CODEC_MPEG2;
+		break;
+	case V4L2_PIX_FMT_MPEG4:
+		codec = HAL_VIDEO_CODEC_MPEG4;
+		break;
+	case V4L2_PIX_FMT_VC1_ANNEX_G:
+	case V4L2_PIX_FMT_VC1_ANNEX_L:
+		codec = HAL_VIDEO_CODEC_VC1;
+		break;
+	case V4L2_PIX_FMT_VP8:
+		codec = HAL_VIDEO_CODEC_VP8;
+		break;
+	case V4L2_PIX_FMT_VP9:
+		codec = HAL_VIDEO_CODEC_VP9;
+		break;
+	case V4L2_PIX_FMT_DIVX_311:
+		codec = HAL_VIDEO_CODEC_DIVX_311;
+		break;
+	case V4L2_PIX_FMT_DIVX:
+		codec = HAL_VIDEO_CODEC_DIVX;
+		break;
+	case V4L2_PIX_FMT_HEVC:
+		codec = HAL_VIDEO_CODEC_HEVC;
+		break;
+	case V4L2_PIX_FMT_HEVC_HYBRID:
+		codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
+		codec = HAL_UNUSED_CODEC;
+		break;
+	}
+
+	return codec;
+}
+
+static enum hal_uncompressed_format get_hal_uncompressed(int fourcc)
+{
+	enum hal_uncompressed_format format = HAL_UNUSED_COLOR;
+
+	switch (fourcc) {
+	case V4L2_PIX_FMT_NV12:
+		format = HAL_COLOR_FORMAT_NV12;
+		break;
+	case V4L2_PIX_FMT_NV21:
+		format = HAL_COLOR_FORMAT_NV21;
+		break;
+	case V4L2_PIX_FMT_NV12_UBWC:
+		format = HAL_COLOR_FORMAT_NV12_UBWC;
+		break;
+	case V4L2_PIX_FMT_NV12_TP10_UBWC:
+		format = HAL_COLOR_FORMAT_NV12_TP10_UBWC;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		format = HAL_COLOR_FORMAT_RGBA8888;
+		break;
+	case V4L2_PIX_FMT_RGBA8888_UBWC:
+		format = HAL_COLOR_FORMAT_RGBA8888_UBWC;
+		break;
+	default:
+		format = HAL_UNUSED_COLOR;
+		break;
+	}
+
+	return format;
+}
+
+static int msm_comm_vote_bus(struct msm_vidc_core *core)
+{
+	int rc = 0, vote_data_count = 0, i = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_inst *inst = NULL;
+	struct vidc_bus_vote_data *vote_data = NULL;
+	unsigned long core_freq = 0;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, core);
+		return -EINVAL;
+	}
+
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s Invalid device handle: %pK\n",
+			__func__, hdev);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list)
+		++vote_data_count;
+
+	vote_data = kcalloc(vote_data_count, sizeof(*vote_data),
+			GFP_TEMPORARY);
+	if (!vote_data) {
+		dprintk(VIDC_ERR, "%s: failed to allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail_alloc;
+	}
+
+	core_freq = call_hfi_op(hdev, get_core_clock_rate,
+			hdev->hfi_device_data, 0);
+
+	list_for_each_entry(inst, &core->instances, list) {
+		int codec = 0, yuv = 0;
+		struct v4l2_control ctrl;
+
+		codec = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[OUTPUT_PORT].fourcc :
+			inst->fmts[CAPTURE_PORT].fourcc;
+
+		yuv = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[CAPTURE_PORT].fourcc :
+			inst->fmts[OUTPUT_PORT].fourcc;
+
+		vote_data[i].domain = get_hal_domain(inst->session_type);
+		vote_data[i].codec = get_hal_codec(codec);
+		vote_data[i].width =  max(inst->prop.width[CAPTURE_PORT],
+			inst->prop.width[OUTPUT_PORT]);
+		vote_data[i].height = max(inst->prop.height[CAPTURE_PORT],
+			inst->prop.height[OUTPUT_PORT]);
+
+		ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE;
+		rc = msm_comm_g_ctrl(inst, &ctrl);
+		if (!rc && ctrl.value)
+			vote_data[i].fps = (ctrl.value >> 16) ?
+				ctrl.value >> 16 : 1;
+		else
+			vote_data[i].fps = inst->prop.fps;
+
+		if (msm_comm_turbo_session(inst))
+			vote_data[i].power_mode = VIDC_POWER_TURBO;
+		else if (is_low_power_session(inst))
+			vote_data[i].power_mode = VIDC_POWER_LOW;
+		else
+			vote_data[i].power_mode = VIDC_POWER_NORMAL;
+		if (i == 0) {
+			vote_data[i].imem_ab_tbl = core->resources.imem_ab_tbl;
+			vote_data[i].imem_ab_tbl_size =
+				core->resources.imem_ab_tbl_size;
+			vote_data[i].core_freq = core_freq;
+		}
+
+		/*
+		 * TODO: support for OBP-DBP split mode hasn't been yet
+		 * implemented, once it is, this part of code needs to be
+		 * revisited since passing in accurate information to the bus
+		 * governor will drastically reduce bandwidth
+		 */
+		vote_data[i].color_formats[0] = get_hal_uncompressed(yuv);
+		vote_data[i].num_formats = 1;
+		i++;
+	}
+	mutex_unlock(&core->lock);
+
+	rc = call_hfi_op(hdev, vote_bus, hdev->hfi_device_data, vote_data,
+			vote_data_count);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to scale bus: %d\n", rc);
+
+	kfree(vote_data);
+	return rc;
+
+fail_alloc:
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+struct msm_vidc_core *get_vidc_core(int core_id)
+{
+	struct msm_vidc_core *core;
+	int found = 0;
+
+	if (core_id > MSM_VIDC_CORES_MAX) {
+		dprintk(VIDC_ERR, "Core id = %d is greater than max = %d\n",
+			core_id, MSM_VIDC_CORES_MAX);
+		return NULL;
+	}
+	mutex_lock(&vidc_driver->lock);
+	list_for_each_entry(core, &vidc_driver->cores, list) {
+		if (core->id == core_id) {
+			found = 1;
+			break;
+		}
+	}
+	mutex_unlock(&vidc_driver->lock);
+	if (found)
+		return core;
+	return NULL;
+}
+
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+	const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
+{
+	int i, k = 0;
+
+	if (!fmt || index < 0) {
+		dprintk(VIDC_ERR, "Invalid inputs, fmt = %pK, index = %d\n",
+						fmt, index);
+		return NULL;
+	}
+	for (i = 0; i < size; i++) {
+		if (fmt[i].type != fmt_type)
+			continue;
+		if (k == index)
+			break;
+		k++;
+	}
+	if (i == size) {
+		dprintk(VIDC_INFO, "Format not found\n");
+		return NULL;
+	}
+	return &fmt[i];
+}
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+	struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+{
+	int i;
+
+	if (!fmt) {
+		dprintk(VIDC_ERR, "Invalid inputs, fmt = %pK\n", fmt);
+		return NULL;
+	}
+	for (i = 0; i < size; i++) {
+		if (fmt[i].fourcc == fourcc)
+			break;
+	}
+	if (i == size) {
+		dprintk(VIDC_INFO, "Format not found\n");
+		return NULL;
+	}
+	return &fmt[i];
+}
+
+struct buf_queue *msm_comm_get_vb2q(
+		struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return &inst->bufq[CAPTURE_PORT];
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return &inst->bufq[OUTPUT_PORT];
+	return NULL;
+}
+
+static void handle_sys_init_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core;
+	struct vidc_hal_sys_init_done *sys_init_msg;
+	u32 index;
+
+	if (!IS_HAL_SYS_CMD(cmd)) {
+		dprintk(VIDC_ERR, "%s - invalid cmd\n", __func__);
+		return;
+	}
+
+	index = SYS_MSG_INDEX(cmd);
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys init\n");
+		return;
+	}
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		dprintk(VIDC_ERR, "Wrong device_id received\n");
+		return;
+	}
+	sys_init_msg = &response->data.sys_init_done;
+	if (!sys_init_msg) {
+		dprintk(VIDC_ERR, "sys_init_done message not proper\n");
+		return;
+	}
+
+	core->enc_codec_supported = sys_init_msg->enc_codec_supported;
+	core->dec_codec_supported = sys_init_msg->dec_codec_supported;
+
+	/* This should come from sys_init_done */
+	core->resources.max_inst_count =
+		sys_init_msg->max_sessions_supported ? :
+		MAX_SUPPORTED_INSTANCES;
+
+	core->resources.max_secure_inst_count =
+		core->resources.max_secure_inst_count ? :
+		core->resources.max_inst_count;
+
+	if (core->id == MSM_VIDC_CORE_VENUS &&
+		(core->dec_codec_supported & HAL_VIDEO_CODEC_H264))
+		core->dec_codec_supported |=
+		HAL_VIDEO_CODEC_MVC;
+
+	core->codec_count = sys_init_msg->codec_count;
+	memcpy(core->capabilities, sys_init_msg->capabilities,
+		sys_init_msg->codec_count * sizeof(struct msm_vidc_capability));
+
+	dprintk(VIDC_DBG,
+		"%s: supported_codecs[%d]: enc = %#x, dec = %#x\n",
+		__func__, core->codec_count, core->enc_codec_supported,
+		core->dec_codec_supported);
+
+	complete(&(core->completions[index]));
+
+}
+
+void put_inst(struct msm_vidc_inst *inst)
+{
+	void put_inst_helper(struct kref *kref)
+	{
+		struct msm_vidc_inst *inst = container_of(kref,
+				struct msm_vidc_inst, kref);
+		msm_vidc_destroy(inst);
+	}
+
+	if (!inst)
+		return;
+
+	kref_put(&inst->kref, put_inst_helper);
+}
+
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
+		void *session_id)
+{
+	struct msm_vidc_inst *inst = NULL;
+	bool matches = false;
+
+	if (!core || !session_id)
+		return NULL;
+
+	mutex_lock(&core->lock);
+	/*
+	 * This is as good as !list_empty(!inst->list), but at this point
+	 * we don't really know if inst was kfree'd via close syscall before
+	 * hardware could respond.  So manually walk thru the list of active
+	 * sessions
+	 */
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst == session_id) {
+			/*
+			 * Even if the instance is valid, we really shouldn't
+			 * be receiving or handling callbacks when we've deleted
+			 * our session with HFI
+			 */
+			matches = !!inst->session;
+			break;
+		}
+	}
+
+	/*
+	 * kref_* is atomic_int backed, so no need for inst->lock.  But we can
+	 * always acquire inst->lock and release it in put_inst for a stronger
+	 * locking system.
+	 */
+	inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL;
+	mutex_unlock(&core->lock);
+
+	return inst;
+}
+
+static void handle_session_release_buf_done(enum hal_command_response cmd,
+	void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct internal_buf *buf;
+	struct list_head *ptr, *next;
+	struct hal_buffer_info *buffer;
+	u32 buf_found = false;
+	u32 address;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid release_buf_done response\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	buffer = &response->data.buffer_info;
+	address = buffer->buffer_addr;
+
+	mutex_lock(&inst->scratchbufs.lock);
+	list_for_each_safe(ptr, next, &inst->scratchbufs.list) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		if (address == (u32)buf->handle->device_addr) {
+			dprintk(VIDC_DBG, "releasing scratch: %pa\n",
+					&buf->handle->device_addr);
+			buf_found = true;
+		}
+	}
+	mutex_unlock(&inst->scratchbufs.lock);
+
+	mutex_lock(&inst->persistbufs.lock);
+	list_for_each_safe(ptr, next, &inst->persistbufs.list) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		if (address == (u32)buf->handle->device_addr) {
+			dprintk(VIDC_DBG, "releasing persist: %pa\n",
+					&buf->handle->device_addr);
+			buf_found = true;
+		}
+	}
+	mutex_unlock(&inst->persistbufs.lock);
+
+	if (!buf_found)
+		dprintk(VIDC_ERR, "invalid buffer received from firmware");
+	if (IS_HAL_SESSION_CMD(cmd))
+		complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+	else
+		dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+
+	put_inst(inst);
+}
+
+static void handle_sys_release_res_done(
+		enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys init\n");
+		return;
+	}
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		dprintk(VIDC_ERR, "Wrong device_id received\n");
+		return;
+	}
+	complete(&core->completions[
+			SYS_MSG_INDEX(HAL_SYS_RELEASE_RESOURCE_DONE)]);
+}
+
+static void change_inst_state(struct msm_vidc_inst *inst,
+	enum instance_state state)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid parameter %s\n", __func__);
+		return;
+	}
+	mutex_lock(&inst->lock);
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_DBG,
+			"Inst: %pK is in bad state can't change state to %d\n",
+			inst, state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG, "Moved inst: %pK from state: %d to state: %d\n",
+		   inst, inst->state, state);
+	inst->state = state;
+exit:
+	mutex_unlock(&inst->lock);
+}
+
+static int signal_session_msg_receipt(enum hal_command_response cmd,
+		struct msm_vidc_inst *inst)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid(%pK) instance id\n", inst);
+		return -EINVAL;
+	}
+	if (IS_HAL_SESSION_CMD(cmd)) {
+		complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+	} else {
+		dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
+	enum hal_command_response cmd)
+{
+	int rc = 0;
+
+	if (!IS_HAL_SESSION_CMD(cmd)) {
+		dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd);
+		return -EINVAL;
+	}
+	rc = wait_for_completion_timeout(
+		&inst->completions[SESSION_MSG_INDEX(cmd)],
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR, "Wait interrupted or timed out: %d\n",
+				SESSION_MSG_INDEX(cmd));
+		msm_comm_kill_session(inst);
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -EIO;
+	} else {
+		rc = 0;
+	}
+	return rc;
+}
+
+static int wait_for_state(struct msm_vidc_inst *inst,
+	enum instance_state flipped_state,
+	enum instance_state desired_state,
+	enum hal_command_response hal_cmd)
+{
+	int rc = 0;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
+		dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto err_same_state;
+	}
+	dprintk(VIDC_DBG, "Waiting for hal_cmd: %d\n", hal_cmd);
+	rc = wait_for_sess_signal_receipt(inst, hal_cmd);
+	if (!rc)
+		change_inst_state(inst, desired_state);
+err_same_state:
+	return rc;
+}
+
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type)
+{
+	struct v4l2_event event = {.id = 0, .type = event_type};
+
+	v4l2_event_queue_fh(&inst->event_handler, &event);
+}
+
+static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst)
+{
+	enum hal_command_response cmd = HAL_SESSION_ERROR;
+	struct msm_vidc_cb_cmd_done response = {0};
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+	dprintk(VIDC_ERR, "%s: Too many clients\n", __func__);
+	response.session_id = inst;
+	response.status = VIDC_ERR_MAX_CLIENTS;
+	handle_session_error(cmd, (void *)&response);
+}
+
+static void print_cap(const char *type,
+		struct hal_capability_supported *cap)
+{
+	dprintk(VIDC_DBG,
+		"%-24s: %-8d %-8d %-8d\n",
+		type, cap->min, cap->max, cap->step_size);
+}
+
+static void handle_session_init_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst = NULL;
+	struct vidc_hal_session_init_done *session_init_done = NULL;
+	struct msm_vidc_capability *capability = NULL;
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+	u32 i, codec;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+				"Failed to get valid response for session init\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+		response->session_id);
+
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	if (response->status) {
+		dprintk(VIDC_ERR,
+			"Session init response from FW : %#x\n",
+			response->status);
+		if (response->status == VIDC_ERR_MAX_CLIENTS)
+			msm_comm_generate_max_clients_error(inst);
+		else
+			msm_comm_generate_session_error(inst);
+
+		signal_session_msg_receipt(cmd, inst);
+		put_inst(inst);
+		return;
+	}
+
+	core = inst->core;
+	hdev = inst->core->device;
+	codec = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[OUTPUT_PORT].fourcc :
+			inst->fmts[CAPTURE_PORT].fourcc;
+
+	/* check if capabilities are available for this session */
+	for (i = 0; i < VIDC_MAX_SESSIONS; i++) {
+		if (core->capabilities[i].codec ==
+				get_hal_codec(codec) &&
+			core->capabilities[i].domain ==
+				get_hal_domain(inst->session_type)) {
+			capability = &core->capabilities[i];
+			break;
+		}
+	}
+
+	if (capability) {
+		dprintk(VIDC_DBG,
+			"%s: capabilities available for codec 0x%x, domain %#x\n",
+			__func__, capability->codec, capability->domain);
+		memcpy(&inst->capability, capability,
+			sizeof(struct msm_vidc_capability));
+	} else {
+		session_init_done = (struct vidc_hal_session_init_done *)
+				&response->data.session_init_done;
+		if (!session_init_done) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to get valid response for session init\n",
+				__func__);
+			return;
+		}
+		capability = &session_init_done->capability;
+		dprintk(VIDC_DBG,
+			"%s: got capabilities for codec 0x%x, domain 0x%x\n",
+			__func__, capability->codec,
+			capability->domain);
+		memcpy(&inst->capability, capability,
+			sizeof(struct msm_vidc_capability));
+	}
+	inst->capability.pixelprocess_capabilities =
+		call_hfi_op(hdev, get_core_capabilities, hdev->hfi_device_data);
+
+	dprintk(VIDC_DBG,
+		"Capability type : min      max      step size\n");
+	print_cap("width", &inst->capability.width);
+	print_cap("height", &inst->capability.height);
+	print_cap("mbs_per_frame", &inst->capability.mbs_per_frame);
+	print_cap("frame_rate", &inst->capability.frame_rate);
+	print_cap("scale_x", &inst->capability.scale_x);
+	print_cap("scale_y", &inst->capability.scale_y);
+	print_cap("hier_p", &inst->capability.hier_p);
+	print_cap("ltr_count", &inst->capability.ltr_count);
+	print_cap("mbs_per_sec_low_power",
+		&inst->capability.mbs_per_sec_power_save);
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+static void handle_event_change(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_inst *inst = NULL;
+	struct msm_vidc_cb_event *event_notify = data;
+	int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+	struct v4l2_event seq_changed_event = {0};
+	int rc = 0;
+	struct hfi_device *hdev;
+	u32 *ptr = NULL;
+
+	if (!event_notify) {
+		dprintk(VIDC_WARN, "Got an empty event from hfi\n");
+		goto err_bad_event;
+	}
+
+	inst = get_inst(get_vidc_core(event_notify->device_id),
+			event_notify->session_id);
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		goto err_bad_event;
+	}
+	hdev = inst->core->device;
+
+	switch (event_notify->hal_event_type) {
+	case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+
+		rc = msm_comm_g_ctrl_for_id(inst,
+			V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER);
+
+		if (!IS_ERR_VALUE((unsigned long)rc) && rc == true) {
+			event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+
+			if (msm_comm_get_stream_output_mode(inst) ==
+				HAL_VIDEO_DECODER_SECONDARY) {
+				struct hal_frame_size frame_sz;
+
+				frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
+				frame_sz.width = event_notify->width;
+				frame_sz.height = event_notify->height;
+				dprintk(VIDC_DBG,
+					"Update OPB dimensions to firmware if buffer requirements are sufficient\n");
+				rc = msm_comm_try_set_prop(inst,
+					HAL_PARAM_FRAME_SIZE, &frame_sz);
+			}
+
+			dprintk(VIDC_DBG,
+				"send session_continue after sufficient event\n");
+			rc = call_hfi_op(hdev, session_continue,
+					(void *) inst->session);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s - failed to send session_continue\n",
+					__func__);
+				goto err_bad_event;
+			}
+		}
+		break;
+	case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		break;
+	case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
+	{
+		struct v4l2_event buf_event = {0};
+		struct buffer_info *binfo = NULL, *temp = NULL;
+		u32 *ptr = NULL;
+
+		dprintk(VIDC_DBG, "%s - inst: %pK buffer: %pa extra: %pa\n",
+				__func__, inst, &event_notify->packet_buffer,
+				&event_notify->extra_data_buffer);
+
+		if (inst->state == MSM_VIDC_CORE_INVALID ||
+				inst->core->state == VIDC_CORE_INVALID) {
+			dprintk(VIDC_DBG,
+					"Event release buf ref received in invalid state - discard\n");
+			goto err_bad_event;
+		}
+
+		/*
+		 * Get the buffer_info entry for the
+		 * device address.
+		 */
+		binfo = device_to_uvaddr(&inst->registeredbufs,
+				event_notify->packet_buffer);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+					"%s buffer not found in registered list\n",
+					__func__);
+			goto err_bad_event;
+		}
+
+		/* Fill event data to be sent to client*/
+		buf_event.type = V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
+		ptr = (u32 *)buf_event.u.data;
+		ptr[0] = binfo->fd[0];
+		ptr[1] = binfo->buff_off[0];
+
+		dprintk(VIDC_DBG,
+				"RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
+				ptr[0], ptr[1]);
+
+		/* Decrement buffer reference count*/
+		mutex_lock(&inst->registeredbufs.lock);
+		list_for_each_entry(temp, &inst->registeredbufs.list,
+				list) {
+			if (temp == binfo) {
+				buf_ref_put(inst, binfo);
+				break;
+			}
+		}
+
+		/*
+		 * Release buffer and remove from list
+		 * if reference goes to zero.
+		 */
+		if (unmap_and_deregister_buf(inst, binfo))
+			dprintk(VIDC_ERR,
+					"%s: buffer unmap failed\n", __func__);
+		mutex_unlock(&inst->registeredbufs.lock);
+
+		/*send event to client*/
+		v4l2_event_queue_fh(&inst->event_handler, &buf_event);
+		goto err_bad_event;
+	}
+	default:
+		break;
+	}
+
+	/* Bit depth and pic struct changed event are combined into a single
+	 * event (insufficient event) for the userspace. Currently bitdepth
+	 * changes is only for HEVC and interlaced support is for all
+	 * codecs except HEVC
+	 * event data is now as follows:
+	 * u32 *ptr = seq_changed_event.u.data;
+	 * ptr[0] = height
+	 * ptr[1] = width
+	 * ptr[2] = flag to indicate bit depth or/and pic struct changed
+	 * ptr[3] = bit depth
+	 * ptr[4] = pic struct (progressive or interlaced)
+	 * ptr[5] = colour space
+	 */
+
+	ptr = (u32 *)seq_changed_event.u.data;
+	ptr[2] = 0x0;
+	ptr[3] = inst->bit_depth;
+	ptr[4] = inst->pic_struct;
+	ptr[5] = inst->colour_space;
+
+	if (inst->bit_depth != event_notify->bit_depth) {
+		inst->bit_depth = event_notify->bit_depth;
+		ptr[2] |= V4L2_EVENT_BITDEPTH_FLAG;
+		ptr[3] = inst->bit_depth;
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to bit-depth change\n");
+	}
+
+	if (inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_NV12 &&
+		event_notify->pic_struct != MSM_VIDC_PIC_STRUCT_UNKNOWN &&
+		inst->pic_struct != event_notify->pic_struct) {
+		inst->pic_struct = event_notify->pic_struct;
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		ptr[2] |= V4L2_EVENT_PICSTRUCT_FLAG;
+		ptr[4] = inst->pic_struct;
+		dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to pic-struct change\n");
+	}
+
+	if (inst->bit_depth == MSM_VIDC_BIT_DEPTH_10
+		&& inst->colour_space !=
+		event_notify->colour_space) {
+		inst->colour_space = event_notify->colour_space;
+		event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+		ptr[2] |= V4L2_EVENT_COLOUR_SPACE_FLAG;
+		ptr[5] = inst->colour_space;
+		dprintk(VIDC_DBG,
+				"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to colour space change\n");
+	}
+
+	if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+		dprintk(VIDC_DBG, "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n");
+		inst->reconfig_height = event_notify->height;
+		inst->reconfig_width = event_notify->width;
+		inst->in_reconfig = true;
+	} else {
+		dprintk(VIDC_DBG, "V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
+		dprintk(VIDC_DBG,
+			"event_notify->height = %d event_notify->width = %d\n",
+			event_notify->height,
+			event_notify->width);
+		inst->prop.height[OUTPUT_PORT] = event_notify->height;
+		inst->prop.width[OUTPUT_PORT] = event_notify->width;
+	}
+
+	inst->seqchanged_count++;
+
+	if (inst->session_type == MSM_VIDC_DECODER)
+		msm_dcvs_init_load(inst);
+
+	rc = msm_vidc_check_session_supported(inst);
+	if (!rc) {
+		seq_changed_event.type = event;
+		if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+			u32 *ptr = NULL;
+
+			ptr = (u32 *)seq_changed_event.u.data;
+			ptr[0] = event_notify->height;
+			ptr[1] = event_notify->width;
+		}
+		v4l2_event_queue_fh(&inst->event_handler, &seq_changed_event);
+	} else if (rc == -ENOTSUPP) {
+		msm_vidc_queue_v4l2_event(inst,
+				V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED);
+	} else if (rc == -EBUSY) {
+		msm_vidc_queue_v4l2_event(inst,
+				V4L2_EVENT_MSM_VIDC_HW_OVERLOAD);
+	}
+
+err_bad_event:
+	put_inst(inst);
+}
+
+static void handle_session_prop_info(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct getprop_buf *getprop;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for prop info\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	getprop = kzalloc(sizeof(*getprop), GFP_KERNEL);
+	if (!getprop) {
+		dprintk(VIDC_ERR, "%s: getprop kzalloc failed\n", __func__);
+		goto err_prop_info;
+	}
+
+	getprop->data = kmemdup(&response->data.property,
+			sizeof(union hal_get_property), GFP_KERNEL);
+	if (!getprop->data) {
+		dprintk(VIDC_ERR, "%s: kmemdup failed\n", __func__);
+		kfree(getprop);
+		goto err_prop_info;
+	}
+
+	mutex_lock(&inst->pending_getpropq.lock);
+	list_add_tail(&getprop->list, &inst->pending_getpropq.list);
+	mutex_unlock(&inst->pending_getpropq.lock);
+
+	signal_session_msg_receipt(cmd, inst);
+err_prop_info:
+	put_inst(inst);
+}
+
+static void handle_load_resource_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for load resource\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	if (response->status) {
+		dprintk(VIDC_ERR,
+				"Load resource response from FW : %#x\n",
+				response->status);
+		msm_comm_generate_session_error(inst);
+	}
+
+	put_inst(inst);
+}
+
+static void handle_start_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Failed to get valid response for start\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+static void handle_stop_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Failed to get valid response for stop\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+static void handle_release_res_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for release resource\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	put_inst(inst);
+}
+
+void validate_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct internal_buf *binfo;
+	u32 buffers_owned_by_driver = 0;
+	struct hal_buffer_requirements *output_buf;
+
+	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_OUTPUT);
+		return;
+	}
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+		if (binfo->buffer_ownership != DRIVER) {
+			dprintk(VIDC_DBG,
+				"This buffer is with FW %pa\n",
+				&binfo->handle->device_addr);
+			continue;
+		}
+		buffers_owned_by_driver++;
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	if (buffers_owned_by_driver != output_buf->buffer_count_actual)
+		dprintk(VIDC_WARN,
+			"OUTPUT Buffer count mismatch %d of %d\n",
+			buffers_owned_by_driver,
+			output_buf->buffer_count_actual);
+
+}
+
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct internal_buf *binfo;
+	struct hfi_device *hdev;
+	struct msm_smem *handle;
+	struct vidc_frame_data frame_data = {0};
+	struct hal_buffer_requirements *output_buf, *extra_buf;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			HAL_BUFFER_OUTPUT);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"output: num = %d, size = %d\n",
+		output_buf->buffer_count_actual,
+		output_buf->buffer_size);
+
+	extra_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+		if (binfo->buffer_ownership != DRIVER)
+			continue;
+		handle = binfo->handle;
+		frame_data.alloc_len = output_buf->buffer_size;
+		frame_data.filled_len = 0;
+		frame_data.offset = 0;
+		frame_data.device_addr = handle->device_addr;
+		frame_data.flags = 0;
+		frame_data.extradata_addr = handle->device_addr +
+		output_buf->buffer_size;
+		frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+		frame_data.extradata_size = extra_buf ?
+			extra_buf->buffer_size : 0;
+		rc = call_hfi_op(hdev, session_ftb,
+			(void *) inst->session, &frame_data);
+		binfo->buffer_ownership = FIRMWARE;
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	return 0;
+}
+
+static void handle_session_flush(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct v4l2_event flush_event = {0};
+	u32 *ptr = NULL;
+	enum hal_flush flush_type;
+	int rc;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Failed to get valid response for flush\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	if (msm_comm_get_stream_output_mode(inst) ==
+			HAL_VIDEO_DECODER_SECONDARY) {
+		validate_output_buffers(inst);
+		if (!inst->in_reconfig) {
+			rc = msm_comm_queue_output_buffers(inst);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed to queue output buffers: %d\n",
+						rc);
+			}
+		}
+	}
+	atomic_dec(&inst->in_flush);
+	flush_event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+	ptr = (u32 *)flush_event.u.data;
+
+	flush_type = response->data.flush_type;
+	switch (flush_type) {
+	case HAL_FLUSH_INPUT:
+		ptr[0] = V4L2_QCOM_CMD_FLUSH_OUTPUT;
+		break;
+	case HAL_FLUSH_OUTPUT:
+		ptr[0] = V4L2_QCOM_CMD_FLUSH_CAPTURE;
+		break;
+	case HAL_FLUSH_ALL:
+		ptr[0] |= V4L2_QCOM_CMD_FLUSH_CAPTURE;
+		ptr[0] |= V4L2_QCOM_CMD_FLUSH_OUTPUT;
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid flush type received!");
+		goto exit;
+	}
+
+	dprintk(VIDC_DBG,
+		"Notify flush complete, flush_type: %x\n", flush_type);
+	v4l2_event_queue_fh(&inst->event_handler, &flush_event);
+
+exit:
+	put_inst(inst);
+}
+
+static void handle_session_error(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct hfi_device *hdev = NULL;
+	struct msm_vidc_inst *inst = NULL;
+	int event = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for session error\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	hdev = inst->core->device;
+	dprintk(VIDC_WARN, "Session error received for session %pK\n", inst);
+	change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+
+	if (response->status == VIDC_ERR_MAX_CLIENTS) {
+		dprintk(VIDC_WARN, "Too many clients, rejecting %pK", inst);
+		event = V4L2_EVENT_MSM_VIDC_MAX_CLIENTS;
+
+		/*
+		 * Clean the HFI session now. Since inst->state is moved to
+		 * INVALID, forward thread doesn't know FW has valid session
+		 * or not. This is the last place driver knows that there is
+		 * no session in FW. Hence clean HFI session now.
+		 */
+
+		msm_comm_session_clean(inst);
+	} else if (response->status == VIDC_ERR_NOT_SUPPORTED) {
+		dprintk(VIDC_WARN, "Unsupported bitstream in %pK", inst);
+		event = V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED;
+	} else {
+		dprintk(VIDC_WARN, "Unknown session error (%d) for %pK\n",
+				response->status, inst);
+		event = V4L2_EVENT_MSM_VIDC_SYS_ERROR;
+	}
+
+	msm_vidc_queue_v4l2_event(inst, event);
+	put_inst(inst);
+}
+
+static void msm_comm_clean_notify_client(struct msm_vidc_core *core)
+{
+	struct msm_vidc_inst *inst = NULL;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+		return;
+	}
+
+	dprintk(VIDC_WARN, "%s: Core %pK\n", __func__, core);
+	mutex_lock(&core->lock);
+	core->state = VIDC_CORE_INVALID;
+
+	list_for_each_entry(inst, &core->instances, list) {
+		mutex_lock(&inst->lock);
+		inst->state = MSM_VIDC_CORE_INVALID;
+		mutex_unlock(&inst->lock);
+		dprintk(VIDC_WARN,
+			"%s Send sys error for inst %pK\n", __func__, inst);
+		msm_vidc_queue_v4l2_event(inst,
+				V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+	}
+	mutex_unlock(&core->lock);
+}
+
+static void handle_sys_error(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_core *core = NULL;
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	subsystem_crashed("venus");
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for sys error\n");
+		return;
+	}
+
+	core = get_vidc_core(response->device_id);
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Got SYS_ERR but unable to identify core\n");
+		return;
+	}
+
+	dprintk(VIDC_WARN, "SYS_ERROR %d received for core %pK\n", cmd, core);
+	msm_comm_clean_notify_client(core);
+
+	hdev = core->device;
+	mutex_lock(&core->lock);
+	if (core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_DBG, "Calling core_release\n");
+		rc = call_hfi_op(hdev, core_release,
+						 hdev->hfi_device_data);
+		if (rc) {
+			dprintk(VIDC_ERR, "core_release failed\n");
+			mutex_unlock(&core->lock);
+			return;
+		}
+		core->state = VIDC_CORE_UNINIT;
+	}
+	mutex_unlock(&core->lock);
+}
+
+void msm_comm_session_clean(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev = NULL;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return;
+	}
+
+	hdev = inst->core->device;
+	mutex_lock(&inst->lock);
+	if (hdev && inst->session) {
+		dprintk(VIDC_DBG, "cleaning up instance: %pK\n", inst);
+		rc = call_hfi_op(hdev, session_clean,
+				(void *)inst->session);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Session clean failed :%pK\n", inst);
+		}
+		inst->session = NULL;
+	}
+	mutex_unlock(&inst->lock);
+}
+
+static void handle_session_close(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_cmd_done *response = data;
+	struct msm_vidc_inst *inst;
+
+	if (!response) {
+		dprintk(VIDC_ERR,
+			"Failed to get valid response for session close\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	signal_session_msg_receipt(cmd, inst);
+	show_stats(inst);
+	put_inst(inst);
+}
+
+static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq,
+		unsigned long dev_addr)
+{
+	struct vb2_buffer *vb = NULL;
+	struct vb2_queue *q = NULL;
+	int found = 0;
+
+	if (!bufq) {
+		dprintk(VIDC_ERR, "Invalid parameter\n");
+		return NULL;
+	}
+	q = &bufq->vb2_bufq;
+	mutex_lock(&bufq->lock);
+	list_for_each_entry(vb, &q->queued_list, queued_entry) {
+		if (vb->planes[0].m.userptr == dev_addr &&
+			vb->state == VB2_BUF_STATE_ACTIVE) {
+			found = 1;
+			dprintk(VIDC_DBG, "Found v4l2_buf index : %d\n",
+					vb->index);
+			break;
+		}
+	}
+	mutex_unlock(&bufq->lock);
+	if (!found) {
+		dprintk(VIDC_DBG,
+			"Failed to find buffer in queued list: %#lx, qtype = %d\n",
+			dev_addr, q->type);
+		vb = NULL;
+	}
+	return vb;
+}
+
+static void handle_ebd(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct vb2_buffer *vb;
+	struct msm_vidc_inst *inst;
+	struct vidc_hal_ebd *empty_buf_done;
+	struct vb2_v4l2_buffer *vbuf = NULL;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	vb = get_vb_from_device_addr(&inst->bufq[OUTPUT_PORT],
+			response->input_done.packet_buffer);
+	if (vb) {
+		vbuf = to_vb2_v4l2_buffer(vb);
+		vb->planes[0].bytesused = response->input_done.filled_len;
+		vb->planes[0].data_offset = response->input_done.offset;
+		if (vb->planes[0].data_offset > vb->planes[0].length)
+			dprintk(VIDC_INFO, "data_offset overflow length\n");
+		if (vb->planes[0].bytesused > vb->planes[0].length)
+			dprintk(VIDC_INFO, "bytesused overflow length\n");
+		if (vb->planes[0].m.userptr !=
+			response->clnt_data)
+			dprintk(VIDC_INFO, "Client data != bufaddr\n");
+		empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
+		if (empty_buf_done) {
+			if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) {
+				dprintk(VIDC_INFO,
+					"Failed : Unsupported input stream\n");
+				vbuf->flags |=
+					V4L2_QCOM_BUF_INPUT_UNSUPPORTED;
+			}
+			if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) {
+				dprintk(VIDC_INFO,
+					"Failed : Corrupted input stream\n");
+				vbuf->flags |=
+					V4L2_QCOM_BUF_DATA_CORRUPT;
+			}
+			if (empty_buf_done->status ==
+				VIDC_ERR_START_CODE_NOT_FOUND) {
+				vbuf->flags |=
+					V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND;
+				dprintk(VIDC_INFO,
+					"Failed: Start code not found\n");
+			}
+			if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME)
+				vbuf->flags |=
+					V4L2_QCOM_BUF_FLAG_IDRFRAME |
+					V4L2_BUF_FLAG_KEYFRAME;
+		}
+		dprintk(VIDC_DBG,
+			"Got ebd from hal: device_addr: %pa, alloc: %d, status: %#x, pic_type: %#x, flags: %#x\n",
+			&empty_buf_done->packet_buffer,
+			empty_buf_done->alloc_len, empty_buf_done->status,
+			empty_buf_done->picture_type, empty_buf_done->flags);
+
+		mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD);
+	}
+
+	put_inst(inst);
+}
+
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+	int cnt = 0;
+
+	if (!inst || !binfo)
+		return -EINVAL;
+
+	atomic_inc(&binfo->ref_count);
+	cnt = atomic_read(&binfo->ref_count);
+	if (cnt > 2) {
+		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+		cnt = -EINVAL;
+	}
+	if (cnt == 2)
+		inst->buffers_held_in_driver++;
+
+	dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+
+	return cnt;
+}
+
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+	int rc = 0;
+	int cnt;
+	bool release_buf = false;
+	bool qbuf_again = false;
+
+	if (!inst || !binfo)
+		return -EINVAL;
+
+	atomic_dec(&binfo->ref_count);
+	cnt = atomic_read(&binfo->ref_count);
+	dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+	if (!cnt)
+		release_buf = true;
+	else if (cnt == 1)
+		qbuf_again = true;
+	else {
+		dprintk(VIDC_DBG, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+		cnt = -EINVAL;
+	}
+
+	if (cnt < 0)
+		return cnt;
+
+	if (release_buf) {
+		/*
+		 * We can not delete binfo here as we need to set the user
+		 * virtual address saved in binfo->uvaddr to the dequeued v4l2
+		 * buffer.
+		 *
+		 * We will set the pending_deletion flag to true here and delete
+		 * binfo from registered list in dqbuf after setting the uvaddr.
+		 */
+		dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n",
+			binfo->fd[0]);
+		binfo->pending_deletion = true;
+	} else if (qbuf_again) {
+		inst->buffers_held_in_driver--;
+		rc = qbuf_dynamic_buf(inst, binfo);
+		if (!rc)
+			return rc;
+	}
+	return cnt;
+}
+
+static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
+		ion_phys_addr_t device_addr, u32 flags)
+{
+	struct buffer_info *binfo = NULL, *temp = NULL;
+
+	/*
+	 * Update reference count and release OR queue back the buffer,
+	 * only when firmware is not holding a reference.
+	 */
+	if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+		binfo = device_to_uvaddr(&inst->registeredbufs, device_addr);
+		if (!binfo) {
+			dprintk(VIDC_ERR,
+				"%s buffer not found in registered list\n",
+				__func__);
+			return;
+		}
+		if (flags & HAL_BUFFERFLAG_READONLY) {
+			dprintk(VIDC_DBG,
+				"FBD fd[0] = %d -> Reference with f/w, addr: %pa\n",
+				binfo->fd[0], &device_addr);
+		} else {
+			dprintk(VIDC_DBG,
+				"FBD fd[0] = %d -> FBD_ref_released, addr: %pa\n",
+				binfo->fd[0], &device_addr);
+
+			mutex_lock(&inst->registeredbufs.lock);
+			list_for_each_entry(temp, &inst->registeredbufs.list,
+							list) {
+				if (temp == binfo) {
+					buf_ref_put(inst, binfo);
+					break;
+				}
+			}
+			mutex_unlock(&inst->registeredbufs.lock);
+		}
+	}
+}
+
+static int handle_multi_stream_buffers(struct msm_vidc_inst *inst,
+		ion_phys_addr_t dev_addr)
+{
+	struct internal_buf *binfo;
+	struct msm_smem *handle;
+	bool found = false;
+
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry(binfo, &inst->outputbufs.list, list) {
+		handle = binfo->handle;
+		if (handle && dev_addr == handle->device_addr) {
+			if (binfo->buffer_ownership == DRIVER) {
+				dprintk(VIDC_ERR,
+					"FW returned same buffer: %pa\n",
+					&dev_addr);
+				break;
+			}
+			binfo->buffer_ownership = DRIVER;
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	if (!found) {
+		dprintk(VIDC_ERR,
+			"Failed to find output buffer in queued list: %pa\n",
+			&dev_addr);
+	}
+
+	return 0;
+}
+
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst)
+{
+	if (msm_comm_get_stream_output_mode(inst) ==
+		HAL_VIDEO_DECODER_SECONDARY)
+		return HAL_BUFFER_OUTPUT2;
+	else
+		return HAL_BUFFER_OUTPUT;
+}
+
+static void handle_fbd(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct vb2_buffer *vb = NULL;
+	struct vidc_hal_fbd *fill_buf_done;
+	enum hal_buffer buffer_type;
+	int extra_idx = 0;
+	int64_t time_usec = 0;
+	static int first_enc_frame = 1;
+	struct vb2_v4l2_buffer *vbuf = NULL;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	buffer_type = msm_comm_get_hal_output_buffer(inst);
+	if (fill_buf_done->buffer_type == buffer_type) {
+		vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+				fill_buf_done->packet_buffer1);
+	} else {
+		if (handle_multi_stream_buffers(inst,
+				fill_buf_done->packet_buffer1))
+			dprintk(VIDC_ERR,
+				"Failed : Output buffer not found %pa\n",
+				&fill_buf_done->packet_buffer1);
+		goto err_handle_fbd;
+	}
+
+	if (vb) {
+		vbuf = to_vb2_v4l2_buffer(vb);
+		vb->planes[0].bytesused = fill_buf_done->filled_len1;
+		vb->planes[0].data_offset = fill_buf_done->offset1;
+		if (vb->planes[0].data_offset > vb->planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow data_offset = %d; length = %d\n",
+				vb->planes[0].data_offset,
+				vb->planes[0].length);
+		if (vb->planes[0].bytesused > vb->planes[0].length)
+			dprintk(VIDC_INFO,
+				"fbd:Overflow bytesused = %d; length = %d\n",
+				vb->planes[0].bytesused,
+				vb->planes[0].length);
+		if (!(fill_buf_done->flags1 &
+			HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
+			time_usec = fill_buf_done->timestamp_hi;
+			time_usec = (time_usec << 32) |
+				fill_buf_done->timestamp_lo;
+		} else {
+			time_usec = 0;
+			dprintk(VIDC_DBG,
+					"Set zero timestamp for buffer %pa, filled: %d, (hi:%u, lo:%u)\n",
+					&fill_buf_done->packet_buffer1,
+					fill_buf_done->filled_len1,
+					fill_buf_done->timestamp_hi,
+					fill_buf_done->timestamp_lo);
+		}
+		vb->timestamp = (time_usec * NSEC_PER_USEC);
+		vbuf->flags = 0;
+		extra_idx =
+			EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			vb->planes[extra_idx].m.userptr =
+				(unsigned long)fill_buf_done->extra_data_buffer;
+			vb->planes[extra_idx].bytesused =
+				vb->planes[extra_idx].length;
+			vb->planes[extra_idx].data_offset = 0;
+		}
+
+		handle_dynamic_buffer(inst, fill_buf_done->packet_buffer1,
+					fill_buf_done->flags1);
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_READONLY;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOS;
+		/* if (fill_buf_done->flags1 & HAL_BUFFERFLAG_ENDOFFRAME)
+		 * vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_ENDOFFRAME;
+		 */
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
+			vbuf->flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT)
+			vbuf->flags |= V4L2_QCOM_BUF_DATA_CORRUPT;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME)
+			vbuf->flags |= V4L2_QCOM_BUF_DROP_FRAME;
+		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_MBAFF)
+			vbuf->flags |= V4L2_MSM_BUF_FLAG_MBAFF;
+
+		switch (fill_buf_done->picture_type) {
+		case HAL_PICTURE_IDR:
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+			vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+			break;
+		case HAL_PICTURE_I:
+			vbuf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+			break;
+		case HAL_PICTURE_P:
+			vbuf->flags |= V4L2_BUF_FLAG_PFRAME;
+			break;
+		case HAL_PICTURE_B:
+			vbuf->flags |= V4L2_BUF_FLAG_BFRAME;
+			break;
+		case HAL_FRAME_NOTCODED:
+		case HAL_UNUSED_PICT:
+			/* Do we need to care about these? */
+		case HAL_FRAME_YUV:
+			break;
+		default:
+			break;
+		}
+
+		inst->count.fbd++;
+
+		if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
+			dprintk(VIDC_DBG,
+				"extradata: userptr = %pK;"
+				" bytesused = %d; length = %d\n",
+				(u8 *)vb->planes[extra_idx].m.userptr,
+				vb->planes[extra_idx].bytesused,
+				vb->planes[extra_idx].length);
+		}
+		if (first_enc_frame == 1) {
+			boot_stats_init();
+			pr_debug("KPI: First Encoded frame received\n");
+			first_enc_frame++;
+		}
+		dprintk(VIDC_DBG,
+		"Got fbd from hal: device_addr: %pa, alloc: %d, filled: %d, offset: %d, ts: %lld, flags: %#x, crop: %d %d %d %d, pic_type: %#x, mark_data: %#x\n",
+		&fill_buf_done->packet_buffer1, fill_buf_done->alloc_len1,
+		fill_buf_done->filled_len1, fill_buf_done->offset1, time_usec,
+		fill_buf_done->flags1, fill_buf_done->start_x_coord,
+		fill_buf_done->start_y_coord, fill_buf_done->frame_width,
+		fill_buf_done->frame_height, fill_buf_done->picture_type,
+		fill_buf_done->mark_data);
+
+		mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
+		vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FBD);
+	}
+
+err_handle_fbd:
+	put_inst(inst);
+}
+
+static void handle_seq_hdr_done(enum hal_command_response cmd, void *data)
+{
+	struct msm_vidc_cb_data_done *response = data;
+	struct msm_vidc_inst *inst;
+	struct vb2_buffer *vb;
+	struct vidc_hal_fbd *fill_buf_done;
+	struct vb2_v4l2_buffer *vbuf;
+
+	if (!response) {
+		dprintk(VIDC_ERR, "Invalid response from vidc_hal\n");
+		return;
+	}
+
+	inst = get_inst(get_vidc_core(response->device_id),
+			response->session_id);
+	if (!inst) {
+		dprintk(VIDC_WARN, "Got a response for an inactive session\n");
+		return;
+	}
+
+	fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+	vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
+				fill_buf_done->packet_buffer1);
+	if (!vb) {
+		dprintk(VIDC_ERR,
+				"Failed to find video buffer for seq_hdr_done: %pa\n",
+				&fill_buf_done->packet_buffer1);
+		goto err_seq_hdr_done;
+	}
+	vbuf = to_vb2_v4l2_buffer(vb);
+	vb->planes[0].bytesused = fill_buf_done->filled_len1;
+	vb->planes[0].data_offset = fill_buf_done->offset1;
+
+	vbuf->flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+	vb->timestamp = 0;
+
+	dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
+				vb->planes[0].bytesused,
+				vb->planes[0].data_offset,
+				vbuf->flags);
+	mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
+	vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+	mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
+
+err_seq_hdr_done:
+	put_inst(inst);
+}
+
+void handle_cmd_response(enum hal_command_response cmd, void *data)
+{
+	dprintk(VIDC_DBG, "Command response = %d\n", cmd);
+	switch (cmd) {
+	case HAL_SYS_INIT_DONE:
+		handle_sys_init_done(cmd, data);
+		break;
+	case HAL_SYS_RELEASE_RESOURCE_DONE:
+		handle_sys_release_res_done(cmd, data);
+		break;
+	case HAL_SESSION_INIT_DONE:
+		handle_session_init_done(cmd, data);
+		break;
+	case HAL_SESSION_PROPERTY_INFO:
+		handle_session_prop_info(cmd, data);
+		break;
+	case HAL_SESSION_LOAD_RESOURCE_DONE:
+		handle_load_resource_done(cmd, data);
+		break;
+	case HAL_SESSION_START_DONE:
+		handle_start_done(cmd, data);
+		break;
+	case HAL_SESSION_ETB_DONE:
+		handle_ebd(cmd, data);
+		break;
+	case HAL_SESSION_FTB_DONE:
+		handle_fbd(cmd, data);
+		break;
+	case HAL_SESSION_STOP_DONE:
+		handle_stop_done(cmd, data);
+		break;
+	case HAL_SESSION_RELEASE_RESOURCE_DONE:
+		handle_release_res_done(cmd, data);
+		break;
+	case HAL_SESSION_END_DONE:
+	case HAL_SESSION_ABORT_DONE:
+		handle_session_close(cmd, data);
+		break;
+	case HAL_SESSION_EVENT_CHANGE:
+		handle_event_change(cmd, data);
+		break;
+	case HAL_SESSION_FLUSH_DONE:
+		handle_session_flush(cmd, data);
+		break;
+	case HAL_SESSION_GET_SEQ_HDR_DONE:
+		handle_seq_hdr_done(cmd, data);
+		break;
+	case HAL_SYS_WATCHDOG_TIMEOUT:
+	case HAL_SYS_ERROR:
+		handle_sys_error(cmd, data);
+		break;
+	case HAL_SESSION_ERROR:
+		handle_session_error(cmd, data);
+		break;
+	case HAL_SESSION_RELEASE_BUFFER_DONE:
+		handle_session_release_buf_done(cmd, data);
+		break;
+	default:
+		dprintk(VIDC_DBG, "response unhandled: %d\n", cmd);
+		break;
+	}
+}
+
+int msm_comm_scale_clocks(struct msm_vidc_core *core)
+{
+	int num_mbs_per_sec =
+		msm_comm_get_load(core, MSM_VIDC_ENCODER, LOAD_CALC_NO_QUIRKS) +
+		msm_comm_get_load(core, MSM_VIDC_DECODER, LOAD_CALC_NO_QUIRKS);
+	return msm_comm_scale_clocks_load(core, num_mbs_per_sec,
+				LOAD_CALC_NO_QUIRKS);
+}
+
+int msm_comm_scale_clocks_load(struct msm_vidc_core *core,
+		int num_mbs_per_sec, enum load_calc_quirks quirks)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_inst *inst = NULL;
+	unsigned long instant_bitrate = 0;
+	int num_sessions = 0;
+	struct vidc_clk_scale_data clk_scale_data = { {0} };
+	int codec = 0;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, core);
+		return -EINVAL;
+	}
+
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s Invalid device handle: %pK\n",
+			__func__, hdev);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+
+		codec = inst->session_type == MSM_VIDC_DECODER ?
+			inst->fmts[OUTPUT_PORT].fourcc :
+			inst->fmts[CAPTURE_PORT].fourcc;
+
+		if (msm_comm_turbo_session(inst))
+			clk_scale_data.power_mode[num_sessions] =
+				VIDC_POWER_TURBO;
+		else if (is_low_power_session(inst))
+			clk_scale_data.power_mode[num_sessions] =
+				VIDC_POWER_LOW;
+		else
+			clk_scale_data.power_mode[num_sessions] =
+				VIDC_POWER_NORMAL;
+
+		if (inst->dcvs_mode)
+			clk_scale_data.load[num_sessions] = inst->dcvs.load;
+		else
+			clk_scale_data.load[num_sessions] =
+				msm_comm_get_inst_load(inst, quirks);
+
+		clk_scale_data.session[num_sessions] =
+				VIDC_VOTE_DATA_SESSION_VAL(
+				get_hal_codec(codec),
+				get_hal_domain(inst->session_type));
+		num_sessions++;
+
+		if (inst->instant_bitrate > instant_bitrate)
+			instant_bitrate = inst->instant_bitrate;
+
+	}
+	clk_scale_data.num_sessions = num_sessions;
+	mutex_unlock(&core->lock);
+
+
+	rc = call_hfi_op(hdev, scale_clocks,
+		hdev->hfi_device_data, num_mbs_per_sec,
+		&clk_scale_data, instant_bitrate);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to set clock rate: %d\n", rc);
+
+	return rc;
+}
+
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return;
+	}
+	core = inst->core;
+	hdev = core->device;
+
+	if (msm_comm_scale_clocks(core)) {
+		dprintk(VIDC_WARN,
+				"Failed to scale clocks. Performance might be impacted\n");
+	}
+	if (msm_comm_vote_bus(core)) {
+		dprintk(VIDC_WARN,
+				"Failed to scale DDR bus. Performance might be impacted\n");
+	}
+}
+
+static inline enum msm_vidc_thermal_level msm_comm_vidc_thermal_level(int level)
+{
+	switch (level) {
+	case 0:
+		return VIDC_THERMAL_NORMAL;
+	case 1:
+		return VIDC_THERMAL_LOW;
+	case 2:
+		return VIDC_THERMAL_HIGH;
+	default:
+		return VIDC_THERMAL_CRITICAL;
+	}
+}
+
+static unsigned long msm_comm_get_clock_rate(struct msm_vidc_core *core)
+{
+	struct hfi_device *hdev;
+	unsigned long freq = 0;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	hdev = core->device;
+
+	freq = call_hfi_op(hdev, get_core_clock_rate, hdev->hfi_device_data, 1);
+	dprintk(VIDC_DBG, "clock freq %ld\n", freq);
+
+	return freq;
+}
+
+static bool is_core_turbo(struct msm_vidc_core *core, unsigned long freq)
+{
+	int i = 0;
+	struct msm_vidc_platform_resources *res = &core->resources;
+	struct load_freq_table *table = res->load_freq_tbl;
+	u32 max_freq = 0;
+
+	for (i = 0; i < res->load_freq_tbl_size; i++) {
+		if (max_freq < table[i].freq)
+			max_freq = table[i].freq;
+	}
+	return freq >= max_freq;
+}
+
+static bool is_thermal_permissible(struct msm_vidc_core *core)
+{
+	enum msm_vidc_thermal_level tl;
+	unsigned long freq = 0;
+	bool is_turbo = false;
+
+	if (!core->resources.thermal_mitigable)
+		return true;
+
+	if (!msm_vidc_thermal_mitigation_disabled) {
+		dprintk(VIDC_DBG,
+			"Thermal mitigation not enabled. debugfs %d\n",
+			msm_vidc_thermal_mitigation_disabled);
+		return true;
+	}
+
+	tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level);
+	freq = msm_comm_get_clock_rate(core);
+
+	is_turbo = is_core_turbo(core, freq);
+	dprintk(VIDC_DBG,
+		"Core freq %ld Thermal level %d Turbo mode %d\n",
+		freq, tl, is_turbo);
+
+	if (is_turbo && tl >= VIDC_THERMAL_LOW) {
+		dprintk(VIDC_ERR,
+			"Video session not allowed. Turbo mode %d Thermal level %d\n",
+			is_turbo, tl);
+		return false;
+	}
+	return true;
+}
+
+static int msm_comm_session_abort(struct msm_vidc_inst *inst)
+{
+	int rc = 0, abort_completion = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+	abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE);
+	init_completion(&inst->completions[abort_completion]);
+
+	rc = call_hfi_op(hdev, session_abort, (void *)inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s session_abort failed rc: %d\n", __func__, rc);
+		return rc;
+	}
+	rc = wait_for_completion_timeout(
+			&inst->completions[abort_completion],
+			msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR,
+				"%s: Wait interrupted or timed out [%pK]: %d\n",
+				__func__, inst, abort_completion);
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -EBUSY;
+	} else {
+		rc = 0;
+	}
+	msm_comm_session_clean(inst);
+	return rc;
+}
+
+static void handle_thermal_event(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct msm_vidc_inst *inst;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return;
+	}
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (!inst->session)
+			continue;
+
+		mutex_unlock(&core->lock);
+		if (inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_CLOSE_DONE) {
+			dprintk(VIDC_WARN, "%s: abort inst %pK\n",
+				__func__, inst);
+			rc = msm_comm_session_abort(inst);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s session_abort failed rc: %d\n",
+					__func__, rc);
+				goto err_sess_abort;
+			}
+			change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+			dprintk(VIDC_WARN,
+				"%s Send sys error for inst %pK\n",
+				__func__, inst);
+			msm_vidc_queue_v4l2_event(inst,
+					V4L2_EVENT_MSM_VIDC_SYS_ERROR);
+		} else {
+			msm_comm_generate_session_error(inst);
+		}
+		mutex_lock(&core->lock);
+	}
+	mutex_unlock(&core->lock);
+	return;
+
+err_sess_abort:
+	msm_comm_clean_notify_client(core);
+}
+
+void msm_comm_handle_thermal_event(void)
+{
+	struct msm_vidc_core *core;
+
+	list_for_each_entry(core, &vidc_driver->cores, list) {
+		if (!is_thermal_permissible(core)) {
+			dprintk(VIDC_WARN,
+				"Thermal level critical, stop all active sessions!\n");
+			handle_thermal_event(core);
+		}
+	}
+}
+
+int msm_comm_check_core_init(struct msm_vidc_core *core)
+{
+	int rc = 0;
+
+	mutex_lock(&core->lock);
+	if (core->state >= VIDC_CORE_INIT_DONE) {
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG, "Waiting for SYS_INIT_DONE\n");
+	rc = wait_for_completion_timeout(
+		&core->completions[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)],
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR, "%s: Wait interrupted or timed out: %d\n",
+				__func__, SYS_MSG_INDEX(HAL_SYS_INIT_DONE));
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -EIO;
+		goto exit;
+	} else {
+		core->state = VIDC_CORE_INIT_DONE;
+		rc = 0;
+	}
+	dprintk(VIDC_DBG, "SYS_INIT_DONE!!!\n");
+exit:
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	rc = msm_comm_check_core_init(inst->core);
+	if (rc) {
+		dprintk(VIDC_ERR, "%s - failed to initialize core\n", __func__);
+		msm_comm_generate_sys_error(inst);
+		return rc;
+	}
+	change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
+	return rc;
+}
+
+static int msm_comm_init_core(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+
+	if (!inst || !inst->core || !inst->core->device)
+		return -EINVAL;
+
+	core = inst->core;
+	hdev = core->device;
+	mutex_lock(&core->lock);
+	if (core->state >= VIDC_CORE_INIT) {
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto core_already_inited;
+	}
+	if (!core->capabilities) {
+		core->capabilities = kzalloc(VIDC_MAX_SESSIONS *
+				sizeof(struct msm_vidc_capability), GFP_KERNEL);
+		if (!core->capabilities) {
+			dprintk(VIDC_ERR,
+				"%s: failed to allocate capabilities\n",
+				__func__);
+			rc = -ENOMEM;
+			goto fail_cap_alloc;
+		}
+	} else {
+		dprintk(VIDC_WARN,
+			"%s: capabilities memory is expected to be freed\n",
+			__func__);
+	}
+
+	init_completion(&core->completions
+			[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)]);
+	rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init core, id = %d\n",
+				core->id);
+		goto fail_core_init;
+	}
+	core->state = VIDC_CORE_INIT;
+	core->smmu_fault_handled = false;
+core_already_inited:
+	change_inst_state(inst, MSM_VIDC_CORE_INIT);
+	mutex_unlock(&core->lock);
+	return rc;
+
+fail_core_init:
+	kfree(core->capabilities);
+fail_cap_alloc:
+	core->capabilities = NULL;
+	core->state = VIDC_CORE_UNINIT;
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	hdev = core->device;
+
+	mutex_lock(&core->lock);
+	if (core->state == VIDC_CORE_UNINIT) {
+		dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n",
+				core->id, core->state);
+		goto core_already_uninited;
+	}
+	mutex_unlock(&core->lock);
+
+	msm_comm_scale_clocks_and_bus(inst);
+
+	mutex_lock(&core->lock);
+
+	if (!core->resources.never_unload_fw) {
+		cancel_delayed_work(&core->fw_unload_work);
+
+		/*
+		 * Delay unloading of firmware. This is useful
+		 * in avoiding firmware download delays in cases where we
+		 * will have a burst of back to back video playback sessions
+		 * e.g. thumbnail generation.
+		 */
+		schedule_delayed_work(&core->fw_unload_work,
+			msecs_to_jiffies(core->state == VIDC_CORE_INVALID ?
+					0 : msm_vidc_firmware_unload_delay));
+
+		dprintk(VIDC_DBG, "firmware unload delayed by %u ms\n",
+			core->state == VIDC_CORE_INVALID ?
+			0 : msm_vidc_firmware_unload_delay);
+	}
+
+core_already_uninited:
+	change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
+	mutex_unlock(&core->lock);
+	return 0;
+}
+
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst)
+{
+	msm_comm_kill_session(inst);
+	return msm_vidc_deinit_core(inst);
+}
+
+static int msm_comm_session_init(int flipped_state,
+	struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	int fourcc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
+		dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto exit;
+	}
+	if (inst->session_type == MSM_VIDC_DECODER) {
+		fourcc = inst->fmts[OUTPUT_PORT].fourcc;
+	} else if (inst->session_type == MSM_VIDC_ENCODER) {
+		fourcc = inst->fmts[CAPTURE_PORT].fourcc;
+	} else {
+		dprintk(VIDC_ERR, "Invalid session\n");
+		return -EINVAL;
+	}
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_INIT_DONE)]);
+
+	rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data,
+			inst, get_hal_domain(inst->session_type),
+			get_hal_codec(fourcc),
+			&inst->session);
+
+	if (rc || !inst->session) {
+		dprintk(VIDC_ERR,
+			"Failed to call session init for: %pK, %pK, %d, %d\n",
+			inst->core->device, inst,
+			inst->session_type, fourcc);
+		rc = -EINVAL;
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+	return rc;
+}
+
+static void msm_vidc_print_running_insts(struct msm_vidc_core *core)
+{
+	struct msm_vidc_inst *temp;
+
+	dprintk(VIDC_ERR, "Running instances:\n");
+	dprintk(VIDC_ERR, "%4s|%4s|%4s|%4s|%4s\n",
+			"type", "w", "h", "fps", "prop");
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(temp, &core->instances, list) {
+		if (temp->state >= MSM_VIDC_OPEN_DONE &&
+				temp->state < MSM_VIDC_STOP_DONE) {
+			char properties[4] = "";
+
+			if (is_thumbnail_session(temp))
+				strlcat(properties, "N", sizeof(properties));
+
+			if (msm_comm_turbo_session(temp))
+				strlcat(properties, "T", sizeof(properties));
+
+			dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d|%4s\n",
+					temp->session_type,
+					max(temp->prop.width[CAPTURE_PORT],
+						temp->prop.width[OUTPUT_PORT]),
+					max(temp->prop.height[CAPTURE_PORT],
+						temp->prop.height[OUTPUT_PORT]),
+					temp->prop.fps, properties);
+		}
+	}
+	mutex_unlock(&core->lock);
+}
+
+static int msm_vidc_load_resources(int flipped_state,
+	struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	int num_mbs_per_sec = 0, max_load_adj = 0;
+	struct msm_vidc_core *core;
+	enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+		LOAD_CALC_IGNORE_THUMBNAIL_LOAD |
+		LOAD_CALC_IGNORE_NON_REALTIME_LOAD;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	if (core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state can't do load res\n");
+		return -EINVAL;
+	}
+
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Instance is in invalid state can't do load res\n");
+		return -EINVAL;
+	}
+
+	num_mbs_per_sec =
+		msm_comm_get_load(core, MSM_VIDC_DECODER, quirks) +
+		msm_comm_get_load(core, MSM_VIDC_ENCODER, quirks);
+
+	max_load_adj = core->resources.max_load +
+		inst->capability.mbs_per_frame.max;
+
+	if (num_mbs_per_sec > max_load_adj) {
+		dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n",
+			num_mbs_per_sec, max_load_adj);
+		msm_vidc_print_running_insts(core);
+		inst->state = MSM_VIDC_CORE_INVALID;
+		msm_comm_kill_session(inst);
+		return -EBUSY;
+	}
+
+	hdev = core->device;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+		dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto exit;
+	}
+
+	rc = call_hfi_op(hdev, session_load_res, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send load resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
+exit:
+	return rc;
+}
+
+static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			inst->core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state can't do start\n");
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+			inst, inst->state);
+		goto exit;
+	}
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_START_DONE)]);
+	rc = call_hfi_op(hdev, session_start, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send start\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_START);
+exit:
+	return rc;
+}
+
+static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+			inst, inst->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG, "Send Stop to hal\n");
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_STOP_DONE)]);
+	rc = call_hfi_op(hdev, session_stop, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to send stop\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_STOP);
+exit:
+	return rc;
+}
+
+static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+			inst, inst->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG,
+		"Send release res to hal\n");
+	init_completion(&inst->completions[
+			SESSION_MSG_INDEX(HAL_SESSION_RELEASE_RESOURCE_DONE)]);
+	rc = call_hfi_op(hdev, session_release_res, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send release resources\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
+exit:
+	return rc;
+}
+
+static int msm_comm_session_close(int flipped_state,
+			struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+	if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
+		dprintk(VIDC_INFO,
+			"inst: %pK is already in state: %d\n",
+						inst, inst->state);
+		goto exit;
+	}
+	dprintk(VIDC_DBG,
+		"Send session close to hal\n");
+	init_completion(
+		&inst->completions[SESSION_MSG_INDEX(HAL_SESSION_END_DONE)]);
+	rc = call_hfi_op(hdev, session_end, (void *) inst->session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to send close\n");
+		goto exit;
+	}
+	change_inst_state(inst, MSM_VIDC_CLOSE);
+exit:
+	return rc;
+}
+
+int msm_comm_suspend(int core_id)
+{
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+	int rc = 0;
+
+	core = get_vidc_core(core_id);
+	if (!core) {
+		dprintk(VIDC_ERR,
+			"%s: Failed to find core for core_id = %d\n",
+			__func__, core_id);
+		return -EINVAL;
+	}
+
+	hdev = (struct hfi_device *)core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s Invalid device handle\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	if (core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"%s - fw is not in proper state, skip suspend\n",
+				__func__);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to suspend\n");
+
+exit:
+	mutex_unlock(&core->lock);
+	return rc;
+}
+
+static int get_flipped_state(int present_state,
+	int desired_state)
+{
+	int flipped_state = present_state;
+
+	if (flipped_state < MSM_VIDC_STOP
+			&& desired_state > MSM_VIDC_STOP) {
+		flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state);
+		flipped_state &= 0xFFFE;
+		flipped_state = flipped_state - 1;
+	} else if (flipped_state > MSM_VIDC_STOP
+			&& desired_state < MSM_VIDC_STOP) {
+		flipped_state = MSM_VIDC_STOP -
+			(flipped_state - MSM_VIDC_STOP + 1);
+		flipped_state &= 0xFFFE;
+		flipped_state = flipped_state - 1;
+	}
+	return flipped_state;
+}
+
+struct hal_buffer_requirements *get_buff_req_buffer(
+		struct msm_vidc_inst *inst, enum hal_buffer buffer_type)
+{
+	int i;
+
+	for (i = 0; i < HAL_BUFFER_MAX; i++) {
+		if (inst->buff_req.buffer[i].buffer_type == buffer_type)
+			return &inst->buff_req.buffer[i];
+	}
+	return NULL;
+}
+
+static int set_output_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type)
+{
+	int rc = 0;
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	u32 smem_flags = 0, buffer_size;
+	struct hal_buffer_requirements *output_buf, *extradata_buf;
+	int i;
+	struct hfi_device *hdev;
+	struct hal_buffer_size_minimum b;
+
+	hdev = inst->core->device;
+
+	output_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!output_buf) {
+		dprintk(VIDC_DBG,
+			"This output buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+	dprintk(VIDC_DBG,
+		"output: num = %d, size = %d\n",
+		output_buf->buffer_count_actual,
+		output_buf->buffer_size);
+
+	buffer_size = output_buf->buffer_size;
+	b.buffer_type = buffer_type;
+	b.buffer_size = buffer_size;
+	rc = call_hfi_op(hdev, session_set_property,
+		inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
+		&b);
+
+	extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT);
+	if (extradata_buf) {
+		dprintk(VIDC_DBG,
+			"extradata: num = %d, size = %d\n",
+			extradata_buf->buffer_count_actual,
+			extradata_buf->buffer_size);
+		buffer_size += extradata_buf->buffer_size;
+	} else {
+		dprintk(VIDC_DBG,
+			"This extradata buffer not required, buffer_type: %x\n",
+			buffer_type);
+	}
+
+	if (inst->flags & VIDC_SECURE)
+		smem_flags |= SMEM_SECURE;
+
+	if (output_buf->buffer_size) {
+		for (i = 0; i < output_buf->buffer_count_actual;
+				i++) {
+			handle = msm_comm_smem_alloc(inst,
+					buffer_size, 1, smem_flags,
+					buffer_type, 0);
+			if (!handle) {
+				dprintk(VIDC_ERR,
+					"Failed to allocate output memory\n");
+				rc = -ENOMEM;
+				goto err_no_mem;
+			}
+			rc = msm_comm_smem_cache_operations(inst,
+					handle, SMEM_CACHE_CLEAN);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Failed to clean cache may cause undefined behavior\n");
+			}
+			binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+			if (!binfo) {
+				dprintk(VIDC_ERR, "Out of memory\n");
+				rc = -ENOMEM;
+				goto fail_kzalloc;
+			}
+
+			binfo->handle = handle;
+			binfo->buffer_type = buffer_type;
+			binfo->buffer_ownership = DRIVER;
+			dprintk(VIDC_DBG, "Output buffer address: %pa\n",
+					&handle->device_addr);
+
+			if (inst->buffer_mode_set[CAPTURE_PORT] ==
+				HAL_BUFFER_MODE_STATIC) {
+				struct vidc_buffer_addr_info buffer_info = {0};
+
+				buffer_info.buffer_size =
+					output_buf->buffer_size;
+				buffer_info.buffer_type = buffer_type;
+				buffer_info.num_buffers = 1;
+				buffer_info.align_device_addr =
+					handle->device_addr;
+				buffer_info.extradata_addr =
+					handle->device_addr +
+					output_buf->buffer_size;
+				if (extradata_buf)
+					buffer_info.extradata_size =
+						extradata_buf->buffer_size;
+				rc = call_hfi_op(hdev, session_set_buffers,
+					(void *) inst->session, &buffer_info);
+				if (rc) {
+					dprintk(VIDC_ERR,
+						"%s : session_set_buffers failed\n",
+						__func__);
+					goto fail_set_buffers;
+				}
+			}
+			mutex_lock(&inst->outputbufs.lock);
+			list_add_tail(&binfo->list, &inst->outputbufs.list);
+			mutex_unlock(&inst->outputbufs.lock);
+		}
+	}
+	return rc;
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_comm_smem_free(inst, handle);
+err_no_mem:
+	return rc;
+}
+
+static inline char *get_buffer_name(enum hal_buffer buffer_type)
+{
+	switch (buffer_type) {
+	case HAL_BUFFER_INPUT: return "input";
+	case HAL_BUFFER_OUTPUT: return "output";
+	case HAL_BUFFER_OUTPUT2: return "output_2";
+	case HAL_BUFFER_EXTRADATA_INPUT: return "input_extra";
+	case HAL_BUFFER_EXTRADATA_OUTPUT: return "output_extra";
+	case HAL_BUFFER_EXTRADATA_OUTPUT2: return "output2_extra";
+	case HAL_BUFFER_INTERNAL_SCRATCH: return "scratch";
+	case HAL_BUFFER_INTERNAL_SCRATCH_1: return "scratch_1";
+	case HAL_BUFFER_INTERNAL_SCRATCH_2: return "scratch_2";
+	case HAL_BUFFER_INTERNAL_PERSIST: return "persist";
+	case HAL_BUFFER_INTERNAL_PERSIST_1: return "persist_1";
+	case HAL_BUFFER_INTERNAL_CMD_QUEUE: return "queue";
+	default: return "????";
+	}
+}
+
+static int set_internal_buf_on_fw(struct msm_vidc_inst *inst,
+				enum hal_buffer buffer_type,
+				struct msm_smem *handle, bool reuse)
+{
+	struct vidc_buffer_addr_info buffer_info;
+	struct hfi_device *hdev;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device || !handle) {
+		dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	rc = msm_comm_smem_cache_operations(inst,
+					handle, SMEM_CACHE_CLEAN);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Failed to clean cache. Undefined behavior\n");
+	}
+
+	buffer_info.buffer_size = handle->size;
+	buffer_info.buffer_type = buffer_type;
+	buffer_info.num_buffers = 1;
+	buffer_info.align_device_addr = handle->device_addr;
+	dprintk(VIDC_DBG, "%s %s buffer : %pa\n",
+				reuse ? "Reusing" : "Allocated",
+				get_buffer_name(buffer_type),
+				&buffer_info.align_device_addr);
+
+	rc = call_hfi_op(hdev, session_set_buffers,
+		(void *) inst->session, &buffer_info);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"vidc_hal_session_set_buffers failed\n");
+		return rc;
+	}
+	return 0;
+}
+
+static bool reuse_internal_buffers(struct msm_vidc_inst *inst,
+		enum hal_buffer buffer_type, struct msm_vidc_list *buf_list)
+{
+	struct internal_buf *buf;
+	int rc = 0;
+	bool reused = false;
+
+	if (!inst || !buf_list) {
+		dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
+		return false;
+	}
+
+	mutex_lock(&buf_list->lock);
+	list_for_each_entry(buf, &buf_list->list, list) {
+		if (!buf->handle) {
+			reused = false;
+			break;
+		}
+
+		if (buf->buffer_type != buffer_type)
+			continue;
+
+		/*
+		 * Persist buffer size won't change with resolution. If they
+		 * are in queue means that they are already allocated and
+		 * given to HW. HW can use them without reallocation. These
+		 * buffers are not released as part of port reconfig. So
+		 * driver no need to set them again.
+		 */
+
+		if (buffer_type != HAL_BUFFER_INTERNAL_PERSIST
+			&& buffer_type != HAL_BUFFER_INTERNAL_PERSIST_1) {
+
+			rc = set_internal_buf_on_fw(inst, buffer_type,
+					buf->handle, true);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"%s: session_set_buffers failed\n",
+					__func__);
+				reused = false;
+				break;
+			}
+		}
+		reused = true;
+		dprintk(VIDC_DBG,
+			"Re-using internal buffer type : %d\n", buffer_type);
+	}
+	mutex_unlock(&buf_list->lock);
+	return reused;
+}
+
+static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst,
+			struct hal_buffer_requirements *internal_bufreq,
+			struct msm_vidc_list *buf_list)
+{
+	struct msm_smem *handle;
+	struct internal_buf *binfo;
+	u32 smem_flags = 0;
+	int rc = 0;
+	int i = 0;
+
+	if (!inst || !internal_bufreq || !buf_list)
+		return -EINVAL;
+
+	if (!internal_bufreq->buffer_size)
+		return 0;
+
+	if (inst->flags & VIDC_SECURE)
+		smem_flags |= SMEM_SECURE;
+
+	for (i = 0; i < internal_bufreq->buffer_count_actual; i++) {
+		handle = msm_comm_smem_alloc(inst, internal_bufreq->buffer_size,
+				1, smem_flags, internal_bufreq->buffer_type, 0);
+		if (!handle) {
+			dprintk(VIDC_ERR,
+				"Failed to allocate scratch memory\n");
+			rc = -ENOMEM;
+			goto err_no_mem;
+		}
+
+		binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+		if (!binfo) {
+			dprintk(VIDC_ERR, "Out of memory\n");
+			rc = -ENOMEM;
+			goto fail_kzalloc;
+		}
+
+		binfo->handle = handle;
+		binfo->buffer_type = internal_bufreq->buffer_type;
+
+		rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type,
+				handle, false);
+		if (rc)
+			goto fail_set_buffers;
+
+		mutex_lock(&buf_list->lock);
+		list_add_tail(&binfo->list, &buf_list->list);
+		mutex_unlock(&buf_list->lock);
+	}
+	return rc;
+
+fail_set_buffers:
+	kfree(binfo);
+fail_kzalloc:
+	msm_comm_smem_free(inst, handle);
+err_no_mem:
+	return rc;
+
+}
+
+static int set_internal_buffers(struct msm_vidc_inst *inst,
+	enum hal_buffer buffer_type, struct msm_vidc_list *buf_list)
+{
+	struct hal_buffer_requirements *internal_buf;
+
+	internal_buf = get_buff_req_buffer(inst, buffer_type);
+	if (!internal_buf) {
+		dprintk(VIDC_DBG,
+			"This internal buffer not required, buffer_type: %x\n",
+			buffer_type);
+		return 0;
+	}
+
+	dprintk(VIDC_DBG, "Buffer type %s: num = %d, size = %d\n",
+		get_buffer_name(buffer_type),
+		internal_buf->buffer_count_actual, internal_buf->buffer_size);
+
+	/*
+	 * Try reusing existing internal buffers first.
+	 * If it's not possible to reuse, allocate new buffers.
+	 */
+	if (reuse_internal_buffers(inst, buffer_type, buf_list))
+		return 0;
+
+	return allocate_and_set_internal_bufs(inst, internal_buf,
+				buf_list);
+}
+
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
+{
+	int rc = 0;
+	int flipped_state;
+	struct msm_vidc_core *core;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	dprintk(VIDC_DBG,
+			"Trying to move inst: %pK from: %#x to %#x\n",
+			inst, inst->state, state);
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->sync_lock);
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR,
+				"Core is in bad state can't change the state\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+	flipped_state = get_flipped_state(inst->state, state);
+	dprintk(VIDC_DBG,
+			"flipped_state = %#x\n", flipped_state);
+	switch (flipped_state) {
+	case MSM_VIDC_CORE_UNINIT_DONE:
+	case MSM_VIDC_CORE_INIT:
+		rc = msm_comm_init_core(inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_CORE_INIT_DONE:
+		rc = msm_comm_init_core_done(inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_OPEN:
+		rc = msm_comm_session_init(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_OPEN_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+			HAL_SESSION_INIT_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_LOAD_RESOURCES:
+		rc = msm_vidc_load_resources(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_LOAD_RESOURCES_DONE:
+	case MSM_VIDC_START:
+		rc = msm_vidc_start(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_START_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE,
+				HAL_SESSION_START_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_STOP:
+		rc = msm_vidc_stop(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_STOP_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE,
+				HAL_SESSION_STOP_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+		dprintk(VIDC_DBG, "Moving to Stop Done state\n");
+	case MSM_VIDC_RELEASE_RESOURCES:
+		rc = msm_vidc_release_res(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_RELEASE_RESOURCES_DONE:
+		rc = wait_for_state(inst, flipped_state,
+			MSM_VIDC_RELEASE_RESOURCES_DONE,
+			HAL_SESSION_RELEASE_RESOURCE_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+		dprintk(VIDC_DBG,
+				"Moving to release resources done state\n");
+	case MSM_VIDC_CLOSE:
+		rc = msm_comm_session_close(flipped_state, inst);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+	case MSM_VIDC_CLOSE_DONE:
+		rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE,
+				HAL_SESSION_END_DONE);
+		if (rc || state <= get_flipped_state(inst->state, state))
+			break;
+		msm_comm_session_clean(inst);
+	case MSM_VIDC_CORE_UNINIT:
+	case MSM_VIDC_CORE_INVALID:
+		dprintk(VIDC_DBG, "Sending core uninit\n");
+		rc = msm_vidc_deinit_core(inst);
+		if (rc || state == get_flipped_state(inst->state, state))
+			break;
+	default:
+		dprintk(VIDC_ERR, "State not recognized\n");
+		rc = -EINVAL;
+		break;
+	}
+exit:
+	mutex_unlock(&inst->sync_lock);
+	if (rc)
+		dprintk(VIDC_ERR,
+				"Failed to move from state: %d to %d\n",
+				inst->state, state);
+	else
+		trace_msm_vidc_common_state_change((void *)inst,
+				inst->state, state);
+	return rc;
+}
+
+int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct v4l2_decoder_cmd *dec = NULL;
+	struct v4l2_encoder_cmd *enc = NULL;
+	struct msm_vidc_core *core;
+	int which_cmd = 0, flags = 0, rc = 0;
+
+	if (!inst || !inst->core || !cmd) {
+		dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (inst->session_type == MSM_VIDC_ENCODER) {
+		enc = (struct v4l2_encoder_cmd *)cmd;
+		which_cmd = enc->cmd;
+		flags = enc->flags;
+	} else if (inst->session_type == MSM_VIDC_DECODER) {
+		dec = (struct v4l2_decoder_cmd *)cmd;
+		which_cmd = dec->cmd;
+		flags = dec->flags;
+	}
+
+
+	switch (which_cmd) {
+	case V4L2_QCOM_CMD_FLUSH:
+		if (core->state != VIDC_CORE_INVALID &&
+			inst->state ==  MSM_VIDC_CORE_INVALID) {
+			rc = msm_comm_kill_session(inst);
+			if (rc)
+				dprintk(VIDC_ERR,
+					"Fail to clean session: %d\n",
+					rc);
+		}
+		rc = msm_comm_flush(inst, flags);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to flush buffers: %d\n", rc);
+		}
+		break;
+	case V4L2_DEC_QCOM_CMD_RECONFIG_HINT:
+	{
+		u32 *ptr = NULL;
+		struct hal_buffer_requirements *output_buf;
+
+		rc = msm_comm_try_get_bufreqs(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Getting buffer requirements failed: %d\n",
+					rc);
+			break;
+		}
+
+		output_buf = get_buff_req_buffer(inst,
+				msm_comm_get_hal_output_buffer(inst));
+		if (output_buf) {
+			if (dec) {
+				ptr = (u32 *)dec->raw.data;
+				ptr[0] = output_buf->buffer_size;
+				ptr[1] = output_buf->buffer_count_actual;
+				dprintk(VIDC_DBG,
+					"Reconfig hint, size is %u, count is %u\n",
+					ptr[0], ptr[1]);
+			} else {
+				dprintk(VIDC_ERR, "Null decoder\n");
+			}
+		} else {
+			dprintk(VIDC_DBG,
+					"This output buffer not required, buffer_type: %x\n",
+					HAL_BUFFER_OUTPUT);
+		}
+		break;
+	}
+	default:
+		dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd);
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+static void populate_frame_data(struct vidc_frame_data *data,
+		const struct vb2_buffer *vb, struct msm_vidc_inst *inst)
+{
+	int64_t time_usec;
+	int extra_idx;
+	enum v4l2_buf_type type = vb->type;
+	enum vidc_ports port = type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
+		OUTPUT_PORT : CAPTURE_PORT;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	time_usec = vb->timestamp;
+	do_div(time_usec, NSEC_PER_USEC);
+
+	data->alloc_len = vb->planes[0].length;
+	data->device_addr = vb->planes[0].m.userptr;
+	data->timestamp = time_usec;
+	data->flags = 0;
+	data->clnt_data = data->device_addr;
+
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		bool pic_decoding_mode = msm_comm_g_ctrl_for_id(inst,
+				V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE);
+
+		data->buffer_type = HAL_BUFFER_INPUT;
+		data->filled_len = vb->planes[0].bytesused;
+		data->offset = vb->planes[0].data_offset;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_FLAG_EOS)
+			data->flags |= HAL_BUFFERFLAG_EOS;
+
+		if (vbuf->flags & V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP)
+			data->flags |= HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_FLAG_CODECCONFIG)
+			data->flags |= HAL_BUFFERFLAG_CODECCONFIG;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY)
+			data->flags |= HAL_BUFFERFLAG_DECODEONLY;
+
+		if (vbuf->flags & V4L2_QCOM_BUF_TIMESTAMP_INVALID)
+			data->timestamp = LLONG_MAX;
+
+		/* XXX: This is a dirty hack necessitated by the firmware,
+		 * which refuses to issue FBDs for non I-frames in Picture Type
+		 * Decoding mode, unless we pass in non-zero value in mark_data
+		 * and mark_target.
+		 */
+		data->mark_data = data->mark_target =
+			pic_decoding_mode ? 0xdeadbeef : 0;
+
+	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		data->buffer_type = msm_comm_get_hal_output_buffer(inst);
+	}
+
+	extra_idx = EXTRADATA_IDX(inst->fmts[port].num_planes);
+	if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
+			vb->planes[extra_idx].m.userptr) {
+		data->extradata_addr = vb->planes[extra_idx].m.userptr;
+		data->extradata_size = vb->planes[extra_idx].length;
+		data->flags |= HAL_BUFFERFLAG_EXTRADATA;
+	}
+}
+
+static unsigned int count_single_batch(struct msm_vidc_list *list,
+		enum v4l2_buf_type type)
+{
+	struct vb2_buf_entry *buf;
+	int count = 0;
+	struct vb2_v4l2_buffer *vbuf = NULL;
+
+	mutex_lock(&list->lock);
+	list_for_each_entry(buf, &list->list, list) {
+		if (buf->vb->type != type)
+			continue;
+
+		++count;
+
+		vbuf = to_vb2_v4l2_buffer(buf->vb);
+		if (!(vbuf->flags & V4L2_MSM_BUF_FLAG_DEFER))
+			goto found_batch;
+	}
+	 /* don't have a full batch */
+	count = 0;
+
+found_batch:
+	mutex_unlock(&list->lock);
+	return count;
+}
+
+static unsigned int count_buffers(struct msm_vidc_list *list,
+		enum v4l2_buf_type type)
+{
+	struct vb2_buf_entry *buf;
+	int count = 0;
+
+	mutex_lock(&list->lock);
+	list_for_each_entry(buf, &list->list, list) {
+		if (buf->vb->type != type)
+			continue;
+
+		++count;
+	}
+	mutex_unlock(&list->lock);
+
+	return count;
+}
+
+static void log_frame(struct msm_vidc_inst *inst, struct vidc_frame_data *data,
+		enum v4l2_buf_type type)
+{
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		dprintk(VIDC_DBG,
+				"Sending etb (%pa) to hal: filled: %d, ts: %lld, flags = %#x\n",
+				&data->device_addr, data->filled_len,
+				data->timestamp, data->flags);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_ETB);
+
+		if (msm_vidc_bitrate_clock_scaling &&
+			inst->session_type == MSM_VIDC_DECODER &&
+			!inst->dcvs_mode)
+			inst->instant_bitrate =
+				data->filled_len * 8 * inst->prop.fps;
+		else
+			inst->instant_bitrate = 0;
+	} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+		dprintk(VIDC_DBG,
+				"Sending ftb (%pa) to hal: size: %d, ts: %lld, flags = %#x\n",
+				&data->device_addr, data->alloc_len,
+				data->timestamp, data->flags);
+		msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FTB);
+	}
+
+	msm_dcvs_check_and_scale_clocks(inst,
+			type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+	if (msm_vidc_bitrate_clock_scaling && !inst->dcvs_mode &&
+		type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+		inst->session_type == MSM_VIDC_DECODER)
+		if (msm_comm_scale_clocks(inst->core))
+			dprintk(VIDC_WARN,
+				"Failed to scale clocks. Performance might be impacted\n");
+}
+
+static int request_seq_header(struct msm_vidc_inst *inst,
+		struct vidc_frame_data *data)
+{
+	struct vidc_seq_hdr seq_hdr = {
+		.seq_hdr = data->device_addr,
+		.seq_hdr_len = data->alloc_len,
+	};
+
+	dprintk(VIDC_DBG, "Requesting sequence header in %pa\n",
+			&seq_hdr.seq_hdr);
+	return call_hfi_op(inst->core->device, session_get_seq_hdr,
+			inst->session, &seq_hdr);
+}
+
+/*
+ * Attempts to queue `vb` to hardware.  If, for various reasons, the buffer
+ * cannot be queued to hardware, the buffer will be staged for commit in the
+ * pending queue.  Once the hardware reaches a good state (or if `vb` is NULL,
+ * the subsequent *_qbuf will commit the previously staged buffers to hardware.
+ */
+int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb)
+{
+	int rc = 0;
+	int capture_count, output_count;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+	struct {
+		struct vidc_frame_data *data;
+		int count;
+	} etbs, ftbs;
+	bool defer = false, batch_mode;
+	struct vb2_buf_entry *temp, *next;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	hdev = core->device;
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+		core->state == VIDC_CORE_INVALID ||
+		core->state == VIDC_CORE_UNINIT) {
+		dprintk(VIDC_ERR, "Core is in bad state. Can't Queue\n");
+		return -EINVAL;
+	}
+
+	/* Stick the buffer into the pendinq, we'll pop it out later on
+	 * if we want to commit it to hardware
+	 */
+	if (vb) {
+		temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+		if (!temp) {
+			dprintk(VIDC_ERR, "Out of memory\n");
+			goto err_no_mem;
+		}
+
+		temp->vb = vb;
+		mutex_lock(&inst->pendingq.lock);
+		list_add_tail(&temp->list, &inst->pendingq.list);
+		mutex_unlock(&inst->pendingq.lock);
+	}
+
+	batch_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_VIDC_QBUF_MODE)
+		== V4L2_VIDC_QBUF_BATCHED;
+	capture_count = (batch_mode ? &count_single_batch : &count_buffers)
+		(&inst->pendingq, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+	output_count = (batch_mode ? &count_single_batch : &count_buffers)
+		(&inst->pendingq, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+	/*
+	 * Somewhat complicated logic to prevent queuing the buffer to hardware.
+	 * Don't queue if:
+	 * 1) Hardware isn't ready (that's simple)
+	 */
+	defer = defer ?: inst->state != MSM_VIDC_START_DONE;
+
+	/*
+	 * 2) The client explicitly tells us not to because it wants this
+	 * buffer to be batched with future frames.  The batch size (on both
+	 * capabilities) is completely determined by the client.
+	 */
+	defer = defer ?: vbuf && vbuf->flags & V4L2_MSM_BUF_FLAG_DEFER;
+
+	/* 3) If we're in batch mode, we must have full batches of both types */
+	defer = defer ?: batch_mode && (!output_count || !capture_count);
+
+	if (defer) {
+		dprintk(VIDC_DBG, "Deferring queue of %pK\n", vb);
+		return 0;
+	}
+
+	dprintk(VIDC_DBG, "%sing %d etbs and %d ftbs\n",
+			batch_mode ? "Batch" : "Process",
+			output_count, capture_count);
+
+	etbs.data = kcalloc(output_count, sizeof(*etbs.data), GFP_KERNEL);
+	ftbs.data = kcalloc(capture_count, sizeof(*ftbs.data), GFP_KERNEL);
+	/* Note that it's perfectly normal for (e|f)tbs.data to be NULL if
+	 * we're not in batch mode (i.e. (output|capture)_count == 0)
+	 */
+	if ((!etbs.data && output_count) ||
+			(!ftbs.data && capture_count)) {
+		dprintk(VIDC_ERR, "Failed to alloc memory for batching\n");
+		kfree(etbs.data);
+		etbs.data = NULL;
+
+		kfree(ftbs.data);
+		ftbs.data = NULL;
+		goto err_no_mem;
+	}
+
+	etbs.count = ftbs.count = 0;
+
+	/*
+	 * Try to collect all pending buffers into 2 batches of ftb and etb
+	 * Note that these "batches" might be empty if we're no in batching mode
+	 * and the pendingq is empty
+	 */
+	mutex_lock(&inst->pendingq.lock);
+	list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) {
+		struct vidc_frame_data *frame_data = NULL;
+
+		switch (temp->vb->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+			if (ftbs.count < capture_count && ftbs.data)
+				frame_data = &ftbs.data[ftbs.count++];
+			break;
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			if (etbs.count < output_count && etbs.data)
+				frame_data = &etbs.data[etbs.count++];
+			break;
+		default:
+			break;
+		}
+
+		if (!frame_data)
+			continue;
+
+		populate_frame_data(frame_data, temp->vb, inst);
+
+		list_del(&temp->list);
+		kfree(temp);
+	}
+	mutex_unlock(&inst->pendingq.lock);
+
+	/* Finally commit all our frame(s) to H/W */
+	if (batch_mode) {
+		int ftb_index = 0, c = 0;
+
+		for (c = 0; atomic_read(&inst->seq_hdr_reqs) > 0; ++c) {
+			rc = request_seq_header(inst, &ftbs.data[c]);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed requesting sequence header: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			atomic_dec(&inst->seq_hdr_reqs);
+		}
+
+		ftb_index = c;
+		rc = call_hfi_op(hdev, session_process_batch, inst->session,
+				etbs.count, etbs.data,
+				ftbs.count - ftb_index, &ftbs.data[ftb_index]);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to queue batch of %d ETBs and %d FTBs\n",
+				etbs.count, ftbs.count);
+			goto err_bad_input;
+		}
+
+		for (c = ftb_index; c < ftbs.count; ++c) {
+			log_frame(inst, &ftbs.data[c],
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		}
+
+		for (c = 0; c < etbs.count; ++c) {
+			log_frame(inst, &etbs.data[c],
+					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+		}
+	}
+
+	if (!batch_mode && etbs.count) {
+		int c = 0;
+
+		for (c = 0; c < etbs.count; ++c) {
+			struct vidc_frame_data *frame_data = &etbs.data[c];
+
+			rc = call_hfi_op(hdev, session_etb, inst->session,
+					frame_data);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed to issue etb: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			log_frame(inst, frame_data,
+					V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+		}
+	}
+
+	if (!batch_mode && ftbs.count) {
+		int c = 0;
+
+		for (c = 0; atomic_read(&inst->seq_hdr_reqs) > 0; ++c) {
+			rc = request_seq_header(inst, &ftbs.data[c]);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed requesting sequence header: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			atomic_dec(&inst->seq_hdr_reqs);
+		}
+
+		for (; c < ftbs.count; ++c) {
+			struct vidc_frame_data *frame_data = &ftbs.data[c];
+
+			rc = call_hfi_op(hdev, session_ftb,
+					inst->session, frame_data);
+			if (rc) {
+				dprintk(VIDC_ERR, "Failed to issue ftb: %d\n",
+						rc);
+				goto err_bad_input;
+			}
+
+			log_frame(inst, frame_data,
+					V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+		}
+	}
+
+err_bad_input:
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to queue buffer\n");
+
+	kfree(etbs.data);
+	kfree(ftbs.data);
+err_no_mem:
+	return rc;
+}
+
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
+{
+	int rc = 0, i = 0;
+	union hal_get_property hprop;
+
+	rc = msm_comm_try_get_prop(inst, HAL_PARAM_GET_BUFFER_REQUIREMENTS,
+					&hprop);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed getting buffer requirements: %d", rc);
+		return rc;
+	}
+
+	dprintk(VIDC_DBG, "Buffer requirements:\n");
+	dprintk(VIDC_DBG, "%15s %8s %8s\n", "buffer type", "count", "size");
+	for (i = 0; i < HAL_BUFFER_MAX; i++) {
+		struct hal_buffer_requirements req = hprop.buf_req.buffer[i];
+
+		inst->buff_req.buffer[i] = req;
+		dprintk(VIDC_DBG, "%15s %8d %8d\n",
+				get_buffer_name(req.buffer_type),
+				req.buffer_count_actual, req.buffer_size);
+	}
+
+	dprintk(VIDC_PROF, "Input buffers: %d, Output buffers: %d\n",
+			inst->buff_req.buffer[0].buffer_count_actual,
+			inst->buff_req.buffer[1].buffer_count_actual);
+	return rc;
+}
+
+int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
+				union hal_get_property *hprop)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct getprop_buf *buf;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	mutex_lock(&inst->sync_lock);
+	if (inst->state < MSM_VIDC_OPEN_DONE ||
+			inst->state >= MSM_VIDC_CLOSE) {
+
+		/* No need to check inst->state == MSM_VIDC_INVALID since
+		 * INVALID is > CLOSE_DONE. When core went to INVALID state,
+		 * we put all the active instances in INVALID. So > CLOSE_DONE
+		 * is enough check to have.
+		 */
+
+		dprintk(VIDC_ERR,
+			"In Wrong state to call Buf Req: Inst %pK or Core %pK\n",
+				inst, inst->core);
+		rc = -EAGAIN;
+		mutex_unlock(&inst->sync_lock);
+		goto exit;
+	}
+	mutex_unlock(&inst->sync_lock);
+
+	init_completion(&inst->completions[
+			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)]);
+	switch (ptype) {
+	case HAL_PARAM_PROFILE_LEVEL_CURRENT:
+	case HAL_CONFIG_VDEC_ENTROPY:
+		rc = call_hfi_op(hdev, session_get_property, inst->session,
+				ptype);
+		break;
+	case HAL_PARAM_GET_BUFFER_REQUIREMENTS:
+		rc = call_hfi_op(hdev, session_get_buf_req, inst->session);
+		break;
+	default:
+		rc = -EAGAIN;
+		break;
+	}
+
+	if (rc) {
+		dprintk(VIDC_ERR, "Can't query hardware for property: %d\n",
+				rc);
+		goto exit;
+	}
+
+	rc = wait_for_completion_timeout(&inst->completions[
+			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)],
+		msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
+	if (!rc) {
+		dprintk(VIDC_ERR,
+			"%s: Wait interrupted or timed out [%pK]: %d\n",
+			__func__, inst,
+			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO));
+		inst->state = MSM_VIDC_CORE_INVALID;
+		msm_comm_kill_session(inst);
+		WARN_ON(msm_vidc_debug_timeout);
+		rc = -ETIMEDOUT;
+		goto exit;
+	} else {
+		/* wait_for_completion_timeout returns jiffies before expiry */
+		rc = 0;
+	}
+
+	mutex_lock(&inst->pending_getpropq.lock);
+	if (!list_empty(&inst->pending_getpropq.list)) {
+		buf = list_first_entry(&inst->pending_getpropq.list,
+					struct getprop_buf, list);
+		*hprop = *(union hal_get_property *)buf->data;
+		kfree(buf->data);
+		list_del(&buf->list);
+		kfree(buf);
+	} else {
+		dprintk(VIDC_ERR, "%s getprop list empty\n", __func__);
+		rc = -EINVAL;
+	}
+	mutex_unlock(&inst->pending_getpropq.lock);
+exit:
+	return rc;
+}
+
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_smem *handle;
+	struct internal_buf *buf, *dummy;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->outputbufs.lock);
+	if (list_empty(&inst->outputbufs.list)) {
+		dprintk(VIDC_DBG, "%s - No OUTPUT buffers allocated\n",
+			__func__);
+		mutex_unlock(&inst->outputbufs.lock);
+		return 0;
+	}
+	mutex_unlock(&inst->outputbufs.lock);
+
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+	mutex_lock(&inst->outputbufs.lock);
+	list_for_each_entry_safe(buf, dummy, &inst->outputbufs.list, list) {
+		handle = buf->handle;
+		if (!handle) {
+			dprintk(VIDC_ERR, "%s - invalid handle\n", __func__);
+			goto exit;
+		}
+
+		buffer_info.buffer_size = handle->size;
+		buffer_info.buffer_type = buf->buffer_type;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = handle->device_addr;
+		if (inst->buffer_mode_set[CAPTURE_PORT] ==
+			HAL_BUFFER_MODE_STATIC &&
+			inst->state != MSM_VIDC_CORE_INVALID &&
+				core->state != VIDC_CORE_INVALID) {
+			buffer_info.response_required = false;
+			rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Rel output buf fail:%pa, %d\n",
+					&buffer_info.align_device_addr,
+					buffer_info.buffer_size);
+			}
+		}
+
+		list_del(&buf->list);
+		msm_comm_smem_free(inst, buf->handle);
+		kfree(buf);
+	}
+
+exit:
+	mutex_unlock(&inst->outputbufs.lock);
+	return rc;
+}
+
+static enum hal_buffer scratch_buf_sufficient(struct msm_vidc_inst *inst,
+				enum hal_buffer buffer_type)
+{
+	struct hal_buffer_requirements *bufreq = NULL;
+	struct internal_buf *buf;
+	int count = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+		goto not_sufficient;
+	}
+
+	bufreq = get_buff_req_buffer(inst, buffer_type);
+	if (!bufreq)
+		goto not_sufficient;
+
+	/* Check if current scratch buffers are sufficient */
+	mutex_lock(&inst->scratchbufs.lock);
+
+	list_for_each_entry(buf, &inst->scratchbufs.list, list) {
+		if (!buf->handle) {
+			dprintk(VIDC_ERR, "%s: invalid buf handle\n", __func__);
+			mutex_unlock(&inst->scratchbufs.lock);
+			goto not_sufficient;
+		}
+		if (buf->buffer_type == buffer_type &&
+			buf->handle->size >= bufreq->buffer_size)
+			count++;
+	}
+	mutex_unlock(&inst->scratchbufs.lock);
+
+	if (count != bufreq->buffer_count_actual)
+		goto not_sufficient;
+
+	dprintk(VIDC_DBG,
+		"Existing scratch buffer is sufficient for buffer type %#x\n",
+		buffer_type);
+
+	return buffer_type;
+
+not_sufficient:
+	return HAL_BUFFER_NONE;
+}
+
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
+					bool check_for_reuse)
+{
+	struct msm_smem *handle;
+	struct internal_buf *buf, *dummy;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+	enum hal_buffer sufficiency = HAL_BUFFER_NONE;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+
+	if (check_for_reuse) {
+		sufficiency |= scratch_buf_sufficient(inst,
+					HAL_BUFFER_INTERNAL_SCRATCH);
+
+		sufficiency |= scratch_buf_sufficient(inst,
+					HAL_BUFFER_INTERNAL_SCRATCH_1);
+
+		sufficiency |= scratch_buf_sufficient(inst,
+					HAL_BUFFER_INTERNAL_SCRATCH_2);
+	}
+
+	mutex_lock(&inst->scratchbufs.lock);
+	list_for_each_entry_safe(buf, dummy, &inst->scratchbufs.list, list) {
+		if (!buf->handle) {
+			dprintk(VIDC_ERR, "%s - buf->handle NULL\n", __func__);
+			rc = -EINVAL;
+			goto exit;
+		}
+
+		handle = buf->handle;
+		buffer_info.buffer_size = handle->size;
+		buffer_info.buffer_type = buf->buffer_type;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = handle->device_addr;
+		if (inst->state != MSM_VIDC_CORE_INVALID &&
+				core->state != VIDC_CORE_INVALID) {
+			buffer_info.response_required = true;
+			init_completion(&inst->completions[SESSION_MSG_INDEX
+			   (HAL_SESSION_RELEASE_BUFFER_DONE)]);
+			rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Rel scrtch buf fail:%pa, %d\n",
+					&buffer_info.align_device_addr,
+					buffer_info.buffer_size);
+			}
+			mutex_unlock(&inst->scratchbufs.lock);
+			rc = wait_for_sess_signal_receipt(inst,
+				HAL_SESSION_RELEASE_BUFFER_DONE);
+			if (rc) {
+				change_inst_state(inst,
+					MSM_VIDC_CORE_INVALID);
+				msm_comm_kill_session(inst);
+			}
+			mutex_lock(&inst->scratchbufs.lock);
+		}
+
+		/*If scratch buffers can be reused, do not free the buffers*/
+		if (sufficiency & buf->buffer_type)
+			continue;
+
+		list_del(&buf->list);
+		msm_comm_smem_free(inst, buf->handle);
+		kfree(buf);
+	}
+
+exit:
+	mutex_unlock(&inst->scratchbufs.lock);
+	return rc;
+}
+
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst)
+{
+	struct msm_smem *handle;
+	struct list_head *ptr, *next;
+	struct internal_buf *buf;
+	struct vidc_buffer_addr_info buffer_info;
+	int rc = 0;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst->persistbufs.lock);
+	list_for_each_safe(ptr, next, &inst->persistbufs.list) {
+		buf = list_entry(ptr, struct internal_buf, list);
+		handle = buf->handle;
+		buffer_info.buffer_size = handle->size;
+		buffer_info.buffer_type = buf->buffer_type;
+		buffer_info.num_buffers = 1;
+		buffer_info.align_device_addr = handle->device_addr;
+		if (inst->state != MSM_VIDC_CORE_INVALID &&
+				core->state != VIDC_CORE_INVALID) {
+			buffer_info.response_required = true;
+			init_completion(
+			   &inst->completions[SESSION_MSG_INDEX
+			   (HAL_SESSION_RELEASE_BUFFER_DONE)]);
+			rc = call_hfi_op(hdev, session_release_buffers,
+				(void *)inst->session, &buffer_info);
+			if (rc) {
+				dprintk(VIDC_WARN,
+					"Rel prst buf fail:%pa, %d\n",
+					&buffer_info.align_device_addr,
+					buffer_info.buffer_size);
+			}
+			mutex_unlock(&inst->persistbufs.lock);
+			rc = wait_for_sess_signal_receipt(inst,
+				HAL_SESSION_RELEASE_BUFFER_DONE);
+			if (rc) {
+				change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+				msm_comm_kill_session(inst);
+			}
+			mutex_lock(&inst->persistbufs.lock);
+		}
+		list_del(&buf->list);
+		msm_comm_smem_free(inst, buf->handle);
+		kfree(buf);
+	}
+	mutex_unlock(&inst->persistbufs.lock);
+	return rc;
+}
+
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, void *pdata)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid input: %pK\n", inst);
+		return -EINVAL;
+	}
+
+	if (!inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+	hdev = inst->core->device;
+
+	mutex_lock(&inst->sync_lock);
+	if (inst->state < MSM_VIDC_OPEN_DONE || inst->state >= MSM_VIDC_CLOSE) {
+		dprintk(VIDC_ERR, "Not in proper state to set property\n");
+		rc = -EAGAIN;
+		goto exit;
+	}
+	rc = call_hfi_op(hdev, session_set_property, (void *)inst->session,
+			ptype, pdata);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to set hal property for framesize\n");
+exit:
+	mutex_unlock(&inst->sync_lock);
+	return rc;
+}
+
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_comm_release_output_buffers(inst))
+		dprintk(VIDC_WARN, "Failed to release output buffers\n");
+
+	rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT);
+	if (rc)
+		goto error;
+	return rc;
+error:
+	msm_comm_release_output_buffers(inst);
+	return rc;
+}
+
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_comm_release_scratch_buffers(inst, true))
+		dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH,
+		&inst->scratchbufs);
+	if (rc)
+		goto error;
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_1,
+		&inst->scratchbufs);
+	if (rc)
+		goto error;
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_2,
+		&inst->scratchbufs);
+	if (rc)
+		goto error;
+
+	return rc;
+error:
+	msm_comm_release_scratch_buffers(inst, false);
+	return rc;
+}
+
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST,
+		&inst->persistbufs);
+	if (rc)
+		goto error;
+
+	rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST_1,
+		&inst->persistbufs);
+	if (rc)
+		goto error;
+	return rc;
+error:
+	msm_comm_release_persist_buffers(inst);
+	return rc;
+}
+
+static void msm_comm_flush_in_invalid_state(struct msm_vidc_inst *inst)
+{
+	struct list_head *ptr, *next;
+	enum vidc_ports ports[] = {OUTPUT_PORT, CAPTURE_PORT};
+	int c = 0;
+
+	for (c = 0; c < ARRAY_SIZE(ports); ++c) {
+		enum vidc_ports port = ports[c];
+
+		dprintk(VIDC_DBG, "Flushing buffers of type %d in bad state\n",
+				port);
+		mutex_lock(&inst->bufq[port].lock);
+		list_for_each_safe(ptr, next, &inst->bufq[port].
+				vb2_bufq.queued_list) {
+			struct vb2_buffer *vb = container_of(ptr,
+					struct vb2_buffer, queued_entry);
+
+			vb->planes[0].bytesused = 0;
+			vb->planes[0].data_offset = 0;
+
+			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+		}
+		mutex_unlock(&inst->bufq[port].lock);
+	}
+
+	msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
+}
+
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+	struct buffer_info *binfo = NULL;
+
+	if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+		return;
+
+	/*
+	 * dynamic buffer mode:- if flush is called during seek
+	 * driver should not queue any new buffer it has been holding.
+	 *
+	 * Each dynamic o/p buffer can have one of following ref_count:
+	 * ref_count : 0 - f/w has released reference and sent fbd back.
+	 *		  The buffer has been returned back to client.
+	 *
+	 * ref_count : 1 - f/w is holding reference. f/w may have released
+	 *                 fbd as read_only OR fbd is pending. f/w will
+	 *		  release reference before sending flush_done.
+	 *
+	 * ref_count : 2 - f/w is holding reference, f/w has released fbd as
+	 *                 read_only, which client has queued back to driver.
+	 *                 driver holds this buffer and will queue back
+	 *                 only when f/w releases the reference. During
+	 *		  flush_done, f/w will release the reference but driver
+	 *		  should not queue back the buffer to f/w.
+	 *		  Flush all buffers with ref_count 2.
+	 */
+	mutex_lock(&inst->registeredbufs.lock);
+	if (!list_empty(&inst->registeredbufs.list)) {
+		struct v4l2_event buf_event = {0};
+		u32 *ptr = NULL;
+
+		list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
+			if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+				atomic_read(&binfo->ref_count) == 2) {
+
+				atomic_dec(&binfo->ref_count);
+				buf_event.type =
+				V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER;
+				ptr = (u32 *)buf_event.u.data;
+				ptr[0] = binfo->fd[0];
+				ptr[1] = binfo->buff_off[0];
+				ptr[2] = binfo->uvaddr[0];
+				ptr[3] = (u32) binfo->timestamp.tv_sec;
+				ptr[4] = (u32) binfo->timestamp.tv_usec;
+				ptr[5] = binfo->v4l2_index;
+				dprintk(VIDC_DBG,
+					"released buffer held in driver before issuing flush: %pa fd[0]: %d\n",
+					&binfo->device_addr[0], binfo->fd[0]);
+				/*send event to client*/
+				v4l2_event_queue_fh(&inst->event_handler,
+					&buf_event);
+			}
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+}
+
+void msm_comm_flush_pending_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+	struct buffer_info *binfo = NULL;
+
+	if (!inst)
+		return;
+
+	if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+		return;
+
+	if (list_empty(&inst->pendingq.list) ||
+		list_empty(&inst->registeredbufs.list))
+		return;
+
+	/*
+	 * Dynamic Buffer mode - Since pendingq is not empty
+	 * no output buffers have been sent to firmware yet.
+	 * Hence remove reference to all pendingq o/p buffers
+	 * before flushing them.
+	 */
+
+	mutex_lock(&inst->registeredbufs.lock);
+	list_for_each_entry(binfo, &inst->registeredbufs.list, list) {
+		if (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			dprintk(VIDC_DBG,
+				"%s: binfo = %pK device_addr = %pa\n",
+				__func__, binfo, &binfo->device_addr[0]);
+			buf_ref_put(inst, binfo);
+		}
+	}
+	mutex_unlock(&inst->registeredbufs.lock);
+}
+
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
+{
+	int rc =  0;
+	bool ip_flush = false;
+	bool op_flush = false;
+	struct vb2_buf_entry *temp, *next;
+	struct mutex *lock;
+	struct msm_vidc_core *core;
+	struct hfi_device *hdev;
+
+	if (!inst) {
+		dprintk(VIDC_ERR,
+				"Invalid instance pointer = %pK\n", inst);
+		return -EINVAL;
+	}
+	core = inst->core;
+	if (!core) {
+		dprintk(VIDC_ERR,
+				"Invalid core pointer = %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (!hdev) {
+		dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev);
+		return -EINVAL;
+	}
+
+	ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
+	op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
+
+	if (ip_flush && !op_flush) {
+		dprintk(VIDC_INFO, "Input only flush not supported\n");
+		return 0;
+	}
+
+	msm_comm_flush_dynamic_buffers(inst);
+
+	if (inst->state == MSM_VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_INVALID ||
+			core->state == VIDC_CORE_UNINIT) {
+		dprintk(VIDC_ERR,
+				"Core %pK and inst %pK are in bad state\n",
+					core, inst);
+		msm_comm_flush_in_invalid_state(inst);
+		return 0;
+	}
+
+	if (inst->in_reconfig && !ip_flush && op_flush) {
+		mutex_lock(&inst->pendingq.lock);
+		if (!list_empty(&inst->pendingq.list)) {
+			/*
+			 * Execution can never reach here since port reconfig
+			 * wont happen unless pendingq is emptied out
+			 * (both pendingq and flush being secured with same
+			 * lock). Printing a message here incase this breaks.
+			 */
+			dprintk(VIDC_WARN,
+			"FLUSH BUG: Pending q not empty! It should be empty\n");
+		}
+		mutex_unlock(&inst->pendingq.lock);
+		atomic_inc(&inst->in_flush);
+		dprintk(VIDC_DBG, "Send flush Output to firmware\n");
+		rc = call_hfi_op(hdev, session_flush, inst->session,
+				HAL_FLUSH_OUTPUT);
+	} else {
+		msm_comm_flush_pending_dynamic_buffers(inst);
+		/*
+		 * If flush is called after queueing buffers but before
+		 * streamon driver should flush the pending queue
+		 */
+		mutex_lock(&inst->pendingq.lock);
+		list_for_each_entry_safe(temp, next,
+				&inst->pendingq.list, list) {
+			enum v4l2_buf_type type = temp->vb->type;
+
+			if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+				lock = &inst->bufq[CAPTURE_PORT].lock;
+			else
+				lock = &inst->bufq[OUTPUT_PORT].lock;
+
+			temp->vb->planes[0].bytesused = 0;
+
+			mutex_lock(lock);
+			vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
+			msm_vidc_debugfs_update(inst,
+				type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ?
+					MSM_VIDC_DEBUGFS_EVENT_FBD :
+					MSM_VIDC_DEBUGFS_EVENT_EBD);
+			list_del(&temp->list);
+			mutex_unlock(lock);
+
+			kfree(temp);
+		}
+		mutex_unlock(&inst->pendingq.lock);
+
+		/*Do not send flush in case of session_error */
+		if (!(inst->state == MSM_VIDC_CORE_INVALID &&
+			  core->state != VIDC_CORE_INVALID))
+			atomic_inc(&inst->in_flush);
+			dprintk(VIDC_DBG, "Send flush all to firmware\n");
+			rc = call_hfi_op(hdev, session_flush, inst->session,
+				HAL_FLUSH_ALL);
+	}
+
+	return rc;
+}
+
+
+enum hal_extradata_id msm_comm_get_hal_extradata_index(
+	enum v4l2_mpeg_vidc_extradata index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case V4L2_MPEG_VIDC_EXTRADATA_NONE:
+		ret = HAL_EXTRADATA_NONE;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION:
+		ret = HAL_EXTRADATA_MB_QUANTIZATION;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO:
+		ret = HAL_EXTRADATA_INTERLACE_VIDEO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP:
+		ret = HAL_EXTRADATA_VC1_FRAMEDISP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP:
+		ret = HAL_EXTRADATA_VC1_SEQDISP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP:
+		ret = HAL_EXTRADATA_TIMESTAMP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING:
+		ret = HAL_EXTRADATA_S3D_FRAME_PACKING;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE:
+		ret = HAL_EXTRADATA_FRAME_RATE;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW:
+		ret = HAL_EXTRADATA_PANSCAN_WINDOW;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI:
+		ret = HAL_EXTRADATA_RECOVERY_POINT_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
+		ret = HAL_EXTRADATA_MULTISLICE_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB:
+		ret = HAL_EXTRADATA_NUM_CONCEALED_MB;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER:
+		ret = HAL_EXTRADATA_METADATA_FILLER;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO:
+		ret = HAL_EXTRADATA_ASPECT_RATIO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP:
+		ret = HAL_EXTRADATA_INPUT_CROP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM:
+		ret = HAL_EXTRADATA_DIGITAL_ZOOM;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP:
+		ret = HAL_EXTRADATA_MPEG2_SEQDISP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA:
+		ret = HAL_EXTRADATA_STREAM_USERDATA;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP:
+		ret = HAL_EXTRADATA_FRAME_QP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO:
+		ret = HAL_EXTRADATA_FRAME_BITS_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_LTR:
+		ret = HAL_EXTRADATA_LTR_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
+		ret = HAL_EXTRADATA_METADATA_MBI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI:
+		ret = HAL_EXTRADATA_VQZIP_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS:
+		ret = HAL_EXTRADATA_YUV_STATS;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP:
+		ret = HAL_EXTRADATA_ROI_QP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP:
+		ret = HAL_EXTRADATA_OUTPUT_CROP;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI:
+		ret = HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI:
+		ret = HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY:
+		ret = HAL_EXTRADATA_VUI_DISPLAY_INFO;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE:
+		ret = HAL_EXTRADATA_VPX_COLORSPACE;
+		break;
+	case V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO:
+		ret = HAL_EXTRADATA_PQ_INFO;
+		break;
+	default:
+		dprintk(VIDC_WARN, "Extradata not found: %d\n", index);
+		break;
+	}
+	return ret;
+};
+
+enum hal_buffer_layout_type msm_comm_get_hal_buffer_layout(
+	enum v4l2_mpeg_vidc_video_mvc_layout index)
+{
+	int ret = 0;
+
+	switch (index) {
+	case V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL:
+		ret = HAL_BUFFER_LAYOUT_SEQ;
+		break;
+	case V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM:
+		ret = HAL_BUFFER_LAYOUT_TOP_BOTTOM;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+	enum hal_ssr_trigger_type type)
+{
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_WARN, "Invalid parameters: %pK\n", core);
+		return -EINVAL;
+	}
+	hdev = core->device;
+	if (core->state == VIDC_CORE_INIT_DONE)
+		rc = call_hfi_op(hdev, core_trigger_ssr,
+				hdev->hfi_device_data, type);
+	return rc;
+}
+
+static int msm_vidc_load_supported(struct msm_vidc_inst *inst)
+{
+	int num_mbs_per_sec = 0, max_load_adj = 0;
+	enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
+		LOAD_CALC_IGNORE_THUMBNAIL_LOAD |
+		LOAD_CALC_IGNORE_NON_REALTIME_LOAD;
+
+	if (inst->state == MSM_VIDC_OPEN_DONE) {
+		max_load_adj = inst->core->resources.max_load +
+			inst->capability.mbs_per_frame.max;
+		num_mbs_per_sec = msm_comm_get_load(inst->core,
+					MSM_VIDC_DECODER, quirks);
+		num_mbs_per_sec += msm_comm_get_load(inst->core,
+					MSM_VIDC_ENCODER, quirks);
+		if (num_mbs_per_sec > max_load_adj) {
+			dprintk(VIDC_ERR,
+				"H/W is overloaded. needed: %d max: %d\n",
+				num_mbs_per_sec,
+				max_load_adj);
+			msm_vidc_print_running_insts(inst->core);
+			return -EBUSY;
+		}
+	}
+	return 0;
+}
+
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst)
+{
+	u32 x_min, x_max, y_min, y_max;
+	u32 input_height, input_width, output_height, output_width;
+
+	input_height = inst->prop.height[OUTPUT_PORT];
+	input_width = inst->prop.width[OUTPUT_PORT];
+	output_height = inst->prop.height[CAPTURE_PORT];
+	output_width = inst->prop.width[CAPTURE_PORT];
+
+	if (!input_height || !input_width || !output_height || !output_width) {
+		dprintk(VIDC_ERR,
+			"Invalid : Input height = %d width = %d output height = %d width = %d\n",
+			input_height, input_width, output_height,
+			output_width);
+		return -ENOTSUPP;
+	}
+
+	if (!inst->capability.scale_x.min ||
+		!inst->capability.scale_x.max ||
+		!inst->capability.scale_y.min ||
+		!inst->capability.scale_y.max) {
+
+		if (input_width * input_height !=
+			output_width * output_height) {
+			dprintk(VIDC_ERR,
+				"%s: scaling is not supported (%dx%d != %dx%d)\n",
+				__func__, input_width, input_height,
+				output_width, output_height);
+			return -ENOTSUPP;
+		}
+		dprintk(VIDC_DBG, "%s: supported WxH = %dx%d\n",
+			__func__, input_width, input_height);
+		return 0;
+	}
+
+	x_min = (1<<16)/inst->capability.scale_x.min;
+	y_min = (1<<16)/inst->capability.scale_y.min;
+	x_max = inst->capability.scale_x.max >> 16;
+	y_max = inst->capability.scale_y.max >> 16;
+
+	if (input_height > output_height) {
+		if (input_height > x_min * output_height) {
+			dprintk(VIDC_ERR,
+				"Unsupported height downscale ratio %d vs %d\n",
+				input_height/output_height, x_min);
+			return -ENOTSUPP;
+		}
+	} else {
+		if (output_height > x_max * input_height) {
+			dprintk(VIDC_ERR,
+				"Unsupported height upscale ratio %d vs %d\n",
+				input_height/output_height, x_max);
+			return -ENOTSUPP;
+		}
+	}
+	if (input_width > output_width) {
+		if (input_width > y_min * output_width) {
+			dprintk(VIDC_ERR,
+				"Unsupported width downscale ratio %d vs %d\n",
+				input_width/output_width, y_min);
+			return -ENOTSUPP;
+		}
+	} else {
+		if (output_width > y_max * input_width) {
+			dprintk(VIDC_ERR,
+				"Unsupported width upscale ratio %d vs %d\n",
+				input_width/output_width, y_max);
+			return -ENOTSUPP;
+		}
+	}
+	return 0;
+}
+
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_capability *capability;
+	int rc = 0;
+	struct hfi_device *hdev;
+	struct msm_vidc_core *core;
+	int mbs_per_frame = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+	capability = &inst->capability;
+	hdev = inst->core->device;
+	core = inst->core;
+	rc = msm_vidc_load_supported(inst);
+	if (rc) {
+		change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+		msm_comm_kill_session(inst);
+		dprintk(VIDC_WARN,
+			"%s: Hardware is overloaded\n", __func__);
+		return rc;
+	}
+
+	if (!is_thermal_permissible(core)) {
+		dprintk(VIDC_WARN,
+			"Thermal level critical, stop all active sessions!\n");
+		return -ENOTSUPP;
+	}
+
+	if (!rc) {
+		if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
+			inst->prop.height[CAPTURE_PORT] <
+			capability->height.min) {
+			dprintk(VIDC_ERR,
+				"Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
+				inst->prop.width[CAPTURE_PORT],
+				inst->prop.height[CAPTURE_PORT],
+				capability->width.min,
+				capability->height.min);
+			rc = -ENOTSUPP;
+		}
+		if (!rc && inst->prop.width[CAPTURE_PORT] >
+			capability->width.max) {
+			dprintk(VIDC_ERR,
+				"Unsupported width = %u supported max width = %u",
+				inst->prop.width[CAPTURE_PORT],
+				capability->width.max);
+				rc = -ENOTSUPP;
+		}
+
+		if (!rc && inst->prop.height[CAPTURE_PORT] >
+			capability->height.max) {
+			dprintk(VIDC_ERR,
+				"Unsupported height = %u supported max height = %u",
+				inst->prop.height[CAPTURE_PORT],
+				capability->height.max);
+				rc = -ENOTSUPP;
+		}
+
+		mbs_per_frame = msm_comm_get_mbs_per_frame(inst);
+		if (!rc && mbs_per_frame > capability->mbs_per_frame.max) {
+			dprintk(VIDC_ERR,
+			"Unsupported mbs per frame = %u, max supported is - %u\n",
+			mbs_per_frame,
+			capability->mbs_per_frame.max);
+			rc = -ENOTSUPP;
+		}
+	}
+	if (rc) {
+		change_inst_state(inst, MSM_VIDC_CORE_INVALID);
+		msm_comm_kill_session(inst);
+		dprintk(VIDC_ERR,
+			"%s: Resolution unsupported\n", __func__);
+	}
+	return rc;
+}
+
+static void msm_comm_generate_session_error(struct msm_vidc_inst *inst)
+{
+	enum hal_command_response cmd = HAL_SESSION_ERROR;
+	struct msm_vidc_cb_cmd_done response = {0};
+
+	dprintk(VIDC_WARN, "msm_comm_generate_session_error\n");
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+
+	response.session_id = inst;
+	response.status = VIDC_ERR_FAIL;
+	handle_session_error(cmd, (void *)&response);
+}
+
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	enum hal_command_response cmd = HAL_SYS_ERROR;
+	struct msm_vidc_cb_cmd_done response  = {0};
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return;
+	}
+	core = inst->core;
+	response.device_id = (u32) core->id;
+	handle_sys_error(cmd, (void *) &response);
+
+}
+
+int msm_comm_kill_session(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__);
+		return -EINVAL;
+	} else if (!inst->session) {
+		/* There's no hfi session to kill */
+		return 0;
+	}
+
+	/*
+	 * We're internally forcibly killing the session, if fw is aware of
+	 * the session send session_abort to firmware to clean up and release
+	 * the session, else just kill the session inside the driver.
+	 */
+	if ((inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_CLOSE_DONE) ||
+			inst->state == MSM_VIDC_CORE_INVALID) {
+		rc = msm_comm_session_abort(inst);
+		if (rc == -EBUSY) {
+			msm_comm_generate_sys_error(inst);
+			return 0;
+		} else if (rc) {
+			return rc;
+		}
+		change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
+		msm_comm_generate_session_error(inst);
+	} else {
+		dprintk(VIDC_WARN,
+				"Inactive session %pK, triggering an internal session error\n",
+				inst);
+		msm_comm_generate_session_error(inst);
+
+	}
+
+	return rc;
+}
+
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+			size_t size, u32 align, u32 flags,
+			enum hal_buffer buffer_type, int map_kernel)
+{
+	struct msm_smem *m = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
+		return NULL;
+	}
+	m = msm_smem_alloc(inst->mem_client, size, align,
+				flags, buffer_type, map_kernel);
+	return m;
+}
+
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem)
+{
+	if (!inst || !inst->core || !mem) {
+		dprintk(VIDC_ERR,
+			"%s: invalid params: %pK %pK\n", __func__, inst, mem);
+		return;
+	}
+	msm_smem_free(inst->mem_client, mem);
+}
+
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+		struct msm_smem *mem, enum smem_cache_ops cache_ops)
+{
+	if (!inst || !mem) {
+		dprintk(VIDC_ERR,
+			"%s: invalid params: %pK %pK\n", __func__, inst, mem);
+		return -EINVAL;
+	}
+	return msm_smem_cache_operations(inst->mem_client, mem, cache_ops);
+}
+
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+			int fd, u32 offset, enum hal_buffer buffer_type)
+{
+	struct msm_smem *m = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s: invalid inst: %pK\n", __func__, inst);
+		return NULL;
+	}
+
+	if (inst->state == MSM_VIDC_CORE_INVALID) {
+		dprintk(VIDC_ERR, "Core in Invalid state, returning from %s\n",
+			__func__);
+		return NULL;
+	}
+
+	m = msm_smem_user_to_kernel(inst->mem_client,
+			fd, offset, buffer_type);
+	return m;
+}
+
+void msm_vidc_fw_unload_handler(struct work_struct *work)
+{
+	struct msm_vidc_core *core = NULL;
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	core = container_of(work, struct msm_vidc_core, fw_unload_work.work);
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "%s - invalid work or core handle\n",
+				__func__);
+		return;
+	}
+
+	hdev = core->device;
+
+	mutex_lock(&core->lock);
+	if (list_empty(&core->instances) &&
+		core->state != VIDC_CORE_UNINIT) {
+		if (core->state > VIDC_CORE_INIT) {
+			dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n");
+			rc = call_hfi_op(hdev, core_release,
+					hdev->hfi_device_data);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to release core, id = %d\n",
+					core->id);
+				mutex_unlock(&core->lock);
+				return;
+			}
+		}
+		core->state = VIDC_CORE_UNINIT;
+		kfree(core->capabilities);
+		core->capabilities = NULL;
+	}
+	mutex_unlock(&core->lock);
+}
+
+int msm_comm_set_color_format(struct msm_vidc_inst *inst,
+		enum hal_buffer buffer_type, int fourcc)
+{
+	struct hal_uncompressed_format_select hal_fmt = {0};
+	enum hal_uncompressed_format format = HAL_UNUSED_COLOR;
+	int rc = 0;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+
+	format = get_hal_uncompressed(fourcc);
+	if (format == HAL_UNUSED_COLOR) {
+		dprintk(VIDC_ERR, "Using unsupported colorformat %#x\n",
+				fourcc);
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
+	hal_fmt.buffer_type = buffer_type;
+	hal_fmt.format = format;
+
+	rc = call_hfi_op(hdev, session_set_property, inst->session,
+		HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, &hal_fmt);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to set input color format\n");
+	else
+		dprintk(VIDC_DBG, "Setting uncompressed colorformat to %#x\n",
+				format);
+
+exit:
+	return rc;
+}
+
+int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
+{
+	u32 property_id = 0;
+	u64 us_per_frame = 0;
+	void *pdata;
+	int rc = 0, fps = 0;
+	struct hal_frame_rate frame_rate;
+	struct hfi_device *hdev;
+
+	if (!inst || !inst->core || !inst->core->device || !a) {
+		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	hdev = inst->core->device;
+	property_id = HAL_CONFIG_FRAME_RATE;
+
+	if (a->parm.output.timeperframe.denominator) {
+		switch (a->type) {
+		case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+			us_per_frame = a->parm.output.timeperframe.numerator *
+				(u64)USEC_PER_SEC;
+			do_div(us_per_frame, a->parm.output.
+				timeperframe.denominator);
+			break;
+		default:
+			dprintk(VIDC_ERR,
+					"Scale clocks : Unknown buffer type %d\n",
+					a->type);
+			break;
+		}
+	}
+
+	if (!us_per_frame) {
+		dprintk(VIDC_ERR,
+				"Failed to scale clocks : time between frames is 0\n");
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	fps = USEC_PER_SEC;
+	do_div(fps, us_per_frame);
+
+	if (fps % 15 == 14 || fps % 24 == 23)
+		fps = fps + 1;
+	else if ((fps > 1) && (fps % 24 == 1 || fps % 15 == 1))
+		fps = fps - 1;
+
+	if (inst->prop.fps != fps) {
+		dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
+				inst, inst->prop.fps, fps);
+		inst->prop.fps = fps;
+		frame_rate.frame_rate = inst->prop.fps * BIT(16);
+		frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
+		pdata = &frame_rate;
+		if (inst->session_type == MSM_VIDC_ENCODER) {
+			rc = call_hfi_op(hdev, session_set_property,
+				inst->session, property_id, pdata);
+
+			if (rc)
+				dprintk(VIDC_WARN,
+					"Failed to set frame rate %d\n", rc);
+		} else {
+			msm_dcvs_init_load(inst);
+		}
+		msm_comm_scale_clocks_and_bus(inst);
+	}
+exit:
+	return rc;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.h
new file mode 100644
index 0000000..9b71709
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.h
@@ -0,0 +1,103 @@
+/*Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MSM_VIDC_COMMON_H_
+#define _MSM_VIDC_COMMON_H_
+#include "msm_vidc_internal.h"
+struct vb2_buf_entry {
+	struct list_head list;
+	struct vb2_buffer *vb;
+};
+
+extern const char *const mpeg_video_vidc_extradata[];
+
+enum load_calc_quirks {
+	LOAD_CALC_NO_QUIRKS = 0,
+	LOAD_CALC_IGNORE_TURBO_LOAD = 1 << 0,
+	LOAD_CALC_IGNORE_THUMBNAIL_LOAD = 1 << 1,
+	LOAD_CALC_IGNORE_NON_REALTIME_LOAD = 1 << 2,
+};
+
+struct msm_vidc_core *get_vidc_core(int core_id);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+	const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
+struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+	struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct buf_queue *msm_comm_get_vb2q(
+		struct msm_vidc_inst *inst, enum v4l2_buf_type type);
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_try_set_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, void *pdata);
+int msm_comm_try_get_prop(struct msm_vidc_inst *inst,
+	enum hal_property ptype, union hal_get_property *hprop);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb);
+void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
+int msm_comm_scale_clocks(struct msm_vidc_core *core);
+int msm_comm_scale_clocks_load(struct msm_vidc_core *core,
+		int num_mbs_per_sec, enum load_calc_quirks quirks);
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst);
+int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
+int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
+					bool check_for_reuse);
+int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
+int msm_comm_release_output_buffers(struct msm_vidc_inst *inst);
+int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
+int msm_comm_suspend(int core_id);
+enum hal_extradata_id msm_comm_get_hal_extradata_index(
+	enum v4l2_mpeg_vidc_extradata index);
+enum hal_buffer_layout_type msm_comm_get_hal_buffer_layout(
+	enum v4l2_mpeg_vidc_video_mvc_layout index);
+struct hal_buffer_requirements *get_buff_req_buffer(
+			struct msm_vidc_inst *inst, u32 buffer_type);
+#define IS_PRIV_CTRL(idx) (\
+		(V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_MPEG) && \
+		V4L2_CTRL_DRIVER_PRIV(idx))
+void msm_comm_session_clean(struct msm_vidc_inst *inst);
+int msm_comm_kill_session(struct msm_vidc_inst *inst);
+enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
+enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
+struct msm_smem *msm_comm_smem_alloc(struct msm_vidc_inst *inst,
+			size_t size, u32 align, u32 flags,
+			enum hal_buffer buffer_type, int map_kernel);
+void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem);
+int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
+		struct msm_smem *mem, enum smem_cache_ops cache_ops);
+struct msm_smem *msm_comm_smem_user_to_kernel(struct msm_vidc_inst *inst,
+			int fd, u32 offset, enum hal_buffer buffer_type);
+enum hal_video_codec get_hal_codec(int fourcc);
+enum hal_domain get_hal_domain(int session_type);
+int msm_comm_check_core_init(struct msm_vidc_core *core);
+int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
+			enum load_calc_quirks quirks);
+int msm_comm_get_load(struct msm_vidc_core *core,
+			enum session_type type, enum load_calc_quirks quirks);
+int msm_comm_set_color_format(struct msm_vidc_inst *inst,
+		enum hal_buffer buffer_type, int fourcc);
+int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl);
+int msm_comm_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl);
+int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id);
+int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
+		struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
+		const struct v4l2_ctrl_ops *ctrl_ops);
+int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst);
+void msm_comm_cleanup_internal_buffers(struct msm_vidc_inst *inst);
+int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a);
+bool msm_comm_turbo_session(struct msm_vidc_inst *inst);
+struct msm_vidc_inst *get_inst(struct msm_vidc_core *core, void *session_id);
+void put_inst(struct msm_vidc_inst *inst);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.c
new file mode 100644
index 0000000..ac338e1
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.c
@@ -0,0 +1,703 @@
+/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_vidc_common.h"
+#include "vidc_hfi_api.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dcvs.h"
+
+#define IS_VALID_DCVS_SESSION(__cur_mbpf, __min_mbpf) \
+		((__cur_mbpf) >= (__min_mbpf))
+
+static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst);
+static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst);
+static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst);
+static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd);
+
+static inline int msm_dcvs_get_mbs_per_frame(struct msm_vidc_inst *inst)
+{
+	int height, width;
+
+	if (!inst->in_reconfig) {
+		height = max(inst->prop.height[CAPTURE_PORT],
+				inst->prop.height[OUTPUT_PORT]);
+		width = max(inst->prop.width[CAPTURE_PORT],
+				inst->prop.width[OUTPUT_PORT]);
+	} else {
+		height = inst->reconfig_height;
+		width = inst->reconfig_width;
+	}
+
+	return NUM_MBS_PER_FRAME(height, width);
+}
+
+static inline int msm_dcvs_count_active_instances(struct msm_vidc_core *core)
+{
+	int active_instances = 0;
+	struct msm_vidc_inst *inst = NULL;
+
+	if (!core) {
+		dprintk(VIDC_ERR, "%s: Invalid args: %pK\n", __func__, core);
+		return -EINVAL;
+	}
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (inst->state >= MSM_VIDC_OPEN_DONE &&
+			inst->state < MSM_VIDC_STOP_DONE)
+			active_instances++;
+	}
+	mutex_unlock(&core->lock);
+	return active_instances;
+}
+
+static bool msm_dcvs_check_codec_supported(int fourcc,
+		unsigned long codecs_supported, enum session_type type)
+{
+	int codec_bit, session_type_bit;
+	bool codec_type, session_type;
+	unsigned long session;
+
+	session = VIDC_VOTE_DATA_SESSION_VAL(get_hal_codec(fourcc),
+		get_hal_domain(type));
+
+	if (!codecs_supported || !session)
+		return false;
+
+	/* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
+	codec_bit = ffs(session) - 1;
+	session_type_bit = codec_bit + 1;
+
+	codec_type =
+		test_bit(codec_bit, &codecs_supported) ==
+		test_bit(codec_bit, &session);
+	session_type =
+		test_bit(session_type_bit, &codecs_supported) ==
+		test_bit(session_type_bit, &session);
+
+	return codec_type && session_type;
+}
+
+static void msm_dcvs_update_dcvs_params(int idx, struct msm_vidc_inst *inst)
+{
+	struct dcvs_stats *dcvs = NULL;
+	struct msm_vidc_platform_resources *res = NULL;
+	struct dcvs_table *table = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	dcvs = &inst->dcvs;
+	res = &inst->core->resources;
+	table = res->dcvs_tbl;
+
+	dcvs->load_low = table[idx].load_low;
+	dcvs->load_high = table[idx].load_high;
+	dcvs->supported_codecs = table[idx].supported_codecs;
+}
+
+static void msm_dcvs_enc_check_and_scale_clocks(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (inst->session_type == MSM_VIDC_ENCODER && msm_vidc_enc_dcvs_mode) {
+		inst->dcvs_mode = msm_dcvs_check_supported(inst);
+		dprintk(VIDC_DBG, "%s: session DCVS %s supported\n",
+				__func__, inst->dcvs_mode ? "" : "not");
+
+		if (inst->dcvs_mode) {
+			rc = msm_dcvs_enc_scale_clocks(inst);
+			if (rc) {
+				dprintk(VIDC_DBG,
+				"ENC_DCVS: error while scaling clocks\n");
+			}
+		}
+	}
+}
+
+static void msm_dcvs_dec_check_and_scale_clocks(struct msm_vidc_inst *inst)
+{
+	int rc = 0;
+
+	if (inst->session_type != MSM_VIDC_DECODER || !msm_vidc_dec_dcvs_mode)
+		return;
+
+	if (msm_dcvs_check_supported(inst)) {
+		inst->dcvs_mode = true;
+		dprintk(VIDC_DBG,
+			"%s: session DCVS supported, decode_dcvs_mode = %d\n",
+			__func__, inst->dcvs_mode);
+	} else {
+		inst->dcvs_mode = false;
+		dprintk(VIDC_DBG,
+			"%s: session DCVS not supported, decode_dcvs_mode = %d\n",
+			__func__, inst->dcvs_mode);
+	}
+
+	if (msm_vidc_dec_dcvs_mode && inst->dcvs_mode) {
+		msm_dcvs_monitor_buffer(inst);
+		rc = msm_dcvs_dec_scale_clocks(inst, false);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to scale clocks in DCVS: %d\n",
+				__func__, rc);
+		}
+	}
+}
+
+void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	if (is_etb)
+		msm_dcvs_enc_check_and_scale_clocks(inst);
+	else
+		msm_dcvs_dec_check_and_scale_clocks(inst);
+}
+
+static inline int get_pending_bufs_fw(struct msm_vidc_inst *inst)
+{
+	int fw_out_qsize = 0, buffers_in_driver = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->state >= MSM_VIDC_OPEN_DONE &&
+		inst->state < MSM_VIDC_STOP_DONE) {
+		fw_out_qsize = inst->count.ftb - inst->count.fbd;
+		buffers_in_driver = inst->buffers_held_in_driver;
+	}
+
+	return fw_out_qsize + buffers_in_driver;
+}
+
+static inline void msm_dcvs_print_dcvs_stats(struct dcvs_stats *dcvs)
+{
+	dprintk(VIDC_DBG,
+		"DCVS: Load_Low %d, Load High %d\n",
+		dcvs->load_low,
+		dcvs->load_high);
+
+	dprintk(VIDC_DBG,
+		"DCVS: ThrDispBufLow %d, ThrDispBufHigh %d\n",
+		dcvs->threshold_disp_buf_low,
+		dcvs->threshold_disp_buf_high);
+
+	dprintk(VIDC_DBG,
+		"DCVS: min_threshold %d, max_threshold %d\n",
+		dcvs->min_threshold, dcvs->max_threshold);
+}
+
+void msm_dcvs_init_load(struct msm_vidc_inst *inst)
+{
+	struct msm_vidc_core *core;
+	struct hal_buffer_requirements *output_buf_req;
+	struct dcvs_stats *dcvs;
+	struct dcvs_table *table;
+	struct msm_vidc_platform_resources *res = NULL;
+	int i, num_rows, fourcc;
+
+	dprintk(VIDC_DBG, "Init DCVS Load\n");
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	core = inst->core;
+	dcvs = &inst->dcvs;
+	res = &core->resources;
+	dcvs->load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+
+	num_rows = res->dcvs_tbl_size;
+	table = res->dcvs_tbl;
+
+	if (!num_rows || !table) {
+		dprintk(VIDC_ERR,
+				"%s: Dcvs table entry not found.\n", __func__);
+		return;
+	}
+
+	fourcc = inst->session_type == MSM_VIDC_DECODER ?
+				inst->fmts[OUTPUT_PORT].fourcc :
+				inst->fmts[CAPTURE_PORT].fourcc;
+
+	for (i = 0; i < num_rows; i++) {
+		bool matches = msm_dcvs_check_codec_supported(
+					fourcc,
+					table[i].supported_codecs,
+					inst->session_type);
+		if (!matches)
+			continue;
+
+		if (dcvs->load > table[i].load) {
+			msm_dcvs_update_dcvs_params(i, inst);
+			break;
+		}
+	}
+
+	if (inst->session_type == MSM_VIDC_ENCODER)
+		goto print_stats;
+
+	output_buf_req = get_buff_req_buffer(inst,
+		msm_comm_get_hal_output_buffer(inst));
+
+	if (!output_buf_req) {
+		dprintk(VIDC_ERR,
+			"%s: No buffer requirement for buffer type %x\n",
+			__func__, HAL_BUFFER_OUTPUT);
+		return;
+	}
+
+	dcvs->transition_turbo = false;
+
+	/* calculating the min and max threshold */
+	if (output_buf_req->buffer_count_actual) {
+		dcvs->min_threshold = output_buf_req->buffer_count_actual -
+			output_buf_req->buffer_count_min -
+			msm_dcvs_get_extra_buff_count(inst) + 1;
+		dcvs->max_threshold = output_buf_req->buffer_count_actual;
+		if (dcvs->max_threshold <= dcvs->min_threshold)
+			dcvs->max_threshold =
+				dcvs->min_threshold + DCVS_BUFFER_SAFEGUARD;
+		dcvs->threshold_disp_buf_low = dcvs->min_threshold;
+		dcvs->threshold_disp_buf_high = dcvs->max_threshold;
+	}
+
+print_stats:
+	msm_dcvs_print_dcvs_stats(dcvs);
+}
+
+void msm_dcvs_init(struct msm_vidc_inst *inst)
+{
+	dprintk(VIDC_DBG, "Init DCVS Struct\n");
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+
+	inst->dcvs = (struct dcvs_stats){ {0} };
+	inst->dcvs.threshold_disp_buf_high = DCVS_NOMINAL_THRESHOLD;
+	inst->dcvs.threshold_disp_buf_low = DCVS_TURBO_THRESHOLD;
+}
+
+void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst)
+{
+	int new_ftb, i, prev_buf_count;
+	int fw_pending_bufs, total_output_buf, buffers_outside_fw;
+	struct dcvs_stats *dcvs;
+	struct hal_buffer_requirements *output_buf_req;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		return;
+	}
+	dcvs = &inst->dcvs;
+
+	mutex_lock(&inst->lock);
+	output_buf_req = get_buff_req_buffer(inst,
+				msm_comm_get_hal_output_buffer(inst));
+	if (!output_buf_req) {
+		dprintk(VIDC_ERR, "%s : Get output buffer req failed %pK\n",
+			__func__, inst);
+		mutex_unlock(&inst->lock);
+		return;
+	}
+
+	total_output_buf = output_buf_req->buffer_count_actual;
+	fw_pending_bufs = get_pending_bufs_fw(inst);
+	mutex_unlock(&inst->lock);
+
+	buffers_outside_fw = total_output_buf - fw_pending_bufs;
+	dcvs->num_ftb[dcvs->ftb_index] = buffers_outside_fw;
+	dcvs->ftb_index = (dcvs->ftb_index + 1) % DCVS_FTB_WINDOW;
+
+	if (dcvs->ftb_counter < DCVS_FTB_WINDOW)
+		dcvs->ftb_counter++;
+
+	dprintk(VIDC_PROF,
+		"DCVS: ftb_counter %d\n", dcvs->ftb_counter);
+
+	if (dcvs->ftb_counter == DCVS_FTB_WINDOW) {
+		new_ftb = 0;
+		for (i = 0; i < dcvs->ftb_counter; i++) {
+			if (dcvs->num_ftb[i] > new_ftb)
+				new_ftb = dcvs->num_ftb[i];
+		}
+
+		dcvs->threshold_disp_buf_high = new_ftb;
+		if (dcvs->threshold_disp_buf_high <=
+			dcvs->threshold_disp_buf_low +
+			DCVS_BUFFER_SAFEGUARD) {
+			dcvs->threshold_disp_buf_high =
+				dcvs->threshold_disp_buf_low +
+				DCVS_BUFFER_SAFEGUARD
+				+ (DCVS_BUFFER_SAFEGUARD == 0);
+		}
+
+		dcvs->threshold_disp_buf_high =
+			clamp(dcvs->threshold_disp_buf_high,
+				dcvs->min_threshold,
+				dcvs->max_threshold);
+	}
+
+	if (dcvs->ftb_counter == DCVS_FTB_WINDOW &&
+			dcvs->load == dcvs->load_low) {
+		prev_buf_count =
+			dcvs->num_ftb[((dcvs->ftb_index - 2 +
+				DCVS_FTB_WINDOW) % DCVS_FTB_WINDOW)];
+		if (prev_buf_count == dcvs->threshold_disp_buf_low &&
+			buffers_outside_fw <= dcvs->threshold_disp_buf_low) {
+			dcvs->transition_turbo = true;
+		} else if (buffers_outside_fw > dcvs->threshold_disp_buf_low &&
+			(buffers_outside_fw -
+			 (prev_buf_count - buffers_outside_fw))
+			< dcvs->threshold_disp_buf_low){
+			dcvs->transition_turbo = true;
+		}
+	}
+
+	dprintk(VIDC_PROF,
+		"DCVS: total_output_buf %d buffers_outside_fw %d load %d transition_turbo %d\n",
+		total_output_buf, buffers_outside_fw, dcvs->load_low,
+		dcvs->transition_turbo);
+}
+
+static int msm_dcvs_enc_scale_clocks(struct msm_vidc_inst *inst)
+{
+	int rc = 0, fw_pending_bufs = 0, total_input_buf = 0;
+	struct msm_vidc_core *core;
+	struct dcvs_stats *dcvs;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	dcvs = &inst->dcvs;
+
+	mutex_lock(&inst->lock);
+	total_input_buf = inst->buff_req.buffer[0].buffer_count_actual;
+	fw_pending_bufs = (inst->count.etb - inst->count.ebd);
+	mutex_unlock(&inst->lock);
+
+	dprintk(VIDC_PROF,
+		"DCVS: total_input_buf %d, fw_pending_bufs %d\n",
+		total_input_buf, fw_pending_bufs);
+
+	if (dcvs->etb_counter < total_input_buf) {
+		dcvs->etb_counter++;
+		if (dcvs->etb_counter != total_input_buf)
+			return rc;
+	}
+
+	dprintk(VIDC_PROF,
+		"DCVS: total_input_buf %d, fw_pending_bufs %d etb_counter %d  dcvs->load %d\n",
+		total_input_buf, fw_pending_bufs,
+		dcvs->etb_counter, dcvs->load);
+
+	if (fw_pending_bufs <= DCVS_ENC_LOW_THR &&
+		dcvs->load > dcvs->load_low) {
+		dcvs->load = dcvs->load_low;
+		dcvs->prev_freq_lowered = true;
+	} else {
+		dcvs->prev_freq_lowered = false;
+	}
+
+	if (fw_pending_bufs >= DCVS_ENC_HIGH_THR &&
+		dcvs->load <= dcvs->load_low) {
+		dcvs->load = dcvs->load_high;
+		dcvs->prev_freq_increased = true;
+	} else {
+		dcvs->prev_freq_increased = false;
+	}
+
+	if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
+		dprintk(VIDC_PROF,
+			"DCVS: (Scaling Clock %s)  etb clock set = %d total_input_buf = %d fw_pending_bufs %d\n",
+			dcvs->prev_freq_lowered ? "Lower" : "Higher",
+			dcvs->load, total_input_buf, fw_pending_bufs);
+
+		rc = msm_comm_scale_clocks_load(core, dcvs->load,
+				LOAD_CALC_NO_QUIRKS);
+		if (rc) {
+			dprintk(VIDC_PROF,
+				"Failed to set clock rate in FBD: %d\n", rc);
+		}
+	} else {
+		dprintk(VIDC_PROF,
+			"DCVS: etb clock load_old = %d total_input_buf = %d fw_pending_bufs %d\n",
+			dcvs->load, total_input_buf, fw_pending_bufs);
+	}
+
+	return rc;
+}
+
+
+/*
+ * In DCVS scale_clocks will be done both in qbuf and FBD
+ * 1 indicates call made from fbd that lowers clock
+ * 0 indicates call made from qbuf that increases clock
+ * based on DCVS algorithm
+ */
+
+static int msm_dcvs_dec_scale_clocks(struct msm_vidc_inst *inst, bool fbd)
+{
+	int rc = 0;
+	int fw_pending_bufs = 0;
+	int total_output_buf = 0;
+	int buffers_outside_fw = 0;
+	struct msm_vidc_core *core;
+	struct hal_buffer_requirements *output_buf_req;
+	struct dcvs_stats *dcvs;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+	dcvs = &inst->dcvs;
+	mutex_lock(&inst->lock);
+	fw_pending_bufs = get_pending_bufs_fw(inst);
+
+	output_buf_req = get_buff_req_buffer(inst,
+		msm_comm_get_hal_output_buffer(inst));
+	mutex_unlock(&inst->lock);
+	if (!output_buf_req) {
+		dprintk(VIDC_ERR,
+			"%s: No buffer requirement for buffer type %x\n",
+			__func__, HAL_BUFFER_OUTPUT);
+		return -EINVAL;
+	}
+
+	/* Total number of output buffers */
+	total_output_buf = output_buf_req->buffer_count_actual;
+
+	/* Buffers outside FW are with display */
+	buffers_outside_fw = total_output_buf - fw_pending_bufs;
+
+	if (buffers_outside_fw >= dcvs->threshold_disp_buf_high &&
+		!dcvs->prev_freq_increased &&
+		dcvs->load > dcvs->load_low) {
+		dcvs->load = dcvs->load_low;
+		dcvs->prev_freq_lowered = true;
+		dcvs->prev_freq_increased = false;
+	} else if (dcvs->transition_turbo && dcvs->load == dcvs->load_low) {
+		dcvs->load = dcvs->load_high;
+		dcvs->prev_freq_increased = true;
+		dcvs->prev_freq_lowered = false;
+		dcvs->transition_turbo = false;
+	} else {
+		dcvs->prev_freq_increased = false;
+		dcvs->prev_freq_lowered = false;
+	}
+
+	if (dcvs->prev_freq_lowered || dcvs->prev_freq_increased) {
+		dprintk(VIDC_PROF,
+			"DCVS: clock set = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
+			dcvs->load, total_output_buf, buffers_outside_fw,
+			dcvs->threshold_disp_buf_high, dcvs->transition_turbo);
+
+		rc = msm_comm_scale_clocks_load(core, dcvs->load,
+				LOAD_CALC_NO_QUIRKS);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set clock rate in FBD: %d\n", rc);
+		}
+	} else {
+		dprintk(VIDC_PROF,
+			"DCVS: clock old = %d tot_output_buf = %d buffers_outside_fw %d threshold_high %d transition_turbo %d\n",
+			dcvs->load, total_output_buf, buffers_outside_fw,
+			dcvs->threshold_disp_buf_high, dcvs->transition_turbo);
+	}
+	return rc;
+}
+
+static bool msm_dcvs_enc_check(struct msm_vidc_inst *inst)
+{
+	int num_mbs_per_frame = 0;
+	long int instance_load = 0;
+	long int dcvs_limit = 0;
+	bool dcvs_check_passed = false, is_codec_supported  = false;
+	struct msm_vidc_platform_resources *res = NULL;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
+		return dcvs_check_passed;
+	}
+
+	res = &inst->core->resources;
+	if (!res->dcvs_limit) {
+		dprintk(VIDC_ERR,
+			"%s Dcvs limit table uninitialized\n", __func__);
+		return false;
+	}
+
+	is_codec_supported =
+		msm_dcvs_check_codec_supported(
+				inst->fmts[CAPTURE_PORT].fourcc,
+				inst->dcvs.supported_codecs,
+				inst->session_type);
+
+	num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+	instance_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+	dcvs_limit =
+		(long int)res->dcvs_limit[inst->session_type].min_mbpf *
+		res->dcvs_limit[inst->session_type].fps;
+
+	if (msm_vidc_enc_dcvs_mode && is_codec_supported &&
+		inst->dcvs.is_power_save_mode &&
+		IS_VALID_DCVS_SESSION(num_mbs_per_frame,
+			res->dcvs_limit[inst->session_type].min_mbpf) &&
+		IS_VALID_DCVS_SESSION(instance_load, dcvs_limit)) {
+		dcvs_check_passed = true;
+	}
+	return dcvs_check_passed;
+}
+
+static bool msm_dcvs_check_supported(struct msm_vidc_inst *inst)
+{
+	int num_mbs_per_frame = 0, instance_count = 0;
+	long int instance_load = 0;
+	long int dcvs_limit = 0;
+	struct msm_vidc_inst *temp = NULL;
+	struct msm_vidc_core *core;
+	struct hal_buffer_requirements *output_buf_req;
+	struct dcvs_stats *dcvs;
+	bool is_codec_supported = false;
+	struct msm_vidc_platform_resources *res = NULL;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	core = inst->core;
+	dcvs = &inst->dcvs;
+	res = &core->resources;
+
+	if (!res->dcvs_limit) {
+		dprintk(VIDC_WARN,
+				"%s: dcvs limit table not found\n", __func__);
+		return false;
+	}
+	instance_count = msm_dcvs_count_active_instances(core);
+
+	if (instance_count == 1 && inst->session_type == MSM_VIDC_DECODER &&
+		!msm_comm_turbo_session(inst)) {
+		num_mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+		instance_load = msm_comm_get_inst_load(inst,
+			LOAD_CALC_NO_QUIRKS);
+		output_buf_req = get_buff_req_buffer(inst,
+			msm_comm_get_hal_output_buffer(inst));
+		dcvs_limit =
+			(long int)res->dcvs_limit[inst->session_type].min_mbpf *
+			res->dcvs_limit[inst->session_type].fps;
+		is_codec_supported =
+			msm_dcvs_check_codec_supported(
+					inst->fmts[OUTPUT_PORT].fourcc,
+					inst->dcvs.supported_codecs,
+					inst->session_type);
+		if (!is_codec_supported ||
+			!IS_VALID_DCVS_SESSION(num_mbs_per_frame,
+				res->dcvs_limit[inst->session_type].min_mbpf) ||
+			!IS_VALID_DCVS_SESSION(instance_load, dcvs_limit) ||
+			inst->seqchanged_count > 1)
+			return false;
+
+		if (!output_buf_req) {
+			dprintk(VIDC_ERR,
+				"%s: No buffer requirement for buffer type %x\n",
+				__func__, HAL_BUFFER_OUTPUT);
+			return false;
+		}
+	} else if (instance_count == 1 &&
+			inst->session_type == MSM_VIDC_ENCODER &&
+			!msm_comm_turbo_session(inst)) {
+		if (!msm_dcvs_enc_check(inst))
+			return false;
+	} else {
+		/*
+		 * For multiple instance use case with 4K, clocks will be scaled
+		 * as per load in streamon, but the clocks may be scaled
+		 * down as DCVS is running for first playback instance
+		 * Rescaling the core clock for multiple instance use case
+		 */
+		if (!dcvs->is_clock_scaled) {
+			if (!msm_comm_scale_clocks(core)) {
+				dcvs->is_clock_scaled = true;
+				dprintk(VIDC_DBG,
+					"%s: Scaled clocks = %d\n",
+					__func__, dcvs->is_clock_scaled);
+			} else {
+				dprintk(VIDC_DBG,
+					"%s: Failed to Scale clocks. Perf might be impacted\n",
+					__func__);
+			}
+		}
+		/*
+		 * For multiple instance use case turn OFF DCVS algorithm
+		 * immediately
+		 */
+		if (instance_count > 1) {
+			mutex_lock(&core->lock);
+			list_for_each_entry(temp, &core->instances, list)
+				temp->dcvs_mode = false;
+			mutex_unlock(&core->lock);
+		}
+
+		return false;
+	}
+
+	return true;
+}
+
+int msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst)
+{
+	int extra_buffer = 0;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+		return 0;
+	}
+
+	if (inst->session_type == MSM_VIDC_ENCODER) {
+		if (msm_dcvs_enc_check(inst))
+			extra_buffer = DCVS_ENC_EXTRA_OUTPUT_BUFFERS;
+	} else if (inst->session_type == MSM_VIDC_DECODER) {
+		if (msm_dcvs_check_supported(inst))
+			extra_buffer = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
+	}
+	return extra_buffer;
+}
+
+
+void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst,
+					bool is_power_save_mode)
+{
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+		return;
+	}
+
+	inst->dcvs.is_power_save_mode = is_power_save_mode;
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.h
new file mode 100644
index 0000000..0f4d69e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_dcvs.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _MSM_VIDC_DCVS_H_
+#define _MSM_VIDC_DCVS_H_
+#include "msm_vidc_internal.h"
+
+/* Low threshold for encoder dcvs */
+#define DCVS_ENC_LOW_THR 4
+/* High threshold for encoder dcvs */
+#define DCVS_ENC_HIGH_THR 9
+/* extra o/p buffers in case of encoder dcvs */
+#define DCVS_ENC_EXTRA_OUTPUT_BUFFERS 2
+/* extra o/p buffers in case of decoder dcvs */
+#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4
+/* Default threshold to reduce the core frequency */
+#define DCVS_NOMINAL_THRESHOLD 8
+/* Default threshold to increase the core frequency */
+#define DCVS_TURBO_THRESHOLD 4
+
+/* Considering one safeguard buffer */
+#define DCVS_BUFFER_SAFEGUARD (DCVS_DEC_EXTRA_OUTPUT_BUFFERS - 1)
+
+void msm_dcvs_init(struct msm_vidc_inst *inst);
+void msm_dcvs_init_load(struct msm_vidc_inst *inst);
+void msm_dcvs_monitor_buffer(struct msm_vidc_inst *inst);
+void msm_dcvs_check_and_scale_clocks(struct msm_vidc_inst *inst, bool is_etb);
+int  msm_dcvs_get_extra_buff_count(struct msm_vidc_inst *inst);
+void msm_dcvs_enc_set_power_save_mode(struct msm_vidc_inst *inst,
+		bool is_power_save_mode);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.c
new file mode 100644
index 0000000..57e84bc
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.c
@@ -0,0 +1,550 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 CREATE_TRACE_POINTS
+#include "msm_vidc_common.h"
+#define MAX_SSR_STRING_LEN 10
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_api.h"
+
+int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
+int msm_vidc_debug_out = VIDC_OUT_PRINTK;
+int msm_vidc_fw_debug = 0x18;
+int msm_vidc_fw_debug_mode = 1;
+int msm_vidc_fw_low_power_mode = 1;
+int msm_vidc_hw_rsp_timeout = 1000;
+bool msm_vidc_fw_coverage = true;
+bool msm_vidc_dec_dcvs_mode = true;
+bool msm_vidc_enc_dcvs_mode = true;
+bool msm_vidc_sys_idle_indicator = true;
+int msm_vidc_firmware_unload_delay = 15000;
+bool msm_vidc_thermal_mitigation_disabled = true;
+bool msm_vidc_bitrate_clock_scaling = 1;
+bool msm_vidc_debug_timeout = true;
+
+#define MAX_DBG_BUF_SIZE 4096
+
+#define DYNAMIC_BUF_OWNER(__binfo) ({ \
+	atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\
+})
+
+struct core_inst_pair {
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst;
+};
+
+static int core_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static u32 write_str(char *buffer,
+		size_t size, const char *fmt, ...)
+{
+	va_list args;
+	u32 len;
+
+	va_start(args, fmt);
+	len = vscnprintf(buffer, size, fmt, args);
+	va_end(args);
+	return len;
+}
+
+static ssize_t core_info_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct msm_vidc_core *core = file->private_data;
+	struct hfi_device *hdev;
+	struct hal_fw_info fw_info = { {0} };
+	char *dbuf, *cur, *end;
+	int i = 0, rc = 0;
+	ssize_t len = 0;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core);
+		return 0;
+	}
+
+	dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL);
+	if (!dbuf) {
+		dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
+		return -ENOMEM;
+	}
+	cur = dbuf;
+	end = cur + MAX_DBG_BUF_SIZE;
+	hdev = core->device;
+
+	cur += write_str(cur, end - cur, "===============================\n");
+	cur += write_str(cur, end - cur, "CORE %d: %pK\n", core->id, core);
+	cur += write_str(cur, end - cur, "===============================\n");
+	cur += write_str(cur, end - cur, "Core state: %d\n", core->state);
+	rc = call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data, &fw_info);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to read FW info\n");
+		goto err_fw_info;
+	}
+
+	cur += write_str(cur, end - cur,
+		"FW version : %s\n", &fw_info.version);
+	cur += write_str(cur, end - cur,
+		"base addr: 0x%x\n", fw_info.base_addr);
+	cur += write_str(cur, end - cur,
+		"register_base: 0x%x\n", fw_info.register_base);
+	cur += write_str(cur, end - cur,
+		"register_size: %u\n", fw_info.register_size);
+	cur += write_str(cur, end - cur, "irq: %u\n", fw_info.irq);
+
+err_fw_info:
+	for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
+		cur += write_str(cur, end - cur, "completions[%d]: %s\n", i,
+			completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
+			"pending" : "done");
+	}
+	len = simple_read_from_buffer(buf, count, ppos,
+			dbuf, cur - dbuf);
+
+	kfree(dbuf);
+	return len;
+}
+
+static const struct file_operations core_info_fops = {
+	.open = core_info_open,
+	.read = core_info_read,
+};
+
+static int trigger_ssr_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *ppos) {
+	unsigned long ssr_trigger_val = 0;
+	int rc = 0;
+	struct msm_vidc_core *core = filp->private_data;
+	size_t size = MAX_SSR_STRING_LEN;
+	char kbuf[MAX_SSR_STRING_LEN + 1] = {0};
+
+	if (!count)
+		goto exit;
+
+	if (count < size)
+		size = count;
+
+	if (copy_from_user(kbuf, buf, size)) {
+		dprintk(VIDC_WARN, "%s User memory fault\n", __func__);
+		rc = -EFAULT;
+		goto exit;
+	}
+
+	rc = kstrtoul(kbuf, 0, &ssr_trigger_val);
+	if (rc) {
+		dprintk(VIDC_WARN, "returning error err %d\n", rc);
+		rc = -EINVAL;
+	} else {
+		msm_vidc_trigger_ssr(core, ssr_trigger_val);
+		rc = count;
+	}
+exit:
+	return rc;
+}
+
+static const struct file_operations ssr_fops = {
+	.open = trigger_ssr_open,
+	.write = trigger_ssr_write,
+};
+
+struct dentry *msm_vidc_debugfs_init_drv(void)
+{
+	bool ok = false;
+	struct dentry *dir = NULL;
+
+	dir = debugfs_create_dir("msm_vidc", NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		dir = NULL;
+		goto failed_create_dir;
+	}
+
+#define __debugfs_create(__type, __name, __value) ({                          \
+	struct dentry *f = debugfs_create_##__type(__name, 0644, \
+		dir, __value);                                                \
+	if (IS_ERR_OR_NULL(f)) {                                              \
+		dprintk(VIDC_ERR, "Failed creating debugfs file '%pd/%s'\n",  \
+			dir, __name);                                         \
+		f = NULL;                                                     \
+	}                                                                     \
+	f;                                                                    \
+})
+
+	ok =
+	__debugfs_create(x32, "debug_level", &msm_vidc_debug) &&
+	__debugfs_create(x32, "fw_level", &msm_vidc_fw_debug) &&
+	__debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) &&
+	__debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) &&
+	__debugfs_create(bool, "dcvs_dec_mode", &msm_vidc_dec_dcvs_mode) &&
+	__debugfs_create(bool, "dcvs_enc_mode", &msm_vidc_enc_dcvs_mode) &&
+	__debugfs_create(u32, "fw_low_power_mode",
+			&msm_vidc_fw_low_power_mode) &&
+	__debugfs_create(u32, "debug_output", &msm_vidc_debug_out) &&
+	__debugfs_create(u32, "hw_rsp_timeout", &msm_vidc_hw_rsp_timeout) &&
+	__debugfs_create(bool, "sys_idle_indicator",
+			&msm_vidc_sys_idle_indicator) &&
+	__debugfs_create(u32, "firmware_unload_delay",
+			&msm_vidc_firmware_unload_delay) &&
+	__debugfs_create(bool, "disable_thermal_mitigation",
+			&msm_vidc_thermal_mitigation_disabled) &&
+	__debugfs_create(bool, "bitrate_clock_scaling",
+			&msm_vidc_bitrate_clock_scaling) &&
+	__debugfs_create(bool, "debug_timeout",
+			&msm_vidc_debug_timeout);
+
+#undef __debugfs_create
+
+	if (!ok)
+		goto failed_create_dir;
+
+	return dir;
+
+failed_create_dir:
+	if (dir)
+		debugfs_remove_recursive(vidc_driver->debugfs_root);
+
+	return NULL;
+}
+
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+		struct dentry *parent)
+{
+	struct dentry *dir = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+
+	if (!core) {
+		dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core);
+		goto failed_create_dir;
+	}
+
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (!dir) {
+		dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+		goto failed_create_dir;
+	}
+
+	if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+	if (!debugfs_create_file("trigger_ssr", 0200,
+			dir, core, &ssr_fops)) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_dir;
+	}
+failed_create_dir:
+	return dir;
+}
+
+static int inst_info_open(struct inode *inode, struct file *file)
+{
+	dprintk(VIDC_INFO, "Open inode ptr: %pK\n", inode->i_private);
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static int publish_unreleased_reference(struct msm_vidc_inst *inst,
+		char **dbuf, char *end)
+{
+	char *cur = *dbuf;
+	struct buffer_info *temp = NULL;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+		cur += write_str(cur, end - cur, "Pending buffer references\n");
+
+		mutex_lock(&inst->registeredbufs.lock);
+		list_for_each_entry(temp, &inst->registeredbufs.list, list) {
+			if (temp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+			!temp->inactive && atomic_read(&temp->ref_count)) {
+				cur += write_str(cur, end - cur,
+					"\tpending buffer: %#lx fd[0] = %d ref_count = %d held by: %s\n",
+					temp->device_addr[0],
+					temp->fd[0],
+					atomic_read(&temp->ref_count),
+					DYNAMIC_BUF_OWNER(temp));
+			}
+		}
+		mutex_unlock(&inst->registeredbufs.lock);
+	}
+
+	*dbuf = cur;
+	return 0;
+}
+
+static void put_inst_helper(struct kref *kref)
+{
+	struct msm_vidc_inst *inst = container_of(kref,
+			struct msm_vidc_inst, kref);
+
+	msm_vidc_destroy(inst);
+}
+
+static ssize_t inst_info_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct core_inst_pair *idata = file->private_data;
+	struct msm_vidc_core *core;
+	struct msm_vidc_inst *inst, *temp = NULL;
+	char *dbuf, *cur, *end;
+	int i, j;
+	ssize_t len = 0;
+
+	if (!idata || !idata->core || !idata->inst) {
+		dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+		return 0;
+	}
+
+	core = idata->core;
+	inst = idata->inst;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(temp, &core->instances, list) {
+		if (temp == inst)
+			break;
+	}
+	inst = ((temp == inst) && kref_get_unless_zero(&inst->kref)) ?
+		inst : NULL;
+	mutex_unlock(&core->lock);
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "%s: Instance has become obsolete", __func__);
+		return 0;
+	}
+
+	dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL);
+	if (!dbuf) {
+		dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
+		len = -ENOMEM;
+		goto failed_alloc;
+	}
+	cur = dbuf;
+	end = cur + MAX_DBG_BUF_SIZE;
+
+	cur += write_str(cur, end - cur, "==============================\n");
+	cur += write_str(cur, end - cur, "INSTANCE: %pK (%s)\n", inst,
+		inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
+	cur += write_str(cur, end - cur, "==============================\n");
+	cur += write_str(cur, end - cur, "core: %pK\n", inst->core);
+	cur += write_str(cur, end - cur, "height: %d\n",
+		inst->prop.height[CAPTURE_PORT]);
+	cur += write_str(cur, end - cur, "width: %d\n",
+		inst->prop.width[CAPTURE_PORT]);
+	cur += write_str(cur, end - cur, "fps: %d\n", inst->prop.fps);
+	cur += write_str(cur, end - cur, "state: %d\n", inst->state);
+	cur += write_str(cur, end - cur, "secure: %d\n",
+		!!(inst->flags & VIDC_SECURE));
+	cur += write_str(cur, end - cur, "-----------Formats-------------\n");
+	for (i = 0; i < MAX_PORT_NUM; i++) {
+		cur += write_str(cur, end - cur, "capability: %s\n",
+			i == OUTPUT_PORT ? "Output" : "Capture");
+		cur += write_str(cur, end - cur, "name : %s\n",
+			inst->fmts[i].name);
+		cur += write_str(cur, end - cur, "planes : %d\n",
+			inst->fmts[i].num_planes);
+		cur += write_str(cur, end - cur,
+			"type: %s\n", inst->fmts[i].type == OUTPUT_PORT ?
+			"Output" : "Capture");
+
+		switch (inst->buffer_mode_set[i]) {
+		case HAL_BUFFER_MODE_STATIC:
+			cur += write_str(cur, end - cur,
+				"buffer mode : %s\n", "static");
+			break;
+		case HAL_BUFFER_MODE_RING:
+			cur += write_str(cur, end - cur,
+				"buffer mode : %s\n", "ring");
+			break;
+		case HAL_BUFFER_MODE_DYNAMIC:
+			cur += write_str(cur, end - cur,
+				"buffer mode : %s\n", "dynamic");
+			break;
+		default:
+			cur += write_str(cur, end - cur,
+				"buffer mode : unsupported\n");
+		}
+
+		cur += write_str(cur, end - cur, "count: %u\n",
+				inst->bufq[i].vb2_bufq.num_buffers);
+
+		for (j = 0; j < inst->fmts[i].num_planes; j++)
+			cur += write_str(cur, end - cur,
+			"size for plane %d: %u\n", j,
+			inst->bufq[i].plane_sizes[j]);
+
+		if (i < MAX_PORT_NUM - 1)
+			cur += write_str(cur, end - cur, "\n");
+	}
+	cur += write_str(cur, end - cur, "-------------------------------\n");
+	for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
+		cur += write_str(cur, end - cur, "completions[%d]: %s\n", i,
+		completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
+		"pending" : "done");
+	}
+
+	cur += write_str(cur, end - cur, "ETB Count: %d\n", inst->count.etb);
+	cur += write_str(cur, end - cur, "EBD Count: %d\n", inst->count.ebd);
+	cur += write_str(cur, end - cur, "FTB Count: %d\n", inst->count.ftb);
+	cur += write_str(cur, end - cur, "FBD Count: %d\n", inst->count.fbd);
+
+	publish_unreleased_reference(inst, &cur, end);
+	len = simple_read_from_buffer(buf, count, ppos,
+		dbuf, cur - dbuf);
+
+	kfree(dbuf);
+failed_alloc:
+	kref_put(&inst->kref, put_inst_helper);
+	return len;
+}
+
+static int inst_info_release(struct inode *inode, struct file *file)
+{
+	dprintk(VIDC_INFO, "Release inode ptr: %pK\n", inode->i_private);
+	file->private_data = NULL;
+	return 0;
+}
+
+static const struct file_operations inst_info_fops = {
+	.open = inst_info_open,
+	.read = inst_info_read,
+	.release = inst_info_release,
+};
+
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+		struct dentry *parent)
+{
+	struct dentry *dir = NULL, *info = NULL;
+	char debugfs_name[MAX_DEBUGFS_NAME];
+	struct core_inst_pair *idata = NULL;
+
+	if (!inst) {
+		dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst);
+		goto exit;
+	}
+	snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%pK", inst);
+
+	idata = kzalloc(sizeof(struct core_inst_pair), GFP_KERNEL);
+	if (!idata) {
+		dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
+		goto exit;
+	}
+
+	idata->core = inst->core;
+	idata->inst = inst;
+
+	dir = debugfs_create_dir(debugfs_name, parent);
+	if (!dir) {
+		dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
+		goto failed_create_dir;
+	}
+
+	info = debugfs_create_file("info", 0444, dir,
+			idata, &inst_info_fops);
+	if (!info) {
+		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+		goto failed_create_file;
+	}
+
+	dir->d_inode->i_private = info->d_inode->i_private;
+	inst->debug.pdata[FRAME_PROCESSING].sampling = true;
+	return dir;
+
+failed_create_file:
+	debugfs_remove_recursive(dir);
+	dir = NULL;
+failed_create_dir:
+	kfree(idata);
+exit:
+	return dir;
+}
+
+void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst)
+{
+	struct dentry *dentry = NULL;
+
+	if (!inst || !inst->debugfs_root)
+		return;
+
+	dentry = inst->debugfs_root;
+	if (dentry->d_inode) {
+		dprintk(VIDC_INFO, "Destroy %pK\n", dentry->d_inode->i_private);
+		kfree(dentry->d_inode->i_private);
+		dentry->d_inode->i_private = NULL;
+	}
+	debugfs_remove_recursive(dentry);
+	inst->debugfs_root = NULL;
+}
+
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+	enum msm_vidc_debugfs_event e)
+{
+	struct msm_vidc_debug *d = &inst->debug;
+	char a[64] = "Frame processing";
+
+	switch (e) {
+	case MSM_VIDC_DEBUGFS_EVENT_ETB:
+		mutex_lock(&inst->lock);
+		inst->count.etb++;
+		mutex_unlock(&inst->lock);
+		if (inst->count.ebd && inst->count.ftb > inst->count.fbd) {
+			d->pdata[FRAME_PROCESSING].name[0] = '\0';
+			tic(inst, FRAME_PROCESSING, a);
+		}
+	break;
+	case MSM_VIDC_DEBUGFS_EVENT_EBD:
+		mutex_lock(&inst->lock);
+		inst->count.ebd++;
+		mutex_unlock(&inst->lock);
+		if (inst->count.ebd && inst->count.ebd == inst->count.etb) {
+			toc(inst, FRAME_PROCESSING);
+			dprintk(VIDC_PROF, "EBD: FW needs input buffers\n");
+		}
+		if (inst->count.ftb == inst->count.fbd)
+			dprintk(VIDC_PROF, "EBD: FW needs output buffers\n");
+	break;
+	case MSM_VIDC_DEBUGFS_EVENT_FTB: {
+		inst->count.ftb++;
+		if (inst->count.ebd && inst->count.etb > inst->count.ebd) {
+			d->pdata[FRAME_PROCESSING].name[0] = '\0';
+			tic(inst, FRAME_PROCESSING, a);
+		}
+	}
+	break;
+	case MSM_VIDC_DEBUGFS_EVENT_FBD:
+		inst->debug.samples++;
+		if (inst->count.ebd && inst->count.fbd == inst->count.ftb) {
+			toc(inst, FRAME_PROCESSING);
+			dprintk(VIDC_PROF, "FBD: FW needs output buffers\n");
+		}
+		if (inst->count.etb == inst->count.ebd)
+			dprintk(VIDC_PROF, "FBD: FW needs input buffers\n");
+		break;
+	default:
+		dprintk(VIDC_ERR, "Invalid state in debugfs: %d\n", e);
+		break;
+	}
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.h
new file mode 100644
index 0000000..9b75c72
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_debug.h
@@ -0,0 +1,184 @@
+/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_VIDC_DEBUG__
+#define __MSM_VIDC_DEBUG__
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include "msm_vidc_internal.h"
+#include "trace/events/msm_vidc.h"
+
+#ifndef VIDC_DBG_LABEL
+#define VIDC_DBG_LABEL "msm_vidc"
+#endif
+
+#define VIDC_DBG_TAG VIDC_DBG_LABEL ": %4s: "
+#define VIDC_DBG_WARN_ENABLE (msm_vidc_debug & VIDC_INFO)
+
+/* To enable messages OR these values and
+ * echo the result to debugfs file.
+ *
+ * To enable all messages set debug_level = 0x101F
+ */
+
+enum vidc_msg_prio {
+	VIDC_ERR  = 0x0001,
+	VIDC_WARN = 0x0002,
+	VIDC_INFO = 0x0004,
+	VIDC_DBG  = 0x0008,
+	VIDC_PROF = 0x0010,
+	VIDC_PKT  = 0x0020,
+	VIDC_FW   = 0x1000,
+};
+
+enum vidc_msg_out {
+	VIDC_OUT_PRINTK = 0,
+	VIDC_OUT_FTRACE,
+};
+
+enum msm_vidc_debugfs_event {
+	MSM_VIDC_DEBUGFS_EVENT_ETB,
+	MSM_VIDC_DEBUGFS_EVENT_EBD,
+	MSM_VIDC_DEBUGFS_EVENT_FTB,
+	MSM_VIDC_DEBUGFS_EVENT_FBD,
+};
+
+extern int msm_vidc_debug;
+extern int msm_vidc_debug_out;
+extern int msm_vidc_fw_debug;
+extern int msm_vidc_fw_debug_mode;
+extern int msm_vidc_fw_low_power_mode;
+extern int msm_vidc_hw_rsp_timeout;
+extern bool msm_vidc_fw_coverage;
+extern int msm_vidc_vpe_csc_601_to_709;
+extern bool msm_vidc_dec_dcvs_mode;
+extern bool msm_vidc_enc_dcvs_mode;
+extern bool msm_vidc_sys_idle_indicator;
+extern int msm_vidc_firmware_unload_delay;
+extern bool msm_vidc_thermal_mitigation_disabled;
+extern bool msm_vidc_bitrate_clock_scaling;
+extern bool msm_vidc_debug_timeout;
+
+static inline char *VIDC_MSG_PRIO2STRING(int __level)
+{
+	char *__str;
+
+	switch (__level) {
+	case VIDC_ERR:
+		__str = "err";
+		break;
+	case VIDC_WARN:
+		__str = "warn";
+		break;
+	case VIDC_INFO:
+		__str = "info";
+		break;
+	case VIDC_DBG:
+		__str = "dbg";
+		break;
+	case VIDC_PROF:
+		__str = "prof";
+		break;
+	case VIDC_PKT:
+		__str = "pkt";
+		break;
+	case VIDC_FW:
+		__str = "fw";
+		break;
+	default:
+		__str = "????";
+		break;
+	}
+	return __str;
+}
+
+#define dprintk(__level, __fmt, arg...)	\
+	do { \
+		if (msm_vidc_debug & __level) { \
+			if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \
+				pr_info(VIDC_DBG_TAG __fmt, \
+						VIDC_MSG_PRIO2STRING(__level), \
+						## arg); \
+			} else if (msm_vidc_debug_out == VIDC_OUT_FTRACE) { \
+				trace_printk(KERN_DEBUG VIDC_DBG_TAG __fmt, \
+						VIDC_MSG_PRIO2STRING(__level), \
+						## arg); \
+			} \
+		} \
+	} while (0)
+
+
+
+struct dentry *msm_vidc_debugfs_init_drv(void);
+struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
+		struct dentry *parent);
+struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
+		struct dentry *parent);
+void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst);
+void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
+		enum msm_vidc_debugfs_event e);
+
+static inline void tic(struct msm_vidc_inst *i, enum profiling_points p,
+				 char *b)
+{
+	struct timeval __ddl_tv;
+
+	if (!i->debug.pdata[p].name[0])
+		memcpy(i->debug.pdata[p].name, b, 64);
+	if ((msm_vidc_debug & VIDC_PROF) &&
+		i->debug.pdata[p].sampling) {
+		do_gettimeofday(&__ddl_tv);
+		i->debug.pdata[p].start =
+			(__ddl_tv.tv_sec * 1000) + (__ddl_tv.tv_usec / 1000);
+			i->debug.pdata[p].sampling = false;
+	}
+}
+
+static inline void toc(struct msm_vidc_inst *i, enum profiling_points p)
+{
+	struct timeval __ddl_tv;
+
+	if ((msm_vidc_debug & VIDC_PROF) &&
+		!i->debug.pdata[p].sampling) {
+		do_gettimeofday(&__ddl_tv);
+		i->debug.pdata[p].stop = (__ddl_tv.tv_sec * 1000)
+			+ (__ddl_tv.tv_usec / 1000);
+		i->debug.pdata[p].cumulative += i->debug.pdata[p].stop -
+			i->debug.pdata[p].start;
+		i->debug.pdata[p].sampling = true;
+	}
+}
+
+static inline void show_stats(struct msm_vidc_inst *i)
+{
+	int x;
+
+	for (x = 0; x < MAX_PROFILING_POINTS; x++) {
+		if (i->debug.pdata[x].name[0] &&
+				(msm_vidc_debug & VIDC_PROF)) {
+			if (i->debug.samples) {
+				dprintk(VIDC_PROF, "%s averaged %d ms/sample\n",
+						i->debug.pdata[x].name,
+						i->debug.pdata[x].cumulative /
+						i->debug.samples);
+			}
+
+			dprintk(VIDC_PROF, "%s Samples: %d\n",
+					i->debug.pdata[x].name,
+					i->debug.samples);
+		}
+	}
+}
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
new file mode 100644
index 0000000..177e09c
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h
@@ -0,0 +1,382 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 _MSM_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/atomic.h>
+#include <linux/list.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/kref.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/msm_vidc.h>
+#include <media/msm_media_info.h>
+
+#include "vidc_hfi_api.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1)
+#define MAX_DEBUGFS_NAME 50
+#define DEFAULT_TIMEOUT 3
+#define DEFAULT_HEIGHT 1088
+#define DEFAULT_WIDTH 1920
+#define MIN_SUPPORTED_WIDTH 32
+#define MIN_SUPPORTED_HEIGHT 32
+#define DEFAULT_FPS 15
+
+/* Maintains the number of FTB's between each FBD over a window */
+#define DCVS_FTB_WINDOW 32
+
+#define V4L2_EVENT_VIDC_BASE  10
+
+#define SYS_MSG_START HAL_SYS_INIT_DONE
+#define SYS_MSG_END HAL_SYS_ERROR
+#define SESSION_MSG_START HAL_SESSION_EVENT_CHANGE
+#define SESSION_MSG_END HAL_SESSION_ERROR
+#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
+#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
+
+
+#define MAX_NAME_LENGTH 64
+
+#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0)
+
+#define NUM_MBS_PER_SEC(__height, __width, __fps) \
+	(NUM_MBS_PER_FRAME(__height, __width) * __fps)
+
+#define NUM_MBS_PER_FRAME(__height, __width) \
+	((ALIGN(__height, 16) / 16) * (ALIGN(__width, 16) / 16))
+
+enum vidc_ports {
+	OUTPUT_PORT,
+	CAPTURE_PORT,
+	MAX_PORT_NUM
+};
+
+enum vidc_core_state {
+	VIDC_CORE_UNINIT = 0,
+	VIDC_CORE_INIT,
+	VIDC_CORE_INIT_DONE,
+	VIDC_CORE_INVALID
+};
+
+/* Do not change the enum values unless
+ * you know what you are doing
+ */
+enum instance_state {
+	MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
+	MSM_VIDC_CORE_INIT,
+	MSM_VIDC_CORE_INIT_DONE,
+	MSM_VIDC_OPEN,
+	MSM_VIDC_OPEN_DONE,
+	MSM_VIDC_LOAD_RESOURCES,
+	MSM_VIDC_LOAD_RESOURCES_DONE,
+	MSM_VIDC_START,
+	MSM_VIDC_START_DONE,
+	MSM_VIDC_STOP,
+	MSM_VIDC_STOP_DONE,
+	MSM_VIDC_RELEASE_RESOURCES,
+	MSM_VIDC_RELEASE_RESOURCES_DONE,
+	MSM_VIDC_CLOSE,
+	MSM_VIDC_CLOSE_DONE,
+	MSM_VIDC_CORE_UNINIT,
+	MSM_VIDC_CORE_INVALID
+};
+
+struct buf_info {
+	struct list_head list;
+	struct vb2_buffer *buf;
+};
+
+struct msm_vidc_list {
+	struct list_head list;
+	struct mutex lock;
+};
+
+static inline void INIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist)
+{
+	mutex_init(&mlist->lock);
+	INIT_LIST_HEAD(&mlist->list);
+}
+
+enum buffer_owner {
+	DRIVER,
+	FIRMWARE,
+	CLIENT,
+	MAX_OWNER
+};
+
+struct internal_buf {
+	struct list_head list;
+	enum hal_buffer buffer_type;
+	struct msm_smem *handle;
+	enum buffer_owner buffer_ownership;
+};
+
+struct msm_vidc_format {
+	char name[MAX_NAME_LENGTH];
+	u8 description[32];
+	u32 fourcc;
+	int num_planes;
+	int type;
+	u32 (*get_frame_size)(int plane, u32 height, u32 width);
+};
+
+struct msm_vidc_drv {
+	struct mutex lock;
+	struct list_head cores;
+	int num_cores;
+	struct dentry *debugfs_root;
+	int thermal_level;
+	u32 platform_version;
+	u32 capability_version;
+};
+
+struct msm_video_device {
+	int type;
+	struct video_device vdev;
+};
+
+struct session_prop {
+	u32 width[MAX_PORT_NUM];
+	u32 height[MAX_PORT_NUM];
+	u32 fps;
+	u32 bitrate;
+};
+
+struct buf_queue {
+	struct vb2_queue vb2_bufq;
+	struct mutex lock;
+	unsigned int plane_sizes[VB2_MAX_PLANES];
+	int num_planes;
+};
+
+
+enum profiling_points {
+	SYS_INIT = 0,
+	SESSION_INIT,
+	LOAD_RESOURCES,
+	FRAME_PROCESSING,
+	FW_IDLE,
+	MAX_PROFILING_POINTS,
+};
+
+struct buf_count {
+	int etb;
+	int ftb;
+	int fbd;
+	int ebd;
+};
+
+struct dcvs_stats {
+	int num_ftb[DCVS_FTB_WINDOW];
+	bool transition_turbo;
+	int ftb_index;
+	int ftb_counter;
+	bool prev_freq_lowered;
+	bool prev_freq_increased;
+	int threshold_disp_buf_high;
+	int threshold_disp_buf_low;
+	int load;
+	int load_low;
+	int load_high;
+	int min_threshold;
+	int max_threshold;
+	bool is_clock_scaled;
+	int etb_counter;
+	bool is_power_save_mode;
+	u32 supported_codecs;
+};
+
+struct profile_data {
+	int start;
+	int stop;
+	int cumulative;
+	char name[64];
+	int sampling;
+	int average;
+};
+
+struct msm_vidc_debug {
+	struct profile_data pdata[MAX_PROFILING_POINTS];
+	int profile;
+	int samples;
+};
+
+enum msm_vidc_modes {
+	VIDC_SECURE = BIT(0),
+	VIDC_TURBO = BIT(1),
+	VIDC_THUMBNAIL = BIT(2),
+	VIDC_LOW_POWER = BIT(3),
+};
+
+struct msm_vidc_core {
+	struct list_head list;
+	struct mutex lock;
+	int id;
+	struct hfi_device *device;
+	struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
+	struct v4l2_device v4l2_dev;
+	struct list_head instances;
+	struct dentry *debugfs_root;
+	enum vidc_core_state state;
+	struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+	enum msm_vidc_hfi_type hfi_type;
+	struct msm_vidc_platform_resources resources;
+	u32 enc_codec_supported;
+	u32 dec_codec_supported;
+	u32 codec_count;
+	struct msm_vidc_capability *capabilities;
+	struct delayed_work fw_unload_work;
+	bool smmu_fault_handled;
+};
+
+struct msm_vidc_inst {
+	struct list_head list;
+	struct mutex sync_lock, lock;
+	struct msm_vidc_core *core;
+	enum session_type session_type;
+	void *session;
+	struct session_prop prop;
+	enum instance_state state;
+	struct msm_vidc_format fmts[MAX_PORT_NUM];
+	struct buf_queue bufq[MAX_PORT_NUM];
+	struct msm_vidc_list pendingq;
+	struct msm_vidc_list scratchbufs;
+	struct msm_vidc_list persistbufs;
+	struct msm_vidc_list pending_getpropq;
+	struct msm_vidc_list outputbufs;
+	struct msm_vidc_list registeredbufs;
+	struct buffer_requirements buff_req;
+	void *mem_client;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+	struct v4l2_ctrl **cluster;
+	struct v4l2_fh event_handler;
+	struct msm_smem *extradata_handle;
+	bool in_reconfig;
+	u32 reconfig_width;
+	u32 reconfig_height;
+	u32 seqchanged_count;
+	struct dentry *debugfs_root;
+	void *priv;
+	struct msm_vidc_debug debug;
+	struct buf_count count;
+	struct dcvs_stats dcvs;
+	enum msm_vidc_modes flags;
+	struct msm_vidc_capability capability;
+	u32 buffer_size_limit;
+	enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
+	atomic_t seq_hdr_reqs;
+	struct v4l2_ctrl **ctrls;
+	bool dcvs_mode;
+	enum msm_vidc_pixel_depth bit_depth;
+	struct kref kref;
+	unsigned long instant_bitrate;
+	u32 buffers_held_in_driver;
+	atomic_t in_flush;
+	u32 pic_struct;
+	u32 colour_space;
+};
+
+extern struct msm_vidc_drv *vidc_driver;
+
+struct msm_vidc_ctrl_cluster {
+	struct v4l2_ctrl **cluster;
+	struct list_head list;
+};
+
+struct msm_vidc_ctrl {
+	u32 id;
+	char name[MAX_NAME_LENGTH];
+	enum v4l2_ctrl_type type;
+	s32 minimum;
+	s32 maximum;
+	s32 default_value;
+	u32 step;
+	u32 menu_skip_mask;
+	u32 flags;
+	const char * const *qmenu;
+};
+
+void handle_cmd_response(enum hal_command_response cmd, void *data);
+int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
+	enum hal_ssr_trigger_type type);
+int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
+int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
+void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+
+struct buffer_info {
+	struct list_head list;
+	int type;
+	int num_planes;
+	int fd[VIDEO_MAX_PLANES];
+	int buff_off[VIDEO_MAX_PLANES];
+	int size[VIDEO_MAX_PLANES];
+	unsigned long uvaddr[VIDEO_MAX_PLANES];
+	ion_phys_addr_t device_addr[VIDEO_MAX_PLANES];
+	struct msm_smem *handle[VIDEO_MAX_PLANES];
+	enum v4l2_memory memory;
+	u32 v4l2_index;
+	bool pending_deletion;
+	atomic_t ref_count;
+	bool dequeued;
+	bool inactive;
+	bool mapped[VIDEO_MAX_PLANES];
+	int same_fd_ref[VIDEO_MAX_PLANES];
+	struct timeval timestamp;
+};
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_list *buf_list,
+				ion_phys_addr_t device_addr);
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+				struct buffer_info *binfo);
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo);
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+			struct buffer_info *binfo);
+
+void msm_comm_handle_thermal_event(void);
+void *msm_smem_new_client(enum smem_type mtype,
+		void *platform_resources, enum session_type stype);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
+		enum hal_buffer buffer_type, int map_kernel);
+void msm_smem_free(void *clt, struct msm_smem *mem);
+void msm_smem_delete_client(void *clt);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+		enum smem_cache_ops);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+				enum hal_buffer buffer_type);
+struct context_bank_info *msm_smem_get_context_bank(void *clt,
+		bool is_secure, enum hal_buffer buffer_type);
+void msm_vidc_fw_unload_handler(struct work_struct *work);
+bool msm_smem_compare_buffers(void *clt, int fd, void *priv);
+/* XXX: normally should be in msm_vidc.h, but that's meant for public APIs,
+ * whereas this is private
+ */
+int msm_vidc_destroy(struct msm_vidc_inst *inst);
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
new file mode 100644
index 0000000..82e3b40
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
@@ -0,0 +1,1777 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include "msm_vidc_debug.h"
+#include "msm_vidc_resources.h"
+#include "msm_vidc_res_parse.h"
+#include "venus_boot.h"
+#include "soc/qcom/secure_buffer.h"
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+enum clock_properties {
+	CLOCK_PROP_HAS_SCALING = 1 << 0,
+};
+
+struct regulator *gdsc_venus;
+struct regulator *gdsc_venus_core0;
+
+static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
+{
+	return NULL;
+}
+
+static int msm_vidc_populate_legacy_context_bank(
+			struct msm_vidc_platform_resources *res);
+
+static size_t get_u32_array_num_elements(struct device_node *np,
+					char *name)
+{
+	int len;
+	size_t num_elements = 0;
+
+	if (!of_get_property(np, name, &len)) {
+		dprintk(VIDC_ERR, "Failed to read %s from device tree\n",
+			name);
+		goto fail_read;
+	}
+
+	num_elements = len / sizeof(u32);
+	if (num_elements <= 0) {
+		dprintk(VIDC_ERR, "%s not specified in device tree\n",
+			name);
+		goto fail_read;
+	}
+	return num_elements;
+
+fail_read:
+	return 0;
+}
+
+static int venus_regulator_setup(struct msm_vidc_platform_resources *res)
+{
+	const char *reg_name = "venus";
+	const char *reg_name_core0 = "venus-core0";
+	int rc = 0;
+
+	gdsc_venus = devm_regulator_get(&res->pdev->dev, reg_name);
+	if (IS_ERR(gdsc_venus))
+		dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+
+	rc = regulator_enable(gdsc_venus);
+	if (rc)
+		dprintk(VIDC_ERR, "Venus GDSC enable failed\n");
+
+	gdsc_venus_core0 = devm_regulator_get(&res->pdev->dev, reg_name_core0);
+	if (IS_ERR(gdsc_venus_core0))
+		dprintk(VIDC_ERR, "Failed to get Venus-Core0 GDSC\n");
+
+	rc = regulator_enable(gdsc_venus_core0);
+	if (rc)
+		dprintk(VIDC_ERR, "Venus-Core0 GDSC enable failed\n");
+
+	dprintk(VIDC_DBG, "Vensu, Venus-Core0 GDSC's are enabled\n");
+	return rc;
+}
+
+
+static int venus_clock_setup(struct msm_vidc_platform_resources *res,
+		unsigned long rate)
+{
+	int i, rc = 0;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	dprintk(VIDC_DBG, " %s In\n", __func__);
+	for (i = 0; i < res->clock_set.count; i++) {
+	cl = &res->clock_set.clock_tbl[i];
+		if (!cl->has_scaling)
+			continue;
+
+		clk = clk_get(&res->pdev->dev, cl->name);
+		rc = clk_set_rate(clk, clk_round_rate(clk, rate));
+
+		if (rc)
+			dprintk(VIDC_ERR,
+				"%s: Failed to set clock rate %s: %d\n",
+				__func__, cl->name, rc);
+
+		dprintk(VIDC_DBG, "%s clock set clock rate to %lu\n",
+				cl->name, rate);
+	}
+
+	dprintk(VIDC_DBG, " %s exit\n", __func__);
+	return rc;
+}
+
+static int venus_clock_prepare_enable(struct msm_vidc_platform_resources *res)
+{
+	int i, rc = 0;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	dprintk(VIDC_DBG, " %s In\n", __func__);
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk = clk_get(&res->pdev->dev, cl->name);
+		rc = clk_prepare_enable(clk);
+
+		if (rc) {
+			dprintk(VIDC_ERR, "failed to enable %s clock\n",
+					cl->name);
+			for (i--; i >= 0; i--) {
+				cl = &res->clock_set.clock_tbl[i];
+				clk = clk_get(&res->pdev->dev, cl->name);
+				clk_disable_unprepare(clk);
+				dprintk(VIDC_ERR, "clock %s unprepared\n",
+						cl->name);
+			}
+			return rc;
+		}
+		dprintk(VIDC_DBG, " Clock : %s enabled\n", cl->name);
+	}
+
+	dprintk(VIDC_DBG, " %s exit\n", __func__);
+	return rc;
+}
+
+static void venus_clk_disable_unprepare(struct msm_vidc_platform_resources *res)
+{
+	int i;
+	struct clock_info *cl;
+	struct clk *clk = NULL;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk = clk_get(&res->pdev->dev, cl->name);
+		dprintk(VIDC_DBG, "clock %s unprepared\n", cl->name);
+		clk_disable_unprepare(clk);
+	}
+
+	if (gdsc_venus) {
+		regulator_disable(gdsc_venus);
+		dprintk(VIDC_DBG, "Venus Regulator disabled\n");
+		gdsc_venus = NULL;
+	}
+	if (gdsc_venus_core0) {
+		regulator_disable(gdsc_venus_core0);
+		dprintk(VIDC_DBG, "Venus-Core0 Regulator disabled\n");
+		gdsc_venus_core0 = NULL;
+	}
+}
+
+static inline enum imem_type read_imem_type(struct platform_device *pdev)
+{
+	bool is_compatible(char *compat)
+	{
+		return !!of_find_compatible_node(NULL, NULL, compat);
+	}
+
+	return is_compatible("qcom,msm-ocmem") ? IMEM_OCMEM :
+		is_compatible("qcom,msm-vmem") ? IMEM_VMEM :
+						IMEM_NONE;
+
+}
+
+static inline void msm_vidc_free_allowed_clocks_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->allowed_clks_tbl = NULL;
+}
+
+static inline void msm_vidc_free_cycles_per_mb_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->clock_freq_tbl.clk_prof_entries = NULL;
+}
+
+static inline void msm_vidc_free_platform_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->pf_ver_tbl = NULL;
+}
+
+static inline void msm_vidc_free_capability_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->pf_cap_tbl = NULL;
+}
+
+static inline void msm_vidc_free_freq_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->load_freq_tbl = NULL;
+}
+
+static inline void msm_vidc_free_dcvs_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->dcvs_tbl = NULL;
+}
+
+static inline void msm_vidc_free_dcvs_limit(
+		struct msm_vidc_platform_resources *res)
+{
+	res->dcvs_limit = NULL;
+}
+
+static inline void msm_vidc_free_imem_ab_table(
+		struct msm_vidc_platform_resources *res)
+{
+	res->imem_ab_tbl = NULL;
+}
+
+static inline void msm_vidc_free_reg_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->reg_set.reg_tbl = NULL;
+}
+
+static inline void msm_vidc_free_qdss_addr_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->qdss_addr_set.addr_tbl = NULL;
+}
+
+static inline void msm_vidc_free_bus_vectors(
+			struct msm_vidc_platform_resources *res)
+{
+	kfree(res->bus_set.bus_tbl);
+	res->bus_set.bus_tbl = NULL;
+	res->bus_set.count = 0;
+}
+
+static inline void msm_vidc_free_buffer_usage_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->buffer_usage_set.buffer_usage_tbl = NULL;
+}
+
+static inline void msm_vidc_free_regulator_table(
+			struct msm_vidc_platform_resources *res)
+{
+	int c = 0;
+
+	for (c = 0; c < res->regulator_set.count; ++c) {
+		struct regulator_info *rinfo =
+			&res->regulator_set.regulator_tbl[c];
+
+		rinfo->name = NULL;
+	}
+
+	res->regulator_set.regulator_tbl = NULL;
+	res->regulator_set.count = 0;
+}
+
+static inline void msm_vidc_free_clock_table(
+			struct msm_vidc_platform_resources *res)
+{
+	res->clock_set.clock_tbl = NULL;
+	res->clock_set.count = 0;
+}
+
+void msm_vidc_free_platform_resources(
+			struct msm_vidc_platform_resources *res)
+{
+	msm_vidc_free_clock_table(res);
+	msm_vidc_free_regulator_table(res);
+	msm_vidc_free_freq_table(res);
+	msm_vidc_free_platform_version_table(res);
+	msm_vidc_free_capability_version_table(res);
+	msm_vidc_free_dcvs_table(res);
+	msm_vidc_free_dcvs_limit(res);
+	msm_vidc_free_cycles_per_mb_table(res);
+	msm_vidc_free_allowed_clocks_table(res);
+	msm_vidc_free_reg_table(res);
+	msm_vidc_free_qdss_addr_table(res);
+	msm_vidc_free_bus_vectors(res);
+	msm_vidc_free_buffer_usage_table(res);
+}
+
+static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res)
+{
+	struct reg_set *reg_set;
+	struct platform_device *pdev = res->pdev;
+	int i;
+	int rc = 0;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,reg-presets", NULL)) {
+		/* qcom,reg-presets is an optional property.  It likely won't be
+		 * present if we don't have any register settings to program
+		 */
+		dprintk(VIDC_DBG, "qcom,reg-presets not found\n");
+		return 0;
+	}
+
+	reg_set = &res->reg_set;
+	reg_set->count = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,reg-presets");
+	reg_set->count /=  sizeof(*reg_set->reg_tbl) / sizeof(u32);
+
+	if (!reg_set->count) {
+		dprintk(VIDC_DBG, "no elements in reg set\n");
+		return rc;
+	}
+
+	reg_set->reg_tbl = devm_kzalloc(&pdev->dev, reg_set->count *
+			sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
+	if (!reg_set->reg_tbl) {
+		dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets",
+		(u32 *)reg_set->reg_tbl, reg_set->count * 2)) {
+		dprintk(VIDC_ERR, "Failed to read register table\n");
+		msm_vidc_free_reg_table(res);
+		return -EINVAL;
+	}
+	for (i = 0; i < reg_set->count; i++) {
+		dprintk(VIDC_DBG,
+			"reg = %x, value = %x\n",
+			reg_set->reg_tbl[i].reg,
+			reg_set->reg_tbl[i].value
+		);
+	}
+	return rc;
+}
+static int msm_vidc_load_qdss_table(struct msm_vidc_platform_resources *res)
+{
+	struct addr_set *qdss_addr_set;
+	struct platform_device *pdev = res->pdev;
+	int i;
+	int rc = 0;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,qdss-presets", NULL)) {
+		/* qcom,qdss-presets is an optional property. It likely won't be
+		 * present if we don't have any register settings to program
+		 */
+		dprintk(VIDC_DBG, "qcom,qdss-presets not found\n");
+		return rc;
+	}
+
+	qdss_addr_set = &res->qdss_addr_set;
+	qdss_addr_set->count = get_u32_array_num_elements(pdev->dev.of_node,
+					"qcom,qdss-presets");
+	qdss_addr_set->count /= sizeof(*qdss_addr_set->addr_tbl) / sizeof(u32);
+
+	if (!qdss_addr_set->count) {
+		dprintk(VIDC_DBG, "no elements in qdss reg set\n");
+		return rc;
+	}
+
+	qdss_addr_set->addr_tbl = devm_kzalloc(&pdev->dev,
+			qdss_addr_set->count * sizeof(*qdss_addr_set->addr_tbl),
+			GFP_KERNEL);
+	if (!qdss_addr_set->addr_tbl) {
+		dprintk(VIDC_ERR, "%s Failed to alloc register table\n",
+			__func__);
+		rc = -ENOMEM;
+		goto err_qdss_addr_tbl;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,qdss-presets",
+		(u32 *)qdss_addr_set->addr_tbl, qdss_addr_set->count * 2);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read qdss address table\n");
+		msm_vidc_free_qdss_addr_table(res);
+		rc = -EINVAL;
+		goto err_qdss_addr_tbl;
+	}
+
+	for (i = 0; i < qdss_addr_set->count; i++) {
+		dprintk(VIDC_DBG, "qdss addr = %x, value = %x\n",
+				qdss_addr_set->addr_tbl[i].start,
+				qdss_addr_set->addr_tbl[i].size);
+	}
+err_qdss_addr_tbl:
+	return rc;
+}
+
+static int msm_vidc_load_imem_ab_table(struct msm_vidc_platform_resources *res)
+{
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,imem-ab-tbl", NULL)) {
+		/* optional property */
+		dprintk(VIDC_DBG, "qcom,imem-freq-tbl not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,imem-ab-tbl");
+	num_elements /= (sizeof(*res->imem_ab_tbl) / sizeof(u32));
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in imem ab table\n");
+		return -EINVAL;
+	}
+
+	res->imem_ab_tbl = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->imem_ab_tbl), GFP_KERNEL);
+	if (!res->imem_ab_tbl) {
+		dprintk(VIDC_ERR, "Failed to alloc imem_ab_tbl\n");
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,imem-ab-tbl", (u32 *)res->imem_ab_tbl,
+		num_elements * sizeof(*res->imem_ab_tbl) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read imem_ab_tbl\n");
+		msm_vidc_free_imem_ab_table(res);
+		return -EINVAL;
+	}
+
+	res->imem_ab_tbl_size = num_elements;
+
+	return 0;
+}
+
+/**
+ * msm_vidc_load_u32_table() - load dtsi table entries
+ * @pdev: A pointer to the platform device.
+ * @of_node:      A pointer to the device node.
+ * @table_name:   A pointer to the dtsi table entry name.
+ * @struct_size:  The size of the structure which is nothing but
+ *                a single entry in the dtsi table.
+ * @table:        A pointer to the table pointer which needs to be
+ *                filled by the dtsi table entries.
+ * @num_elements: Number of elements pointer which needs to be filled
+ *                with the number of elements in the table.
+ *
+ * This is a generic implementation to load single or multiple array
+ * table from dtsi. The array elements should be of size equal to u32.
+ *
+ * Return:        Return '0' for success else appropriate error value.
+ */
+int msm_vidc_load_u32_table(struct platform_device *pdev,
+		struct device_node *of_node, char *table_name, int struct_size,
+		u32 **table, u32 *num_elements)
+{
+	int rc = 0, num_elemts = 0;
+	u32 *ptbl = NULL;
+
+	if (!of_find_property(of_node, table_name, NULL)) {
+		dprintk(VIDC_DBG, "%s not found\n", table_name);
+		return 0;
+	}
+
+	num_elemts = get_u32_array_num_elements(of_node, table_name);
+	if (!num_elemts) {
+		dprintk(VIDC_ERR, "no elements in %s\n", table_name);
+		return 0;
+	}
+	num_elemts /= struct_size / sizeof(u32);
+
+	ptbl = devm_kzalloc(&pdev->dev, num_elemts * struct_size, GFP_KERNEL);
+	if (!ptbl) {
+		dprintk(VIDC_ERR, "Failed to alloc table %s\n", table_name);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(of_node, table_name, ptbl,
+			num_elemts * struct_size / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read %s\n", table_name);
+		return -EINVAL;
+	}
+
+	*table = ptbl;
+	if (num_elements)
+		*num_elements = num_elemts;
+
+	return rc;
+}
+
+static int msm_vidc_load_platform_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node,
+			"qcom,platform-version", NULL)) {
+		dprintk(VIDC_DBG, "qcom,platform-version not found\n");
+		return 0;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+			"qcom,platform-version",
+			sizeof(*res->pf_ver_tbl),
+			(u32 **)&res->pf_ver_tbl,
+			NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read platform version table\n",
+			__func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int msm_vidc_load_capability_version_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node,
+			"qcom,capability-version", NULL)) {
+		dprintk(VIDC_DBG, "qcom,capability-version not found\n");
+		return 0;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+			"qcom,capability-version",
+			sizeof(*res->pf_cap_tbl),
+			(u32 **)&res->pf_cap_tbl,
+			NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read platform version table\n",
+			__func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void clock_override(struct platform_device *pdev,
+	struct msm_vidc_platform_resources *platform_res,
+	struct allowed_clock_rates_table *clk_table)
+{
+	struct resource *res;
+	void __iomem *base = NULL;
+	u32 config_efuse, bin;
+	u32 venus_uplift_freq;
+	u32 is_speed_bin = 7;
+	int rc = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"efuse");
+	if (!res) {
+		dprintk(VIDC_DBG,
+			"Failed to get resource efuse\n");
+		return;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,venus-uplift-freq",
+			&venus_uplift_freq);
+	if (rc) {
+		dprintk(VIDC_DBG,
+			"Failed to determine venus-uplift-freq: %d\n", rc);
+		return;
+	}
+
+	if (!of_find_property(pdev->dev.of_node,
+		"qcom,speedbin-version", NULL)) {
+		dprintk(VIDC_DBG, "qcom,speedbin-version not found\n");
+		return;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+		"qcom,speedbin-version",
+		sizeof(*platform_res->pf_speedbin_tbl),
+		(u32 **)&platform_res->pf_speedbin_tbl,
+		NULL);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read speedbin version table\n",
+			__func__);
+		return;
+	}
+	base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!base) {
+		dev_warn(&pdev->dev,
+			"Unable to ioremap efuse reg address. Defaulting to 0.\n");
+		return;
+	}
+
+	config_efuse = readl_relaxed(base);
+	devm_iounmap(&pdev->dev, base);
+
+	bin = (config_efuse >> platform_res->pf_speedbin_tbl->version_shift) &
+		platform_res->pf_speedbin_tbl->version_mask;
+
+	if (bin == is_speed_bin) {
+		dprintk(VIDC_DBG,
+			"Venus speed binning available overwriting %d to %d\n",
+			clk_table[0].clock_rate, venus_uplift_freq);
+		clk_table[0].clock_rate = venus_uplift_freq;
+	}
+}
+
+static int msm_vidc_load_allowed_clocks_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node,
+			"qcom,allowed-clock-rates", NULL)) {
+		dprintk(VIDC_DBG, "qcom,allowed-clock-rates not found\n");
+		return 0;
+	}
+
+	rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
+				"qcom,allowed-clock-rates",
+				sizeof(*res->allowed_clks_tbl),
+				(u32 **)&res->allowed_clks_tbl,
+				&res->allowed_clks_tbl_size);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"%s: failed to read allowed clocks table\n", __func__);
+		return rc;
+	}
+	if (res->allowed_clks_tbl_size)
+		clock_override(pdev, res, res->allowed_clks_tbl);
+
+	return 0;
+}
+
+static int msm_vidc_load_cycles_per_mb_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0, i = 0;
+	struct clock_freq_table *clock_freq_tbl = &res->clock_freq_tbl;
+	struct clock_profile_entry *entry = NULL;
+	struct device_node *parent_node = NULL;
+	struct device_node *child_node = NULL;
+	struct platform_device *pdev = res->pdev;
+
+	parent_node = of_find_node_by_name(pdev->dev.of_node,
+			"qcom,clock-freq-tbl");
+	if (!parent_node) {
+		dprintk(VIDC_DBG, "Node qcom,clock-freq-tbl not found.\n");
+		return 0;
+	}
+
+	clock_freq_tbl->count = 0;
+	for_each_child_of_node(parent_node, child_node)
+		clock_freq_tbl->count++;
+
+	if (!clock_freq_tbl->count) {
+		dprintk(VIDC_DBG, "No child nodes in qcom,clock-freq-tbl\n");
+		return 0;
+	}
+
+	clock_freq_tbl->clk_prof_entries = devm_kzalloc(&pdev->dev,
+		sizeof(*clock_freq_tbl->clk_prof_entries) *
+		clock_freq_tbl->count, GFP_KERNEL);
+	if (!clock_freq_tbl->clk_prof_entries) {
+		dprintk(VIDC_DBG, "no memory to allocate clk_prof_entries\n");
+		return -ENOMEM;
+	}
+
+	for_each_child_of_node(parent_node, child_node) {
+
+		if (i >= clock_freq_tbl->count) {
+			dprintk(VIDC_ERR,
+				"qcom,clock-freq-tbl: invalid child node %d, max is %d\n",
+				i, clock_freq_tbl->count);
+			break;
+		}
+
+		entry = &clock_freq_tbl->clk_prof_entries[i];
+		dprintk(VIDC_DBG, "qcom,clock-freq-tbl: profile[%d]\n", i);
+
+		if (of_find_property(child_node, "qcom,codec-mask", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,codec-mask", &entry->codec_mask);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,codec-mask not found\n");
+				goto error;
+			}
+		} else {
+			entry->codec_mask = 0;
+		}
+		dprintk(VIDC_DBG, "codec_mask %#x\n", entry->codec_mask);
+
+		if (of_find_property(child_node, "qcom,cycles-per-mb", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,cycles-per-mb", &entry->cycles);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,cycles-per-mb not found\n");
+				goto error;
+			}
+		} else {
+			entry->cycles = 0;
+		}
+		dprintk(VIDC_DBG, "cycles_per_mb %d\n", entry->cycles);
+
+		if (of_find_property(child_node,
+				"qcom,low-power-mode-factor", NULL)) {
+			rc = of_property_read_u32(child_node,
+					"qcom,low-power-mode-factor",
+					&entry->low_power_factor);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"qcom,low-power-mode-factor not found\n");
+				goto error;
+			}
+		} else {
+			entry->low_power_factor = 0;
+		}
+		dprintk(VIDC_DBG, "low_power_factor %d\n",
+				entry->low_power_factor);
+
+		i++;
+	}
+
+error:
+	return rc;
+}
+
+static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	/* A comparator to compare loads (needed later on) */
+	int cmp(const void *a, const void *b)
+	{
+		/* want to sort in reverse so flip the comparison */
+		return ((struct load_freq_table *)b)->load -
+			((struct load_freq_table *)a)->load;
+	}
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,load-freq-tbl", NULL)) {
+		/* qcom,load-freq-tbl is an optional property.  It likely won't
+		 * be present on cores that we can't clock scale on.
+		 */
+		dprintk(VIDC_DBG, "qcom,load-freq-tbl not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,load-freq-tbl");
+	num_elements /= sizeof(*res->load_freq_tbl) / sizeof(u32);
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in frequency table\n");
+		return rc;
+	}
+
+	res->load_freq_tbl = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->load_freq_tbl), GFP_KERNEL);
+	if (!res->load_freq_tbl) {
+		dprintk(VIDC_ERR,
+				"%s Failed to alloc load_freq_tbl\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,load-freq-tbl", (u32 *)res->load_freq_tbl,
+		num_elements * sizeof(*res->load_freq_tbl) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read frequency table\n");
+		msm_vidc_free_freq_table(res);
+		return -EINVAL;
+	}
+
+	res->load_freq_tbl_size = num_elements;
+
+	/* The entries in the DT might not be sorted (for aesthetic purposes).
+	 * Given that we expect the loads in descending order for our scaling
+	 * logic to work, just sort it ourselves
+	 */
+	sort(res->load_freq_tbl, res->load_freq_tbl_size,
+			sizeof(*res->load_freq_tbl), cmp, NULL);
+	return rc;
+}
+
+static int msm_vidc_load_dcvs_table(struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,dcvs-tbl", NULL)) {
+		/*
+		 * qcom,dcvs-tbl is an optional property. Incase qcom,dcvs-limit
+		 * property is present, it becomes mandatory. It likely won't
+		 * be present on targets that does not support the feature
+		 */
+		dprintk(VIDC_DBG, "qcom,dcvs-tbl not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,dcvs-tbl");
+	num_elements /= sizeof(*res->dcvs_tbl) / sizeof(u32);
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in dcvs table\n");
+		return rc;
+	}
+
+	res->dcvs_tbl = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->dcvs_tbl), GFP_KERNEL);
+	if (!res->dcvs_tbl) {
+		dprintk(VIDC_ERR,
+				"%s Failed to alloc dcvs_tbl\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,dcvs-tbl", (u32 *)res->dcvs_tbl,
+		num_elements * sizeof(*res->dcvs_tbl) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read dcvs table\n");
+		msm_vidc_free_dcvs_table(res);
+		return -EINVAL;
+	}
+	res->dcvs_tbl_size = num_elements;
+
+	return rc;
+}
+
+static int msm_vidc_load_dcvs_limit(struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	int num_elements = 0;
+	struct platform_device *pdev = res->pdev;
+
+	if (!of_find_property(pdev->dev.of_node, "qcom,dcvs-limit", NULL)) {
+		/*
+		 * qcom,dcvs-limit is an optional property. Incase qcom,dcvs-tbl
+		 * property is present, it becomes mandatory. It likely won't
+		 * be present on targets that does not support the feature
+		 */
+		dprintk(VIDC_DBG, "qcom,dcvs-limit not found\n");
+		return 0;
+	}
+
+	num_elements = get_u32_array_num_elements(pdev->dev.of_node,
+			"qcom,dcvs-limit");
+	num_elements /= sizeof(*res->dcvs_limit) / sizeof(u32);
+	if (!num_elements) {
+		dprintk(VIDC_ERR, "no elements in dcvs limit\n");
+		res->dcvs_limit = NULL;
+		return rc;
+	}
+
+	res->dcvs_limit = devm_kzalloc(&pdev->dev, num_elements *
+			sizeof(*res->dcvs_limit), GFP_KERNEL);
+	if (!res->dcvs_limit) {
+		dprintk(VIDC_ERR,
+				"%s Failed to alloc dcvs_limit\n",
+				__func__);
+		return -ENOMEM;
+	}
+	if (of_property_read_u32_array(pdev->dev.of_node,
+		"qcom,dcvs-limit", (u32 *)res->dcvs_limit,
+		num_elements * sizeof(*res->dcvs_limit) / sizeof(u32))) {
+		dprintk(VIDC_ERR, "Failed to read dcvs limit\n");
+		msm_vidc_free_dcvs_limit(res);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+
+static int msm_vidc_populate_bus(struct device *dev,
+		struct msm_vidc_platform_resources *res)
+{
+	struct bus_set *buses = &res->bus_set;
+	const char *temp_name = NULL;
+	struct bus_info *bus = NULL, *temp_table;
+	u32 range[2];
+	int rc = 0;
+
+	temp_table = krealloc(buses->bus_tbl, sizeof(*temp_table) *
+			(buses->count + 1), GFP_KERNEL);
+	if (!temp_table) {
+		dprintk(VIDC_ERR, "%s: Failed to allocate memory", __func__);
+		rc = -ENOMEM;
+		goto err_bus;
+	}
+
+	buses->bus_tbl = temp_table;
+	bus = &buses->bus_tbl[buses->count];
+
+	rc = of_property_read_string(dev->of_node, "label", &temp_name);
+	if (rc) {
+		dprintk(VIDC_ERR, "'label' not found in node\n");
+		goto err_bus;
+	}
+	/* need a non-const version of name, hence copying it over */
+	bus->name = devm_kstrdup(dev, temp_name, GFP_KERNEL);
+	if (!bus->name) {
+		rc = -ENOMEM;
+		goto err_bus;
+	}
+
+	rc = of_property_read_u32(dev->of_node, "qcom,bus-master",
+			&bus->master);
+	if (rc) {
+		dprintk(VIDC_ERR, "'qcom,bus-master' not found in node\n");
+		goto err_bus;
+	}
+
+	rc = of_property_read_u32(dev->of_node, "qcom,bus-slave", &bus->slave);
+	if (rc) {
+		dprintk(VIDC_ERR, "'qcom,bus-slave' not found in node\n");
+		goto err_bus;
+	}
+
+	rc = of_property_read_string(dev->of_node, "qcom,bus-governor",
+			&bus->governor);
+	if (rc) {
+		rc = 0;
+		dprintk(VIDC_DBG,
+				"'qcom,bus-governor' not found, default to performance governor\n");
+		bus->governor = "performance";
+	}
+
+	rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps",
+			range, ARRAY_SIZE(range));
+	if (rc) {
+		rc = 0;
+		dprintk(VIDC_DBG,
+				"'qcom,range' not found defaulting to <0 INT_MAX>\n");
+		range[0] = 0;
+		range[1] = INT_MAX;
+	}
+
+	bus->range[0] = range[0]; /* min */
+	bus->range[1] = range[1]; /* max */
+
+	buses->count++;
+	bus->dev = dev;
+	dprintk(VIDC_DBG, "Found bus %s [%d->%d] with governor %s\n",
+			bus->name, bus->master, bus->slave, bus->governor);
+
+	venus_clk_disable_unprepare(res);
+err_bus:
+	return rc;
+}
+
+static int msm_vidc_load_buffer_usage_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+	struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set;
+
+	if (!of_find_property(pdev->dev.of_node,
+				"qcom,buffer-type-tz-usage-table", NULL)) {
+		/* qcom,buffer-type-tz-usage-table is an optional property.  It
+		 * likely won't be present if the core doesn't support content
+		 * protection
+		 */
+		dprintk(VIDC_DBG, "buffer-type-tz-usage-table not found\n");
+		return 0;
+	}
+
+	buffer_usage_set->count = get_u32_array_num_elements(
+		pdev->dev.of_node, "qcom,buffer-type-tz-usage-table");
+	buffer_usage_set->count /=
+		sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32);
+	if (!buffer_usage_set->count) {
+		dprintk(VIDC_DBG, "no elements in buffer usage set\n");
+		return 0;
+	}
+
+	buffer_usage_set->buffer_usage_tbl = devm_kzalloc(&pdev->dev,
+			buffer_usage_set->count *
+			sizeof(*buffer_usage_set->buffer_usage_tbl),
+			GFP_KERNEL);
+	if (!buffer_usage_set->buffer_usage_tbl) {
+		dprintk(VIDC_ERR, "%s Failed to alloc buffer usage table\n",
+			__func__);
+		rc = -ENOMEM;
+		goto err_load_buf_usage;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+		    "qcom,buffer-type-tz-usage-table",
+		(u32 *)buffer_usage_set->buffer_usage_tbl,
+		buffer_usage_set->count *
+		sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32));
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read buffer usage table\n");
+		goto err_load_buf_usage;
+	}
+
+	return 0;
+err_load_buf_usage:
+	msm_vidc_free_buffer_usage_table(res);
+	return rc;
+}
+
+static int msm_vidc_load_regulator_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = res->pdev;
+	struct regulator_set *regulators = &res->regulator_set;
+	struct device_node *domains_parent_node = NULL;
+	struct property *domains_property = NULL;
+	int reg_count = 0;
+
+	regulators->count = 0;
+	regulators->regulator_tbl = NULL;
+
+	domains_parent_node = pdev->dev.of_node;
+	for_each_property_of_node(domains_parent_node, domains_property) {
+		const char *search_string = "-supply";
+		char *supply;
+		bool matched = false;
+
+		/* check if current property is possibly a regulator */
+		supply = strnstr(domains_property->name, search_string,
+				strlen(domains_property->name) + 1);
+		matched = supply && (*(supply + strlen(search_string)) == '\0');
+		if (!matched)
+			continue;
+
+		reg_count++;
+	}
+
+	regulators->regulator_tbl = devm_kzalloc(&pdev->dev,
+			sizeof(*regulators->regulator_tbl) *
+			reg_count, GFP_KERNEL);
+
+	if (!regulators->regulator_tbl) {
+		rc = -ENOMEM;
+		dprintk(VIDC_ERR,
+			"Failed to alloc memory for regulator table\n");
+		goto err_reg_tbl_alloc;
+	}
+
+	for_each_property_of_node(domains_parent_node, domains_property) {
+		const char *search_string = "-supply";
+		char *supply;
+		bool matched = false;
+		struct device_node *regulator_node = NULL;
+		struct regulator_info *rinfo = NULL;
+
+		/* check if current property is possibly a regulator */
+		supply = strnstr(domains_property->name, search_string,
+				strlen(domains_property->name) + 1);
+		matched = supply && (supply[strlen(search_string)] == '\0');
+		if (!matched)
+			continue;
+
+		/* make sure prop isn't being misused */
+		regulator_node = of_parse_phandle(domains_parent_node,
+				domains_property->name, 0);
+		if (IS_ERR(regulator_node)) {
+			dprintk(VIDC_WARN, "%s is not a phandle\n",
+					domains_property->name);
+			continue;
+		}
+		regulators->count++;
+
+		/* populate regulator info */
+		rinfo = &regulators->regulator_tbl[regulators->count - 1];
+		rinfo->name = devm_kzalloc(&pdev->dev,
+			(supply - domains_property->name) + 1, GFP_KERNEL);
+		if (!rinfo->name) {
+			rc = -ENOMEM;
+			dprintk(VIDC_ERR,
+					"Failed to alloc memory for regulator name\n");
+			goto err_reg_name_alloc;
+		}
+		strlcpy(rinfo->name, domains_property->name,
+			(supply - domains_property->name) + 1);
+
+		rinfo->has_hw_power_collapse = of_property_read_bool(
+			regulator_node, "qcom,support-hw-trigger");
+
+		dprintk(VIDC_DBG, "Found regulator %s: h/w collapse = %s\n",
+				rinfo->name,
+				rinfo->has_hw_power_collapse ? "yes" : "no");
+	}
+
+	if (!regulators->count)
+		dprintk(VIDC_DBG, "No regulators found");
+
+	return 0;
+
+err_reg_name_alloc:
+err_reg_tbl_alloc:
+	msm_vidc_free_regulator_table(res);
+	return rc;
+}
+
+static int msm_vidc_load_clock_table(
+		struct msm_vidc_platform_resources *res)
+{
+	int rc = 0, num_clocks = 0, c = 0;
+	struct platform_device *pdev = res->pdev;
+	int *clock_props = NULL;
+	struct clock_set *clocks = &res->clock_set;
+
+	num_clocks = of_property_count_strings(pdev->dev.of_node,
+				"clock-names");
+	if (num_clocks <= 0) {
+		dprintk(VIDC_DBG, "No clocks found\n");
+		clocks->count = 0;
+		rc = 0;
+		goto err_load_clk_table_fail;
+	}
+
+	clock_props = devm_kzalloc(&pdev->dev, num_clocks *
+			sizeof(*clock_props), GFP_KERNEL);
+	if (!clock_props) {
+		dprintk(VIDC_ERR, "No memory to read clock properties\n");
+		rc = -ENOMEM;
+		goto err_load_clk_table_fail;
+	}
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+				"qcom,clock-configs", clock_props,
+				num_clocks);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read clock properties: %d\n", rc);
+		goto err_load_clk_prop_fail;
+	}
+
+	clocks->clock_tbl = devm_kzalloc(&pdev->dev, sizeof(*clocks->clock_tbl)
+			* num_clocks, GFP_KERNEL);
+	if (!clocks->clock_tbl) {
+		dprintk(VIDC_ERR, "Failed to allocate memory for clock tbl\n");
+		rc = -ENOMEM;
+		goto err_load_clk_prop_fail;
+	}
+
+	clocks->count = num_clocks;
+	dprintk(VIDC_DBG, "Found %d clocks\n", num_clocks);
+
+	for (c = 0; c < num_clocks; ++c) {
+		struct clock_info *vc = &res->clock_set.clock_tbl[c];
+
+		of_property_read_string_index(pdev->dev.of_node,
+				"clock-names", c, &vc->name);
+
+		if (clock_props[c] & CLOCK_PROP_HAS_SCALING) {
+			vc->has_scaling = true;
+			vc->count = res->load_freq_tbl_size;
+			vc->load_freq_tbl = res->load_freq_tbl;
+		} else {
+			vc->count = 0;
+			vc->load_freq_tbl = NULL;
+			vc->has_scaling = false;
+		}
+
+		dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name,
+			vc->count ? "yes" : "no");
+	}
+
+
+	return 0;
+
+err_load_clk_prop_fail:
+err_load_clk_table_fail:
+	return rc;
+}
+
+int read_platform_resources_from_dt(
+		struct msm_vidc_platform_resources *res)
+{
+	struct platform_device *pdev = res->pdev;
+	struct resource *kres = NULL;
+	int rc = 0;
+	uint32_t firmware_base = 0;
+
+	if (!pdev->dev.of_node) {
+		dprintk(VIDC_ERR, "DT node not found\n");
+		return -ENOENT;
+	}
+
+	INIT_LIST_HEAD(&res->context_banks);
+
+	res->firmware_base = (phys_addr_t)firmware_base;
+
+	kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res->register_base = kres ? kres->start : -1;
+	res->register_size = kres ? (kres->end + 1 - kres->start) : -1;
+
+	kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	res->irq = kres ? kres->start : -1;
+
+	of_property_read_u32(pdev->dev.of_node,
+			"qcom,imem-size", &res->imem_size);
+	res->imem_type = read_imem_type(pdev);
+
+	res->sys_idle_indicator = of_property_read_bool(pdev->dev.of_node,
+			"qcom,enable-idle-indicator");
+
+	res->thermal_mitigable =
+			of_property_read_bool(pdev->dev.of_node,
+			"qcom,enable-thermal-mitigation");
+
+	rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+			&res->fw_name);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to read firmware name: %d\n", rc);
+		goto err_load_freq_table;
+	}
+	dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name);
+
+	rc = of_property_read_string(pdev->dev.of_node, "qcom,hfi-version",
+			&res->hfi_version);
+	if (rc)
+		dprintk(VIDC_DBG, "HFI packetization will default to legacy\n");
+
+	rc = msm_vidc_load_platform_version_table(res);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to load pf version table: %d\n", rc);
+
+	rc = msm_vidc_load_capability_version_table(res);
+	if (rc)
+		dprintk(VIDC_ERR,
+			"Failed to load pf capability table: %d\n", rc);
+
+	rc = msm_vidc_load_freq_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load freq table: %d\n", rc);
+		goto err_load_freq_table;
+	}
+
+	rc = msm_vidc_load_dcvs_table(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load dcvs table: %d\n", rc);
+
+	rc = msm_vidc_load_dcvs_limit(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load dcvs limit: %d\n", rc);
+
+	rc = msm_vidc_load_imem_ab_table(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load freq table: %d\n", rc);
+
+	rc = msm_vidc_load_qdss_table(res);
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to load qdss reg table: %d\n", rc);
+
+	rc = msm_vidc_load_reg_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc);
+		goto err_load_reg_table;
+	}
+
+	rc = msm_vidc_load_buffer_usage_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load buffer usage table: %d\n", rc);
+		goto err_load_buffer_usage_table;
+	}
+
+	rc = msm_vidc_load_regulator_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load list of regulators %d\n", rc);
+		goto err_load_regulator_table;
+	}
+
+	rc = msm_vidc_load_clock_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load clock table: %d\n", rc);
+		goto err_load_clock_table;
+	}
+
+	rc = msm_vidc_load_cycles_per_mb_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load cycles per mb table: %d\n", rc);
+		goto err_load_cycles_per_mb_table;
+	}
+
+	rc = msm_vidc_load_allowed_clocks_table(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to load allowed clocks table: %d\n", rc);
+		goto err_load_allowed_clocks_table;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
+			&res->max_load);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to determine max load supported: %d\n", rc);
+		goto err_load_max_hw_load;
+	}
+
+	rc = msm_vidc_populate_legacy_context_bank(res);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed to setup context banks %d\n", rc);
+		goto err_setup_legacy_cb;
+	}
+
+	res->use_non_secure_pil = of_property_read_bool(pdev->dev.of_node,
+			"qcom,use-non-secure-pil");
+
+	if (res->use_non_secure_pil || !is_iommu_present(res)) {
+		of_property_read_u32(pdev->dev.of_node, "qcom,fw-bias",
+				&firmware_base);
+		res->firmware_base = (phys_addr_t)firmware_base;
+		dprintk(VIDC_DBG,
+				"Using fw-bias : %pa", &res->firmware_base);
+	}
+
+	res->sw_power_collapsible = of_property_read_bool(pdev->dev.of_node,
+					"qcom,sw-power-collapse");
+	dprintk(VIDC_DBG, "Power collapse supported = %s\n",
+		res->sw_power_collapsible ? "yes" : "no");
+
+	res->never_unload_fw = of_property_read_bool(pdev->dev.of_node,
+			"qcom,never-unload-fw");
+
+	of_property_read_u32(pdev->dev.of_node,
+			"qcom,pm-qos-latency-us", &res->pm_qos_latency_us);
+
+	res->slave_side_cp = of_property_read_bool(pdev->dev.of_node,
+					"qcom,slave-side-cp");
+	dprintk(VIDC_DBG, "Slave side cp = %s\n",
+				res->slave_side_cp ? "yes" : "no");
+
+	of_property_read_u32(pdev->dev.of_node,
+			"qcom,max-secure-instances",
+			&res->max_secure_inst_count);
+
+	venus_regulator_setup(res);
+	venus_clock_setup(res, 0);
+	venus_clock_prepare_enable(res);
+	venus_clock_setup(res, 1);
+
+	return rc;
+
+err_setup_legacy_cb:
+err_load_max_hw_load:
+	msm_vidc_free_allowed_clocks_table(res);
+err_load_allowed_clocks_table:
+	msm_vidc_free_cycles_per_mb_table(res);
+err_load_cycles_per_mb_table:
+	msm_vidc_free_clock_table(res);
+err_load_clock_table:
+	msm_vidc_free_regulator_table(res);
+err_load_regulator_table:
+	msm_vidc_free_buffer_usage_table(res);
+err_load_buffer_usage_table:
+	msm_vidc_free_reg_table(res);
+err_load_reg_table:
+	msm_vidc_free_freq_table(res);
+err_load_freq_table:
+	return rc;
+}
+
+static int get_secure_vmid(struct context_bank_info *cb)
+{
+	if (!strcasecmp(cb->name, "venus_sec_bitstream"))
+		return VMID_CP_BITSTREAM;
+	else if (!strcasecmp(cb->name, "venus_sec_pixel"))
+		return VMID_CP_PIXEL;
+	else if (!strcasecmp(cb->name, "venus_sec_non_pixel"))
+		return VMID_CP_NON_PIXEL;
+
+	WARN(1, "No matching secure vmid for cb name: %s\n",
+		cb->name);
+	return VMID_INVAL;
+}
+
+static int msm_vidc_setup_context_bank(struct context_bank_info *cb,
+		struct device *dev)
+{
+	int rc = 0;
+	int secure_vmid = VMID_INVAL;
+	struct bus_type *bus;
+
+	if (!dev || !cb) {
+		dprintk(VIDC_ERR,
+			"%s: Invalid Input params\n", __func__);
+		return -EINVAL;
+	}
+	cb->dev = dev;
+
+	bus = cb->dev->bus;
+	if (IS_ERR_OR_NULL(bus)) {
+		dprintk(VIDC_ERR, "%s - failed to get bus type\n", __func__);
+		rc = PTR_ERR(bus) ?: -ENODEV;
+		goto remove_cb;
+	}
+
+	cb->mapping = arm_iommu_create_mapping(bus, cb->addr_range.start,
+					cb->addr_range.size);
+	if (IS_ERR_OR_NULL(cb->mapping)) {
+		dprintk(VIDC_ERR, "%s - failed to create mapping\n", __func__);
+		rc = PTR_ERR(cb->mapping) ?: -ENODEV;
+		goto remove_cb;
+	}
+
+	if (cb->is_secure) {
+		secure_vmid = get_secure_vmid(cb);
+		rc = iommu_domain_set_attr(cb->mapping->domain,
+				DOMAIN_ATTR_SECURE_VMID, &secure_vmid);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"%s - programming secure vmid failed: %s %d\n",
+					__func__, dev_name(dev), rc);
+			goto release_mapping;
+		}
+	}
+
+	rc = arm_iommu_attach_device(cb->dev, cb->mapping);
+	if (rc) {
+		dprintk(VIDC_ERR, "%s - Couldn't arm_iommu_attach_device\n",
+			__func__);
+		goto release_mapping;
+	}
+
+	dprintk(VIDC_DBG, "Attached %s and created mapping\n", dev_name(dev));
+	dprintk(VIDC_DBG,
+		"Context bank name:%s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, mapping: %pK",
+		cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start,
+		cb->addr_range.size, cb->dev, cb->mapping);
+
+	return rc;
+
+release_mapping:
+	arm_iommu_release_mapping(cb->mapping);
+remove_cb:
+	return rc;
+}
+
+int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags, void *token)
+{
+	struct msm_vidc_core *core = token;
+	struct msm_vidc_inst *inst;
+	struct buffer_info *temp;
+	struct internal_buf *buf;
+	int i = 0;
+	bool is_decode = false;
+	enum vidc_ports port;
+
+	if (!domain || !core) {
+		dprintk(VIDC_ERR, "%s - invalid param %pK %pK\n",
+			__func__, domain, core);
+		return -EINVAL;
+	}
+
+	if (core->smmu_fault_handled)
+		return -EINVAL;
+
+	dprintk(VIDC_ERR, "%s - faulting address: %lx\n", __func__, iova);
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		is_decode = inst->session_type == MSM_VIDC_DECODER;
+		port = is_decode ? OUTPUT_PORT : CAPTURE_PORT;
+		dprintk(VIDC_ERR,
+			"%s session, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n",
+			is_decode ? "Decode" : "Encode", inst->fmts[port].name,
+			inst->prop.height[port], inst->prop.width[port],
+			inst->prop.fps, inst->prop.bitrate,
+			!inst->bit_depth ? "8" : "10");
+
+		dprintk(VIDC_ERR,
+			"---Buffer details for inst: %pK of type: %d---\n",
+			inst, inst->session_type);
+		mutex_lock(&inst->registeredbufs.lock);
+		dprintk(VIDC_ERR, "registered buffer list:\n");
+		list_for_each_entry(temp, &inst->registeredbufs.list, list)
+			for (i = 0; i < temp->num_planes; i++)
+				dprintk(VIDC_ERR,
+					"type: %d plane: %d addr: %pa size: %d\n",
+					temp->type, i, &temp->device_addr[i],
+					temp->size[i]);
+
+		mutex_unlock(&inst->registeredbufs.lock);
+
+		mutex_lock(&inst->scratchbufs.lock);
+		dprintk(VIDC_ERR, "scratch buffer list:\n");
+		list_for_each_entry(buf, &inst->scratchbufs.list, list)
+			dprintk(VIDC_ERR, "type: %d addr: %pa size: %u\n",
+				buf->buffer_type, &buf->handle->device_addr,
+				buf->handle->size);
+		mutex_unlock(&inst->scratchbufs.lock);
+
+		mutex_lock(&inst->persistbufs.lock);
+		dprintk(VIDC_ERR, "persist buffer list:\n");
+		list_for_each_entry(buf, &inst->persistbufs.list, list)
+			dprintk(VIDC_ERR, "type: %d addr: %pa size: %u\n",
+				buf->buffer_type, &buf->handle->device_addr,
+				buf->handle->size);
+		mutex_unlock(&inst->persistbufs.lock);
+
+		mutex_lock(&inst->outputbufs.lock);
+		dprintk(VIDC_ERR, "dpb buffer list:\n");
+		list_for_each_entry(buf, &inst->outputbufs.list, list)
+			dprintk(VIDC_ERR, "type: %d addr: %pa size: %u\n",
+				buf->buffer_type, &buf->handle->device_addr,
+				buf->handle->size);
+		mutex_unlock(&inst->outputbufs.lock);
+	}
+	core->smmu_fault_handled = true;
+	mutex_unlock(&core->lock);
+	/*
+	 * Return -ENOSYS to elicit the default behaviour of smmu driver.
+	 * If we return -ENOSYS, then smmu driver assumes page fault handler
+	 * is not installed and prints a list of useful debug information like
+	 * FAR, SID etc. This information is not printed if we return 0.
+	 */
+	return -EINVAL;
+}
+
+static int msm_vidc_populate_context_bank(struct device *dev,
+		struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct context_bank_info *cb = NULL;
+	struct device_node *np = NULL;
+
+	if (!dev || !core) {
+		dprintk(VIDC_ERR, "%s - invalid inputs\n", __func__);
+		return -EINVAL;
+	}
+
+	np = dev->of_node;
+	cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
+	if (!cb) {
+		dprintk(VIDC_ERR, "%s - Failed to allocate cb\n", __func__);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&cb->list);
+	list_add_tail(&cb->list, &core->resources.context_banks);
+
+	rc = of_property_read_string(np, "label", &cb->name);
+	if (rc) {
+		dprintk(VIDC_DBG,
+			"Failed to read cb label from device tree\n");
+		rc = 0;
+	}
+
+	dprintk(VIDC_DBG, "%s: context bank has name %s\n", __func__, cb->name);
+	rc = of_property_read_u32_array(np, "virtual-addr-pool",
+			(u32 *)&cb->addr_range, 2);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Could not read addr pool for context bank : %s %d\n",
+			cb->name, rc);
+		goto err_setup_cb;
+	}
+
+	cb->is_secure = of_property_read_bool(np, "qcom,secure-context-bank");
+	dprintk(VIDC_DBG, "context bank %s : secure = %d\n",
+			cb->name, cb->is_secure);
+
+	/* setup buffer type for each sub device*/
+	rc = of_property_read_u32(np, "buffer-types", &cb->buffer_type);
+	if (rc) {
+		dprintk(VIDC_ERR, "failed to load buffer_type info %d\n", rc);
+		rc = -ENOENT;
+		goto err_setup_cb;
+	}
+	dprintk(VIDC_DBG,
+		"context bank %s address start = %x address size = %x buffer_type = %x\n",
+		cb->name, cb->addr_range.start,
+		cb->addr_range.size, cb->buffer_type);
+
+	rc = msm_vidc_setup_context_bank(cb, dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc);
+		goto err_setup_cb;
+	}
+
+	iommu_set_fault_handler(cb->mapping->domain,
+		msm_vidc_smmu_fault_handler, (void *)core);
+
+	return 0;
+
+err_setup_cb:
+	list_del(&cb->list);
+	return rc;
+}
+
+static int msm_vidc_populate_legacy_context_bank(
+			struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+	struct platform_device *pdev = NULL;
+	struct device_node *domains_parent_node = NULL;
+	struct device_node *domains_child_node = NULL;
+	struct device_node *ctx_node = NULL;
+	struct context_bank_info *cb;
+
+	if (!res || !res->pdev) {
+		dprintk(VIDC_ERR, "%s - invalid inputs\n", __func__);
+		return -EINVAL;
+	}
+	pdev = res->pdev;
+
+	domains_parent_node = of_find_node_by_name(pdev->dev.of_node,
+			"qcom,vidc-iommu-domains");
+	if (!domains_parent_node) {
+		dprintk(VIDC_DBG,
+			"%s legacy iommu domains not present\n", __func__);
+		return 0;
+	}
+
+	/* set up each context bank for legacy DT bindings*/
+	for_each_child_of_node(domains_parent_node,
+		domains_child_node) {
+		cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL);
+		if (!cb) {
+			dprintk(VIDC_ERR,
+				"%s - Failed to allocate cb\n", __func__);
+			return -ENOMEM;
+		}
+		INIT_LIST_HEAD(&cb->list);
+		list_add_tail(&cb->list, &res->context_banks);
+
+		ctx_node = of_parse_phandle(domains_child_node,
+				"qcom,vidc-domain-phandle", 0);
+		if (!ctx_node) {
+			dprintk(VIDC_ERR,
+				"%s Unable to parse pHandle\n", __func__);
+			rc = -EBADHANDLE;
+			goto err_setup_cb;
+		}
+
+		rc = of_property_read_string(ctx_node, "label", &(cb->name));
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s Could not find label\n", __func__);
+			goto err_setup_cb;
+		}
+
+		rc = of_property_read_u32_array(ctx_node,
+			"qcom,virtual-addr-pool", (u32 *)&cb->addr_range, 2);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s Could not read addr pool for group : %s (%d)\n",
+				__func__, cb->name, rc);
+			goto err_setup_cb;
+		}
+
+		cb->is_secure =
+			of_property_read_bool(ctx_node, "qcom,secure-domain");
+
+		rc = of_property_read_u32(domains_child_node,
+				"qcom,vidc-buffer-types", &cb->buffer_type);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s Could not read buffer type (%d)\n",
+				__func__, rc);
+			goto err_setup_cb;
+		}
+
+		cb->dev = msm_iommu_get_ctx(cb->name);
+		if (IS_ERR_OR_NULL(cb->dev)) {
+			dprintk(VIDC_ERR, "%s could not get device for cb %s\n",
+					__func__, cb->name);
+			rc = -ENOENT;
+			goto err_setup_cb;
+		}
+
+		rc = msm_vidc_setup_context_bank(cb, cb->dev);
+		if (rc) {
+			dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc);
+			goto err_setup_cb;
+		}
+		dprintk(VIDC_DBG,
+			"%s: context bank %s secure %d addr start = %#x addr size = %#x buffer_type = %#x\n",
+			__func__, cb->name, cb->is_secure, cb->addr_range.start,
+			cb->addr_range.size, cb->buffer_type);
+	}
+	return rc;
+
+err_setup_cb:
+	list_del(&cb->list);
+	return rc;
+}
+
+int read_context_bank_resources_from_dt(struct platform_device *pdev)
+{
+	struct msm_vidc_core *core;
+	int rc = 0;
+
+	if (!pdev) {
+		dprintk(VIDC_ERR, "Invalid platform device\n");
+		return -EINVAL;
+	} else if (!pdev->dev.parent) {
+		dprintk(VIDC_ERR, "Failed to find a parent for %s\n",
+				dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+
+	core = dev_get_drvdata(pdev->dev.parent);
+	if (!core) {
+		dprintk(VIDC_ERR, "Failed to find cookie in parent device %s",
+				dev_name(pdev->dev.parent));
+		return -EINVAL;
+	}
+
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,fw-context-bank")) {
+		if (core->resources.use_non_secure_pil) {
+			struct context_bank_info *cb;
+
+			cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL);
+			if (!cb) {
+				dprintk(VIDC_ERR, "alloc venus cb failed\n");
+				return -ENOMEM;
+			}
+
+			cb->dev = &pdev->dev;
+			rc = venus_boot_init(&core->resources, cb);
+			if (rc) {
+				dprintk(VIDC_ERR,
+				"Failed to init non-secure PIL %d\n", rc);
+			}
+		}
+	} else {
+		rc = msm_vidc_populate_context_bank(&pdev->dev, core);
+		if (rc)
+			dprintk(VIDC_ERR, "Failed to probe context bank\n");
+		else
+			dprintk(VIDC_DBG, "Successfully probed context bank\n");
+	}
+	return rc;
+}
+
+int read_bus_resources_from_dt(struct platform_device *pdev)
+{
+	struct msm_vidc_core *core;
+
+	if (!pdev) {
+		dprintk(VIDC_ERR, "Invalid platform device\n");
+		return -EINVAL;
+	} else if (!pdev->dev.parent) {
+		dprintk(VIDC_ERR, "Failed to find a parent for %s\n",
+				dev_name(&pdev->dev));
+		return -ENODEV;
+	}
+
+	core = dev_get_drvdata(pdev->dev.parent);
+	if (!core) {
+		dprintk(VIDC_ERR, "Failed to find cookie in parent device %s",
+				dev_name(pdev->dev.parent));
+		return -EINVAL;
+	}
+
+	return msm_vidc_populate_bus(&pdev->dev, &core->resources);
+}
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h
new file mode 100644
index 0000000..8ee02e3
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.h
@@ -0,0 +1,35 @@
+
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef DT_PARSE
+#define DT_PARSE
+#include <linux/of.h>
+#include "msm_vidc_resources.h"
+void msm_vidc_free_platform_resources(
+		struct msm_vidc_platform_resources *res);
+
+int read_hfi_type(struct platform_device *pdev);
+
+int read_platform_resources_from_dt(
+		struct msm_vidc_platform_resources *res);
+
+int read_context_bank_resources_from_dt(struct platform_device *pdev);
+
+int read_bus_resources_from_dt(struct platform_device *pdev);
+
+int msm_vidc_load_u32_table(struct platform_device *pdev,
+		struct device_node *of_node, char *table_name, int struct_size,
+		u32 **table, u32 *num_elements);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h
new file mode 100644
index 0000000..383aeda
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_resources.h
@@ -0,0 +1,203 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __MSM_VIDC_RESOURCES_H__
+#define __MSM_VIDC_RESOURCES_H__
+
+#include <linux/devfreq.h>
+#include <linux/platform_device.h>
+#include <media/msm_vidc.h>
+#define MAX_BUFFER_TYPES 32
+
+struct version_table {
+	u32 version_mask;
+	u32 version_shift;
+};
+
+struct load_freq_table {
+	u32 load;
+	u32 freq;
+	u32 supported_codecs;
+};
+
+struct dcvs_table {
+	u32 load;
+	u32 load_low;
+	u32 load_high;
+	u32 supported_codecs;
+};
+
+struct dcvs_limit {
+	u32 min_mbpf;
+	u32 fps;
+};
+
+struct imem_ab_table {
+	u32 core_freq;
+	u32 imem_ab;
+};
+
+struct reg_value_pair {
+	u32 reg;
+	u32 value;
+};
+
+struct reg_set {
+	struct reg_value_pair *reg_tbl;
+	int count;
+};
+
+struct addr_range {
+	u32 start;
+	u32 size;
+};
+
+struct addr_set {
+	struct addr_range *addr_tbl;
+	int count;
+};
+
+struct context_bank_info {
+	struct list_head list;
+	const char *name;
+	u32 buffer_type;
+	bool is_secure;
+	struct addr_range addr_range;
+	struct device *dev;
+	struct dma_iommu_mapping *mapping;
+};
+
+struct buffer_usage_table {
+	u32 buffer_type;
+	u32 tz_usage;
+};
+
+struct buffer_usage_set {
+	struct buffer_usage_table *buffer_usage_tbl;
+	u32 count;
+};
+
+struct regulator_info {
+	struct regulator *regulator;
+	bool has_hw_power_collapse;
+	char *name;
+};
+
+struct regulator_set {
+	struct regulator_info *regulator_tbl;
+	u32 count;
+};
+
+struct clock_info {
+	const char *name;
+	struct clk *clk;
+	struct load_freq_table *load_freq_tbl;
+	u32 count;
+	bool has_scaling;
+};
+
+struct clock_set {
+	struct clock_info *clock_tbl;
+	u32 count;
+};
+
+struct bus_info {
+	char *name;
+	int master;
+	int slave;
+	unsigned int range[2];
+	const char *governor;
+	struct device *dev;
+	struct devfreq_dev_profile devfreq_prof;
+	struct devfreq *devfreq;
+	struct msm_bus_client_handle *client;
+};
+
+struct bus_set {
+	struct bus_info *bus_tbl;
+	u32 count;
+};
+
+enum imem_type {
+	IMEM_NONE,
+	IMEM_OCMEM,
+	IMEM_VMEM,
+	IMEM_MAX,
+};
+
+struct allowed_clock_rates_table {
+	u32 clock_rate;
+};
+
+struct clock_profile_entry {
+	u32 codec_mask;
+	u32 cycles;
+	u32 low_power_factor;
+};
+
+struct clock_freq_table {
+	struct clock_profile_entry *clk_prof_entries;
+	u32 count;
+};
+
+struct msm_vidc_platform_resources {
+	phys_addr_t firmware_base;
+	phys_addr_t register_base;
+	uint32_t register_size;
+	uint32_t irq;
+	struct version_table *pf_ver_tbl;
+	struct version_table *pf_cap_tbl;
+	struct version_table *pf_speedbin_tbl;
+	struct allowed_clock_rates_table *allowed_clks_tbl;
+	u32 allowed_clks_tbl_size;
+	struct clock_freq_table clock_freq_tbl;
+	struct load_freq_table *load_freq_tbl;
+	uint32_t load_freq_tbl_size;
+	struct dcvs_table *dcvs_tbl;
+	uint32_t dcvs_tbl_size;
+	struct dcvs_limit *dcvs_limit;
+	struct imem_ab_table *imem_ab_tbl;
+	u32 imem_ab_tbl_size;
+	struct reg_set reg_set;
+	struct addr_set qdss_addr_set;
+	struct buffer_usage_set buffer_usage_set;
+	uint32_t imem_size;
+	enum imem_type imem_type;
+	uint32_t max_load;
+	struct platform_device *pdev;
+	struct regulator_set regulator_set;
+	struct clock_set clock_set;
+	struct bus_set bus_set;
+	bool use_non_secure_pil;
+	bool sw_power_collapsible;
+	bool sys_idle_indicator;
+	bool slave_side_cp;
+	struct list_head context_banks;
+	bool thermal_mitigable;
+	const char *fw_name;
+	const char *hfi_version;
+	bool never_unload_fw;
+	uint32_t pm_qos_latency_us;
+	uint32_t max_inst_count;
+	uint32_t max_secure_inst_count;
+};
+
+static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)
+{
+	return !list_empty(&res->context_banks);
+}
+
+extern uint32_t msm_vidc_pwr_collapse_delay;
+
+#endif
+
diff --git a/drivers/media/platform/msm/vidc_3x/venus_boot.c b/drivers/media/platform/msm/vidc_3x/venus_boot.c
new file mode 100644
index 0000000..715492b
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_boot.c
@@ -0,0 +1,488 @@
+/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define VIDC_DBG_LABEL "venus_boot"
+
+#include <asm/dma-iommu.h>
+#include <asm/page.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_io.h"
+#include "venus_boot.h"
+
+/* VENUS WRAPPER registers */
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1018)
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x101C)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1020)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1024)
+
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1020)
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1024)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x1028)
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2 \
+				(VIDC_WRAPPER_BASE_OFFS + 0x102C)
+
+#define VENUS_WRAPPER_SW_RESET	(VIDC_WRAPPER_BASE_OFFS + 0x3000)
+
+/* VENUS VBIF registers */
+#define VENUS_VBIF_CLKON_FORCE_ON			BIT(0)
+
+#define VENUS_VBIF_ADDR_TRANS_EN  (VIDC_VBIF_BASE_OFFS + 0x1000)
+#define VENUS_VBIF_AT_OLD_BASE    (VIDC_VBIF_BASE_OFFS + 0x1004)
+#define VENUS_VBIF_AT_OLD_HIGH    (VIDC_VBIF_BASE_OFFS + 0x1008)
+#define VENUS_VBIF_AT_NEW_BASE    (VIDC_VBIF_BASE_OFFS + 0x1010)
+#define VENUS_VBIF_AT_NEW_HIGH    (VIDC_VBIF_BASE_OFFS + 0x1018)
+
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US				50
+
+#define VENUS_REGION_SIZE				0x00500000
+
+static struct {
+	struct msm_vidc_platform_resources *resources;
+	struct regulator *gdsc;
+	const char *reg_name;
+	void __iomem *reg_base;
+	struct device *iommu_ctx_bank_dev;
+	struct dma_iommu_mapping *mapping;
+	dma_addr_t fw_iova;
+	bool is_booted;
+	bool hw_ver_checked;
+	u32 fw_sz;
+	u32 hw_ver_major;
+	u32 hw_ver_minor;
+	void *venus_notif_hdle;
+} *venus_data = NULL;
+
+/* Get venus clocks and set rates for rate-settable clocks */
+static int venus_clock_setup(void)
+{
+	int i, rc = 0;
+	unsigned long rate;
+	struct msm_vidc_platform_resources *res = venus_data->resources;
+	struct clock_info *cl;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		/* Make sure rate-settable clocks' rates are set */
+		if (!clk_get_rate(cl->clk) && cl->count) {
+			rate = clk_round_rate(cl->clk, 0);
+			rc = clk_set_rate(cl->clk, rate);
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"Failed to set clock rate %lu %s: %d\n",
+						rate, cl->name, rc);
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int venus_clock_prepare_enable(void)
+{
+	int i, rc = 0;
+	struct msm_vidc_platform_resources *res = venus_data->resources;
+	struct clock_info *cl;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			dprintk(VIDC_ERR, "failed to enable %s\n", cl->name);
+			for (i--; i >= 0; i--) {
+				cl = &res->clock_set.clock_tbl[i];
+				clk_disable_unprepare(cl->clk);
+			}
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static void venus_clock_disable_unprepare(void)
+{
+	int i;
+	struct msm_vidc_platform_resources *res = venus_data->resources;
+	struct clock_info *cl;
+
+	for (i = 0; i < res->clock_set.count; i++) {
+		cl = &res->clock_set.clock_tbl[i];
+		clk_disable_unprepare(cl->clk);
+	}
+}
+
+static int venus_setup_cb(struct device *dev,
+				u32 size)
+{
+	dma_addr_t va_start = 0x0;
+	size_t va_size = size;
+
+	venus_data->mapping = arm_iommu_create_mapping(
+		dev->bus, va_start, va_size);
+	if (IS_ERR_OR_NULL(venus_data->mapping)) {
+		dprintk(VIDC_ERR, "%s: failed to create mapping for %s\n",
+		__func__, dev_name(dev));
+		return -ENODEV;
+	}
+	dprintk(VIDC_DBG,
+		"%s Attached device %pK and created mapping %pK for %s\n",
+		__func__, dev, venus_data->mapping, dev_name(dev));
+	return 0;
+}
+
+static int pil_venus_mem_setup(size_t size)
+{
+	int rc = 0;
+
+	if (!venus_data->mapping) {
+		size = round_up(size, SZ_4K);
+		rc = venus_setup_cb(venus_data->iommu_ctx_bank_dev, size);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to setup context bank for venus : %s\n",
+				__func__,
+				dev_name(venus_data->iommu_ctx_bank_dev));
+			return rc;
+		}
+		venus_data->fw_sz = size;
+	}
+
+	return rc;
+}
+
+static int pil_venus_auth_and_reset(void)
+{
+	int rc;
+
+	phys_addr_t fw_bias = venus_data->resources->firmware_base;
+	void __iomem *reg_base = venus_data->reg_base;
+	u32 ver;
+	bool iommu_present = is_iommu_present(venus_data->resources);
+	struct device *dev = venus_data->iommu_ctx_bank_dev;
+
+	if (!fw_bias) {
+		dprintk(VIDC_ERR, "FW bias is not valid\n");
+		return -EINVAL;
+	}
+	venus_data->fw_iova = (dma_addr_t)NULL;
+	/* Get Venus version number */
+	if (!venus_data->hw_ver_checked) {
+		ver = readl_relaxed(reg_base + VIDC_WRAPPER_HW_VERSION);
+		venus_data->hw_ver_minor = (ver & 0x0FFF0000) >> 16;
+		venus_data->hw_ver_major = (ver & 0xF0000000) >> 28;
+		venus_data->hw_ver_checked = 1;
+	}
+
+	if (iommu_present) {
+		u32 cpa_start_addr, cpa_end_addr, fw_start_addr, fw_end_addr;
+		/* Get the cpa and fw start/end addr based on Venus version */
+		if (venus_data->hw_ver_major == 0x1 &&
+				venus_data->hw_ver_minor <= 1) {
+			cpa_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v1;
+			cpa_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v1;
+			fw_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v1;
+			fw_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v1;
+		} else {
+			cpa_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR_v2;
+			cpa_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR_v2;
+			fw_start_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR_v2;
+			fw_end_addr =
+				VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR_v2;
+		}
+
+		/* Program CPA start and end address */
+		writel_relaxed(0, reg_base + cpa_start_addr);
+		writel_relaxed(venus_data->fw_sz, reg_base + cpa_end_addr);
+
+		/* Program FW start and end address */
+		writel_relaxed(0, reg_base + fw_start_addr);
+		writel_relaxed(venus_data->fw_sz, reg_base + fw_end_addr);
+	} else {
+		rc = regulator_enable(venus_data->gdsc);
+		if (rc) {
+			dprintk(VIDC_ERR, "GDSC enable failed\n");
+			goto err;
+		}
+
+		rc = venus_clock_prepare_enable();
+		if (rc) {
+			dprintk(VIDC_ERR, "Clock prepare and enable failed\n");
+			regulator_disable(venus_data->gdsc);
+			goto err;
+		}
+
+		writel_relaxed(0, reg_base + VENUS_VBIF_AT_OLD_BASE);
+		writel_relaxed(VENUS_REGION_SIZE,
+				reg_base + VENUS_VBIF_AT_OLD_HIGH);
+		writel_relaxed(fw_bias, reg_base + VENUS_VBIF_AT_NEW_BASE);
+		writel_relaxed(fw_bias + VENUS_REGION_SIZE,
+				reg_base + VENUS_VBIF_AT_NEW_HIGH);
+		writel_relaxed(0x7F007F, reg_base + VENUS_VBIF_ADDR_TRANS_EN);
+		venus_clock_disable_unprepare();
+		regulator_disable(venus_data->gdsc);
+	}
+	/* Make sure all register writes are committed. */
+	mb();
+
+	/*
+	 * Need to wait 10 cycles of internal clocks before bringing ARM9
+	 * out of reset.
+	 */
+	udelay(1);
+
+	if (iommu_present) {
+		phys_addr_t pa = fw_bias;
+
+		rc = arm_iommu_attach_device(dev, venus_data->mapping);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to attach iommu for %s : %d\n",
+				dev_name(dev), rc);
+			goto release_mapping;
+		}
+
+		dprintk(VIDC_DBG, "Attached and created mapping for %s\n",
+				dev_name(dev));
+
+		/* Map virtual addr space 0 - fw_sz to fw phys addr space */
+		rc = iommu_map(venus_data->mapping->domain,
+			venus_data->fw_iova, pa, venus_data->fw_sz,
+			IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV);
+		if (!rc) {
+			dprintk(VIDC_DBG,
+				"%s - Successfully mapped and performed test translation!\n",
+				dev_name(dev));
+		}
+
+		if (rc || (venus_data->fw_iova != 0)) {
+			dprintk(VIDC_ERR, "%s - Failed to setup IOMMU\n",
+					dev_name(dev));
+			goto err_iommu_map;
+		}
+	}
+	/* Bring Arm9 out of reset */
+	writel_relaxed(0, reg_base + VENUS_WRAPPER_SW_RESET);
+
+	venus_data->is_booted = 1;
+	return 0;
+
+err_iommu_map:
+	if (iommu_present)
+		arm_iommu_detach_device(dev);
+release_mapping:
+	if (iommu_present)
+		arm_iommu_release_mapping(venus_data->mapping);
+err:
+	return rc;
+}
+
+static int pil_venus_shutdown(void)
+{
+	void __iomem *reg_base = venus_data->reg_base;
+	u32 reg;
+	int rc;
+
+	if (!venus_data->is_booted)
+		return 0;
+
+	/* Assert the reset to ARM9 */
+	reg = readl_relaxed(reg_base + VENUS_WRAPPER_SW_RESET);
+	reg |= BIT(4);
+	writel_relaxed(reg, reg_base + VENUS_WRAPPER_SW_RESET);
+
+	/* Make sure reset is asserted before the mapping is removed */
+	mb();
+
+	if (is_iommu_present(venus_data->resources)) {
+		iommu_unmap(venus_data->mapping->domain, venus_data->fw_iova,
+			venus_data->fw_sz);
+		arm_iommu_detach_device(venus_data->iommu_ctx_bank_dev);
+	}
+	/*
+	 * Force the VBIF clk to be on to avoid AXI bridge halt ack failure
+	 * for certain Venus version.
+	 */
+	if (venus_data->hw_ver_major == 0x1 &&
+				(venus_data->hw_ver_minor == 0x2 ||
+				venus_data->hw_ver_minor == 0x3)) {
+		reg = readl_relaxed(reg_base + VIDC_VENUS_VBIF_CLK_ON);
+		reg |= VENUS_VBIF_CLKON_FORCE_ON;
+		writel_relaxed(reg, reg_base + VIDC_VENUS_VBIF_CLK_ON);
+	}
+
+	/* Halt AXI and AXI OCMEM VBIF Access */
+	reg = readl_relaxed(reg_base + VENUS_VBIF_AXI_HALT_CTRL0);
+	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+	writel_relaxed(reg, reg_base + VENUS_VBIF_AXI_HALT_CTRL0);
+
+	/* Request for AXI bus port halt */
+	rc = readl_poll_timeout(reg_base + VENUS_VBIF_AXI_HALT_CTRL1,
+			reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+			POLL_INTERVAL_US,
+			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+	if (rc)
+		dprintk(VIDC_ERR, "Port halt timeout\n");
+
+	venus_data->is_booted = 0;
+
+	return 0;
+}
+
+static int venus_notifier_cb(struct notifier_block *this, unsigned long code,
+							void *ss_handle)
+{
+	struct notif_data *data = (struct notif_data *)ss_handle;
+	static bool venus_data_set;
+	int ret;
+
+	if (!data->no_auth)
+		return NOTIFY_DONE;
+
+	if (!venus_data_set) {
+		ret = venus_clock_setup();
+		if (ret)
+			return ret;
+
+		ret = of_property_read_string(data->pdev->dev.of_node,
+				"qcom,proxy-reg-names", &venus_data->reg_name);
+		if (ret)
+			return ret;
+
+		venus_data->gdsc = devm_regulator_get(
+				&data->pdev->dev, venus_data->reg_name);
+		if (IS_ERR(venus_data->gdsc)) {
+			dprintk(VIDC_ERR, "Failed to get Venus GDSC\n");
+			return -ENODEV;
+		}
+
+		venus_data_set = true;
+	}
+
+	if (code != SUBSYS_AFTER_POWERUP && code != SUBSYS_AFTER_SHUTDOWN)
+		return NOTIFY_DONE;
+
+	ret = regulator_enable(venus_data->gdsc);
+	if (ret) {
+		dprintk(VIDC_ERR, "GDSC enable failed\n");
+		return ret;
+	}
+
+	ret = venus_clock_prepare_enable();
+	if (ret) {
+		dprintk(VIDC_ERR, "Clock prepare and enable failed\n");
+		goto err_clks;
+	}
+
+	if (code == SUBSYS_AFTER_POWERUP) {
+		if (is_iommu_present(venus_data->resources))
+			pil_venus_mem_setup(VENUS_REGION_SIZE);
+		pil_venus_auth_and_reset();
+	} else if (code == SUBSYS_AFTER_SHUTDOWN)
+		pil_venus_shutdown();
+
+	venus_clock_disable_unprepare();
+	regulator_disable(venus_data->gdsc);
+
+	return NOTIFY_DONE;
+err_clks:
+	regulator_disable(venus_data->gdsc);
+	return ret;
+}
+
+static struct notifier_block venus_notifier = {
+	.notifier_call = venus_notifier_cb,
+};
+
+int venus_boot_init(struct msm_vidc_platform_resources *res,
+			struct context_bank_info *cb)
+{
+	int rc = 0;
+
+	if (!res || !cb) {
+		dprintk(VIDC_ERR, "Invalid platform resource handle\n");
+		return -EINVAL;
+	}
+	venus_data = kzalloc(sizeof(*venus_data), GFP_KERNEL);
+	if (!venus_data)
+		return -ENOMEM;
+
+	venus_data->resources = res;
+	venus_data->iommu_ctx_bank_dev = cb->dev;
+	if (!venus_data->iommu_ctx_bank_dev) {
+		dprintk(VIDC_ERR, "Invalid venus context bank device\n");
+		return -ENODEV;
+	}
+	venus_data->reg_base = ioremap_nocache(res->register_base,
+			(unsigned long)res->register_size);
+	if (!venus_data->reg_base) {
+		dprintk(VIDC_ERR,
+				"could not map reg addr %pa of size %d\n",
+				&res->register_base, res->register_size);
+		rc = -ENOMEM;
+		goto err_ioremap_fail;
+	}
+	venus_data->venus_notif_hdle = subsys_notif_register_notifier("venus",
+							&venus_notifier);
+	if (IS_ERR(venus_data->venus_notif_hdle)) {
+		dprintk(VIDC_ERR, "register event notification failed\n");
+		rc = PTR_ERR(venus_data->venus_notif_hdle);
+		goto err_subsys_notif;
+	}
+
+	return rc;
+
+err_subsys_notif:
+err_ioremap_fail:
+	kfree(venus_data);
+	return rc;
+}
+
+void venus_boot_deinit(void)
+{
+	venus_data->resources = NULL;
+	subsys_notif_unregister_notifier(venus_data->venus_notif_hdle,
+			&venus_notifier);
+	kfree(venus_data);
+}
diff --git a/drivers/media/platform/msm/vidc_3x/venus_boot.h b/drivers/media/platform/msm/vidc_3x/venus_boot.h
new file mode 100644
index 0000000..11e2dc4
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_boot.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __VENUS_BOOT_H__
+#define __VENUS_BOOT_H__
+#include "msm_vidc_resources.h"
+
+int venus_boot_init(struct msm_vidc_platform_resources *res,
+		struct context_bank_info *cb);
+void venus_boot_deinit(void);
+
+#endif /* __VENUS_BOOT_H__ */
diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.c b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
new file mode 100644
index 0000000..ec6f9b0
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.c
@@ -0,0 +1,4715 @@
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/dma-iommu.h>
+#include <asm/memory.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/coresight-stm.h>
+#include <linux/delay.h>
+#include <linux/devfreq.h>
+#include <linux/hash.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/smem.h>
+#include <soc/qcom/subsystem_restart.h>
+#include "hfi_packetization.h"
+#include "msm_vidc_debug.h"
+#include "venus_hfi.h"
+#include "vidc_hfi_io.h"
+
+#define FIRMWARE_SIZE			0X00A00000
+#define REG_ADDR_OFFSET_BITMASK	0x000FFFFF
+#define QDSS_IOVA_START 0x80001000
+
+static struct hal_device_data hal_ctxt;
+
+#define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8
+struct tzbsp_memprot {
+	u32 cp_start;
+	u32 cp_size;
+	u32 cp_nonpixel_start;
+	u32 cp_nonpixel_size;
+};
+
+struct tzbsp_resp {
+	int ret;
+};
+
+#define TZBSP_VIDEO_SET_STATE 0xa
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US 50
+
+enum tzbsp_video_state {
+	TZBSP_VIDEO_STATE_SUSPEND = 0,
+	TZBSP_VIDEO_STATE_RESUME = 1,
+	TZBSP_VIDEO_STATE_RESTORE_THRESHOLD = 2,
+};
+
+struct tzbsp_video_set_state_req {
+	u32 state; /* should be tzbsp_video_state enum value */
+	u32 spare; /* reserved for future, should be zero */
+};
+
+const struct msm_vidc_gov_data DEFAULT_BUS_VOTE = {
+	.data = NULL,
+	.data_count = 0,
+	.imem_size = 0,
+};
+
+const int max_packets = 250;
+
+static void venus_hfi_pm_handler(struct work_struct *work);
+static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_handler);
+static inline int __resume(struct venus_hfi_device *device);
+static inline int __suspend(struct venus_hfi_device *device);
+static int __disable_regulators(struct venus_hfi_device *device);
+static int __enable_regulators(struct venus_hfi_device *device);
+static inline int __prepare_enable_clks(struct venus_hfi_device *device);
+static inline void __disable_unprepare_clks(struct venus_hfi_device *device);
+static int __scale_clocks_load(struct venus_hfi_device *device, int load,
+		struct vidc_clk_scale_data *data,
+		unsigned long instant_bitrate);
+static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet);
+static int __initialize_packetization(struct venus_hfi_device *device);
+static struct hal_session *__get_session(struct venus_hfi_device *device,
+		u32 session_id);
+static int __iface_cmdq_write(struct venus_hfi_device *device,
+					void *pkt);
+static int __load_fw(struct venus_hfi_device *device);
+static void __unload_fw(struct venus_hfi_device *device);
+static int __tzbsp_set_video_state(enum tzbsp_video_state state);
+
+
+/**
+ * Utility function to enforce some of our assumptions.  Spam calls to this
+ * in hotspots in code to double check some of the assumptions that we hold.
+ */
+static inline void __strict_check(struct venus_hfi_device *device)
+{
+	if (!mutex_is_locked(&device->lock)) {
+		dprintk(VIDC_WARN,
+			"device->lock mutex is not locked\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+	}
+}
+
+static inline void __set_state(struct venus_hfi_device *device,
+		enum venus_hfi_state state)
+{
+	device->state = state;
+}
+
+static inline bool __core_in_valid_state(struct venus_hfi_device *device)
+{
+	return device->state != VENUS_STATE_DEINIT;
+}
+
+static void __dump_packet(u8 *packet)
+{
+	u32 c = 0, packet_size = *(u32 *)packet;
+	const int row_size = 32;
+	/* row must contain enough for 0xdeadbaad * 8 to be converted into
+	 * "de ad ba ab " * 8 + '\0'
+	 */
+	char row[3 * row_size];
+
+	for (c = 0; c * row_size < packet_size; ++c) {
+		int bytes_to_read = ((c + 1) * row_size > packet_size) ?
+			packet_size % row_size : row_size;
+		hex_dump_to_buffer(packet + c * row_size, bytes_to_read,
+				row_size, 4, row, sizeof(row), false);
+		dprintk(VIDC_PKT, "%s\n", row);
+	}
+}
+
+static void __sim_modify_cmd_packet(u8 *packet, struct venus_hfi_device *device)
+{
+	struct hfi_cmd_sys_session_init_packet *sys_init;
+	struct hal_session *session = NULL;
+	u8 i;
+	phys_addr_t fw_bias = 0;
+
+	if (!device || !packet) {
+		dprintk(VIDC_ERR, "Invalid Param\n");
+		return;
+	} else if (!device->hal_data->firmware_base
+			|| is_iommu_present(device->res)) {
+		return;
+	}
+
+	fw_bias = device->hal_data->firmware_base;
+	sys_init = (struct hfi_cmd_sys_session_init_packet *)packet;
+
+	session = __get_session(device, sys_init->session_id);
+	if (!session) {
+		dprintk(VIDC_DBG, "%s :Invalid session id: %x\n",
+				__func__, sys_init->session_id);
+		return;
+	}
+
+	switch (sys_init->packet_type) {
+	case HFI_CMD_SESSION_EMPTY_BUFFER:
+		if (session->is_decoder) {
+			struct hfi_cmd_session_empty_buffer_compressed_packet
+			*pkt = (struct
+			hfi_cmd_session_empty_buffer_compressed_packet
+			*) packet;
+			pkt->packet_buffer -= fw_bias;
+		} else {
+			struct
+			hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+			*pkt = (struct
+			hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+			*) packet;
+			pkt->packet_buffer -= fw_bias;
+		}
+		break;
+	case HFI_CMD_SESSION_FILL_BUFFER:
+	{
+		struct hfi_cmd_session_fill_buffer_packet *pkt =
+			(struct hfi_cmd_session_fill_buffer_packet *)packet;
+		pkt->packet_buffer -= fw_bias;
+		break;
+	}
+	case HFI_CMD_SESSION_SET_BUFFERS:
+	{
+		struct hfi_cmd_session_set_buffers_packet *pkt =
+			(struct hfi_cmd_session_set_buffers_packet *)packet;
+		if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
+			pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
+			struct hfi_buffer_info *buff;
+
+			buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+			buff->buffer_addr -= fw_bias;
+			if (buff->extra_data_addr >= fw_bias)
+				buff->extra_data_addr -= fw_bias;
+		} else {
+			for (i = 0; i < pkt->num_buffers; i++)
+				pkt->rg_buffer_info[i] -= fw_bias;
+		}
+		break;
+	}
+	case HFI_CMD_SESSION_RELEASE_BUFFERS:
+	{
+		struct hfi_cmd_session_release_buffer_packet *pkt =
+			(struct hfi_cmd_session_release_buffer_packet *)packet;
+		if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
+			pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
+			struct hfi_buffer_info *buff;
+
+			buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
+			buff->buffer_addr -= fw_bias;
+			buff->extra_data_addr -= fw_bias;
+		} else {
+			for (i = 0; i < pkt->num_buffers; i++)
+				pkt->rg_buffer_info[i] -= fw_bias;
+		}
+		break;
+	}
+	case HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER:
+	{
+		struct hfi_cmd_session_parse_sequence_header_packet *pkt =
+			(struct hfi_cmd_session_parse_sequence_header_packet *)
+		packet;
+		pkt->packet_buffer -= fw_bias;
+		break;
+	}
+	case HFI_CMD_SESSION_GET_SEQUENCE_HEADER:
+	{
+		struct hfi_cmd_session_get_sequence_header_packet *pkt =
+			(struct hfi_cmd_session_get_sequence_header_packet *)
+		packet;
+		pkt->packet_buffer -= fw_bias;
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+static int __acquire_regulator(struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	if (rinfo->has_hw_power_collapse) {
+		rc = regulator_set_mode(rinfo->regulator,
+				REGULATOR_MODE_NORMAL);
+		if (rc) {
+			/*
+			 * This is somewhat fatal, but nothing we can do
+			 * about it. We can't disable the regulator w/o
+			 * getting it back under s/w control
+			 */
+			dprintk(VIDC_WARN,
+				"Failed to acquire regulator control: %s\n",
+					rinfo->name);
+		} else {
+
+			dprintk(VIDC_DBG,
+					"Acquire regulator control from HW: %s\n",
+					rinfo->name);
+
+		}
+	}
+
+	if (!regulator_is_enabled(rinfo->regulator)) {
+		dprintk(VIDC_WARN, "Regulator is not enabled %s\n",
+			rinfo->name);
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+	}
+
+	return rc;
+}
+
+static int __hand_off_regulator(struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	if (rinfo->has_hw_power_collapse) {
+		rc = regulator_set_mode(rinfo->regulator,
+				REGULATOR_MODE_FAST);
+		if (rc) {
+			dprintk(VIDC_WARN,
+				"Failed to hand off regulator control: %s\n",
+					rinfo->name);
+		} else {
+			dprintk(VIDC_DBG,
+					"Hand off regulator control to HW: %s\n",
+					rinfo->name);
+		}
+	}
+
+	return rc;
+}
+
+static int __hand_off_regulators(struct venus_hfi_device *device)
+{
+	struct regulator_info *rinfo;
+	int rc = 0, c = 0;
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		rc = __hand_off_regulator(rinfo);
+		/*
+		 * If one regulator hand off failed, driver should take
+		 * the control for other regulators back.
+		 */
+		if (rc)
+			goto err_reg_handoff_failed;
+		c++;
+	}
+
+	return rc;
+err_reg_handoff_failed:
+	venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
+		__acquire_regulator(rinfo);
+
+	return rc;
+}
+
+static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
+		bool *rx_req_is_set)
+{
+	struct hfi_queue_header *queue;
+	u32 packet_size_in_words, new_write_idx;
+	u32 empty_space, read_idx;
+	u32 *write_ptr;
+
+	if (!qinfo || !packet) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	} else if (!qinfo->q_array.align_virtual_addr) {
+		dprintk(VIDC_WARN, "Queues have already been freed\n");
+		return -EINVAL;
+	}
+
+	queue = (struct hfi_queue_header *) qinfo->q_hdr;
+	if (!queue) {
+		dprintk(VIDC_ERR, "queue not present\n");
+		return -ENOENT;
+	}
+
+	if (msm_vidc_debug & VIDC_PKT) {
+		dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
+		__dump_packet(packet);
+	}
+
+	packet_size_in_words = (*(u32 *)packet) >> 2;
+	if (!packet_size_in_words) {
+		dprintk(VIDC_ERR, "Zero packet size\n");
+		return -ENODATA;
+	}
+
+	read_idx = queue->qhdr_read_idx;
+
+	empty_space = (queue->qhdr_write_idx >=  read_idx) ?
+		(queue->qhdr_q_size - (queue->qhdr_write_idx -  read_idx)) :
+		(read_idx - queue->qhdr_write_idx);
+	if (empty_space <= packet_size_in_words) {
+		queue->qhdr_tx_req =  1;
+		dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
+					  empty_space, packet_size_in_words);
+		return -ENOTEMPTY;
+	}
+
+	queue->qhdr_tx_req =  0;
+
+	new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
+	write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+		(queue->qhdr_write_idx << 2));
+	if (new_write_idx < queue->qhdr_q_size) {
+		memcpy(write_ptr, packet, packet_size_in_words << 2);
+	} else {
+		new_write_idx -= queue->qhdr_q_size;
+		memcpy(write_ptr, packet, (packet_size_in_words -
+			new_write_idx) << 2);
+		memcpy((void *)qinfo->q_array.align_virtual_addr,
+			packet + ((packet_size_in_words - new_write_idx) << 2),
+			new_write_idx  << 2);
+	}
+
+	/* Memory barrier to make sure packet is written before updating the
+	 * write index
+	 */
+	mb();
+	queue->qhdr_write_idx = new_write_idx;
+	if (rx_req_is_set)
+		*rx_req_is_set = queue->qhdr_rx_req == 1;
+	/* Memory barrier to make sure write index is updated before an
+	 * interrupt is raised on venus.
+	 */
+	mb();
+	return 0;
+}
+
+static void __hal_sim_modify_msg_packet(u8 *packet,
+					struct venus_hfi_device *device)
+{
+	struct hfi_msg_sys_session_init_done_packet *sys_idle;
+	struct hal_session *session = NULL;
+	phys_addr_t fw_bias = 0;
+
+	if (!device || !packet) {
+		dprintk(VIDC_ERR, "Invalid Param\n");
+		return;
+	} else if (!device->hal_data->firmware_base
+			|| is_iommu_present(device->res)) {
+		return;
+	}
+
+	fw_bias = device->hal_data->firmware_base;
+	sys_idle = (struct hfi_msg_sys_session_init_done_packet *)packet;
+	session = __get_session(device, sys_idle->session_id);
+
+	if (!session) {
+		dprintk(VIDC_DBG, "%s: Invalid session id: %x\n",
+				__func__, sys_idle->session_id);
+		return;
+	}
+
+	switch (sys_idle->packet_type) {
+	case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+		if (session->is_decoder) {
+			struct
+			hfi_msg_session_fbd_uncompressed_plane0_packet
+			*pkt_uc = (struct
+			hfi_msg_session_fbd_uncompressed_plane0_packet
+			*) packet;
+			pkt_uc->packet_buffer += fw_bias;
+		} else {
+			struct
+			hfi_msg_session_fill_buffer_done_compressed_packet
+			*pkt = (struct
+			hfi_msg_session_fill_buffer_done_compressed_packet
+			*) packet;
+			pkt->packet_buffer += fw_bias;
+		}
+		break;
+	case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+	{
+		struct hfi_msg_session_empty_buffer_done_packet *pkt =
+		(struct hfi_msg_session_empty_buffer_done_packet *)packet;
+		pkt->packet_buffer += fw_bias;
+		break;
+	}
+	case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+	{
+		struct
+		hfi_msg_session_get_sequence_header_done_packet
+		*pkt =
+		(struct hfi_msg_session_get_sequence_header_done_packet *)
+		packet;
+		pkt->sequence_header += fw_bias;
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
+		u32 *pb_tx_req_is_set)
+{
+	struct hfi_queue_header *queue;
+	u32 packet_size_in_words, new_read_idx;
+	u32 *read_ptr;
+	u32 receive_request = 0;
+		int rc = 0;
+
+	if (!qinfo || !packet || !pb_tx_req_is_set) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	} else if (!qinfo->q_array.align_virtual_addr) {
+		dprintk(VIDC_WARN, "Queues have already been freed\n");
+		return -EINVAL;
+	}
+
+	/*Memory barrier to make sure data is valid before
+	 *reading it
+	 */
+	mb();
+	queue = (struct hfi_queue_header *) qinfo->q_hdr;
+
+	if (!queue) {
+		dprintk(VIDC_ERR, "Queue memory is not allocated\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Do not set receive request for debug queue, if set,
+	 * Venus generates interrupt for debug messages even
+	 * when there is no response message available.
+	 * In general debug queue will not become full as it
+	 * is being emptied out for every interrupt from Venus.
+	 * Venus will anyway generates interrupt if it is full.
+	 */
+	if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
+		receive_request = 1;
+
+	if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
+		queue->qhdr_rx_req = receive_request;
+		*pb_tx_req_is_set = 0;
+		dprintk(VIDC_DBG,
+			"%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n",
+			receive_request ? "message" : "debug",
+			queue->qhdr_rx_req, queue->qhdr_tx_req,
+			queue->qhdr_read_idx);
+		return -ENODATA;
+	}
+
+	read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+				(queue->qhdr_read_idx << 2));
+	packet_size_in_words = (*read_ptr) >> 2;
+	if (!packet_size_in_words) {
+		dprintk(VIDC_ERR, "Zero packet size\n");
+		return -ENODATA;
+	}
+
+	new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
+	if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
+			&& queue->qhdr_read_idx <= queue->qhdr_q_size) {
+		if (new_read_idx < queue->qhdr_q_size) {
+			memcpy(packet, read_ptr,
+					packet_size_in_words << 2);
+		} else {
+			new_read_idx -= queue->qhdr_q_size;
+			memcpy(packet, read_ptr,
+			(packet_size_in_words - new_read_idx) << 2);
+			memcpy(packet + ((packet_size_in_words -
+					new_read_idx) << 2),
+					(u8 *)qinfo->q_array.align_virtual_addr,
+					new_read_idx << 2);
+		}
+	} else {
+		dprintk(VIDC_WARN,
+			"BAD packet received, read_idx: %#x, pkt_size: %d\n",
+			queue->qhdr_read_idx, packet_size_in_words << 2);
+		dprintk(VIDC_WARN, "Dropping this packet\n");
+		new_read_idx = queue->qhdr_write_idx;
+		rc = -ENODATA;
+	}
+
+	queue->qhdr_read_idx = new_read_idx;
+
+	if (queue->qhdr_read_idx != queue->qhdr_write_idx)
+		queue->qhdr_rx_req = 0;
+	else
+		queue->qhdr_rx_req = receive_request;
+
+	*pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0;
+
+	if (msm_vidc_debug & VIDC_PKT) {
+		dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
+		__dump_packet(packet);
+	}
+
+	return rc;
+}
+
+static int __smem_alloc(struct venus_hfi_device *dev,
+			struct vidc_mem_addr *mem, u32 size, u32 align,
+			u32 flags, u32 usage)
+{
+	struct msm_smem *alloc = NULL;
+	int rc = 0;
+
+	if (!dev || !dev->hal_client || !mem || !size) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	dprintk(VIDC_INFO, "start to alloc size: %d, flags: %d\n", size, flags);
+	alloc = msm_smem_alloc(dev->hal_client, size, align, flags, usage, 1);
+	if (!alloc) {
+		dprintk(VIDC_ERR, "Alloc failed\n");
+		rc = -ENOMEM;
+		goto fail_smem_alloc;
+	}
+
+	dprintk(VIDC_DBG, "__smem_alloc: ptr = %pK, size = %d\n",
+			alloc->kvaddr, size);
+	rc = msm_smem_cache_operations(dev->hal_client, alloc,
+		SMEM_CACHE_CLEAN);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to clean cache\n");
+		dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+	}
+
+	mem->mem_size = alloc->size;
+	mem->mem_data = alloc;
+	mem->align_virtual_addr = alloc->kvaddr;
+	mem->align_device_addr = alloc->device_addr;
+	return rc;
+fail_smem_alloc:
+	return rc;
+}
+
+static void __smem_free(struct venus_hfi_device *dev, struct msm_smem *mem)
+{
+	if (!dev || !mem) {
+		dprintk(VIDC_ERR, "invalid param %pK %pK\n", dev, mem);
+		return;
+	}
+
+	msm_smem_free(dev->hal_client, mem);
+}
+
+static void __write_register(struct venus_hfi_device *device,
+		u32 reg, u32 value)
+{
+	u32 hwiosymaddr = reg;
+	u8 *base_addr;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return;
+	}
+
+	__strict_check(device);
+
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Write register failed : Power is OFF\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+		return;
+	}
+
+	base_addr = device->hal_data->register_base;
+	dprintk(VIDC_DBG, "Base addr: %pK, written to: %#x, Value: %#x...\n",
+		base_addr, hwiosymaddr, value);
+	base_addr += hwiosymaddr;
+	writel_relaxed(value, base_addr);
+	/*
+	 * Memory barrier to make sure value is written into the register.
+	 */
+	wmb();
+}
+
+static int __read_register(struct venus_hfi_device *device, u32 reg)
+{
+	int rc = 0;
+	u8 *base_addr;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN,
+			"HFI Read register failed : Power is OFF\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+		return -EINVAL;
+	}
+
+	base_addr = device->hal_data->register_base;
+
+	rc = readl_relaxed(base_addr + reg);
+	/*
+	 * Memory barrier to make sure value is read correctly from the
+	 * register.
+	 */
+	rmb();
+	dprintk(VIDC_DBG, "Base addr: %pK, read from: %#x, value: %#x...\n",
+		base_addr, reg, rc);
+
+	return rc;
+}
+
+static void __set_registers(struct venus_hfi_device *device)
+{
+	struct reg_set *reg_set;
+	int i;
+
+	if (!device->res) {
+		dprintk(VIDC_ERR,
+			"device resources null, cannot set registers\n");
+		return;
+	}
+
+	reg_set = &device->res->reg_set;
+	for (i = 0; i < reg_set->count; i++) {
+		__write_register(device, reg_set->reg_tbl[i].reg,
+				reg_set->reg_tbl[i].value);
+	}
+}
+
+/*
+ * The existence of this function is a hack for 8996 (or certain Venus versions)
+ * to overcome a hardware bug.  Whenever the GDSCs momentarily power collapse
+ * (after calling __hand_off_regulators()), the values of the threshold
+ * registers (typically programmed by TZ) are incorrectly reset.  As a result
+ * reprogram these registers at certain agreed upon points.
+ */
+static void __set_threshold_registers(struct venus_hfi_device *device)
+{
+	u32 version = __read_register(device, VIDC_WRAPPER_HW_VERSION);
+
+	version &= ~GENMASK(15, 0);
+	if (version != (0x3 << 28 | 0x43 << 16))
+		return;
+
+	if (__tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESTORE_THRESHOLD))
+		dprintk(VIDC_ERR, "Failed to restore threshold values\n");
+}
+
+static void __iommu_detach(struct venus_hfi_device *device)
+{
+	struct context_bank_info *cb;
+
+	if (!device || !device->res) {
+		dprintk(VIDC_ERR, "Invalid parameter: %pK\n", device);
+		return;
+	}
+
+	list_for_each_entry(cb, &device->res->context_banks, list) {
+		if (cb->dev)
+			arm_iommu_detach_device(cb->dev);
+		if (cb->mapping)
+			arm_iommu_release_mapping(cb->mapping);
+	}
+}
+
+static bool __is_session_supported(unsigned long sessions_supported,
+		enum vidc_vote_data_session session_type)
+{
+	bool same_codec, same_session_type;
+	int codec_bit, session_type_bit;
+	unsigned long session = session_type;
+
+	if (!sessions_supported || !session)
+		return false;
+
+	/* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
+	codec_bit = ffs(session) - 1;
+	session_type_bit = codec_bit + 1;
+
+	same_codec = test_bit(codec_bit, &sessions_supported) ==
+		test_bit(codec_bit, &session);
+	same_session_type = test_bit(session_type_bit, &sessions_supported) ==
+		test_bit(session_type_bit, &session);
+
+	return same_codec && same_session_type;
+}
+
+bool venus_hfi_is_session_supported(unsigned long sessions_supported,
+		enum vidc_vote_data_session session_type)
+{
+	return __is_session_supported(sessions_supported, session_type);
+}
+
+static int __devfreq_target(struct device *devfreq_dev,
+		unsigned long *freq, u32 flags)
+{
+	int rc = 0;
+	uint64_t ab = 0;
+	struct bus_info *bus = NULL, *temp = NULL;
+	struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);
+
+	venus_hfi_for_each_bus(device, temp) {
+		if (temp->dev == devfreq_dev) {
+			bus = temp;
+			break;
+		}
+	}
+
+	if (!bus) {
+		rc = -EBADHANDLE;
+		goto err_unknown_device;
+	}
+
+	/*
+	 * Clamp for all non zero frequencies. This clamp is necessary to stop
+	 * devfreq driver from spamming - Couldn't update frequency - logs, if
+	 * the scaled ab value is not part of the frequency table.
+	 */
+	if (*freq)
+		*freq = clamp_t(typeof(*freq), *freq, bus->range[0],
+				bus->range[1]);
+
+	/* we expect governors to provide values in kBps form, convert to Bps */
+	ab = *freq * 1000;
+	rc = msm_bus_scale_update_bw(bus->client, ab, 0);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu\n: %d",
+				bus->name, ab, rc);
+		goto err_unknown_device;
+	}
+
+	dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab);
+
+	return 0;
+err_unknown_device:
+	return rc;
+}
+
+static int __devfreq_get_status(struct device *devfreq_dev,
+		struct devfreq_dev_status *stat)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL, *temp = NULL;
+	struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);
+
+	venus_hfi_for_each_bus(device, temp) {
+		if (temp->dev == devfreq_dev) {
+			bus = temp;
+			break;
+		}
+	}
+
+	if (!bus) {
+		rc = -EBADHANDLE;
+		goto err_unknown_device;
+	}
+
+	*stat = (struct devfreq_dev_status) {
+		.private_data = &device->bus_vote,
+		/*
+		 * Put in dummy place holder values for upstream govs, our
+		 * custom gov only needs .private_data.  We should fill this in
+		 * properly if we can actually measure busy_time accurately
+		 * (which we can't at the moment)
+		 */
+		.total_time = 1,
+		.busy_time = 1,
+		.current_frequency = 0,
+	};
+
+err_unknown_device:
+	return rc;
+}
+
+static int __unvote_buses(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+
+	venus_hfi_for_each_bus(device, bus) {
+		int local_rc = 0;
+		unsigned long zero = 0;
+
+		rc = devfreq_suspend_device(bus->devfreq);
+		if (rc)
+			goto err_unknown_device;
+
+		local_rc = __devfreq_target(bus->dev, &zero, 0);
+		rc = rc ?: local_rc;
+	}
+
+	if (rc)
+		dprintk(VIDC_WARN, "Failed to unvote some buses\n");
+
+err_unknown_device:
+	return rc;
+}
+
+static int __vote_buses(struct venus_hfi_device *device,
+		struct vidc_bus_vote_data *data, int num_data)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+	struct vidc_bus_vote_data *new_data = NULL;
+
+	if (!num_data) {
+		dprintk(VIDC_DBG, "No vote data available\n");
+		goto no_data_count;
+	} else if (!data) {
+		dprintk(VIDC_ERR, "Invalid voting data\n");
+		return -EINVAL;
+	}
+
+	new_data = kmemdup(data, num_data * sizeof(*new_data), GFP_KERNEL);
+	if (!new_data) {
+		dprintk(VIDC_ERR, "Can't alloc memory to cache bus votes\n");
+		rc = -ENOMEM;
+		goto err_no_mem;
+	}
+
+no_data_count:
+	kfree(device->bus_vote.data);
+	device->bus_vote.data = new_data;
+	device->bus_vote.data_count = num_data;
+	device->bus_vote.imem_size = device->res->imem_size;
+
+	venus_hfi_for_each_bus(device, bus) {
+		if (bus && bus->devfreq) {
+			/* NOP if already resume */
+			rc = devfreq_resume_device(bus->devfreq);
+			if (rc)
+				goto err_no_mem;
+
+			/* Kick devfreq awake incase _resume() didn't do it */
+			bus->devfreq->nb.notifier_call(
+				&bus->devfreq->nb, 0, NULL);
+		}
+	}
+
+err_no_mem:
+	return rc;
+}
+
+static int venus_hfi_vote_buses(void *dev, struct vidc_bus_vote_data *d, int n)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = dev;
+
+	if (!device)
+		return -EINVAL;
+
+	mutex_lock(&device->lock);
+	rc = __vote_buses(device, d, n);
+	mutex_unlock(&device->lock);
+
+	return rc;
+
+}
+static int __core_set_resource(struct venus_hfi_device *device,
+		struct vidc_resource_hdr *resource_hdr, void *resource_value)
+{
+	struct hfi_cmd_sys_set_resource_packet *pkt;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	int rc = 0;
+
+	if (!device || !resource_hdr || !resource_value) {
+		dprintk(VIDC_ERR, "set_res: Invalid Params\n");
+		return -EINVAL;
+	}
+
+	pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;
+
+	rc = call_hfi_pkt_op(device, sys_set_resource,
+			pkt, resource_hdr, resource_value);
+	if (rc) {
+		dprintk(VIDC_ERR, "set_res: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	rc = __iface_cmdq_write(device, pkt);
+	if (rc)
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
+static DECLARE_COMPLETION(release_resources_done);
+
+static int __alloc_imem(struct venus_hfi_device *device, unsigned long size)
+{
+	struct imem *imem = NULL;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	imem = &device->resources.imem;
+	if (imem->type) {
+		dprintk(VIDC_ERR, "IMEM of type %d already allocated\n",
+				imem->type);
+		return -ENOMEM;
+	}
+
+	switch (device->res->imem_type) {
+	case IMEM_VMEM:
+	{
+		phys_addr_t vmem_buffer = 0;
+
+		rc = vmem_allocate(size, &vmem_buffer);
+		if (rc) {
+			if (rc == -ENOTSUPP) {
+				dprintk(VIDC_DBG,
+					"Target does not support vmem\n");
+				rc = 0;
+			}
+			goto imem_alloc_failed;
+		} else if (!vmem_buffer) {
+			rc = -ENOMEM;
+			goto imem_alloc_failed;
+		}
+
+		imem->vmem = vmem_buffer;
+		break;
+	}
+	case IMEM_NONE:
+		rc = 0;
+		break;
+
+	default:
+		rc = -ENOTSUPP;
+		goto imem_alloc_failed;
+	}
+
+	imem->type = device->res->imem_type;
+	dprintk(VIDC_DBG, "Allocated %ld bytes of IMEM of type %d\n", size,
+			imem->type);
+	return 0;
+imem_alloc_failed:
+	imem->type = IMEM_NONE;
+	return rc;
+}
+
+static int __free_imem(struct venus_hfi_device *device)
+{
+	struct imem *imem = NULL;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	imem = &device->resources.imem;
+	switch (imem->type) {
+	case IMEM_NONE:
+		/* Follow the semantics of free(NULL), which is a no-op. */
+		break;
+	case IMEM_VMEM:
+		vmem_free(imem->vmem);
+		break;
+	default:
+		rc = -ENOTSUPP;
+		goto imem_free_failed;
+	}
+
+	imem->type = IMEM_NONE;
+	return 0;
+
+imem_free_failed:
+	return rc;
+}
+
+static int __set_imem(struct venus_hfi_device *device, struct imem *imem)
+{
+	struct vidc_resource_hdr rhdr;
+	phys_addr_t addr = 0;
+	int rc = 0;
+
+	if (!device || !device->res || !imem) {
+		dprintk(VIDC_ERR, "Invalid params, core: %pK, imem: %pK\n",
+			device, imem);
+		return -EINVAL;
+	}
+
+	rhdr.resource_handle = imem; /* cookie */
+	rhdr.size = device->res->imem_size;
+	rhdr.resource_id = VIDC_RESOURCE_NONE;
+
+	switch (imem->type) {
+	case IMEM_VMEM:
+		rhdr.resource_id = VIDC_RESOURCE_VMEM;
+		addr = imem->vmem;
+		break;
+	case IMEM_NONE:
+		dprintk(VIDC_DBG, "%s Target does not support IMEM", __func__);
+		rc = 0;
+		goto imem_set_failed;
+	default:
+		dprintk(VIDC_ERR, "IMEM of type %d unsupported\n", imem->type);
+		rc = -ENOTSUPP;
+		goto imem_set_failed;
+	}
+
+	WARN_ON(!addr);
+
+	rc = __core_set_resource(device, &rhdr, (void *)addr);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to set IMEM on driver\n");
+		goto imem_set_failed;
+	}
+
+	dprintk(VIDC_DBG,
+			"Managed to set IMEM buffer of type %d sized %d bytes at %pa\n",
+			rhdr.resource_id, rhdr.size, &addr);
+
+	rc = __vote_buses(device, device->bus_vote.data,
+			device->bus_vote.data_count);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Failed to vote for buses after setting imem: %d\n",
+				rc);
+	}
+
+imem_set_failed:
+	return rc;
+}
+
+static int __tzbsp_set_video_state(enum tzbsp_video_state state)
+{
+	struct tzbsp_video_set_state_req cmd = {0};
+	int tzbsp_rsp = 0;
+	int rc = 0;
+	struct scm_desc desc = {0};
+
+	desc.args[0] = cmd.state = state;
+	desc.args[1] = cmd.spare = 0;
+	desc.arginfo = SCM_ARGS(2);
+
+	if (!is_scm_armv8()) {
+		rc = scm_call(SCM_SVC_BOOT, TZBSP_VIDEO_SET_STATE, &cmd,
+				sizeof(cmd), &tzbsp_rsp, sizeof(tzbsp_rsp));
+	} else {
+		rc = scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT,
+				TZBSP_VIDEO_SET_STATE), &desc);
+		tzbsp_rsp = desc.ret[0];
+	}
+
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed scm_call %d\n", rc);
+		return rc;
+	}
+
+	dprintk(VIDC_DBG, "Set state %d, resp %d\n", state, tzbsp_rsp);
+	if (tzbsp_rsp) {
+		dprintk(VIDC_ERR,
+				"Failed to set video core state to suspend: %d\n",
+				tzbsp_rsp);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int __boot_firmware(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	u32 ctrl_status = 0, count = 0, max_tries = 100;
+
+	__write_register(device, VIDC_CTRL_INIT, 0x1);
+	while (!ctrl_status && count < max_tries) {
+		ctrl_status = __read_register(device, VIDC_CPU_CS_SCIACMDARG0);
+		if ((ctrl_status & 0xFE) == 0x4) {
+			dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
+			break;
+		}
+
+		usleep_range(500, 1000);
+		count++;
+	}
+
+	if (count >= max_tries) {
+		dprintk(VIDC_ERR, "Error booting up vidc firmware\n");
+		rc = -ETIME;
+	}
+	return rc;
+}
+
+static struct clock_info *__get_clock(struct venus_hfi_device *device,
+		char *name)
+{
+	struct clock_info *vc;
+
+	venus_hfi_for_each_clock(device, vc) {
+		if (!strcmp(vc->name, name))
+			return vc;
+	}
+
+	dprintk(VIDC_WARN, "%s Clock %s not found\n", __func__, name);
+
+	return NULL;
+}
+
+static unsigned long __get_clock_rate(struct clock_info *clock,
+	int num_mbs_per_sec, struct vidc_clk_scale_data *data)
+{
+	int num_rows = clock->count;
+	struct load_freq_table *table = clock->load_freq_tbl;
+	unsigned long freq = table[0].freq, max_freq = 0;
+	int i = 0, j = 0;
+	unsigned long instance_freq[VIDC_MAX_SESSIONS] = {0};
+
+	if (!data && !num_rows) {
+		freq = 0;
+		goto print_clk;
+	}
+
+	if ((!num_mbs_per_sec || !data) && num_rows) {
+		freq = table[num_rows - 1].freq;
+		goto print_clk;
+	}
+
+	for (i = 0; i < num_rows; i++) {
+		if (num_mbs_per_sec > table[i].load)
+			break;
+		for (j = 0; j < data->num_sessions; j++) {
+			bool matches = __is_session_supported(
+				table[i].supported_codecs, data->session[j]);
+
+			if (!matches)
+				continue;
+			instance_freq[j] = table[i].freq;
+		}
+	}
+	for (i = 0; i < data->num_sessions; i++)
+		max_freq = max(instance_freq[i], max_freq);
+
+	freq = max_freq ? : freq;
+print_clk:
+	dprintk(VIDC_PROF, "Required clock rate = %lu num_mbs_per_sec %d\n",
+					freq, num_mbs_per_sec);
+	return freq;
+}
+
+static unsigned long __get_clock_rate_with_bitrate(struct clock_info *clock,
+		int num_mbs_per_sec, struct vidc_clk_scale_data *data,
+		unsigned long instant_bitrate)
+{
+	int num_rows = clock->count;
+	struct load_freq_table *table = clock->load_freq_tbl;
+	unsigned long freq = table[0].freq, max_freq = 0;
+	unsigned long base_freq, supported_clk[VIDC_MAX_SESSIONS] = {0};
+	int i, j;
+
+	if (!data && !num_rows) {
+		freq = 0;
+		goto print_clk;
+	}
+	if ((!num_mbs_per_sec || !data) && num_rows) {
+		freq = table[num_rows - 1].freq;
+		goto print_clk;
+	}
+
+	/* Get clock rate based on current load only */
+	base_freq = __get_clock_rate(clock, num_mbs_per_sec, data);
+
+	/*
+	 * Supported bitrate = 40% of clock frequency
+	 * Check if the instant bitrate is supported by the base frequency.
+	 * If not, move on to the next frequency which supports the bitrate.
+	 */
+
+	for (j = 0; j < data->num_sessions; j++) {
+		unsigned long supported_bitrate = 0;
+
+		for (i = num_rows - 1; i >= 0; i--) {
+			bool matches = __is_session_supported(
+				table[i].supported_codecs, data->session[j]);
+
+			if (!matches)
+				continue;
+			freq = table[i].freq;
+
+			supported_bitrate = freq * 40/100;
+			/*
+			 * Store this frequency for each instance, we need
+			 * to select the maximum freq among all the instances.
+			 */
+			if (freq >= base_freq &&
+				supported_bitrate >= instant_bitrate) {
+				supported_clk[j] = freq;
+				break;
+			}
+		}
+
+		/*
+		 * Current bitrate is higher than max supported load.
+		 * Select max frequency to handle this load.
+		 */
+		if (i < 0)
+			supported_clk[j] = table[0].freq;
+	}
+
+	for (i = 0; i < data->num_sessions; i++)
+		max_freq = max(supported_clk[i], max_freq);
+
+	freq = max_freq ? : base_freq;
+
+	if (base_freq == freq)
+		dprintk(VIDC_DBG, "Stay at base freq: %lu bitrate = %lu\n",
+			freq, instant_bitrate);
+	else
+		dprintk(VIDC_DBG, "Move up clock freq: %lu bitrate = %lu\n",
+			freq, instant_bitrate);
+print_clk:
+	dprintk(VIDC_PROF, "Required clock rate = %lu num_mbs_per_sec %d\n",
+					freq, num_mbs_per_sec);
+	return freq;
+}
+
+static unsigned long venus_hfi_get_core_clock_rate(void *dev, bool actual_rate)
+{
+	struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+	struct clock_info *vc;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, device);
+		return -EINVAL;
+	}
+
+	if (actual_rate) {
+		vc = __get_clock(device, "core_clk");
+		if (vc)
+			return clk_get_rate(vc->clk);
+		else
+			return 0;
+	} else {
+		return device->scaled_rate;
+	}
+}
+
+static int venus_hfi_suspend(void *dev)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+		return -EINVAL;
+	} else if (!device->res->sw_power_collapsible) {
+		return -ENOTSUPP;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (device->power_enabled) {
+		dprintk(VIDC_DBG, "Venus is busy\n");
+		rc = -EBUSY;
+	} else {
+		dprintk(VIDC_DBG, "Venus is power suspended\n");
+		rc = 0;
+	}
+
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static enum hal_default_properties venus_hfi_get_default_properties(void *dev)
+{
+	enum hal_default_properties prop = 0;
+	struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (device->packetization_type == HFI_PACKETIZATION_3XX)
+		prop = HAL_VIDEO_DYNAMIC_BUF_MODE;
+
+	mutex_unlock(&device->lock);
+	return prop;
+}
+
+static int __halt_axi(struct venus_hfi_device *device)
+{
+	u32 reg;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid input: %pK\n", device);
+		return -EINVAL;
+	}
+
+	/*
+	 * Driver needs to make sure that clocks are enabled to read Venus AXI
+	 * registers. If not skip AXI HALT.
+	 */
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN,
+			"Clocks are OFF, skipping AXI HALT\n");
+		WARN_ON(VIDC_DBG_WARN_ENABLE);
+		return -EINVAL;
+	}
+
+	/* Halt AXI and AXI IMEM VBIF Access */
+	reg = __read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
+	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+	__write_register(device, VENUS_VBIF_AXI_HALT_CTRL0, reg);
+
+	/* Request for AXI bus port halt */
+	rc = readl_poll_timeout(device->hal_data->register_base
+			+ VENUS_VBIF_AXI_HALT_CTRL1,
+			reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+			POLL_INTERVAL_US,
+			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+	if (rc)
+		dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+
+	return rc;
+}
+
+static int __scale_clocks_cycles_per_mb(struct venus_hfi_device *device,
+		struct vidc_clk_scale_data *data, unsigned long instant_bitrate)
+{
+	int rc = 0, i = 0, j = 0;
+	struct clock_info *cl;
+	struct clock_freq_table *clk_freq_tbl = NULL;
+	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
+	struct clock_profile_entry *entry = NULL;
+	u64 total_freq = 0, rate = 0;
+
+	clk_freq_tbl = &device->res->clock_freq_tbl;
+	allowed_clks_tbl = device->res->allowed_clks_tbl;
+
+	if (!data) {
+		dprintk(VIDC_DBG, "%s: NULL scale data\n", __func__);
+		total_freq = device->clk_freq;
+		goto get_clock_freq;
+	}
+
+	device->clk_bitrate = instant_bitrate;
+
+	for (i = 0; i < data->num_sessions; i++) {
+		/*
+		 * for each active session iterate through all possible
+		 * sessions and get matching session's cycles per mb
+		 * from dtsi and multiply with the session's load to
+		 * get the frequency required for the session.
+		 * accumulate all session's frequencies to get the
+		 * total clock frequency.
+		 */
+		for (j = 0; j < clk_freq_tbl->count; j++) {
+			bool matched = false;
+			u64 freq = 0;
+
+			entry = &clk_freq_tbl->clk_prof_entries[j];
+
+			matched = __is_session_supported(entry->codec_mask,
+					data->session[i]);
+			if (!matched)
+				continue;
+
+			freq = entry->cycles * data->load[i];
+
+			if (data->power_mode[i] == VIDC_POWER_LOW &&
+					entry->low_power_factor) {
+				/* low_power_factor is in Q16 format */
+				freq = (freq * entry->low_power_factor) >> 16;
+			}
+
+			total_freq += freq;
+
+			dprintk(VIDC_DBG,
+				"session[%d] %#x: cycles (%d), load (%d), freq (%llu), factor (%d)\n",
+				i, data->session[i], entry->cycles,
+				data->load[i], freq,
+				entry->low_power_factor);
+		}
+	}
+
+get_clock_freq:
+	/*
+	 * get required clock rate from allowed clock rates table
+	 */
+	for (i = device->res->allowed_clks_tbl_size - 1; i >= 0; i--) {
+		rate = allowed_clks_tbl[i].clock_rate;
+		if (rate >= total_freq)
+			break;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		if (!cl->has_scaling)
+			continue;
+
+		device->clk_freq = rate;
+		rc = clk_set_rate(cl->clk, rate);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: Failed to set clock rate %llu %s: %d\n",
+				__func__, rate, cl->name, rc);
+			return rc;
+		}
+		if (!strcmp(cl->name, "core_clk"))
+			device->scaled_rate = rate;
+
+		dprintk(VIDC_DBG,
+			"scaling clock %s to %llu (required freq %llu)\n",
+			cl->name, rate, total_freq);
+	}
+
+	return rc;
+}
+
+static int __scale_clocks_load(struct venus_hfi_device *device, int load,
+		struct vidc_clk_scale_data *data, unsigned long instant_bitrate)
+{
+	struct clock_info *cl;
+
+	device->clk_bitrate = instant_bitrate;
+
+	venus_hfi_for_each_clock(device, cl) {
+		if (cl->has_scaling) {
+
+			unsigned long rate = 0;
+			int rc;
+			/*
+			 * load_fw and power_on needs to be addressed.
+			 * differently. Below check enforces the same.
+			 */
+			if (!device->clk_bitrate && !data && !load &&
+				device->clk_freq)
+				rate = device->clk_freq;
+
+			if (!rate) {
+				if (!device->clk_bitrate)
+					rate = __get_clock_rate(cl, load,
+							data);
+				else
+					rate = __get_clock_rate_with_bitrate(cl,
+							load, data,
+							instant_bitrate);
+			}
+			device->clk_freq = rate;
+			rc = clk_set_rate(cl->clk, rate);
+			if (rc) {
+				dprintk(VIDC_ERR,
+					"Failed to set clock rate %lu %s: %d\n",
+					rate, cl->name, rc);
+				return rc;
+			}
+
+			if (!strcmp(cl->name, "core_clk"))
+				device->scaled_rate = rate;
+
+			dprintk(VIDC_PROF, "Scaling clock %s to %lu\n",
+					cl->name, rate);
+		}
+	}
+
+	return 0;
+}
+
+static int __scale_clocks(struct venus_hfi_device *device,
+		int load, struct vidc_clk_scale_data *data,
+		unsigned long instant_bitrate)
+{
+	int rc = 0;
+
+	if (device->res->clock_freq_tbl.clk_prof_entries &&
+			device->res->allowed_clks_tbl)
+		rc = __scale_clocks_cycles_per_mb(device,
+				data, instant_bitrate);
+	else if (device->res->load_freq_tbl)
+		rc = __scale_clocks_load(device, load, data, instant_bitrate);
+	else
+		dprintk(VIDC_DBG, "Clock scaling is not supported\n");
+
+	return rc;
+}
+static int venus_hfi_scale_clocks(void *dev, int load,
+					struct vidc_clk_scale_data *data,
+					unsigned long instant_bitrate)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid args: %pK\n", device);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (__resume(device)) {
+		dprintk(VIDC_ERR, "Resume from power collapse failed\n");
+		rc = -ENODEV;
+		goto exit;
+	}
+
+	rc = __scale_clocks(device, load, data, instant_bitrate);
+exit:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+/* Writes into cmdq without raising an interrupt */
+static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device,
+		void *pkt, bool *requires_interrupt)
+{
+	struct vidc_iface_q_info *q_info;
+	struct vidc_hal_cmd_pkt_hdr *cmd_packet;
+	int result = -E2BIG;
+
+	if (!device || !pkt) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+		result = -EINVAL;
+		goto err_q_null;
+	}
+
+	cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt;
+	device->last_packet_type = cmd_packet->packet_type;
+
+	q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	if (!q_info) {
+		dprintk(VIDC_ERR, "cannot write to shared Q's\n");
+		goto err_q_null;
+	}
+
+	if (!q_info->q_array.align_virtual_addr) {
+		dprintk(VIDC_ERR, "cannot write to shared CMD Q's\n");
+		result = -ENODATA;
+		goto err_q_null;
+	}
+
+	__sim_modify_cmd_packet((u8 *)pkt, device);
+	if (__resume(device)) {
+		dprintk(VIDC_ERR, "%s: Power on failed\n", __func__);
+		goto err_q_write;
+	}
+
+	if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) {
+		if (device->res->sw_power_collapsible) {
+			cancel_delayed_work(&venus_hfi_pm_work);
+			if (!queue_delayed_work(device->venus_pm_workq,
+				&venus_hfi_pm_work,
+				msecs_to_jiffies(
+				msm_vidc_pwr_collapse_delay))) {
+				dprintk(VIDC_DBG,
+				"PM work already scheduled\n");
+			}
+		}
+
+		result = 0;
+	} else {
+		dprintk(VIDC_ERR, "__iface_cmdq_write: queue full\n");
+	}
+
+err_q_write:
+err_q_null:
+	return result;
+}
+
+static int __iface_cmdq_write(struct venus_hfi_device *device, void *pkt)
+{
+	bool needs_interrupt = false;
+	int rc = __iface_cmdq_write_relaxed(device, pkt, &needs_interrupt);
+
+	if (!rc && needs_interrupt) {
+		/* Consumer of cmdq prefers that we raise an interrupt */
+		rc = 0;
+		__write_register(device, VIDC_CPU_IC_SOFTINT,
+				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+	}
+
+	return rc;
+}
+
+static int __iface_msgq_read(struct venus_hfi_device *device, void *pkt)
+{
+	u32 tx_req_is_set = 0;
+	int rc = 0;
+	struct vidc_iface_q_info *q_info;
+
+	if (!pkt) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto read_error_null;
+	}
+
+	if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
+		q_array.align_virtual_addr == 0) {
+		dprintk(VIDC_ERR, "cannot read from shared MSG Q's\n");
+		rc = -ENODATA;
+		goto read_error_null;
+	}
+
+	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		__hal_sim_modify_msg_packet((u8 *)pkt, device);
+		if (tx_req_is_set)
+			__write_register(device, VIDC_CPU_IC_SOFTINT,
+				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+		rc = 0;
+	} else
+		rc = -ENODATA;
+
+read_error_null:
+	return rc;
+}
+
+static int __iface_dbgq_read(struct venus_hfi_device *device, void *pkt)
+{
+	u32 tx_req_is_set = 0;
+	int rc = 0;
+	struct vidc_iface_q_info *q_info;
+
+	if (!pkt) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	__strict_check(device);
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
+		rc = -EINVAL;
+		goto dbg_error_null;
+	}
+
+	if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
+		q_array.align_virtual_addr == 0) {
+		dprintk(VIDC_ERR, "cannot read from shared DBG Q's\n");
+		rc = -ENODATA;
+		goto dbg_error_null;
+	}
+
+	q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+	if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+		if (tx_req_is_set)
+			__write_register(device, VIDC_CPU_IC_SOFTINT,
+				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
+		rc = 0;
+	} else
+		rc = -ENODATA;
+
+dbg_error_null:
+	return rc;
+}
+
+static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
+{
+	q_hdr->qhdr_status = 0x1;
+	q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR;
+	q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4;
+	q_hdr->qhdr_pkt_size = 0;
+	q_hdr->qhdr_rx_wm = 0x1;
+	q_hdr->qhdr_tx_wm = 0x1;
+	q_hdr->qhdr_rx_req = 0x1;
+	q_hdr->qhdr_tx_req = 0x0;
+	q_hdr->qhdr_rx_irq_status = 0x0;
+	q_hdr->qhdr_tx_irq_status = 0x0;
+	q_hdr->qhdr_read_idx = 0x0;
+	q_hdr->qhdr_write_idx = 0x0;
+}
+
+static void __interface_queues_release(struct venus_hfi_device *device)
+{
+	int i;
+	struct hfi_mem_map_table *qdss;
+	struct hfi_mem_map *mem_map;
+	int num_entries = device->res->qdss_addr_set.count;
+	unsigned long mem_map_table_base_addr;
+	struct context_bank_info *cb;
+
+	if (device->qdss.mem_data) {
+		qdss = (struct hfi_mem_map_table *)
+			device->qdss.align_virtual_addr;
+		qdss->mem_map_num_entries = num_entries;
+		mem_map_table_base_addr =
+			device->qdss.align_device_addr +
+			sizeof(struct hfi_mem_map_table);
+		qdss->mem_map_table_base_addr =
+			(u32)mem_map_table_base_addr;
+		if ((unsigned long)qdss->mem_map_table_base_addr !=
+			mem_map_table_base_addr) {
+			dprintk(VIDC_ERR,
+				"Invalid mem_map_table_base_addr %#lx",
+				mem_map_table_base_addr);
+		}
+
+		mem_map = (struct hfi_mem_map *)(qdss + 1);
+		cb = msm_smem_get_context_bank(device->hal_client,
+					false, HAL_BUFFER_INTERNAL_CMD_QUEUE);
+
+		for (i = 0; cb && i < num_entries; i++) {
+			iommu_unmap(cb->mapping->domain,
+						mem_map[i].virtual_addr,
+						mem_map[i].size);
+		}
+
+		__smem_free(device, device->qdss.mem_data);
+	}
+
+	__smem_free(device, device->iface_q_table.mem_data);
+	__smem_free(device, device->sfr.mem_data);
+
+	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+		device->iface_queues[i].q_hdr = NULL;
+		device->iface_queues[i].q_array.mem_data = NULL;
+		device->iface_queues[i].q_array.align_virtual_addr = NULL;
+		device->iface_queues[i].q_array.align_device_addr = 0;
+	}
+
+	device->iface_q_table.mem_data = NULL;
+	device->iface_q_table.align_virtual_addr = NULL;
+	device->iface_q_table.align_device_addr = 0;
+
+	device->qdss.mem_data = NULL;
+	device->qdss.align_virtual_addr = NULL;
+	device->qdss.align_device_addr = 0;
+
+	device->sfr.mem_data = NULL;
+	device->sfr.align_virtual_addr = NULL;
+	device->sfr.align_device_addr = 0;
+
+	device->mem_addr.mem_data = NULL;
+	device->mem_addr.align_virtual_addr = NULL;
+	device->mem_addr.align_device_addr = 0;
+
+	msm_smem_delete_client(device->hal_client);
+	device->hal_client = NULL;
+}
+
+static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev,
+		struct hfi_mem_map *mem_map, struct dma_iommu_mapping *mapping)
+{
+	int i;
+	int rc = 0;
+	dma_addr_t iova = QDSS_IOVA_START;
+	int num_entries = dev->res->qdss_addr_set.count;
+	struct addr_range *qdss_addr_tbl = dev->res->qdss_addr_set.addr_tbl;
+
+	if (!num_entries)
+		return -ENODATA;
+
+	for (i = 0; i < num_entries; i++) {
+		if (mapping) {
+			rc = iommu_map(mapping->domain, iova,
+					qdss_addr_tbl[i].start,
+					qdss_addr_tbl[i].size,
+					IOMMU_READ | IOMMU_WRITE);
+
+			if (rc) {
+				dprintk(VIDC_ERR,
+						"IOMMU QDSS mapping failed for addr %#x\n",
+						qdss_addr_tbl[i].start);
+				rc = -ENOMEM;
+				break;
+			}
+		} else {
+			iova =  qdss_addr_tbl[i].start;
+		}
+
+		mem_map[i].virtual_addr = (u32)iova;
+		mem_map[i].physical_addr = qdss_addr_tbl[i].start;
+		mem_map[i].size = qdss_addr_tbl[i].size;
+		mem_map[i].attr = 0x0;
+
+		iova += mem_map[i].size;
+	}
+
+	if (i < num_entries) {
+		dprintk(VIDC_ERR,
+			"QDSS mapping failed, Freeing other entries %d\n", i);
+
+		for (--i; mapping && i >= 0; i--) {
+			iommu_unmap(mapping->domain,
+				mem_map[i].virtual_addr,
+				mem_map[i].size);
+		}
+	}
+
+	return rc;
+}
+
+static void __setup_ucregion_memory_map(struct venus_hfi_device *device)
+{
+	__write_register(device, VIDC_UC_REGION_ADDR,
+			(u32)device->iface_q_table.align_device_addr);
+	__write_register(device, VIDC_UC_REGION_SIZE, SHARED_QSIZE);
+	__write_register(device, VIDC_CPU_CS_SCIACMDARG2,
+			(u32)device->iface_q_table.align_device_addr);
+	__write_register(device, VIDC_CPU_CS_SCIACMDARG1, 0x01);
+	if (device->sfr.align_device_addr)
+		__write_register(device, VIDC_SFR_ADDR,
+				(u32)device->sfr.align_device_addr);
+	if (device->qdss.align_device_addr)
+		__write_register(device, VIDC_MMAP_ADDR,
+				(u32)device->qdss.align_device_addr);
+}
+
+static int __interface_queues_init(struct venus_hfi_device *dev)
+{
+	struct hfi_queue_table_header *q_tbl_hdr;
+	struct hfi_queue_header *q_hdr;
+	u32 i;
+	int rc = 0;
+	struct hfi_mem_map_table *qdss;
+	struct hfi_mem_map *mem_map;
+	struct vidc_iface_q_info *iface_q;
+	struct hfi_sfr_struct *vsfr;
+	struct vidc_mem_addr *mem_addr;
+	int offset = 0;
+	int num_entries = dev->res->qdss_addr_set.count;
+	u32 value = 0;
+	phys_addr_t fw_bias = 0;
+	size_t q_size;
+	unsigned long mem_map_table_base_addr;
+	struct context_bank_info *cb;
+
+	q_size = SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE;
+	mem_addr = &dev->mem_addr;
+	if (!is_iommu_present(dev->res))
+		fw_bias = dev->hal_data->firmware_base;
+	rc = __smem_alloc(dev, mem_addr, q_size, 1, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE);
+	if (rc) {
+		dprintk(VIDC_ERR, "iface_q_table_alloc_fail\n");
+		goto fail_alloc_queue;
+	}
+
+	dev->iface_q_table.align_virtual_addr = mem_addr->align_virtual_addr;
+	dev->iface_q_table.align_device_addr = mem_addr->align_device_addr -
+					fw_bias;
+	dev->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE;
+	dev->iface_q_table.mem_data = mem_addr->mem_data;
+	offset += dev->iface_q_table.mem_size;
+
+	for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
+		iface_q = &dev->iface_queues[i];
+		iface_q->q_array.align_device_addr = mem_addr->align_device_addr
+			+ offset - fw_bias;
+		iface_q->q_array.align_virtual_addr =
+			mem_addr->align_virtual_addr + offset;
+		iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE;
+		iface_q->q_array.mem_data = NULL;
+		offset += iface_q->q_array.mem_size;
+		iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(
+				dev->iface_q_table.align_virtual_addr, i);
+		__set_queue_hdr_defaults(iface_q->q_hdr);
+	}
+
+	if ((msm_vidc_fw_debug_mode & HFI_DEBUG_MODE_QDSS) && num_entries) {
+		rc = __smem_alloc(dev, mem_addr,
+				ALIGNED_QDSS_SIZE, 1, 0,
+				HAL_BUFFER_INTERNAL_CMD_QUEUE);
+		if (rc) {
+			dprintk(VIDC_WARN,
+				"qdss_alloc_fail: QDSS messages logging will not work\n");
+			dev->qdss.align_device_addr = 0;
+		} else {
+			dev->qdss.align_device_addr =
+				mem_addr->align_device_addr - fw_bias;
+			dev->qdss.align_virtual_addr =
+				mem_addr->align_virtual_addr;
+			dev->qdss.mem_size = ALIGNED_QDSS_SIZE;
+			dev->qdss.mem_data = mem_addr->mem_data;
+		}
+	}
+
+	rc = __smem_alloc(dev, mem_addr,
+			ALIGNED_SFR_SIZE, 1, 0,
+			HAL_BUFFER_INTERNAL_CMD_QUEUE);
+	if (rc) {
+		dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work\n");
+		dev->sfr.align_device_addr = 0;
+	} else {
+		dev->sfr.align_device_addr = mem_addr->align_device_addr -
+					fw_bias;
+		dev->sfr.align_virtual_addr = mem_addr->align_virtual_addr;
+		dev->sfr.mem_size = ALIGNED_SFR_SIZE;
+		dev->sfr.mem_data = mem_addr->mem_data;
+	}
+
+	q_tbl_hdr = (struct hfi_queue_table_header *)
+			dev->iface_q_table.align_virtual_addr;
+	q_tbl_hdr->qtbl_version = 0;
+	q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE;
+	q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_table_header);
+	q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header);
+	q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ;
+	q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ;
+
+	iface_q = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
+	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+		iface_q->q_array.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid CMDQ device address (%pa)",
+			&iface_q->q_array.align_device_addr);
+	}
+
+	iface_q = &dev->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
+	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+		iface_q->q_array.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid MSGQ device address (%pa)",
+			&iface_q->q_array.align_device_addr);
+	}
+
+	iface_q = &dev->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
+	q_hdr = iface_q->q_hdr;
+	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
+	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
+	/*
+	 * Set receive request to zero on debug queue as there is no
+	 * need of interrupt from video hardware for debug messages
+	 */
+	q_hdr->qhdr_rx_req = 0;
+	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
+		iface_q->q_array.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid DBGQ device address (%pa)",
+			&iface_q->q_array.align_device_addr);
+	}
+
+	value = (u32)dev->iface_q_table.align_device_addr;
+	if ((ion_phys_addr_t)value !=
+		dev->iface_q_table.align_device_addr) {
+		dprintk(VIDC_ERR,
+			"Invalid iface_q_table device address (%pa)",
+			&dev->iface_q_table.align_device_addr);
+	}
+
+	if (dev->qdss.mem_data) {
+		qdss = (struct hfi_mem_map_table *)dev->qdss.align_virtual_addr;
+		qdss->mem_map_num_entries = num_entries;
+		mem_map_table_base_addr = dev->qdss.align_device_addr +
+			sizeof(struct hfi_mem_map_table);
+		qdss->mem_map_table_base_addr =
+			(u32)mem_map_table_base_addr;
+		if ((ion_phys_addr_t)qdss->mem_map_table_base_addr !=
+				mem_map_table_base_addr) {
+			dprintk(VIDC_ERR,
+					"Invalid mem_map_table_base_addr (%#lx)",
+					mem_map_table_base_addr);
+		}
+
+		mem_map = (struct hfi_mem_map *)(qdss + 1);
+		cb = msm_smem_get_context_bank(dev->hal_client, false,
+				HAL_BUFFER_INTERNAL_CMD_QUEUE);
+
+		if (!cb) {
+			dprintk(VIDC_ERR,
+				"%s: failed to get context bank\n", __func__);
+			return -EINVAL;
+		}
+
+		rc = __get_qdss_iommu_virtual_addr(dev, mem_map, cb->mapping);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"IOMMU mapping failed, Freeing qdss memdata\n");
+			__smem_free(dev, dev->qdss.mem_data);
+			dev->qdss.mem_data = NULL;
+			dev->qdss.align_virtual_addr = NULL;
+			dev->qdss.align_device_addr = 0;
+		}
+
+		value = (u32)dev->qdss.align_device_addr;
+		if ((ion_phys_addr_t)value !=
+				dev->qdss.align_device_addr) {
+			dprintk(VIDC_ERR, "Invalid qdss device address (%pa)",
+					&dev->qdss.align_device_addr);
+		}
+	}
+
+	vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
+	vsfr->bufSize = ALIGNED_SFR_SIZE;
+	value = (u32)dev->sfr.align_device_addr;
+	if ((ion_phys_addr_t)value !=
+		dev->sfr.align_device_addr) {
+		dprintk(VIDC_ERR, "Invalid sfr device address (%pa)",
+			&dev->sfr.align_device_addr);
+	}
+
+	__setup_ucregion_memory_map(dev);
+	return 0;
+fail_alloc_queue:
+	return -ENOMEM;
+}
+
+static int __sys_set_debug(struct venus_hfi_device *device, u32 debug)
+{
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	int rc = 0;
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+
+	rc = call_hfi_pkt_op(device, sys_debug_config, pkt, debug);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Debug mode setting to FW failed\n");
+		return -ENOTEMPTY;
+	}
+
+	if (__iface_cmdq_write(device, pkt))
+		return -ENOTEMPTY;
+	return 0;
+}
+
+static int __sys_set_coverage(struct venus_hfi_device *device, u32 mode)
+{
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	int rc = 0;
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+
+	rc = call_hfi_pkt_op(device, sys_coverage_config,
+			pkt, mode);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Coverage mode setting to FW failed\n");
+		return -ENOTEMPTY;
+	}
+
+	if (__iface_cmdq_write(device, pkt)) {
+		dprintk(VIDC_WARN, "Failed to send coverage pkt to f/w\n");
+		return -ENOTEMPTY;
+	}
+
+	return 0;
+}
+
+static int __sys_set_idle_message(struct venus_hfi_device *device,
+	bool enable)
+{
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+	if (!enable) {
+		dprintk(VIDC_DBG, "sys_idle_indicator is not enabled\n");
+		return 0;
+	}
+
+	call_hfi_pkt_op(device, sys_idle_indicator, pkt, enable);
+	if (__iface_cmdq_write(device, pkt))
+		return -ENOTEMPTY;
+	return 0;
+}
+
+static int __sys_set_power_control(struct venus_hfi_device *device,
+	bool enable)
+{
+	struct regulator_info *rinfo;
+	bool supported = false;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hfi_cmd_sys_set_property_packet *pkt =
+		(struct hfi_cmd_sys_set_property_packet *) &packet;
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		if (rinfo->has_hw_power_collapse) {
+			supported = true;
+			break;
+		}
+	}
+
+	if (!supported)
+		return 0;
+
+	call_hfi_pkt_op(device, sys_power_control, pkt, enable);
+	if (__iface_cmdq_write(device, pkt))
+		return -ENOTEMPTY;
+	return 0;
+}
+
+static int venus_hfi_core_init(void *device)
+{
+	struct hfi_cmd_sys_init_packet pkt;
+	struct hfi_cmd_sys_get_property_packet version_pkt;
+	int rc = 0;
+	struct list_head *ptr, *next;
+	struct hal_session *session = NULL;
+	struct venus_hfi_device *dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid device\n");
+		return -ENODEV;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	init_completion(&release_resources_done);
+
+	rc = __load_fw(dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to load Venus FW\n");
+		goto err_load_fw;
+	}
+
+	__set_state(dev, VENUS_STATE_INIT);
+
+	list_for_each_safe(ptr, next, &dev->sess_head) {
+		/* This means that session list is not empty. Kick stale
+		 * sessions out of our valid instance list, but keep the
+		 * list_head inited so that list_del (in the future, called
+		 * by session_clean()) will be valid. When client doesn't close
+		 * them, then it is a genuine leak which driver can't fix.
+		 */
+		session = list_entry(ptr, struct hal_session, list);
+		list_del_init(&session->list);
+	}
+
+	INIT_LIST_HEAD(&dev->sess_head);
+
+	__set_registers(dev);
+
+	if (!dev->hal_client) {
+		dev->hal_client = msm_smem_new_client(
+				SMEM_ION, dev->res, MSM_VIDC_UNKNOWN);
+		if (dev->hal_client == NULL) {
+			dprintk(VIDC_ERR, "Failed to alloc ION_Client\n");
+			rc = -ENODEV;
+			goto err_core_init;
+		}
+
+		dprintk(VIDC_DBG, "Dev_Virt: %pa, Reg_Virt: %pK\n",
+			&dev->hal_data->firmware_base,
+			dev->hal_data->register_base);
+
+		rc = __interface_queues_init(dev);
+		if (rc) {
+			dprintk(VIDC_ERR, "failed to init queues\n");
+			rc = -ENOMEM;
+			goto err_core_init;
+		}
+	} else {
+		dprintk(VIDC_ERR, "hal_client exists\n");
+		rc = -EEXIST;
+		goto err_core_init;
+	}
+
+	rc = __boot_firmware(dev);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to start core\n");
+		rc = -ENODEV;
+		goto err_core_init;
+	}
+
+	rc =  call_hfi_pkt_op(dev, sys_init, &pkt, HFI_VIDEO_ARCH_OX);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to create sys init pkt\n");
+		goto err_core_init;
+	}
+
+	if (__iface_cmdq_write(dev, &pkt)) {
+		rc = -ENOTEMPTY;
+		goto err_core_init;
+	}
+
+	rc = call_hfi_pkt_op(dev, sys_image_version, &version_pkt);
+	if (rc || __iface_cmdq_write(dev, &version_pkt))
+		dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n");
+
+	if (dev->res->pm_qos_latency_us) {
+#ifdef CONFIG_SMP
+		dev->qos.type = PM_QOS_REQ_AFFINE_IRQ;
+		dev->qos.irq = dev->hal_data->irq;
+#endif
+		pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY,
+				dev->res->pm_qos_latency_us);
+	}
+
+	mutex_unlock(&dev->lock);
+	return rc;
+err_core_init:
+	__set_state(dev, VENUS_STATE_DEINIT);
+	__unload_fw(dev);
+err_load_fw:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int venus_hfi_core_release(void *dev)
+{
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "invalid device\n");
+		return -ENODEV;
+	}
+
+	mutex_lock(&device->lock);
+
+	if (device->res->pm_qos_latency_us &&
+		pm_qos_request_active(&device->qos))
+		pm_qos_remove_request(&device->qos);
+	__set_state(device, VENUS_STATE_DEINIT);
+	__unload_fw(device);
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int __get_q_size(struct venus_hfi_device *dev, unsigned int q_index)
+{
+	struct hfi_queue_header *queue;
+	struct vidc_iface_q_info *q_info;
+	u32 write_ptr, read_ptr;
+
+	if (q_index >= VIDC_IFACEQ_NUMQ) {
+		dprintk(VIDC_ERR, "Invalid q index: %d\n", q_index);
+		return -ENOENT;
+	}
+
+	q_info = &dev->iface_queues[q_index];
+	if (!q_info) {
+		dprintk(VIDC_ERR, "cannot read shared Q's\n");
+		return -ENOENT;
+	}
+
+	queue = (struct hfi_queue_header *)q_info->q_hdr;
+	if (!queue) {
+		dprintk(VIDC_ERR, "queue not present\n");
+		return -ENOENT;
+	}
+
+	write_ptr = (u32)queue->qhdr_write_idx;
+	read_ptr = (u32)queue->qhdr_read_idx;
+	return read_ptr - write_ptr;
+}
+
+static void __core_clear_interrupt(struct venus_hfi_device *device)
+{
+	u32 intr_status = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
+		return;
+	}
+
+	intr_status = __read_register(device, VIDC_WRAPPER_INTR_STATUS);
+
+	if (intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK ||
+		intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK ||
+		intr_status &
+			VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK) {
+		device->intr_status |= intr_status;
+		device->reg_count++;
+		dprintk(VIDC_DBG,
+			"INTERRUPT for device: %pK: times: %d interrupt_status: %d\n",
+			device, device->reg_count, intr_status);
+	} else {
+		device->spur_count++;
+		dprintk(VIDC_INFO,
+			"SPURIOUS_INTR for device: %pK: times: %d interrupt_status: %d\n",
+			device, device->spur_count, intr_status);
+	}
+
+	__write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1);
+	__write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status);
+	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n");
+}
+
+static int venus_hfi_core_ping(void *device)
+{
+	struct hfi_cmd_sys_ping_packet pkt;
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "invalid device\n");
+		return -ENODEV;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	rc = call_hfi_pkt_op(dev, sys_ping, &pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(dev, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int venus_hfi_core_trigger_ssr(void *device,
+		enum hal_ssr_trigger_type type)
+{
+	struct hfi_cmd_sys_test_ssr_packet pkt;
+	int rc = 0;
+	struct venus_hfi_device *dev;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "invalid device\n");
+		return -ENODEV;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	rc = call_hfi_pkt_op(dev, ssr_cmd, type, &pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(dev, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int venus_hfi_session_set_property(void *sess,
+					enum hal_property ptype, void *pdata)
+{
+	u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+	struct hfi_cmd_session_set_property_packet *pkt =
+		(struct hfi_cmd_session_set_property_packet *) &packet;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session || !session->device || !pdata) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	dprintk(VIDC_INFO, "in set_prop,with prop id: %#x\n", ptype);
+
+	rc = call_hfi_pkt_op(device, session_set_property,
+			pkt, session, ptype, pdata);
+
+	if (rc == -ENOTSUPP) {
+		dprintk(VIDC_DBG,
+			"set property: unsupported prop id: %#x\n", ptype);
+		rc = 0;
+		goto err_set_prop;
+	} else if (rc) {
+		dprintk(VIDC_ERR, "set property: failed to create packet\n");
+		rc = -EINVAL;
+		goto err_set_prop;
+	}
+
+	if (__iface_cmdq_write(session->device, pkt)) {
+		rc = -ENOTEMPTY;
+		goto err_set_prop;
+	}
+
+err_set_prop:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_get_property(void *sess,
+					enum hal_property ptype)
+{
+	struct hfi_cmd_session_get_property_packet pkt = {0};
+	struct hal_session *session = sess;
+	int rc = 0;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	dprintk(VIDC_INFO, "%s: property id: %d\n", __func__, ptype);
+
+	rc = call_hfi_pkt_op(device, session_get_property,
+				&pkt, session, ptype);
+	if (rc) {
+		dprintk(VIDC_ERR, "get property profile: pkt failed\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt)) {
+		rc = -ENOTEMPTY;
+		dprintk(VIDC_ERR, "%s cmdq_write error\n", __func__);
+	}
+
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static void __set_default_sys_properties(struct venus_hfi_device *device)
+{
+	if (__sys_set_debug(device, msm_vidc_fw_debug))
+		dprintk(VIDC_WARN, "Setting fw_debug msg ON failed\n");
+	if (__sys_set_idle_message(device,
+		device->res->sys_idle_indicator ||
+		!msm_vidc_sys_idle_indicator))
+		dprintk(VIDC_WARN, "Setting idle response ON failed\n");
+	if (__sys_set_power_control(device, msm_vidc_fw_low_power_mode))
+		dprintk(VIDC_WARN, "Setting h/w power collapse ON failed\n");
+}
+
+static void __session_clean(struct hal_session *session)
+{
+	dprintk(VIDC_DBG, "deleted the session: %pK\n", session);
+	list_del(&session->list);
+	/* Poison the session handle with zeros */
+	*session = (struct hal_session){ {0} };
+	kfree(session);
+}
+
+static int venus_hfi_session_clean(void *session)
+{
+	struct hal_session *sess_close;
+	struct venus_hfi_device *device;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess_close = session;
+	device = sess_close->device;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid device handle %s\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	__session_clean(sess_close);
+	__flush_debug_queue(device, NULL);
+
+	mutex_unlock(&device->lock);
+	return 0;
+}
+
+static int venus_hfi_session_init(void *device, void *session_id,
+		enum hal_domain session_type, enum hal_video_codec codec_type,
+		void **new_session)
+{
+	struct hfi_cmd_sys_session_init_packet pkt;
+	struct venus_hfi_device *dev;
+	struct hal_session *s;
+
+	if (!device || !new_session) {
+		dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	dev = device;
+	mutex_lock(&dev->lock);
+
+	s = kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+	if (!s) {
+		dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+		goto err_session_init_fail;
+	}
+
+	s->session_id = session_id;
+	s->is_decoder = (session_type == HAL_VIDEO_DOMAIN_DECODER);
+	s->device = dev;
+	s->codec = codec_type;
+	s->domain = session_type;
+	dprintk(VIDC_DBG,
+		"%s: inst %pK, session %pK, codec 0x%x, domain 0x%x\n",
+		__func__, session_id, s, s->codec, s->domain);
+
+	list_add_tail(&s->list, &dev->sess_head);
+
+	__set_default_sys_properties(device);
+
+	if (call_hfi_pkt_op(dev, session_init, &pkt,
+			s, session_type, codec_type)) {
+		dprintk(VIDC_ERR, "session_init: failed to create packet\n");
+		goto err_session_init_fail;
+	}
+
+	*new_session = s;
+	if (__iface_cmdq_write(dev, &pkt))
+		goto err_session_init_fail;
+
+	mutex_unlock(&dev->lock);
+	return 0;
+
+err_session_init_fail:
+	if (s)
+		__session_clean(s);
+	*new_session = NULL;
+	mutex_unlock(&dev->lock);
+	return -EINVAL;
+}
+
+static int __send_session_cmd(struct hal_session *session, int pkt_type)
+{
+	struct vidc_hal_session_cmd_pkt pkt;
+	int rc = 0;
+	struct venus_hfi_device *device = session->device;
+
+	rc = call_hfi_pkt_op(device, session_cmd,
+			&pkt, pkt_type, session);
+	if (rc == -EPERM)
+		return 0;
+
+	if (rc) {
+		dprintk(VIDC_ERR, "send session cmd: create pkt failed\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_session_end(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+
+	if (!msm_vidc_fw_coverage) {
+		if (__sys_set_coverage(sess->device, msm_vidc_fw_coverage))
+			dprintk(VIDC_WARN, "Fw_coverage msg ON failed\n");
+	}
+
+	rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_END);
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_abort(void *sess)
+{
+	struct hal_session *session;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	session = sess;
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	device = session->device;
+
+	mutex_lock(&device->lock);
+
+	__flush_debug_queue(device, NULL);
+	rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_ABORT);
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_set_buffers(void *sess,
+				struct vidc_buffer_addr_info *buffer_info)
+{
+	struct hfi_cmd_session_set_buffers_packet *pkt;
+	u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !buffer_info) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
+		/*
+		 * Hardware doesn't care about input buffers being
+		 * published beforehand
+		 */
+		rc = 0;
+		goto err_create_pkt;
+	}
+
+	pkt = (struct hfi_cmd_session_set_buffers_packet *)packet;
+
+	rc = call_hfi_pkt_op(device, session_set_buffers,
+			pkt, session, buffer_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "set buffers: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	dprintk(VIDC_INFO, "set buffers: %#x\n", buffer_info->buffer_type);
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_release_buffers(void *sess,
+				struct vidc_buffer_addr_info *buffer_info)
+{
+	struct hfi_cmd_session_release_buffer_packet *pkt;
+	u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !buffer_info) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
+		rc = 0;
+		goto err_create_pkt;
+	}
+
+	pkt = (struct hfi_cmd_session_release_buffer_packet *) packet;
+
+	rc = call_hfi_pkt_op(device, session_release_buffers,
+			pkt, session, buffer_info);
+	if (rc) {
+		dprintk(VIDC_ERR, "release buffers: failed to create packet\n");
+		goto err_create_pkt;
+	}
+
+	dprintk(VIDC_INFO, "Release buffers: %#x\n", buffer_info->buffer_type);
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_load_res(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_LOAD_RESOURCES);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_release_res(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_RELEASE_RESOURCES);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_start(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_START);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_continue(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_CONTINUE);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int venus_hfi_session_stop(void *session)
+{
+	struct hal_session *sess;
+	struct venus_hfi_device *device;
+	int rc = 0;
+
+	if (!session) {
+		dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
+		return -EINVAL;
+	}
+
+	sess = session;
+	device = sess->device;
+
+	mutex_lock(&device->lock);
+	rc = __send_session_cmd(sess, HFI_CMD_SESSION_STOP);
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int __session_etb(struct hal_session *session,
+		struct vidc_frame_data *input_frame, bool relaxed)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = session->device;
+
+	if (session->is_decoder) {
+		struct hfi_cmd_session_empty_buffer_compressed_packet pkt;
+
+		rc = call_hfi_pkt_op(device, session_etb_decoder,
+				&pkt, session, input_frame);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Session etb decoder: failed to create pkt\n");
+			goto err_create_pkt;
+		}
+
+		if (!relaxed)
+			rc = __iface_cmdq_write(session->device, &pkt);
+		else
+			rc = __iface_cmdq_write_relaxed(session->device,
+					&pkt, NULL);
+		if (rc)
+			goto err_create_pkt;
+	} else {
+		struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
+			pkt;
+
+		rc = call_hfi_pkt_op(device, session_etb_encoder,
+					 &pkt, session, input_frame);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Session etb encoder: failed to create pkt\n");
+			goto err_create_pkt;
+		}
+
+		if (!relaxed)
+			rc = __iface_cmdq_write(session->device, &pkt);
+		else
+			rc = __iface_cmdq_write_relaxed(session->device,
+					&pkt, NULL);
+		if (rc)
+			goto err_create_pkt;
+	}
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_session_etb(void *sess,
+				struct vidc_frame_data *input_frame)
+{
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !input_frame) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+	rc = __session_etb(session, input_frame, false);
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int __session_ftb(struct hal_session *session,
+		struct vidc_frame_data *output_frame, bool relaxed)
+{
+	int rc = 0;
+	struct venus_hfi_device *device = session->device;
+	struct hfi_cmd_session_fill_buffer_packet pkt;
+
+	rc = call_hfi_pkt_op(device, session_ftb,
+			&pkt, session, output_frame);
+	if (rc) {
+		dprintk(VIDC_ERR, "Session ftb: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (!relaxed)
+		rc = __iface_cmdq_write(session->device, &pkt);
+	else
+		rc = __iface_cmdq_write_relaxed(session->device,
+				&pkt, NULL);
+
+err_create_pkt:
+	return rc;
+}
+
+static int venus_hfi_session_ftb(void *sess,
+				struct vidc_frame_data *output_frame)
+{
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !output_frame) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+	rc = __session_ftb(session, output_frame, false);
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_process_batch(void *sess,
+		int num_etbs, struct vidc_frame_data etbs[],
+		int num_ftbs, struct vidc_frame_data ftbs[])
+{
+	int rc = 0, c = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+	struct hfi_cmd_session_sync_process_packet pkt;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "%s: Invalid Params\n", __func__);
+		return -EINVAL;
+	}
+
+	device = session->device;
+
+	mutex_lock(&device->lock);
+	for (c = 0; c < num_ftbs; ++c) {
+		rc = __session_ftb(session, &ftbs[c], true);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to queue batched ftb: %d\n",
+					rc);
+			goto err_etbs_and_ftbs;
+		}
+	}
+
+	for (c = 0; c < num_etbs; ++c) {
+		rc = __session_etb(session, &etbs[c], true);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to queue batched etb: %d\n",
+					rc);
+			goto err_etbs_and_ftbs;
+		}
+	}
+
+	rc = call_hfi_pkt_op(device, session_sync_process, &pkt, session);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to create sync packet\n");
+		goto err_etbs_and_ftbs;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+
+err_etbs_and_ftbs:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_parse_seq_hdr(void *sess,
+					struct vidc_seq_hdr *seq_hdr)
+{
+	struct hfi_cmd_session_parse_sequence_header_packet *pkt;
+	int rc = 0;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !seq_hdr) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	pkt = (struct hfi_cmd_session_parse_sequence_header_packet *)packet;
+	rc = call_hfi_pkt_op(device, session_parse_seq_header,
+			pkt, session, seq_hdr);
+	if (rc) {
+		dprintk(VIDC_ERR,
+		"Session parse seq hdr: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_get_seq_hdr(void *sess,
+				struct vidc_seq_hdr *seq_hdr)
+{
+	struct hfi_cmd_session_get_sequence_header_packet *pkt;
+	int rc = 0;
+	u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device || !seq_hdr) {
+		dprintk(VIDC_ERR, "Invalid Params\n");
+		return -EINVAL;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	pkt = (struct hfi_cmd_session_get_sequence_header_packet *)packet;
+	rc = call_hfi_pkt_op(device, session_get_seq_hdr,
+			pkt, session, seq_hdr);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Session get seq hdr: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_get_buf_req(void *sess)
+{
+	struct hfi_cmd_session_get_property_packet pkt;
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "invalid session");
+		return -ENODEV;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	rc = call_hfi_pkt_op(device, session_get_buf_req,
+			&pkt, session);
+	if (rc) {
+		dprintk(VIDC_ERR,
+				"Session get buf req: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode)
+{
+	struct hfi_cmd_session_flush_packet pkt;
+	int rc = 0;
+	struct hal_session *session = sess;
+	struct venus_hfi_device *device;
+
+	if (!session || !session->device) {
+		dprintk(VIDC_ERR, "invalid session");
+		return -ENODEV;
+	}
+
+	device = session->device;
+	mutex_lock(&device->lock);
+
+	rc = call_hfi_pkt_op(device, session_flush,
+			&pkt, session, flush_mode);
+	if (rc) {
+		dprintk(VIDC_ERR, "Session flush: failed to create pkt\n");
+		goto err_create_pkt;
+	}
+
+	if (__iface_cmdq_write(session->device, &pkt))
+		rc = -ENOTEMPTY;
+err_create_pkt:
+	mutex_unlock(&device->lock);
+	return rc;
+}
+
+static int __check_core_registered(struct hal_device_data core,
+		phys_addr_t fw_addr, u8 *reg_addr, u32 reg_size,
+		phys_addr_t irq)
+{
+	struct venus_hfi_device *device;
+	struct list_head *curr, *next;
+
+	if (core.dev_count) {
+		list_for_each_safe(curr, next, &core.dev_head) {
+			device = list_entry(curr,
+				struct venus_hfi_device, list);
+			if (device && device->hal_data->irq == irq &&
+				(CONTAINS(device->hal_data->
+						firmware_base,
+						FIRMWARE_SIZE, fw_addr) ||
+				CONTAINS(fw_addr, FIRMWARE_SIZE,
+						device->hal_data->
+						firmware_base) ||
+				CONTAINS(device->hal_data->
+						register_base,
+						reg_size, reg_addr) ||
+				CONTAINS(reg_addr, reg_size,
+						device->hal_data->
+						register_base) ||
+				OVERLAPS(device->hal_data->
+						register_base,
+						reg_size, reg_addr, reg_size) ||
+				OVERLAPS(reg_addr, reg_size,
+						device->hal_data->
+						register_base, reg_size) ||
+				OVERLAPS(device->hal_data->
+						firmware_base,
+						FIRMWARE_SIZE, fw_addr,
+						FIRMWARE_SIZE) ||
+				OVERLAPS(fw_addr, FIRMWARE_SIZE,
+						device->hal_data->
+						firmware_base,
+						FIRMWARE_SIZE))) {
+				return 0;
+			}
+			dprintk(VIDC_INFO, "Device not registered\n");
+			return -EINVAL;
+		}
+	} else {
+		dprintk(VIDC_INFO, "no device Registered\n");
+	}
+
+	return -EINVAL;
+}
+
+static void __process_fatal_error(
+		struct venus_hfi_device *device)
+{
+	struct msm_vidc_cb_cmd_done cmd_done = {0};
+
+	cmd_done.device_id = device->device_id;
+	device->callback(HAL_SYS_ERROR, &cmd_done);
+}
+
+static int __prepare_pc(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct hfi_cmd_sys_pc_prep_packet pkt;
+
+	rc = call_hfi_pkt_op(device, sys_pc_prep, &pkt);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to create sys pc prep pkt\n");
+		goto err_pc_prep;
+	}
+
+	if (__iface_cmdq_write(device, &pkt))
+		rc = -ENOTEMPTY;
+	if (rc)
+		dprintk(VIDC_ERR, "Failed to prepare venus for power off");
+err_pc_prep:
+	return rc;
+}
+
+static void venus_hfi_pm_handler(struct work_struct *work)
+{
+	int rc = 0;
+	u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
+	int count = 0;
+	const int max_tries = 5;
+	struct venus_hfi_device *device = list_first_entry(
+			&hal_ctxt.dev_head, struct venus_hfi_device, list);
+	if (!device) {
+		dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
+		return;
+	}
+
+	/*
+	 * It is ok to check this variable outside the lock since
+	 * it is being updated in this context only
+	 */
+	if (device->skip_pc_count >= VIDC_MAX_PC_SKIP_COUNT) {
+		dprintk(VIDC_WARN, "Failed to PC for %d times\n",
+				device->skip_pc_count);
+		device->skip_pc_count = 0;
+		__process_fatal_error(device);
+		return;
+	}
+	mutex_lock(&device->lock);
+	if (!device->power_enabled) {
+		dprintk(VIDC_DBG, "%s: Power already disabled\n",
+				__func__);
+		goto exit;
+	}
+
+	rc = __core_in_valid_state(device);
+	if (!rc) {
+		dprintk(VIDC_WARN,
+				"Core is in bad state, Skipping power collapse\n");
+		goto skip_power_off;
+	}
+	pc_ready = __read_register(device, VIDC_CPU_CS_SCIACMDARG0) &
+		VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY;
+	if (!pc_ready) {
+		wfi_status = __read_register(device,
+				VIDC_WRAPPER_CPU_STATUS);
+		idle_status = __read_register(device,
+				VIDC_CPU_CS_SCIACMDARG0);
+		if (!(wfi_status & BIT(0)) ||
+				!(idle_status & BIT(30))) {
+			dprintk(VIDC_WARN, "Skipping PC\n");
+			goto skip_power_off;
+		}
+
+		rc = __prepare_pc(device);
+		if (rc) {
+			dprintk(VIDC_WARN, "Failed PC %d\n", rc);
+			goto skip_power_off;
+		}
+
+		while (count < max_tries) {
+			wfi_status = __read_register(device,
+					VIDC_WRAPPER_CPU_STATUS);
+			pc_ready = __read_register(device,
+					VIDC_CPU_CS_SCIACMDARG0);
+			if ((wfi_status & BIT(0)) && (pc_ready &
+				VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY))
+				break;
+			usleep_range(1000, 1500);
+			count++;
+		}
+
+		if (count == max_tries) {
+			dprintk(VIDC_ERR,
+					"Skip PC. Core is not in right state (%#x, %#x)\n",
+					wfi_status, pc_ready);
+			goto skip_power_off;
+		}
+	}
+
+	rc = __suspend(device);
+	if (rc)
+		dprintk(VIDC_ERR, "Failed venus power off\n");
+
+	/* Cancel pending delayed works if any */
+	cancel_delayed_work(&venus_hfi_pm_work);
+	device->skip_pc_count = 0;
+
+	mutex_unlock(&device->lock);
+	return;
+
+skip_power_off:
+	device->skip_pc_count++;
+	dprintk(VIDC_WARN, "Skip PC(%d, %#x, %#x, %#x)\n",
+		device->skip_pc_count, wfi_status, idle_status, pc_ready);
+	queue_delayed_work(device->venus_pm_workq,
+			&venus_hfi_pm_work,
+			msecs_to_jiffies(msm_vidc_pwr_collapse_delay));
+exit:
+	mutex_unlock(&device->lock);
+}
+
+static void __dump_venus_debug_registers(struct venus_hfi_device *device)
+{
+	u32 reg;
+
+	dprintk(VIDC_ERR, "Dumping Venus registers...\n");
+	reg = __read_register(device, VENUS_VBIF_XIN_HALT_CTRL1);
+	dprintk(VIDC_ERR, "VENUS_VBIF_XIN_HALT_CTRL1: 0x%x\n", reg);
+
+	reg = __read_register(device,
+		VIDC_VENUS_WRAPPER_MMCC_VENUS0_POWER_STATUS);
+	dprintk(VIDC_ERR,
+		"VIDC_VENUS_WRAPPER_MMCC_VENUS0_POWER_STATUS: 0x%x\n", reg);
+
+	reg = __read_register(device, VIDC_WRAPPER_CPU_STATUS);
+	dprintk(VIDC_ERR, "VIDC_WRAPPER_CPU_STATUS: 0x%x\n", reg);
+
+	reg = __read_register(device, VIDC_CPU_CS_SCIACMDARG0);
+	dprintk(VIDC_ERR, "VIDC_CPU_CS_SCIACMDARG0: 0x%x\n", reg);
+}
+
+static void __process_sys_error(struct venus_hfi_device *device)
+{
+	struct hfi_sfr_struct *vsfr = NULL;
+
+	__set_state(device, VENUS_STATE_DEINIT);
+
+	/* Once SYS_ERROR received from HW, it is safe to halt the AXI.
+	 * With SYS_ERROR, Venus FW may have crashed and HW might be
+	 * active and causing unnecessary transactions. Hence it is
+	 * safe to stop all AXI transactions from venus sub-system.
+	 */
+	if (__halt_axi(device))
+		dprintk(VIDC_WARN, "Failed to halt AXI after SYS_ERROR\n");
+
+	vsfr = (struct hfi_sfr_struct *)device->sfr.align_virtual_addr;
+	if (vsfr) {
+		void *p = memchr(vsfr->rg_data, '\0', vsfr->bufSize);
+		/* SFR isn't guaranteed to be NULL terminated
+		 * since SYS_ERROR indicates that Venus is in the
+		 * process of crashing.
+		 */
+		if (p == NULL)
+			vsfr->rg_data[vsfr->bufSize - 1] = '\0';
+
+		dprintk(VIDC_ERR, "SFR Message from FW: %s\n",
+				vsfr->rg_data);
+	}
+}
+
+static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet)
+{
+	bool local_packet = false;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
+		return;
+	}
+
+	if (!packet) {
+		packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
+		if (!packet) {
+			dprintk(VIDC_ERR, "In %s() Fail to allocate mem\n",
+				__func__);
+			return;
+		}
+
+		local_packet = true;
+	}
+
+	while (!__iface_dbgq_read(device, packet)) {
+		struct hfi_msg_sys_coverage_packet *pkt =
+			(struct hfi_msg_sys_coverage_packet *) packet;
+		if (pkt->packet_type == HFI_MSG_SYS_COV) {
+			int stm_size = 0;
+
+			stm_size = stm_log_inv_ts(0, 0,
+				pkt->rg_msg_data, pkt->msg_size);
+			if (stm_size == 0)
+				dprintk(VIDC_ERR,
+					"In %s, stm_log returned size of 0\n",
+					__func__);
+		} else {
+			struct hfi_msg_sys_debug_packet *pkt =
+				(struct hfi_msg_sys_debug_packet *) packet;
+			dprintk(VIDC_FW, "%s", pkt->rg_msg_data);
+		}
+	}
+
+	if (local_packet)
+		kfree(packet);
+}
+
+static struct hal_session *__get_session(struct venus_hfi_device *device,
+		u32 session_id)
+{
+	struct hal_session *temp = NULL;
+
+	list_for_each_entry(temp, &device->sess_head, list) {
+		if (session_id == hash32_ptr(temp))
+			return temp;
+	}
+
+	return NULL;
+}
+
+static int __response_handler(struct venus_hfi_device *device)
+{
+	struct msm_vidc_cb_info *packets;
+	int packet_count = 0;
+	u8 *raw_packet = NULL;
+	bool requeue_pm_work = true;
+
+	if (!device || device->state != VENUS_STATE_INIT)
+		return 0;
+
+	packets = device->response_pkt;
+
+	raw_packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
+	if (!raw_packet || !packets) {
+		dprintk(VIDC_ERR, "%s: Failed to allocate memory\n",  __func__);
+		kfree(raw_packet);
+		return 0;
+	}
+
+	if (device->intr_status & VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK) {
+		struct hfi_sfr_struct *vsfr = (struct hfi_sfr_struct *)
+			device->sfr.align_virtual_addr;
+		struct msm_vidc_cb_info info = {
+			.response_type = HAL_SYS_WATCHDOG_TIMEOUT,
+			.response.cmd = {
+				.device_id = device->device_id,
+			}
+		};
+
+		if (vsfr)
+			dprintk(VIDC_ERR, "SFR Message from FW: %s\n",
+					vsfr->rg_data);
+
+		__dump_venus_debug_registers(device);
+		dprintk(VIDC_ERR, "Received watchdog timeout\n");
+		packets[packet_count++] = info;
+		goto exit;
+	}
+
+	/* Bleed the msg queue dry of packets */
+	while (!__iface_msgq_read(device, raw_packet)) {
+		void **session_id = NULL;
+		struct msm_vidc_cb_info *info = &packets[packet_count++];
+		struct vidc_hal_sys_init_done sys_init_done = {0};
+		int rc = 0;
+
+		rc = hfi_process_msg_packet(device->device_id,
+			(struct vidc_hal_msg_pkt_hdr *)raw_packet, info);
+		if (rc) {
+			dprintk(VIDC_WARN,
+					"Corrupt/unknown packet found, discarding\n");
+			--packet_count;
+			continue;
+		}
+
+		/* Process the packet types that we're interested in */
+		switch (info->response_type) {
+		case HAL_SYS_ERROR:
+			__dump_venus_debug_registers(device);
+			__process_sys_error(device);
+			break;
+		case HAL_SYS_RELEASE_RESOURCE_DONE:
+			dprintk(VIDC_DBG, "Received SYS_RELEASE_RESOURCE\n");
+			complete(&release_resources_done);
+			break;
+		case HAL_SYS_INIT_DONE:
+			dprintk(VIDC_DBG, "Received SYS_INIT_DONE\n");
+			/* Video driver intentionally does not unset
+			 * IMEM on venus to simplify power collapse.
+			 */
+			if (__set_imem(device, &device->resources.imem))
+				dprintk(VIDC_WARN,
+				"Failed to set IMEM. Performance will be impacted\n");
+			sys_init_done.capabilities =
+				device->sys_init_capabilities;
+			hfi_process_sys_init_done_prop_read(
+				(struct hfi_msg_sys_init_done_packet *)
+					raw_packet, &sys_init_done);
+			info->response.cmd.data.sys_init_done = sys_init_done;
+			break;
+		case HAL_SESSION_LOAD_RESOURCE_DONE:
+			/*
+			 * Work around for H/W bug, need to re-program these
+			 * registers as part of a handshake agreement with the
+			 * firmware.  This strictly only needs to be done for
+			 * decoder secure sessions, but there's no harm in doing
+			 * so for all sessions as it's at worst a NO-OP.
+			 */
+			__set_threshold_registers(device);
+			break;
+		default:
+			break;
+		}
+
+		/* For session-related packets, validate session */
+		switch (info->response_type) {
+		case HAL_SESSION_LOAD_RESOURCE_DONE:
+		case HAL_SESSION_INIT_DONE:
+		case HAL_SESSION_END_DONE:
+		case HAL_SESSION_ABORT_DONE:
+		case HAL_SESSION_START_DONE:
+		case HAL_SESSION_STOP_DONE:
+		case HAL_SESSION_FLUSH_DONE:
+		case HAL_SESSION_SUSPEND_DONE:
+		case HAL_SESSION_RESUME_DONE:
+		case HAL_SESSION_SET_PROP_DONE:
+		case HAL_SESSION_GET_PROP_DONE:
+		case HAL_SESSION_PARSE_SEQ_HDR_DONE:
+		case HAL_SESSION_RELEASE_BUFFER_DONE:
+		case HAL_SESSION_RELEASE_RESOURCE_DONE:
+		case HAL_SESSION_PROPERTY_INFO:
+			session_id = &info->response.cmd.session_id;
+			break;
+		case HAL_SESSION_ERROR:
+		case HAL_SESSION_GET_SEQ_HDR_DONE:
+		case HAL_SESSION_ETB_DONE:
+		case HAL_SESSION_FTB_DONE:
+			session_id = &info->response.data.session_id;
+			break;
+		case HAL_SESSION_EVENT_CHANGE:
+			session_id = &info->response.event.session_id;
+			break;
+		case HAL_RESPONSE_UNUSED:
+		default:
+			session_id = NULL;
+			break;
+		}
+
+		/*
+		 * hfi_process_msg_packet provides a session_id that's a hashed
+		 * value of struct hal_session, we need to coerce the hashed
+		 * value back to pointer that we can use. Ideally, hfi_process\
+		 * _msg_packet should take care of this, but it doesn't have
+		 * required information for it
+		 */
+		if (session_id) {
+			struct hal_session *session = NULL;
+
+			if (upper_32_bits((uintptr_t)*session_id) != 0) {
+				dprintk(VIDC_WARN,
+					"Upper 32 bits of session_id != 0\n");
+				WARN_ON(VIDC_DBG_WARN_ENABLE);
+			}
+			session = __get_session(device,
+					(u32)(uintptr_t)*session_id);
+			if (!session) {
+				dprintk(VIDC_ERR,
+						"Received a packet (%#x) for an unrecognized session (%pK), discarding\n",
+						info->response_type,
+						*session_id);
+				--packet_count;
+				continue;
+			}
+
+			*session_id = session->session_id;
+		}
+
+		if (packet_count >= max_packets &&
+				__get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) {
+			dprintk(VIDC_WARN,
+					"Too many packets in message queue to handle at once, deferring read\n");
+			break;
+		}
+	}
+
+	if (requeue_pm_work && device->res->sw_power_collapsible) {
+		cancel_delayed_work(&venus_hfi_pm_work);
+		if (!queue_delayed_work(device->venus_pm_workq,
+			&venus_hfi_pm_work,
+			msecs_to_jiffies(msm_vidc_pwr_collapse_delay))) {
+			dprintk(VIDC_ERR, "PM work already scheduled\n");
+		}
+	}
+
+exit:
+	__flush_debug_queue(device, raw_packet);
+
+	kfree(raw_packet);
+	return packet_count;
+}
+
+static void venus_hfi_core_work_handler(struct work_struct *work)
+{
+	struct venus_hfi_device *device = list_first_entry(
+		&hal_ctxt.dev_head, struct venus_hfi_device, list);
+	int num_responses = 0, i = 0;
+
+	mutex_lock(&device->lock);
+
+	dprintk(VIDC_INFO, "Handling interrupt\n");
+
+	if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "%s - Core not in init state\n", __func__);
+		goto err_no_work;
+	}
+
+	if (!device->callback) {
+		dprintk(VIDC_ERR, "No interrupt callback function: %pK\n",
+				device);
+		goto err_no_work;
+	}
+
+	if (__resume(device)) {
+		dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__);
+		goto err_no_work;
+	}
+
+	__core_clear_interrupt(device);
+	num_responses = __response_handler(device);
+
+err_no_work:
+	/* We need re-enable the irq which was disabled in ISR handler */
+	if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+		enable_irq(device->hal_data->irq);
+
+	mutex_unlock(&device->lock);
+
+	/*
+	 * Issue the callbacks outside of the locked contex to preserve
+	 * re-entrancy.
+	 */
+
+	for (i = 0; !IS_ERR_OR_NULL(device->response_pkt) &&
+		i < num_responses; ++i) {
+		struct msm_vidc_cb_info *r = &device->response_pkt[i];
+
+		device->callback(r->response_type, &r->response);
+	}
+
+	/*
+	 * XXX: Don't add any code beyond here.  Reacquiring locks after release
+	 * it above doesn't guarantee the atomicity that we're aiming for.
+	 */
+}
+
+static DECLARE_WORK(venus_hfi_work, venus_hfi_core_work_handler);
+
+static irqreturn_t venus_hfi_isr(int irq, void *dev)
+{
+	struct venus_hfi_device *device = dev;
+
+	dprintk(VIDC_INFO, "Received an interrupt %d\n", irq);
+	disable_irq_nosync(irq);
+	queue_work(device->vidc_workq, &venus_hfi_work);
+	return IRQ_HANDLED;
+}
+
+static int __init_regs_and_interrupts(struct venus_hfi_device *device,
+		struct msm_vidc_platform_resources *res)
+{
+	struct hal_data *hal = NULL;
+	int rc = 0;
+
+	rc = __check_core_registered(hal_ctxt, res->firmware_base,
+			(u8 *)(uintptr_t)res->register_base,
+			res->register_size, res->irq);
+	if (!rc) {
+		dprintk(VIDC_ERR, "Core present/Already added\n");
+		rc = -EEXIST;
+		goto err_core_init;
+	}
+
+	dprintk(VIDC_DBG, "HAL_DATA will be assigned now\n");
+	hal = (struct hal_data *)
+		kzalloc(sizeof(struct hal_data), GFP_KERNEL);
+	if (!hal) {
+		dprintk(VIDC_ERR, "Failed to alloc\n");
+		rc = -ENOMEM;
+		goto err_core_init;
+	}
+
+	hal->irq = res->irq;
+	hal->firmware_base = res->firmware_base;
+	hal->register_base = devm_ioremap_nocache(&res->pdev->dev,
+			res->register_base, res->register_size);
+	hal->register_size = res->register_size;
+	if (!hal->register_base) {
+		dprintk(VIDC_ERR,
+			"could not map reg addr %pa of size %d\n",
+			&res->register_base, res->register_size);
+		goto error_irq_fail;
+	}
+
+	device->hal_data = hal;
+	rc = request_irq(res->irq, venus_hfi_isr, IRQF_TRIGGER_HIGH,
+			"msm_vidc", device);
+	if (unlikely(rc)) {
+		dprintk(VIDC_ERR, "() :request_irq failed\n");
+		goto error_irq_fail;
+	}
+
+	disable_irq_nosync(res->irq);
+	dprintk(VIDC_INFO,
+		"firmware_base = %pa, register_base = %pa, register_size = %d\n",
+		&res->firmware_base, &res->register_base,
+		res->register_size);
+	return rc;
+
+error_irq_fail:
+	kfree(hal);
+err_core_init:
+	return rc;
+
+}
+
+static inline void __deinit_clocks(struct venus_hfi_device *device)
+{
+	struct clock_info *cl;
+
+	device->clk_freq = 0;
+	venus_hfi_for_each_clock_reverse(device, cl) {
+		if (cl->clk) {
+			clk_put(cl->clk);
+			cl->clk = NULL;
+		}
+	}
+}
+
+static inline int __init_clocks(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct clock_info *cl = NULL;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		int i = 0;
+
+		dprintk(VIDC_DBG, "%s: scalable? %d, count %d\n",
+				cl->name, cl->has_scaling, cl->count);
+		for (i = 0; i < cl->count; ++i) {
+			dprintk(VIDC_DBG,
+				"\tload = %d, freq = %d codecs supported %#x\n",
+				cl->load_freq_tbl[i].load,
+				cl->load_freq_tbl[i].freq,
+				cl->load_freq_tbl[i].supported_codecs);
+		}
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		if (!cl->clk) {
+			cl->clk = clk_get(&device->res->pdev->dev, cl->name);
+			if (IS_ERR_OR_NULL(cl->clk)) {
+				dprintk(VIDC_ERR,
+					"Failed to get clock: %s\n", cl->name);
+				rc = PTR_ERR(cl->clk) ?: -EINVAL;
+				cl->clk = NULL;
+				goto err_clk_get;
+			}
+		}
+	}
+	device->clk_freq = 0;
+	return 0;
+
+err_clk_get:
+	__deinit_clocks(device);
+	return rc;
+}
+
+
+static inline void __disable_unprepare_clks(struct venus_hfi_device *device)
+{
+	struct clock_info *cl;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		usleep_range(100, 500);
+		dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n",
+				cl->name);
+		clk_disable_unprepare(cl->clk);
+	}
+}
+
+static inline int __prepare_enable_clks(struct venus_hfi_device *device)
+{
+	struct clock_info *cl = NULL, *cl_fail = NULL;
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	}
+
+	venus_hfi_for_each_clock(device, cl) {
+		/*
+		 * For the clocks we control, set the rate prior to preparing
+		 * them.  Since we don't really have a load at this point, scale
+		 * it to the lowest frequency possible
+		 */
+		if (cl->has_scaling)
+			clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0));
+
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to enable clocks\n");
+			cl_fail = cl;
+			goto fail_clk_enable;
+		}
+
+		dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name);
+	}
+
+	__write_register(device, VIDC_WRAPPER_CLOCK_CONFIG, 0);
+	__write_register(device, VIDC_WRAPPER_CPU_CLOCK_CONFIG, 0);
+	return rc;
+
+fail_clk_enable:
+	venus_hfi_for_each_clock(device, cl) {
+		if (cl_fail == cl)
+			break;
+		usleep_range(100, 500);
+		dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n",
+			cl->name);
+		clk_disable_unprepare(cl->clk);
+	}
+
+	return rc;
+}
+
+static void __deinit_bus(struct venus_hfi_device *device)
+{
+	struct bus_info *bus = NULL;
+
+	if (!device)
+		return;
+
+	kfree(device->bus_vote.data);
+	device->bus_vote = DEFAULT_BUS_VOTE;
+
+	venus_hfi_for_each_bus_reverse(device, bus) {
+		devfreq_remove_device(bus->devfreq);
+		bus->devfreq = NULL;
+		dev_set_drvdata(bus->dev, NULL);
+
+		msm_bus_scale_unregister(bus->client);
+		bus->client = NULL;
+	}
+}
+
+static int __init_bus(struct venus_hfi_device *device)
+{
+	struct bus_info *bus = NULL;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	venus_hfi_for_each_bus(device, bus) {
+		struct devfreq_dev_profile profile = {
+			.initial_freq = 0,
+			.polling_ms = INT_MAX,
+			.freq_table = NULL,
+			.max_state = 0,
+			.target = __devfreq_target,
+			.get_dev_status = __devfreq_get_status,
+			.exit = NULL,
+		};
+
+		/*
+		 * This is stupid, but there's no other easy way to ahold
+		 * of struct bus_info in venus_hfi_devfreq_*()
+		 */
+		WARN(dev_get_drvdata(bus->dev), "%s's drvdata already set\n",
+				dev_name(bus->dev));
+		dev_set_drvdata(bus->dev, device);
+
+		bus->client = msm_bus_scale_register(bus->master, bus->slave,
+				bus->name, false);
+		if (IS_ERR_OR_NULL(bus->client)) {
+			rc = PTR_ERR(bus->client) ?: -EBADHANDLE;
+			dprintk(VIDC_ERR, "Failed to register bus %s: %d\n",
+					bus->name, rc);
+			bus->client = NULL;
+			goto err_add_dev;
+		}
+
+		bus->devfreq_prof = profile;
+		bus->devfreq = devfreq_add_device(bus->dev,
+				&bus->devfreq_prof, bus->governor, NULL);
+		if (IS_ERR_OR_NULL(bus->devfreq)) {
+			rc = PTR_ERR(bus->devfreq) ?: -EBADHANDLE;
+			dprintk(VIDC_ERR,
+					"Failed to add devfreq device for bus %s and governor %s: %d\n",
+					bus->name, bus->governor, rc);
+			bus->devfreq = NULL;
+			goto err_add_dev;
+		}
+
+		/*
+		 * Devfreq starts monitoring immediately, since we are just
+		 * initializing stuff at this point, force it to suspend
+		 */
+		devfreq_suspend_device(bus->devfreq);
+	}
+
+	device->bus_vote = DEFAULT_BUS_VOTE;
+	return 0;
+
+err_add_dev:
+	__deinit_bus(device);
+	return rc;
+}
+
+static void __deinit_regulators(struct venus_hfi_device *device)
+{
+	struct regulator_info *rinfo = NULL;
+
+	venus_hfi_for_each_regulator_reverse(device, rinfo) {
+		if (rinfo->regulator) {
+			regulator_put(rinfo->regulator);
+			rinfo->regulator = NULL;
+		}
+	}
+}
+
+static int __init_regulators(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	struct regulator_info *rinfo = NULL;
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		rinfo->regulator = regulator_get(&device->res->pdev->dev,
+				rinfo->name);
+		if (IS_ERR_OR_NULL(rinfo->regulator)) {
+			rc = PTR_ERR(rinfo->regulator) ?: -EBADHANDLE;
+			dprintk(VIDC_ERR, "Failed to get regulator: %s\n",
+					rinfo->name);
+			rinfo->regulator = NULL;
+			goto err_reg_get;
+		}
+	}
+
+	return 0;
+
+err_reg_get:
+	__deinit_regulators(device);
+	return rc;
+}
+
+static int __init_resources(struct venus_hfi_device *device,
+				struct msm_vidc_platform_resources *res)
+{
+	int rc = 0;
+
+	rc = __init_regulators(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to get all regulators\n");
+		return -ENODEV;
+	}
+
+	rc = __init_clocks(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init clocks\n");
+		rc = -ENODEV;
+		goto err_init_clocks;
+	}
+
+	rc = __init_bus(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init bus: %d\n", rc);
+		goto err_init_bus;
+	}
+
+	device->sys_init_capabilities =
+		kzalloc(sizeof(struct msm_vidc_capability)
+		* VIDC_MAX_SESSIONS, GFP_TEMPORARY);
+
+	return rc;
+
+err_init_bus:
+	__deinit_clocks(device);
+err_init_clocks:
+	__deinit_regulators(device);
+	return rc;
+}
+
+static void __deinit_resources(struct venus_hfi_device *device)
+{
+	__deinit_bus(device);
+	__deinit_clocks(device);
+	__deinit_regulators(device);
+	kfree(device->sys_init_capabilities);
+	device->sys_init_capabilities = NULL;
+}
+
+static int __protect_cp_mem(struct venus_hfi_device *device)
+{
+	struct tzbsp_memprot memprot;
+	unsigned int resp = 0;
+	int rc = 0;
+	struct context_bank_info *cb;
+	struct scm_desc desc = {0};
+
+	if (!device)
+		return -EINVAL;
+
+	memprot.cp_start = 0x0;
+	memprot.cp_size = 0x0;
+	memprot.cp_nonpixel_start = 0x0;
+	memprot.cp_nonpixel_size = 0x0;
+
+	list_for_each_entry(cb, &device->res->context_banks, list) {
+		if (!strcmp(cb->name, "venus_ns")) {
+			desc.args[1] = memprot.cp_size =
+				cb->addr_range.start;
+			dprintk(VIDC_DBG, "%s memprot.cp_size: %#x\n",
+				__func__, memprot.cp_size);
+		}
+
+		if (!strcmp(cb->name, "venus_sec_non_pixel")) {
+			desc.args[2] = memprot.cp_nonpixel_start =
+				cb->addr_range.start;
+			desc.args[3] = memprot.cp_nonpixel_size =
+				cb->addr_range.size;
+			dprintk(VIDC_DBG,
+				"%s memprot.cp_nonpixel_start: %#x size: %#x\n",
+				__func__, memprot.cp_nonpixel_start,
+				memprot.cp_nonpixel_size);
+		}
+	}
+
+	if (!is_scm_armv8()) {
+		rc = scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
+			sizeof(memprot), &resp, sizeof(resp));
+	} else {
+		desc.arginfo = SCM_ARGS(4);
+		rc = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
+			       TZBSP_MEM_PROTECT_VIDEO_VAR), &desc);
+		resp = desc.ret[0];
+	}
+
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to protect memory(%d) response: %d\n",
+				rc, resp);
+	}
+
+	trace_venus_hfi_var_done(
+		memprot.cp_start, memprot.cp_size,
+		memprot.cp_nonpixel_start, memprot.cp_nonpixel_size);
+	return rc;
+}
+
+static int __disable_regulator(struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	dprintk(VIDC_DBG, "Disabling regulator %s\n", rinfo->name);
+
+	/*
+	 * This call is needed. Driver needs to acquire the control back
+	 * from HW in order to disable the regualtor. Else the behavior
+	 * is unknown.
+	 */
+
+	rc = __acquire_regulator(rinfo);
+	if (rc) {
+		/* This is somewhat fatal, but nothing we can do
+		 * about it. We can't disable the regulator w/o
+		 * getting it back under s/w control
+		 */
+		dprintk(VIDC_WARN,
+			"Failed to acquire control on %s\n",
+			rinfo->name);
+
+		goto disable_regulator_failed;
+	}
+
+	rc = regulator_disable(rinfo->regulator);
+	if (rc) {
+		dprintk(VIDC_WARN,
+			"Failed to disable %s: %d\n",
+			rinfo->name, rc);
+		goto disable_regulator_failed;
+	}
+
+	return 0;
+disable_regulator_failed:
+
+	/* Bring attention to this issue */
+	WARN_ON(VIDC_DBG_WARN_ENABLE);
+	return rc;
+}
+
+static int __enable_hw_power_collapse(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (!msm_vidc_fw_low_power_mode) {
+		dprintk(VIDC_DBG, "Not enabling hardware power collapse\n");
+		return 0;
+	}
+
+	rc = __hand_off_regulators(device);
+	if (rc)
+		dprintk(VIDC_WARN,
+			"%s : Failed to enable HW power collapse %d\n",
+				__func__, rc);
+	return rc;
+}
+
+static int __enable_regulators(struct venus_hfi_device *device)
+{
+	int rc = 0, c = 0;
+	struct regulator_info *rinfo;
+
+	dprintk(VIDC_DBG, "Enabling regulators\n");
+
+	venus_hfi_for_each_regulator(device, rinfo) {
+		rc = regulator_enable(rinfo->regulator);
+		if (rc) {
+			dprintk(VIDC_ERR,
+					"Failed to enable %s: %d\n",
+					rinfo->name, rc);
+			goto err_reg_enable_failed;
+		}
+
+		dprintk(VIDC_DBG, "Enabled regulator %s\n",
+				rinfo->name);
+		c++;
+	}
+
+	return 0;
+
+err_reg_enable_failed:
+	venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
+		__disable_regulator(rinfo);
+
+	return rc;
+}
+
+static int __disable_regulators(struct venus_hfi_device *device)
+{
+	struct regulator_info *rinfo;
+	int rc = 0;
+
+	dprintk(VIDC_DBG, "Disabling regulators\n");
+
+	venus_hfi_for_each_regulator_reverse(device, rinfo)
+		__disable_regulator(rinfo);
+
+	return rc;
+}
+
+static int __venus_power_on(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (device->power_enabled)
+		return 0;
+
+	device->power_enabled = true;
+	/* Vote for all hardware resources */
+	rc = __vote_buses(device, device->bus_vote.data,
+			device->bus_vote.data_count);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to vote buses, err: %d\n", rc);
+		goto fail_vote_buses;
+	}
+
+	rc = __alloc_imem(device, device->res->imem_size);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to allocate IMEM\n");
+		goto fail_alloc_imem;
+	}
+
+	rc = __enable_regulators(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to enable GDSC, err = %d\n", rc);
+		goto fail_enable_gdsc;
+	}
+
+	rc = __prepare_enable_clks(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
+		goto fail_enable_clks;
+	}
+
+	rc = __scale_clocks(device, 0, NULL, 0);
+	if (rc) {
+		dprintk(VIDC_WARN,
+				"Failed to scale clocks, performance might be affected\n");
+		rc = 0;
+	}
+	__write_register(device, VIDC_WRAPPER_INTR_MASK,
+			VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK);
+	device->intr_status = 0;
+	enable_irq(device->hal_data->irq);
+
+	/*
+	 * Hand off control of regulators to h/w _after_ enabling clocks.
+	 * Note that the GDSC will turn off when switching from normal
+	 * (s/w triggered) to fast (HW triggered) unless the h/w vote is
+	 * present. Since Venus isn't up yet, the GDSC will be off briefly.
+	 */
+	if (__enable_hw_power_collapse(device))
+		dprintk(VIDC_ERR, "Failed to enabled inter-frame PC\n");
+
+	return rc;
+
+fail_enable_clks:
+	__disable_regulators(device);
+fail_enable_gdsc:
+	__free_imem(device);
+fail_alloc_imem:
+	__unvote_buses(device);
+fail_vote_buses:
+	device->power_enabled = false;
+	return rc;
+}
+
+static void __venus_power_off(struct venus_hfi_device *device, bool halt_axi)
+{
+	if (!device->power_enabled)
+		return;
+
+	if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+		disable_irq_nosync(device->hal_data->irq);
+	device->intr_status = 0;
+
+	/* Halt the AXI to make sure there are no pending transactions.
+	 * Clocks should be unprepared after making sure axi is halted.
+	 */
+	if (halt_axi && __halt_axi(device))
+		dprintk(VIDC_WARN, "Failed to halt AXI\n");
+
+	__disable_unprepare_clks(device);
+	if (__disable_regulators(device))
+		dprintk(VIDC_WARN, "Failed to disable regulators\n");
+
+	__free_imem(device);
+
+	if (__unvote_buses(device))
+		dprintk(VIDC_WARN, "Failed to unvote for buses\n");
+	device->power_enabled = false;
+}
+
+static inline int __suspend(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	} else if (!device->power_enabled) {
+		dprintk(VIDC_DBG, "Power already disabled\n");
+		return 0;
+	}
+
+	dprintk(VIDC_DBG, "Entering power collapse\n");
+
+	if (device->res->pm_qos_latency_us &&
+		pm_qos_request_active(&device->qos))
+		pm_qos_remove_request(&device->qos);
+
+	rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+	if (rc) {
+		dprintk(VIDC_WARN, "Failed to suspend video core %d\n", rc);
+		goto err_tzbsp_suspend;
+	}
+
+	__venus_power_off(device, true);
+	dprintk(VIDC_INFO, "Venus power collapsed\n");
+	return rc;
+
+err_tzbsp_suspend:
+	return rc;
+}
+
+static inline int __resume(struct venus_hfi_device *device)
+{
+	int rc = 0;
+
+	if (!device) {
+		dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
+		return -EINVAL;
+	} else if (device->power_enabled) {
+		dprintk(VIDC_DBG, "Power is already enabled\n");
+		goto exit;
+	} else if (!__core_in_valid_state(device)) {
+		dprintk(VIDC_DBG, "venus_hfi_device in deinit state.");
+		return -EINVAL;
+	}
+
+	dprintk(VIDC_DBG, "Resuming from power collapse\n");
+	rc = __venus_power_on(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to power on venus\n");
+		goto err_venus_power_on;
+	}
+
+	/* Reboot the firmware */
+	rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc);
+		goto err_set_video_state;
+	}
+
+	/*
+	 * Re-program all of the registers that get reset as a result of
+	 * regulator_disable() and _enable()
+	 */
+	__set_registers(device);
+	__setup_ucregion_memory_map(device);
+	/* Wait for boot completion */
+	rc = __boot_firmware(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to reset venus core\n");
+		goto err_reset_core;
+	}
+
+	/*
+	 * Work around for H/W bug, need to reprogram these registers once
+	 * firmware is out reset
+	 */
+	__set_threshold_registers(device);
+
+	if (device->res->pm_qos_latency_us) {
+#ifdef CONFIG_SMP
+		device->qos.type = PM_QOS_REQ_AFFINE_IRQ;
+		device->qos.irq = device->hal_data->irq;
+#endif
+		pm_qos_add_request(&device->qos, PM_QOS_CPU_DMA_LATENCY,
+				device->res->pm_qos_latency_us);
+	}
+	dprintk(VIDC_INFO, "Resumed from power collapse\n");
+exit:
+	device->skip_pc_count = 0;
+	return rc;
+err_reset_core:
+	__tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
+err_set_video_state:
+	__venus_power_off(device, true);
+err_venus_power_on:
+	dprintk(VIDC_ERR, "Failed to resume from power collapse\n");
+	return rc;
+}
+
+static int __load_fw(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	/* Initialize resources */
+	rc = __init_resources(device, device->res);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
+		goto fail_init_res;
+	}
+
+	rc = __initialize_packetization(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to initialize packetization\n");
+		goto fail_init_pkt;
+	}
+	trace_msm_v4l2_vidc_fw_load_start("msm_v4l2_vidc venus_fw load start");
+
+	rc = __venus_power_on(device);
+	if (rc) {
+		dprintk(VIDC_ERR, "Failed to power on venus in in load_fw\n");
+		goto fail_venus_power_on;
+	}
+
+	if ((!device->res->use_non_secure_pil && !device->res->firmware_base)
+			|| device->res->use_non_secure_pil) {
+		if (!device->resources.fw.cookie)
+			device->resources.fw.cookie =
+				subsystem_get_with_fwname("venus",
+				device->res->fw_name);
+
+		if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
+			dprintk(VIDC_ERR, "Failed to download firmware\n");
+			device->resources.fw.cookie = NULL;
+			rc = -ENOMEM;
+			goto fail_load_fw;
+		}
+	}
+
+	if (!device->res->use_non_secure_pil && !device->res->firmware_base) {
+		rc = __protect_cp_mem(device);
+		if (rc) {
+			dprintk(VIDC_ERR, "Failed to protect memory\n");
+			goto fail_protect_mem;
+		}
+	}
+	trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
+	return rc;
+fail_protect_mem:
+	if (device->resources.fw.cookie)
+		subsystem_put(device->resources.fw.cookie);
+	device->resources.fw.cookie = NULL;
+fail_load_fw:
+	__venus_power_off(device, true);
+fail_venus_power_on:
+fail_init_pkt:
+	__deinit_resources(device);
+fail_init_res:
+	trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
+	return rc;
+}
+
+static void __unload_fw(struct venus_hfi_device *device)
+{
+	if (!device->resources.fw.cookie)
+		return;
+
+	cancel_delayed_work(&venus_hfi_pm_work);
+	if (device->state != VENUS_STATE_DEINIT)
+		flush_workqueue(device->venus_pm_workq);
+
+	__vote_buses(device, NULL, 0);
+	subsystem_put(device->resources.fw.cookie);
+	__interface_queues_release(device);
+	__venus_power_off(device, false);
+	device->resources.fw.cookie = NULL;
+	__deinit_resources(device);
+}
+
+static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info)
+{
+	int i = 0, j = 0;
+	struct venus_hfi_device *device = dev;
+	u32 smem_block_size = 0;
+	u8 *smem_table_ptr;
+	char version[VENUS_VERSION_LENGTH];
+	const u32 smem_image_index_venus = 14 * 128;
+
+	if (!device || !fw_info) {
+		dprintk(VIDC_ERR,
+			"%s Invalid parameter: device = %pK fw_info = %pK\n",
+			__func__, device, fw_info);
+		return -EINVAL;
+	}
+
+	mutex_lock(&device->lock);
+
+	smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+			&smem_block_size, 0, SMEM_ANY_HOST_FLAG);
+	if (smem_table_ptr &&
+			((smem_image_index_venus +
+			  VENUS_VERSION_LENGTH) <= smem_block_size))
+		memcpy(version,
+			smem_table_ptr + smem_image_index_venus,
+			VENUS_VERSION_LENGTH);
+
+	while (version[i++] != 'V' && i < VENUS_VERSION_LENGTH)
+		;
+
+	if (i == VENUS_VERSION_LENGTH - 1) {
+		dprintk(VIDC_WARN, "Venus version string is not proper\n");
+		fw_info->version[0] = '\0';
+		goto fail_version_string;
+	}
+
+	for (i--; i < VENUS_VERSION_LENGTH && j < VENUS_VERSION_LENGTH - 1; i++)
+		fw_info->version[j++] = version[i];
+	fw_info->version[j] = '\0';
+
+fail_version_string:
+	dprintk(VIDC_DBG, "F/W version retrieved : %s\n", fw_info->version);
+	fw_info->base_addr = device->hal_data->firmware_base;
+	fw_info->register_base = device->res->register_base;
+	fw_info->register_size = device->hal_data->register_size;
+	fw_info->irq = device->hal_data->irq;
+
+	mutex_unlock(&device->lock);
+	return 0;
+}
+
+static int venus_hfi_get_core_capabilities(void *dev)
+{
+	struct venus_hfi_device *device = dev;
+	int rc = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	mutex_lock(&device->lock);
+
+	rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY |
+		HAL_VIDEO_ENCODER_SCALING_CAPABILITY |
+		HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY |
+		HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY;
+
+	mutex_unlock(&device->lock);
+
+	return rc;
+}
+
+static int __initialize_packetization(struct venus_hfi_device *device)
+{
+	int rc = 0;
+	const char *hfi_version;
+
+	if (!device || !device->res) {
+		dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	hfi_version = device->res->hfi_version;
+
+	if (!hfi_version) {
+		device->packetization_type = HFI_PACKETIZATION_LEGACY;
+	} else if (!strcmp(hfi_version, "3xx")) {
+		device->packetization_type = HFI_PACKETIZATION_3XX;
+	} else {
+		dprintk(VIDC_ERR, "Unsupported hfi version\n");
+		return -EINVAL;
+	}
+
+	device->pkt_ops = hfi_get_pkt_ops_handle(device->packetization_type);
+	if (!device->pkt_ops) {
+		rc = -EINVAL;
+		dprintk(VIDC_ERR, "Failed to get pkt_ops handle\n");
+	}
+
+	return rc;
+}
+
+static struct venus_hfi_device *__add_device(u32 device_id,
+			struct msm_vidc_platform_resources *res,
+			hfi_cmd_response_callback callback)
+{
+	struct venus_hfi_device *hdevice = NULL;
+	int rc = 0;
+
+	if (!res || !callback) {
+		dprintk(VIDC_ERR, "Invalid Parameters\n");
+		return NULL;
+	}
+
+	dprintk(VIDC_INFO, "entered , device_id: %d\n", device_id);
+
+	hdevice = (struct venus_hfi_device *)
+			kzalloc(sizeof(struct venus_hfi_device), GFP_KERNEL);
+	if (!hdevice) {
+		dprintk(VIDC_ERR, "failed to allocate new device\n");
+		goto exit;
+	}
+
+	hdevice->response_pkt = kmalloc_array(max_packets,
+				sizeof(*hdevice->response_pkt), GFP_TEMPORARY);
+	if (!hdevice->response_pkt) {
+		dprintk(VIDC_ERR, "failed to allocate response_pkt\n");
+		goto err_cleanup;
+	}
+
+	rc = __init_regs_and_interrupts(hdevice, res);
+	if (rc)
+		goto err_cleanup;
+
+	hdevice->res = res;
+	hdevice->device_id = device_id;
+	hdevice->callback = callback;
+
+	hdevice->vidc_workq = create_singlethread_workqueue(
+		"msm_vidc_workerq_venus");
+	if (!hdevice->vidc_workq) {
+		dprintk(VIDC_ERR, ": create vidc workq failed\n");
+		goto err_cleanup;
+	}
+
+	hdevice->venus_pm_workq = create_singlethread_workqueue(
+			"pm_workerq_venus");
+	if (!hdevice->venus_pm_workq) {
+		dprintk(VIDC_ERR, ": create pm workq failed\n");
+		goto err_cleanup;
+	}
+
+	if (!hal_ctxt.dev_count)
+		INIT_LIST_HEAD(&hal_ctxt.dev_head);
+
+	mutex_init(&hdevice->lock);
+	INIT_LIST_HEAD(&hdevice->list);
+	INIT_LIST_HEAD(&hdevice->sess_head);
+	list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
+	hal_ctxt.dev_count++;
+
+	return hdevice;
+
+err_cleanup:
+	if (hdevice->vidc_workq)
+		destroy_workqueue(hdevice->vidc_workq);
+	kfree(hdevice->response_pkt);
+	kfree(hdevice);
+exit:
+	return NULL;
+}
+
+static struct venus_hfi_device *__get_device(u32 device_id,
+				struct msm_vidc_platform_resources *res,
+				hfi_cmd_response_callback callback)
+{
+	if (!res || !callback) {
+		dprintk(VIDC_ERR, "Invalid params: %pK %pK\n", res, callback);
+		return NULL;
+	}
+
+	return __add_device(device_id, res, callback);
+}
+
+void venus_hfi_delete_device(void *device)
+{
+	struct venus_hfi_device *close, *tmp, *dev;
+
+	if (!device)
+		return;
+
+	dev = (struct venus_hfi_device *) device;
+
+	mutex_lock(&dev->lock);
+	__iommu_detach(dev);
+	mutex_unlock(&dev->lock);
+
+	list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
+		if (close->hal_data->irq == dev->hal_data->irq) {
+			hal_ctxt.dev_count--;
+			list_del(&close->list);
+			destroy_workqueue(close->vidc_workq);
+			destroy_workqueue(close->venus_pm_workq);
+			free_irq(dev->hal_data->irq, close);
+			iounmap(dev->hal_data->register_base);
+			kfree(close->hal_data);
+			kfree(close->response_pkt);
+			kfree(close);
+			break;
+		}
+	}
+}
+
+static void venus_init_hfi_callbacks(struct hfi_device *hdev)
+{
+	hdev->core_init = venus_hfi_core_init;
+	hdev->core_release = venus_hfi_core_release;
+	hdev->core_ping = venus_hfi_core_ping;
+	hdev->core_trigger_ssr = venus_hfi_core_trigger_ssr;
+	hdev->session_init = venus_hfi_session_init;
+	hdev->session_end = venus_hfi_session_end;
+	hdev->session_abort = venus_hfi_session_abort;
+	hdev->session_clean = venus_hfi_session_clean;
+	hdev->session_set_buffers = venus_hfi_session_set_buffers;
+	hdev->session_release_buffers = venus_hfi_session_release_buffers;
+	hdev->session_load_res = venus_hfi_session_load_res;
+	hdev->session_release_res = venus_hfi_session_release_res;
+	hdev->session_start = venus_hfi_session_start;
+	hdev->session_continue = venus_hfi_session_continue;
+	hdev->session_stop = venus_hfi_session_stop;
+	hdev->session_etb = venus_hfi_session_etb;
+	hdev->session_ftb = venus_hfi_session_ftb;
+	hdev->session_process_batch = venus_hfi_session_process_batch;
+	hdev->session_parse_seq_hdr = venus_hfi_session_parse_seq_hdr;
+	hdev->session_get_seq_hdr = venus_hfi_session_get_seq_hdr;
+	hdev->session_get_buf_req = venus_hfi_session_get_buf_req;
+	hdev->session_flush = venus_hfi_session_flush;
+	hdev->session_set_property = venus_hfi_session_set_property;
+	hdev->session_get_property = venus_hfi_session_get_property;
+	hdev->scale_clocks = venus_hfi_scale_clocks;
+	hdev->vote_bus = venus_hfi_vote_buses;
+	hdev->get_fw_info = venus_hfi_get_fw_info;
+	hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
+	hdev->suspend = venus_hfi_suspend;
+	hdev->get_core_clock_rate = venus_hfi_get_core_clock_rate;
+	hdev->get_default_properties = venus_hfi_get_default_properties;
+}
+
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+		struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback)
+{
+	int rc = 0;
+
+	if (!hdev || !res || !callback) {
+		dprintk(VIDC_ERR, "Invalid params: %pK %pK %pK\n",
+			hdev, res, callback);
+		rc = -EINVAL;
+		goto err_venus_hfi_init;
+	}
+
+	hdev->hfi_device_data = __get_device(device_id, res, callback);
+
+	if (IS_ERR_OR_NULL(hdev->hfi_device_data)) {
+		rc = PTR_ERR(hdev->hfi_device_data) ?: -EINVAL;
+		goto err_venus_hfi_init;
+	}
+
+	venus_init_hfi_callbacks(hdev);
+
+err_venus_hfi_init:
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/venus_hfi.h b/drivers/media/platform/msm/vidc_3x/venus_hfi.h
new file mode 100644
index 0000000..9400430
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/venus_hfi.h
@@ -0,0 +1,263 @@
+/* Copyright (c) 2012-2015, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __H_VENUS_HFI_H__
+#define __H_VENUS_HFI_H__
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/spinlock.h>
+#include "vmem/vmem.h"
+#include "vidc_hfi_api.h"
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+#include "vidc_hfi.h"
+#include "msm_vidc_resources.h"
+#include "hfi_packetization.h"
+
+#define HFI_MASK_QHDR_TX_TYPE			0xFF000000
+#define HFI_MASK_QHDR_RX_TYPE			0x00FF0000
+#define HFI_MASK_QHDR_PRI_TYPE			0x0000FF00
+#define HFI_MASK_QHDR_Q_ID_TYPE			0x000000FF
+#define HFI_Q_ID_HOST_TO_CTRL_CMD_Q		0x00
+#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q		0x01
+#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q	0x02
+#define HFI_MASK_QHDR_STATUS			0x000000FF
+
+#define VIDC_MAX_UNCOMPRESSED_FMT_PLANES	3
+
+#define VIDC_IFACEQ_NUMQ					3
+#define VIDC_IFACEQ_CMDQ_IDX				0
+#define VIDC_IFACEQ_MSGQ_IDX				1
+#define VIDC_IFACEQ_DBGQ_IDX				2
+#define VIDC_IFACEQ_MAX_BUF_COUNT			50
+#define VIDC_IFACE_MAX_PARALLEL_CLNTS		16
+#define VIDC_IFACEQ_DFLT_QHDR				0x01010000
+
+#define VIDC_MAX_NAME_LENGTH 64
+#define VIDC_MAX_PC_SKIP_COUNT 10
+struct hfi_queue_table_header {
+	u32 qtbl_version;
+	u32 qtbl_size;
+	u32 qtbl_qhdr0_offset;
+	u32 qtbl_qhdr_size;
+	u32 qtbl_num_q;
+	u32 qtbl_num_active_q;
+};
+
+struct hfi_queue_header {
+	u32 qhdr_status;
+	u32 qhdr_start_addr;
+	u32 qhdr_type;
+	u32 qhdr_q_size;
+	u32 qhdr_pkt_size;
+	u32 qhdr_pkt_drop_cnt;
+	u32 qhdr_rx_wm;
+	u32 qhdr_tx_wm;
+	u32 qhdr_rx_req;
+	u32 qhdr_tx_req;
+	u32 qhdr_rx_irq_status;
+	u32 qhdr_tx_irq_status;
+	u32 qhdr_read_idx;
+	u32 qhdr_write_idx;
+};
+
+struct hfi_mem_map_table {
+	u32 mem_map_num_entries;
+	u32 mem_map_table_base_addr;
+};
+
+struct hfi_mem_map {
+	u32 virtual_addr;
+	u32 physical_addr;
+	u32 size;
+	u32 attr;
+};
+
+#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
+	+ sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
+
+#define VIDC_IFACEQ_QUEUE_SIZE	(VIDC_IFACEQ_MAX_PKT_SIZE *  \
+	VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS)
+
+#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i)     \
+	(void *)((ptr + sizeof(struct hfi_queue_table_header)) + \
+		(i * sizeof(struct hfi_queue_header)))
+
+#define QDSS_SIZE 4096
+#define SFR_SIZE 4096
+
+#define QUEUE_SIZE (VIDC_IFACEQ_TABLE_SIZE + \
+	(VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ))
+
+#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K)
+#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K)
+#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K)
+#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \
+			ALIGNED_QDSS_SIZE, SZ_1M)
+
+enum vidc_hw_reg {
+	VIDC_HWREG_CTRL_STATUS =  0x1,
+	VIDC_HWREG_QTBL_INFO =  0x2,
+	VIDC_HWREG_QTBL_ADDR =  0x3,
+	VIDC_HWREG_CTRLR_RESET =  0x4,
+	VIDC_HWREG_IFACEQ_FWRXREQ =  0x5,
+	VIDC_HWREG_IFACEQ_FWTXREQ =  0x6,
+	VIDC_HWREG_VHI_SOFTINTEN =  0x7,
+	VIDC_HWREG_VHI_SOFTINTSTATUS =  0x8,
+	VIDC_HWREG_VHI_SOFTINTCLR =  0x9,
+	VIDC_HWREG_HVI_SOFTINTEN =  0xA,
+};
+
+struct vidc_mem_addr {
+	ion_phys_addr_t align_device_addr;
+	u8 *align_virtual_addr;
+	u32 mem_size;
+	struct msm_smem *mem_data;
+};
+
+struct vidc_iface_q_info {
+	void *q_hdr;
+	struct vidc_mem_addr q_array;
+};
+
+/*
+ * These are helper macros to iterate over various lists within
+ * venus_hfi_device->res.  The intention is to cut down on a lot of boiler-plate
+ * code
+ */
+
+/* Read as "for each 'thing' in a set of 'thingies'" */
+#define venus_hfi_for_each_thing(__device, __thing, __thingy) \
+	venus_hfi_for_each_thing_continue(__device, __thing, __thingy, 0)
+
+#define venus_hfi_for_each_thing_reverse(__device, __thing, __thingy) \
+	venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
+			(__device)->res->__thingy##_set.count - 1)
+
+/* TODO: the __from parameter technically not required since we can figure it
+ * out with some pointer magic (i.e. __thing - __thing##_tbl[0]).  If this macro
+ * sees extensive use, probably worth cleaning it up but for now omitting it
+ * since it introduces unneccessary complexity.
+ */
+#define venus_hfi_for_each_thing_continue(__device, __thing, __thingy, __from) \
+	for (__thing = &(__device)->res->\
+			__thingy##_set.__thingy##_tbl[__from]; \
+		__thing < &(__device)->res->__thingy##_set.__thingy##_tbl[0] + \
+			((__device)->res->__thingy##_set.count - __from); \
+		++__thing)
+
+#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
+		__from) \
+	for (__thing = &(__device)->res->\
+			__thingy##_set.__thingy##_tbl[__from]; \
+		__thing >= &(__device)->res->__thingy##_set.__thingy##_tbl[0]; \
+		--__thing)
+
+/* Regular set helpers */
+#define venus_hfi_for_each_regulator(__device, __rinfo) \
+	venus_hfi_for_each_thing(__device, __rinfo, regulator)
+
+#define venus_hfi_for_each_regulator_reverse(__device, __rinfo) \
+	venus_hfi_for_each_thing_reverse(__device, __rinfo, regulator)
+
+#define venus_hfi_for_each_regulator_reverse_continue(__device, __rinfo, \
+		__from) \
+	venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \
+			regulator, __from)
+
+/* Clock set helpers */
+#define venus_hfi_for_each_clock(__device, __cinfo) \
+	venus_hfi_for_each_thing(__device, __cinfo, clock)
+
+#define venus_hfi_for_each_clock_reverse(__device, __cinfo) \
+	venus_hfi_for_each_thing_reverse(__device, __cinfo, clock)
+
+/* Bus set helpers */
+#define venus_hfi_for_each_bus(__device, __binfo) \
+	venus_hfi_for_each_thing(__device, __binfo, bus)
+#define venus_hfi_for_each_bus_reverse(__device, __binfo) \
+	venus_hfi_for_each_thing_reverse(__device, __binfo, bus)
+
+
+/* Internal data used in vidc_hal not exposed to msm_vidc*/
+struct hal_data {
+	u32 irq;
+	phys_addr_t firmware_base;
+	u8 __iomem *register_base;
+	u32 register_size;
+};
+
+struct imem {
+	enum imem_type type;
+	union {
+		phys_addr_t vmem;
+	};
+};
+
+struct venus_resources {
+	struct msm_vidc_fw fw;
+	struct imem imem;
+};
+
+enum venus_hfi_state {
+	VENUS_STATE_DEINIT = 1,
+	VENUS_STATE_INIT,
+};
+
+struct venus_hfi_device {
+	struct list_head list;
+	struct list_head sess_head;
+	u32 intr_status;
+	u32 device_id;
+	u32 clk_freq;
+	u32 last_packet_type;
+	unsigned long clk_bitrate;
+	unsigned long scaled_rate;
+	struct msm_vidc_gov_data bus_vote;
+	bool power_enabled;
+	struct mutex lock;
+	msm_vidc_callback callback;
+	struct vidc_mem_addr iface_q_table;
+	struct vidc_mem_addr qdss;
+	struct vidc_mem_addr sfr;
+	struct vidc_mem_addr mem_addr;
+	struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ];
+	struct smem_client *hal_client;
+	struct hal_data *hal_data;
+	struct workqueue_struct *vidc_workq;
+	struct workqueue_struct *venus_pm_workq;
+	int spur_count;
+	int reg_count;
+	struct venus_resources resources;
+	struct msm_vidc_platform_resources *res;
+	enum venus_hfi_state state;
+	struct hfi_packetization_ops *pkt_ops;
+	enum hfi_packetization_type packetization_type;
+	struct msm_vidc_cb_info *response_pkt;
+	struct pm_qos_request qos;
+	unsigned int skip_pc_count;
+	struct msm_vidc_capability *sys_init_capabilities;
+};
+
+void venus_hfi_delete_device(void *device);
+
+int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
+		struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback);
+bool venus_hfi_is_session_supported(unsigned long sessions_supported,
+		enum vidc_vote_data_session session_type);
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi.c b/drivers/media/platform/msm/vidc_3x/vidc_hfi.c
new file mode 100644
index 0000000..98abd72
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include "msm_vidc_debug.h"
+#include "vidc_hfi_api.h"
+#include "venus_hfi.h"
+
+struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type,
+		u32 device_id, struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback)
+{
+	struct hfi_device *hdev = NULL;
+	int rc = 0;
+
+	hdev = (struct hfi_device *)
+			kzalloc(sizeof(struct hfi_device), GFP_KERNEL);
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s: failed to allocate hdev\n", __func__);
+		return NULL;
+	}
+
+	switch (hfi_type) {
+	case VIDC_HFI_VENUS:
+		rc = venus_hfi_initialize(hdev, device_id, res, callback);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+		goto err_hfi_init;
+	}
+
+	if (rc) {
+		if (rc != -EPROBE_DEFER)
+			dprintk(VIDC_ERR, "%s device init failed rc = %d",
+				__func__, rc);
+		goto err_hfi_init;
+	}
+
+	return hdev;
+
+err_hfi_init:
+	kfree(hdev);
+	return ERR_PTR(rc);
+}
+
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+			struct hfi_device *hdev)
+{
+	if (!hdev) {
+		dprintk(VIDC_ERR, "%s invalid device %pK", __func__, hdev);
+		return;
+	}
+
+	switch (hfi_type) {
+	case VIDC_HFI_VENUS:
+		venus_hfi_delete_device(hdev->hfi_device_data);
+		break;
+	default:
+		dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
+	}
+
+	kfree(hdev);
+}
+
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi.h
new file mode 100644
index 0000000..d0fd493
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi.h
@@ -0,0 +1,934 @@
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __H_VIDC_HFI_H__
+#define __H_VIDC_HFI_H__
+
+#include <media/msm_media_info.h>
+#include "vidc_hfi_helper.h"
+#include "vidc_hfi_api.h"
+
+#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
+#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+#define HFI_EVENT_SESSION_LTRUSE_FAILED (HFI_OX_BASE + 0x5)
+#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6)
+
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES	\
+	(HFI_OX_BASE + 0x1)
+#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES	\
+	(HFI_OX_BASE + 0x2)
+
+#define HFI_BUFFERFLAG_EOS			0x00000001
+#define HFI_BUFFERFLAG_STARTTIME		0x00000002
+#define HFI_BUFFERFLAG_DECODEONLY		0x00000004
+#define HFI_BUFFERFLAG_DATACORRUPT		0x00000008
+#define HFI_BUFFERFLAG_ENDOFFRAME		0x00000010
+#define HFI_BUFFERFLAG_SYNCFRAME		0x00000020
+#define HFI_BUFFERFLAG_EXTRADATA		0x00000040
+#define HFI_BUFFERFLAG_CODECCONFIG		0x00000080
+#define HFI_BUFFERFLAG_TIMESTAMPINVALID		0x00000100
+#define HFI_BUFFERFLAG_READONLY			0x00000200
+#define HFI_BUFFERFLAG_ENDOFSUBFRAME		0x00000400
+#define HFI_BUFFERFLAG_EOSEQ			0x00200000
+#define HFI_BUFFER_FLAG_MBAFF			0x08000000
+#define HFI_BUFFERFLAG_VPE_YUV_601_709_CSC_CLAMP \
+						0x10000000
+#define HFI_BUFFERFLAG_DROP_FRAME               0x20000000
+#define HFI_BUFFERFLAG_TEI			0x40000000
+#define HFI_BUFFERFLAG_DISCONTINUITY		0x80000000
+
+
+#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING	\
+	(HFI_OX_BASE + 0x1001)
+#define HFI_ERR_SESSION_SAME_STATE_OPERATION		\
+	(HFI_OX_BASE + 0x1002)
+#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED		\
+	(HFI_OX_BASE + 0x1003)
+#define  HFI_ERR_SESSION_START_CODE_NOT_FOUND		\
+	(HFI_OX_BASE + 0x1004)
+
+#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5)
+#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6)
+
+#define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1)
+#define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2)
+#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
+
+#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1)
+#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2)
+#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4)
+
+#define HFI_EXTRADATA_NONE					0x00000000
+#define HFI_EXTRADATA_MB_QUANTIZATION		0x00000001
+#define HFI_EXTRADATA_INTERLACE_VIDEO		0x00000002
+#define HFI_EXTRADATA_VC1_FRAMEDISP			0x00000003
+#define HFI_EXTRADATA_VC1_SEQDISP			0x00000004
+#define HFI_EXTRADATA_TIMESTAMP				0x00000005
+#define HFI_EXTRADATA_S3D_FRAME_PACKING		0x00000006
+#define HFI_EXTRADATA_FRAME_RATE			0x00000007
+#define HFI_EXTRADATA_PANSCAN_WINDOW		0x00000008
+#define HFI_EXTRADATA_RECOVERY_POINT_SEI	0x00000009
+#define HFI_EXTRADATA_MPEG2_SEQDISP		0x0000000D
+#define HFI_EXTRADATA_STREAM_USERDATA		0x0000000E
+#define HFI_EXTRADATA_FRAME_QP			0x0000000F
+#define HFI_EXTRADATA_FRAME_BITS_INFO		0x00000010
+#define HFI_EXTRADATA_VPX_COLORSPACE		0x00000014
+#define HFI_EXTRADATA_MULTISLICE_INFO		0x7F100000
+#define HFI_EXTRADATA_NUM_CONCEALED_MB		0x7F100001
+#define HFI_EXTRADATA_INDEX					0x7F100002
+#define HFI_EXTRADATA_METADATA_LTR			0x7F100004
+#define HFI_EXTRADATA_METADATA_FILLER		0x7FE00002
+
+#define HFI_INDEX_EXTRADATA_INPUT_CROP		0x0700000E
+#define HFI_INDEX_EXTRADATA_OUTPUT_CROP		0x0700000F
+#define HFI_INDEX_EXTRADATA_ASPECT_RATIO	0x7F100003
+
+struct hfi_buffer_alloc_mode {
+	u32 buffer_type;
+	u32 buffer_mode;
+};
+
+
+struct hfi_index_extradata_config {
+	int enable;
+	u32 index_extra_data_id;
+};
+
+struct hfi_extradata_header {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 type;
+	u32 data_size;
+	u8 rg_data[1];
+};
+
+#define HFI_INTERLACE_FRAME_PROGRESSIVE					0x01
+#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST	0x02
+#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST	0x04
+#define HFI_INTERLACE_FRAME_TOPFIELDFIRST				0x08
+#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST			0x10
+
+#define HFI_PROPERTY_SYS_OX_START			\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000)
+
+#define HFI_PROPERTY_PARAM_OX_START				\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_CHROMA_SITE					\
+(HFI_PROPERTY_PARAM_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG		\
+	(HFI_PROPERTY_PARAM_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA             \
+	(HFI_PROPERTY_PARAM_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_DIVX_FORMAT					\
+	(HFI_PROPERTY_PARAM_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \
+	(HFI_PROPERTY_PARAM_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED	\
+	(HFI_PROPERTY_PARAM_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT			\
+	(HFI_PROPERTY_PARAM_OX_START + 0x00E)
+
+#define HFI_PROPERTY_CONFIG_OX_START					\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
+#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS			\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_REALTIME					\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_PRIORITY					\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x003)
+#define HFI_PROPERTY_CONFIG_BATCH_INFO					\
+	(HFI_PROPERTY_CONFIG_OX_START + 0x004)
+
+#define HFI_PROPERTY_PARAM_VDEC_OX_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003)
+#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER			\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION			\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006)
+#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007)
+#define HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008)
+#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA  \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B)
+#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE   \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
+
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
+#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012)
+#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA			\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
+#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA	\
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014)
+#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015)
+#define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016)
+#define HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x017)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x018)
+#define HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x019)
+#define HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01A)
+#define HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01B)
+#define HFI_PROPERTY_PARAM_VDEC_VQZIP_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001C)
+#define HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001D)
+#define HFI_PROPERTY_PARAM_VDEC_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001E)
+#define HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA \
+	(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001F)
+
+#define HFI_PROPERTY_CONFIG_VDEC_OX_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x4000)
+#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER	\
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING	\
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP			\
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003)
+#define HFI_PROPERTY_CONFIG_VDEC_ENTROPY \
+	(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x004)
+
+#define HFI_PROPERTY_PARAM_VENC_OX_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000)
+#define  HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO       \
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x001)
+#define  HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x002)
+#define  HFI_PROPERTY_PARAM_VENC_LTR_INFO			\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x003)
+#define  HFI_PROPERTY_PARAM_VENC_MBI_DUMPING				\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x005)
+#define HFI_PROPERTY_PARAM_VENC_FRAME_QP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x006)
+#define  HFI_PROPERTY_PARAM_VENC_YUVSTAT_INFO_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x007)
+#define  HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x008)
+#define  HFI_PROPERTY_PARAM_VENC_OVERRIDE_QP_EXTRADATA		\
+	(HFI_PROPERTY_PARAM_VENC_OX_START + 0x009)
+
+#define HFI_PROPERTY_CONFIG_VENC_OX_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
+#define  HFI_PROPERTY_CONFIG_VENC_FRAME_QP				\
+	(HFI_PROPERTY_CONFIG_VENC_OX_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VPE_OX_START					\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
+#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION			\
+	(HFI_PROPERTY_PARAM_VPE_OX_START + 0x001)
+
+#define HFI_PROPERTY_CONFIG_VPE_OX_START				\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
+
+struct hfi_batch_info {
+	u32 input_batch_count;
+	u32 output_batch_count;
+};
+
+struct hfi_buffer_count_actual {
+	u32 buffer_type;
+	u32 buffer_count_actual;
+};
+
+struct hfi_buffer_size_minimum {
+	u32 buffer_type;
+	u32 buffer_size;
+};
+
+struct hfi_buffer_requirements {
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 buffer_region_size;
+	u32 buffer_hold_count;
+	u32 buffer_count_min;
+	u32 buffer_count_actual;
+	u32 contiguous;
+	u32 buffer_alignment;
+};
+
+#define HFI_CHROMA_SITE_0			(HFI_OX_BASE + 0x1)
+#define HFI_CHROMA_SITE_1			(HFI_OX_BASE + 0x2)
+#define HFI_CHROMA_SITE_2			(HFI_OX_BASE + 0x3)
+#define HFI_CHROMA_SITE_3			(HFI_OX_BASE + 0x4)
+#define HFI_CHROMA_SITE_4			(HFI_OX_BASE + 0x5)
+#define HFI_CHROMA_SITE_5			(HFI_OX_BASE + 0x6)
+
+struct hfi_data_payload {
+	u32 size;
+	u8 rg_data[1];
+};
+
+struct hfi_enable_picture {
+	u32 picture_type;
+};
+
+struct hfi_display_picture_buffer_count {
+	int enable;
+	u32 count;
+};
+
+struct hfi_extra_data_header_config {
+	u32 type;
+	u32 buffer_type;
+	u32 version;
+	u32 port_index;
+	u32 client_extra_data_id;
+};
+
+struct hfi_interlace_format_supported {
+	u32 buffer_type;
+	u32 format;
+};
+
+struct hfi_buffer_alloc_mode_supported {
+	u32 buffer_type;
+	u32 num_entries;
+	u32 rg_data[1];
+};
+
+struct hfi_mb_error_map {
+	u32 error_map_size;
+	u8 rg_error_map[1];
+};
+
+struct hfi_metadata_pass_through {
+	int enable;
+	u32 size;
+};
+
+struct hfi_multi_view_select {
+	u32 view_index;
+};
+
+struct hfi_hybrid_hierp {
+	u32 layers;
+};
+
+#define HFI_PRIORITY_LOW		10
+#define HFI_PRIOIRTY_MEDIUM		20
+#define HFI_PRIORITY_HIGH		30
+
+#define HFI_OUTPUT_ORDER_DISPLAY	(HFI_OX_BASE + 0x1)
+#define HFI_OUTPUT_ORDER_DECODE		(HFI_OX_BASE + 0x2)
+
+#define HFI_RATE_CONTROL_OFF		(HFI_OX_BASE + 0x1)
+#define HFI_RATE_CONTROL_VBR_VFR	(HFI_OX_BASE + 0x2)
+#define HFI_RATE_CONTROL_VBR_CFR	(HFI_OX_BASE + 0x3)
+#define HFI_RATE_CONTROL_CBR_VFR	(HFI_OX_BASE + 0x4)
+#define HFI_RATE_CONTROL_CBR_CFR	(HFI_OX_BASE + 0x5)
+#define HFI_RATE_CONTROL_MBR_CFR	(HFI_OX_BASE + 0x6)
+#define HFI_RATE_CONTROL_MBR_VFR	(HFI_OX_BASE + 0x7)
+
+
+struct hfi_uncompressed_plane_actual_constraints_info {
+	u32 buffer_type;
+	u32 num_planes;
+	struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+#define HFI_CMD_SYS_OX_START		\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x0000)
+#define HFI_CMD_SYS_SESSION_ABORT	(HFI_CMD_SYS_OX_START + 0x001)
+#define HFI_CMD_SYS_PING		(HFI_CMD_SYS_OX_START + 0x002)
+
+#define HFI_CMD_SESSION_OX_START	\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_LOAD_RESOURCES	(HFI_CMD_SESSION_OX_START + 0x001)
+#define HFI_CMD_SESSION_START		(HFI_CMD_SESSION_OX_START + 0x002)
+#define HFI_CMD_SESSION_STOP		(HFI_CMD_SESSION_OX_START + 0x003)
+#define HFI_CMD_SESSION_EMPTY_BUFFER	(HFI_CMD_SESSION_OX_START + 0x004)
+#define HFI_CMD_SESSION_FILL_BUFFER	(HFI_CMD_SESSION_OX_START + 0x005)
+#define HFI_CMD_SESSION_SUSPEND		(HFI_CMD_SESSION_OX_START + 0x006)
+#define HFI_CMD_SESSION_RESUME		(HFI_CMD_SESSION_OX_START + 0x007)
+#define HFI_CMD_SESSION_FLUSH		(HFI_CMD_SESSION_OX_START + 0x008)
+#define HFI_CMD_SESSION_GET_PROPERTY	(HFI_CMD_SESSION_OX_START + 0x009)
+#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER	\
+	(HFI_CMD_SESSION_OX_START + 0x00A)
+#define HFI_CMD_SESSION_RELEASE_BUFFERS		\
+	(HFI_CMD_SESSION_OX_START + 0x00B)
+#define HFI_CMD_SESSION_RELEASE_RESOURCES	\
+	(HFI_CMD_SESSION_OX_START + 0x00C)
+#define HFI_CMD_SESSION_CONTINUE	(HFI_CMD_SESSION_OX_START + 0x00D)
+#define HFI_CMD_SESSION_SYNC		(HFI_CMD_SESSION_OX_START + 0x00E)
+
+#define HFI_MSG_SYS_OX_START			\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000)
+#define HFI_MSG_SYS_PING_ACK	(HFI_MSG_SYS_OX_START + 0x2)
+#define HFI_MSG_SYS_SESSION_ABORT_DONE	(HFI_MSG_SYS_OX_START + 0x4)
+
+#define HFI_MSG_SESSION_OX_START		\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x1000)
+#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE	(HFI_MSG_SESSION_OX_START + 0x1)
+#define HFI_MSG_SESSION_START_DONE		(HFI_MSG_SESSION_OX_START + 0x2)
+#define HFI_MSG_SESSION_STOP_DONE		(HFI_MSG_SESSION_OX_START + 0x3)
+#define HFI_MSG_SESSION_SUSPEND_DONE	(HFI_MSG_SESSION_OX_START + 0x4)
+#define HFI_MSG_SESSION_RESUME_DONE		(HFI_MSG_SESSION_OX_START + 0x5)
+#define HFI_MSG_SESSION_FLUSH_DONE		(HFI_MSG_SESSION_OX_START + 0x6)
+#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE	(HFI_MSG_SESSION_OX_START + 0x7)
+#define HFI_MSG_SESSION_FILL_BUFFER_DONE	(HFI_MSG_SESSION_OX_START + 0x8)
+#define HFI_MSG_SESSION_PROPERTY_INFO		(HFI_MSG_SESSION_OX_START + 0x9)
+#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE	\
+	(HFI_MSG_SESSION_OX_START + 0xA)
+#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE		\
+	(HFI_MSG_SESSION_OX_START + 0xB)
+#define  HFI_MSG_SESSION_RELEASE_BUFFERS_DONE			\
+	(HFI_MSG_SESSION_OX_START + 0xC)
+
+#define VIDC_IFACEQ_MAX_PKT_SIZE                        1024
+#define VIDC_IFACEQ_MED_PKT_SIZE                        768
+#define VIDC_IFACEQ_MIN_PKT_SIZE                        8
+#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE          100
+#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE          512
+#define VIDC_IFACEQ_VAR_HUGE_PKT_SIZE          (1024*12)
+
+
+struct hfi_cmd_sys_session_abort_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_sys_ping_packet {
+	u32 size;
+	u32 packet_type;
+	u32 client_data;
+};
+
+struct hfi_cmd_session_load_resources_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_start_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_stop_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_empty_buffer_compressed_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 input_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 view_id;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 input_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer2;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer3;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_fill_buffer_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 stream_id;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 output_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[1];
+};
+
+struct hfi_cmd_session_flush_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 flush_type;
+};
+
+struct hfi_cmd_session_suspend_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_resume_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_get_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_cmd_session_release_buffer_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 extra_data_size;
+	int response_req;
+	u32 num_buffers;
+	u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_release_resources_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_session_parse_sequence_header_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 header_len;
+	u32 packet_buffer;
+};
+
+struct hfi_msg_sys_session_abort_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_sys_idle_packet {
+	u32 size;
+	u32 packet_type;
+};
+
+struct hfi_msg_sys_ping_ack_packet {
+	u32 size;
+	u32 packet_type;
+	u32 client_data;
+};
+
+struct hfi_msg_sys_property_info_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_load_resources_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_start_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_stop_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_suspend_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_resume_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_flush_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 flush_type;
+};
+
+struct hfi_msg_session_empty_buffer_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 offset;
+	u32 filled_len;
+	u32 input_tag;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_compressed_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 error_type;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 input_tag;
+	u32 output_tag;
+	u32 picture_type;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fbd_uncompressed_plane0_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 stream_id;
+	u32 view_id;
+	u32 error_type;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u32 flags;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 frame_width;
+	u32 frame_height;
+	u32 start_x_coord;
+	u32 start_y_coord;
+	u32 input_tag;
+	u32 input_tag2;
+	u32 output_tag;
+	u32 picture_type;
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer2;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
+	u32 flags;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 offset;
+	u32 packet_buffer3;
+	u32 rgData[0];
+};
+
+struct hfi_msg_session_parse_sequence_header_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_property_info_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_session_release_resources_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_release_buffers_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 num_buffers;
+	u32 rg_buffer_info[1];
+};
+
+struct hfi_extradata_mb_quantization_payload {
+	u8 rg_mb_qp[1];
+};
+
+struct hfi_extradata_vc1_pswnd {
+	u32 ps_wnd_h_offset;
+	u32 ps_wnd_v_offset;
+	u32 ps_wnd_width;
+	u32 ps_wnd_height;
+};
+
+struct hfi_extradata_vc1_framedisp_payload {
+	u32 res_pic;
+	u32 ref;
+	u32 range_map_present;
+	u32 range_map_y;
+	u32 range_map_uv;
+	u32 num_pan_scan_wnds;
+	struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
+};
+
+struct hfi_extradata_vc1_seqdisp_payload {
+	u32 prog_seg_frm;
+	u32 uv_sampling_fmt;
+	u32 color_fmt_flag;
+	u32 color_primaries;
+	u32 transfer_char;
+	u32 mat_coeff;
+	u32 aspect_ratio;
+	u32 aspect_horiz;
+	u32 aspect_vert;
+};
+
+struct hfi_extradata_timestamp_payload {
+	u32 time_stamp_low;
+	u32 time_stamp_high;
+};
+
+
+struct hfi_extradata_s3d_frame_packing_payload {
+	u32 fpa_id;
+	int cancel_flag;
+	u32 fpa_type;
+	int quin_cunx_flag;
+	u32 content_interprtation_type;
+	int spatial_flipping_flag;
+	int frame0_flipped_flag;
+	int field_views_flag;
+	int current_frame_isFrame0_flag;
+	int frame0_self_contained_flag;
+	int frame1_self_contained_flag;
+	u32 frame0_graid_pos_x;
+	u32 frame0_graid_pos_y;
+	u32 frame1_graid_pos_x;
+	u32 frame1_graid_pos_y;
+	u32 fpa_reserved_byte;
+	u32 fpa_repetition_period;
+	int fpa_extension_flag;
+};
+
+struct hfi_extradata_interlace_video_payload {
+	u32 format;
+};
+
+struct hfi_extradata_num_concealed_mb_payload {
+	u32 num_mb_concealed;
+};
+
+struct hfi_extradata_sliceinfo {
+	u32 offset_in_stream;
+	u32 slice_length;
+};
+
+struct hfi_extradata_multislice_info_payload {
+	u32 num_slices;
+	struct hfi_extradata_sliceinfo rg_slice_info[1];
+};
+
+struct hfi_index_extradata_input_crop_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_index_extradata_output_crop_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 left;
+	u32 top;
+	u32 display_width;
+	u32 display_height;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_index_extradata_digital_zoom_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	int width;
+	int height;
+};
+
+struct hfi_index_extradata_aspect_ratio_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 aspect_width;
+	u32 aspect_height;
+};
+struct hfi_extradata_panscan_wndw_payload {
+	u32 num_window;
+	struct hfi_extradata_vc1_pswnd wnd[1];
+};
+
+struct hfi_extradata_frame_type_payload {
+	u32 frame_rate;
+};
+
+struct hfi_extradata_recovery_point_sei_payload {
+	u32 flag;
+};
+
+struct hfi_cmd_session_continue_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hal_session {
+	struct list_head list;
+	void *session_id;
+	bool is_decoder;
+	enum hal_video_codec codec;
+	enum hal_domain domain;
+	void *device;
+};
+
+struct hal_device_data {
+	struct list_head dev_head;
+	int dev_count;
+};
+
+struct msm_vidc_fw {
+	void *cookie;
+};
+
+int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+		struct msm_vidc_cb_info *info);
+
+enum vidc_status hfi_process_sys_init_done_prop_read(
+	struct hfi_msg_sys_init_done_packet *pkt,
+	struct vidc_hal_sys_init_done *sys_init_done);
+
+enum vidc_status hfi_process_session_init_done_prop_read(
+	struct hfi_msg_sys_session_init_done_packet *pkt,
+	struct vidc_hal_session_init_done *session_init_done);
+
+#endif
+
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
new file mode 100644
index 0000000..04bf5a8
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h
@@ -0,0 +1,1544 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __VIDC_HFI_API_H__
+#define __VIDC_HFI_API_H__
+
+#include <linux/log2.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <media/msm_vidc.h>
+#include "msm_vidc_resources.h"
+
+#define CONTAINS(__a, __sz, __t) ({\
+	int __rc = __t >= __a && \
+			__t < __a + __sz; \
+	__rc; \
+})
+
+#define OVERLAPS(__t, __tsz, __a, __asz) ({\
+	int __rc = __t <= __a && \
+			__t + __tsz >= __a + __asz; \
+	__rc; \
+})
+
+#define HAL_BUFFERFLAG_EOS              0x00000001
+#define HAL_BUFFERFLAG_STARTTIME        0x00000002
+#define HAL_BUFFERFLAG_DECODEONLY       0x00000004
+#define HAL_BUFFERFLAG_DATACORRUPT      0x00000008
+#define HAL_BUFFERFLAG_ENDOFFRAME       0x00000010
+#define HAL_BUFFERFLAG_SYNCFRAME        0x00000020
+#define HAL_BUFFERFLAG_EXTRADATA        0x00000040
+#define HAL_BUFFERFLAG_CODECCONFIG      0x00000080
+#define HAL_BUFFERFLAG_TIMESTAMPINVALID 0x00000100
+#define HAL_BUFFERFLAG_READONLY         0x00000200
+#define HAL_BUFFERFLAG_ENDOFSUBFRAME    0x00000400
+#define HAL_BUFFERFLAG_EOSEQ            0x00200000
+#define HAL_BUFFERFLAG_MBAFF            0x08000000
+#define HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP   0x10000000
+#define HAL_BUFFERFLAG_DROP_FRAME       0x20000000
+#define HAL_BUFFERFLAG_TS_DISCONTINUITY	0x40000000
+#define HAL_BUFFERFLAG_TS_ERROR		0x80000000
+
+
+
+#define HAL_DEBUG_MSG_LOW				0x00000001
+#define HAL_DEBUG_MSG_MEDIUM			0x00000002
+#define HAL_DEBUG_MSG_HIGH				0x00000004
+#define HAL_DEBUG_MSG_ERROR				0x00000008
+#define HAL_DEBUG_MSG_FATAL				0x00000010
+#define MAX_PROFILE_COUNT	16
+
+#define HAL_MAX_MATRIX_COEFFS 9
+#define HAL_MAX_BIAS_COEFFS 3
+#define HAL_MAX_LIMIT_COEFFS 6
+#define VENUS_VERSION_LENGTH 128
+
+/* 16 encoder and 16 decoder sessions */
+#define VIDC_MAX_SESSIONS               32
+
+enum vidc_status {
+	VIDC_ERR_NONE = 0x0,
+	VIDC_ERR_FAIL = 0x80000000,
+	VIDC_ERR_ALLOC_FAIL,
+	VIDC_ERR_ILLEGAL_OP,
+	VIDC_ERR_BAD_PARAM,
+	VIDC_ERR_BAD_HANDLE,
+	VIDC_ERR_NOT_SUPPORTED,
+	VIDC_ERR_BAD_STATE,
+	VIDC_ERR_MAX_CLIENTS,
+	VIDC_ERR_IFRAME_EXPECTED,
+	VIDC_ERR_HW_FATAL,
+	VIDC_ERR_BITSTREAM_ERR,
+	VIDC_ERR_INDEX_NOMORE,
+	VIDC_ERR_SEQHDR_PARSE_FAIL,
+	VIDC_ERR_INSUFFICIENT_BUFFER,
+	VIDC_ERR_BAD_POWER_STATE,
+	VIDC_ERR_NO_VALID_SESSION,
+	VIDC_ERR_TIMEOUT,
+	VIDC_ERR_CMDQFULL,
+	VIDC_ERR_START_CODE_NOT_FOUND,
+	VIDC_ERR_CLIENT_PRESENT = 0x90000001,
+	VIDC_ERR_CLIENT_FATAL,
+	VIDC_ERR_CMD_QUEUE_FULL,
+	VIDC_ERR_UNUSED = 0x10000000
+};
+
+enum hal_extradata_id {
+	HAL_EXTRADATA_NONE,
+	HAL_EXTRADATA_MB_QUANTIZATION,
+	HAL_EXTRADATA_INTERLACE_VIDEO,
+	HAL_EXTRADATA_VC1_FRAMEDISP,
+	HAL_EXTRADATA_VC1_SEQDISP,
+	HAL_EXTRADATA_TIMESTAMP,
+	HAL_EXTRADATA_S3D_FRAME_PACKING,
+	HAL_EXTRADATA_FRAME_RATE,
+	HAL_EXTRADATA_PANSCAN_WINDOW,
+	HAL_EXTRADATA_RECOVERY_POINT_SEI,
+	HAL_EXTRADATA_MULTISLICE_INFO,
+	HAL_EXTRADATA_INDEX,
+	HAL_EXTRADATA_NUM_CONCEALED_MB,
+	HAL_EXTRADATA_METADATA_FILLER,
+	HAL_EXTRADATA_ASPECT_RATIO,
+	HAL_EXTRADATA_MPEG2_SEQDISP,
+	HAL_EXTRADATA_STREAM_USERDATA,
+	HAL_EXTRADATA_FRAME_QP,
+	HAL_EXTRADATA_FRAME_BITS_INFO,
+	HAL_EXTRADATA_INPUT_CROP,
+	HAL_EXTRADATA_DIGITAL_ZOOM,
+	HAL_EXTRADATA_LTR_INFO,
+	HAL_EXTRADATA_METADATA_MBI,
+	HAL_EXTRADATA_VQZIP_SEI,
+	HAL_EXTRADATA_YUV_STATS,
+	HAL_EXTRADATA_ROI_QP,
+	HAL_EXTRADATA_OUTPUT_CROP,
+	HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI,
+	HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI,
+	HAL_EXTRADATA_VUI_DISPLAY_INFO,
+	HAL_EXTRADATA_VPX_COLORSPACE,
+	HAL_EXTRADATA_PQ_INFO,
+};
+
+enum hal_property {
+	HAL_CONFIG_FRAME_RATE = 0x04000001,
+	HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+	HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
+	HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
+	HAL_PARAM_EXTRA_DATA_HEADER_CONFIG,
+	HAL_PARAM_INDEX_EXTRADATA,
+	HAL_PARAM_FRAME_SIZE,
+	HAL_CONFIG_REALTIME,
+	HAL_PARAM_BUFFER_COUNT_ACTUAL,
+	HAL_PARAM_BUFFER_SIZE_MINIMUM,
+	HAL_PARAM_NAL_STREAM_FORMAT_SELECT,
+	HAL_PARAM_VDEC_OUTPUT_ORDER,
+	HAL_PARAM_VDEC_PICTURE_TYPE_DECODE,
+	HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
+	HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
+	HAL_PARAM_VDEC_MULTI_STREAM,
+	HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
+	HAL_PARAM_DIVX_FORMAT,
+	HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
+	HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
+	HAL_CONFIG_VDEC_MB_ERROR_MAP,
+	HAL_CONFIG_VENC_REQUEST_IFRAME,
+	HAL_PARAM_VENC_MPEG4_SHORT_HEADER,
+	HAL_PARAM_VENC_MPEG4_AC_PREDICTION,
+	HAL_CONFIG_VENC_TARGET_BITRATE,
+	HAL_PARAM_PROFILE_LEVEL_CURRENT,
+	HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
+	HAL_PARAM_VENC_RATE_CONTROL,
+	HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION,
+	HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION,
+	HAL_PARAM_VENC_H264_DEBLOCK_CONTROL,
+	HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
+	HAL_PARAM_VENC_SESSION_QP,
+	HAL_PARAM_VENC_SESSION_QP_RANGE,
+	HAL_CONFIG_VENC_INTRA_PERIOD,
+	HAL_CONFIG_VENC_IDR_PERIOD,
+	HAL_CONFIG_VPE_OPERATIONS,
+	HAL_PARAM_VENC_INTRA_REFRESH,
+	HAL_PARAM_VENC_MULTI_SLICE_CONTROL,
+	HAL_CONFIG_VPE_DEINTERLACE,
+	HAL_SYS_DEBUG_CONFIG,
+	HAL_CONFIG_BUFFER_REQUIREMENTS,
+	HAL_CONFIG_PRIORITY,
+	HAL_CONFIG_BATCH_INFO,
+	HAL_PARAM_METADATA_PASS_THROUGH,
+	HAL_SYS_IDLE_INDICATOR,
+	HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED,
+	HAL_PARAM_INTERLACE_FORMAT_SUPPORTED,
+	HAL_PARAM_CHROMA_SITE,
+	HAL_PARAM_PROPERTIES_SUPPORTED,
+	HAL_PARAM_PROFILE_LEVEL_SUPPORTED,
+	HAL_PARAM_CAPABILITY_SUPPORTED,
+	HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED,
+	HAL_PARAM_MULTI_VIEW_FORMAT,
+	HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE,
+	HAL_PARAM_CODEC_SUPPORTED,
+	HAL_PARAM_VDEC_MULTI_VIEW_SELECT,
+	HAL_PARAM_VDEC_MB_QUANTIZATION,
+	HAL_PARAM_VDEC_NUM_CONCEALED_MB,
+	HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING,
+	HAL_PARAM_VENC_SLICE_DELIVERY_MODE,
+	HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING,
+	HAL_CONFIG_BUFFER_COUNT_ACTUAL,
+	HAL_CONFIG_VDEC_MULTI_STREAM,
+	HAL_PARAM_VENC_MULTI_SLICE_INFO,
+	HAL_CONFIG_VENC_TIMESTAMP_SCALE,
+	HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER,
+	HAL_PARAM_VDEC_SYNC_FRAME_DECODE,
+	HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL,
+	HAL_CONFIG_VENC_MAX_BITRATE,
+	HAL_PARAM_VENC_H264_VUI_TIMING_INFO,
+	HAL_PARAM_VENC_GENERATE_AUDNAL,
+	HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
+	HAL_PARAM_BUFFER_ALLOC_MODE,
+	HAL_PARAM_VDEC_FRAME_ASSEMBLY,
+	HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
+	HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY,
+	HAL_PARAM_VDEC_CONCEAL_COLOR,
+	HAL_PARAM_VDEC_SCS_THRESHOLD,
+	HAL_PARAM_GET_BUFFER_REQUIREMENTS,
+	HAL_PARAM_MVC_BUFFER_LAYOUT,
+	HAL_PARAM_VENC_LTRMODE,
+	HAL_CONFIG_VENC_MARKLTRFRAME,
+	HAL_CONFIG_VENC_USELTRFRAME,
+	HAL_CONFIG_VENC_LTRPERIOD,
+	HAL_CONFIG_VENC_HIER_P_NUM_FRAMES,
+	HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS,
+	HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP,
+	HAL_PARAM_VENC_ENABLE_INITIAL_QP,
+	HAL_PARAM_VENC_SEARCH_RANGE,
+	HAL_PARAM_VPE_COLOR_SPACE_CONVERSION,
+	HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE,
+	HAL_PARAM_VENC_H264_NAL_SVC_EXT,
+	HAL_CONFIG_VENC_PERF_MODE,
+	HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS,
+	HAL_PARAM_VDEC_NON_SECURE_OUTPUT2,
+	HAL_PARAM_VENC_HIER_P_HYBRID_MODE,
+	HAL_PARAM_VENC_MBI_STATISTICS_MODE,
+	HAL_PARAM_SYNC_BASED_INTERRUPT,
+	HAL_CONFIG_VENC_FRAME_QP,
+	HAL_CONFIG_VENC_BASELAYER_PRIORITYID,
+	HAL_PARAM_VENC_VQZIP_SEI,
+	HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO,
+	HAL_CONFIG_VDEC_ENTROPY,
+	HAL_PARAM_VENC_BITRATE_TYPE,
+	HAL_PARAM_VENC_H264_PIC_ORDER_CNT,
+	HAL_PARAM_VENC_LOW_LATENCY,
+	HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED,
+	HAL_CONFIG_VENC_BLUR_RESOLUTION,
+	HAL_PARAM_VENC_VIDEO_SIGNAL_INFO,
+	HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED,
+	HAL_PARAM_VENC_H264_TRANSFORM_8x8,
+	HAL_PARAM_VENC_IFRAMESIZE_TYPE,
+};
+
+enum hal_domain {
+	HAL_VIDEO_DOMAIN_VPE,
+	HAL_VIDEO_DOMAIN_ENCODER,
+	HAL_VIDEO_DOMAIN_DECODER,
+	HAL_UNUSED_DOMAIN = 0x10000000,
+};
+
+enum multi_stream {
+	HAL_VIDEO_DECODER_NONE = 0x00000000,
+	HAL_VIDEO_DECODER_PRIMARY = 0x00000001,
+	HAL_VIDEO_DECODER_SECONDARY = 0x00000002,
+	HAL_VIDEO_DECODER_BOTH_OUTPUTS = 0x00000004,
+	HAL_VIDEO_UNUSED_OUTPUTS = 0x10000000,
+};
+
+enum hal_core_capabilities {
+	HAL_VIDEO_ENCODER_ROTATION_CAPABILITY = 0x00000001,
+	HAL_VIDEO_ENCODER_SCALING_CAPABILITY = 0x00000002,
+	HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY = 0x00000004,
+	HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY = 0x00000008,
+	HAL_VIDEO_UNUSED_CAPABILITY      = 0x10000000,
+};
+
+enum hal_default_properties {
+	HAL_VIDEO_DYNAMIC_BUF_MODE = 0x00000001,
+	HAL_VIDEO_CONTINUE_DATA_TRANSFER = 0x00000002,
+};
+
+enum hal_video_codec {
+	HAL_VIDEO_CODEC_UNKNOWN  = 0x00000000,
+	HAL_VIDEO_CODEC_MVC      = 0x00000001,
+	HAL_VIDEO_CODEC_H264     = 0x00000002,
+	HAL_VIDEO_CODEC_H263     = 0x00000004,
+	HAL_VIDEO_CODEC_MPEG1    = 0x00000008,
+	HAL_VIDEO_CODEC_MPEG2    = 0x00000010,
+	HAL_VIDEO_CODEC_MPEG4    = 0x00000020,
+	HAL_VIDEO_CODEC_DIVX_311 = 0x00000040,
+	HAL_VIDEO_CODEC_DIVX     = 0x00000080,
+	HAL_VIDEO_CODEC_VC1      = 0x00000100,
+	HAL_VIDEO_CODEC_SPARK    = 0x00000200,
+	HAL_VIDEO_CODEC_VP6      = 0x00000400,
+	HAL_VIDEO_CODEC_VP7      = 0x00000800,
+	HAL_VIDEO_CODEC_VP8      = 0x00001000,
+	HAL_VIDEO_CODEC_HEVC     = 0x00002000,
+	HAL_VIDEO_CODEC_VP9      = 0x00004000,
+	HAL_VIDEO_CODEC_HEVC_HYBRID     = 0x80000000,
+	HAL_UNUSED_CODEC = 0x10000000,
+};
+
+enum hal_h263_profile {
+	HAL_H263_PROFILE_BASELINE           = 0x00000001,
+	HAL_H263_PROFILE_H320CODING         = 0x00000002,
+	HAL_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
+	HAL_H263_PROFILE_ISWV2              = 0x00000008,
+	HAL_H263_PROFILE_ISWV3              = 0x00000010,
+	HAL_H263_PROFILE_HIGHCOMPRESSION    = 0x00000020,
+	HAL_H263_PROFILE_INTERNET           = 0x00000040,
+	HAL_H263_PROFILE_INTERLACE          = 0x00000080,
+	HAL_H263_PROFILE_HIGHLATENCY        = 0x00000100,
+	HAL_UNUSED_H263_PROFILE = 0x10000000,
+};
+
+enum hal_h263_level {
+	HAL_H263_LEVEL_10 = 0x00000001,
+	HAL_H263_LEVEL_20 = 0x00000002,
+	HAL_H263_LEVEL_30 = 0x00000004,
+	HAL_H263_LEVEL_40 = 0x00000008,
+	HAL_H263_LEVEL_45 = 0x00000010,
+	HAL_H263_LEVEL_50 = 0x00000020,
+	HAL_H263_LEVEL_60 = 0x00000040,
+	HAL_H263_LEVEL_70 = 0x00000080,
+	HAL_UNUSED_H263_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg2_profile {
+	HAL_MPEG2_PROFILE_SIMPLE  = 0x00000001,
+	HAL_MPEG2_PROFILE_MAIN    = 0x00000002,
+	HAL_MPEG2_PROFILE_422     = 0x00000004,
+	HAL_MPEG2_PROFILE_SNR     = 0x00000008,
+	HAL_MPEG2_PROFILE_SPATIAL = 0x00000010,
+	HAL_MPEG2_PROFILE_HIGH    = 0x00000020,
+	HAL_UNUSED_MPEG2_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg2_level {
+	HAL_MPEG2_LEVEL_LL  = 0x00000001,
+	HAL_MPEG2_LEVEL_ML  = 0x00000002,
+	HAL_MPEG2_LEVEL_H14 = 0x00000004,
+	HAL_MPEG2_LEVEL_HL  = 0x00000008,
+	HAL_UNUSED_MEPG2_LEVEL = 0x10000000,
+};
+
+enum hal_mpeg4_profile {
+	HAL_MPEG4_PROFILE_SIMPLE           = 0x00000001,
+	HAL_MPEG4_PROFILE_ADVANCEDSIMPLE   = 0x00000002,
+	HAL_MPEG4_PROFILE_CORE             = 0x00000004,
+	HAL_MPEG4_PROFILE_MAIN             = 0x00000008,
+	HAL_MPEG4_PROFILE_NBIT             = 0x00000010,
+	HAL_MPEG4_PROFILE_SCALABLETEXTURE  = 0x00000020,
+	HAL_MPEG4_PROFILE_SIMPLEFACE       = 0x00000040,
+	HAL_MPEG4_PROFILE_SIMPLEFBA        = 0x00000080,
+	HAL_MPEG4_PROFILE_BASICANIMATED    = 0x00000100,
+	HAL_MPEG4_PROFILE_HYBRID           = 0x00000200,
+	HAL_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
+	HAL_MPEG4_PROFILE_CORESCALABLE     = 0x00000800,
+	HAL_MPEG4_PROFILE_ADVANCEDCODING   = 0x00001000,
+	HAL_MPEG4_PROFILE_ADVANCEDCORE     = 0x00002000,
+	HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
+	HAL_MPEG4_PROFILE_SIMPLESCALABLE   = 0x00008000,
+	HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
+};
+
+enum hal_mpeg4_level {
+	HAL_MPEG4_LEVEL_0  = 0x00000001,
+	HAL_MPEG4_LEVEL_0b = 0x00000002,
+	HAL_MPEG4_LEVEL_1  = 0x00000004,
+	HAL_MPEG4_LEVEL_2  = 0x00000008,
+	HAL_MPEG4_LEVEL_3  = 0x00000010,
+	HAL_MPEG4_LEVEL_4  = 0x00000020,
+	HAL_MPEG4_LEVEL_4a = 0x00000040,
+	HAL_MPEG4_LEVEL_5  = 0x00000080,
+	HAL_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
+	HAL_MPEG4_LEVEL_6  = 0x7F000001,
+	HAL_MPEG4_LEVEL_7  = 0x7F000002,
+	HAL_MPEG4_LEVEL_8  = 0x7F000003,
+	HAL_MPEG4_LEVEL_9  = 0x7F000004,
+	HAL_MPEG4_LEVEL_3b = 0x7F000005,
+	HAL_UNUSED_MPEG4_LEVEL = 0x10000000,
+};
+
+enum hal_h264_profile {
+	HAL_H264_PROFILE_BASELINE = 0x00000001,
+	HAL_H264_PROFILE_MAIN     = 0x00000002,
+	HAL_H264_PROFILE_HIGH     = 0x00000004,
+	HAL_H264_PROFILE_EXTENDED = 0x00000008,
+	HAL_H264_PROFILE_HIGH10   = 0x00000010,
+	HAL_H264_PROFILE_HIGH422  = 0x00000020,
+	HAL_H264_PROFILE_HIGH444  = 0x00000040,
+	HAL_H264_PROFILE_CONSTRAINED_BASE  = 0x00000080,
+	HAL_H264_PROFILE_CONSTRAINED_HIGH  = 0x00000100,
+	HAL_UNUSED_H264_PROFILE = 0x10000000,
+};
+
+enum hal_h264_level {
+	HAL_H264_LEVEL_1  = 0x00000001,
+	HAL_H264_LEVEL_1b = 0x00000002,
+	HAL_H264_LEVEL_11 = 0x00000004,
+	HAL_H264_LEVEL_12 = 0x00000008,
+	HAL_H264_LEVEL_13 = 0x00000010,
+	HAL_H264_LEVEL_2  = 0x00000020,
+	HAL_H264_LEVEL_21 = 0x00000040,
+	HAL_H264_LEVEL_22 = 0x00000080,
+	HAL_H264_LEVEL_3  = 0x00000100,
+	HAL_H264_LEVEL_31 = 0x00000200,
+	HAL_H264_LEVEL_32 = 0x00000400,
+	HAL_H264_LEVEL_4  = 0x00000800,
+	HAL_H264_LEVEL_41 = 0x00001000,
+	HAL_H264_LEVEL_42 = 0x00002000,
+	HAL_H264_LEVEL_5  = 0x00004000,
+	HAL_H264_LEVEL_51 = 0x00008000,
+	HAL_H264_LEVEL_52 = 0x00010000,
+	HAL_UNUSED_H264_LEVEL = 0x10000000,
+};
+
+enum hal_hevc_profile {
+	HAL_HEVC_PROFILE_MAIN           = 0x00000001,
+	HAL_HEVC_PROFILE_MAIN10         = 0x00000002,
+	HAL_HEVC_PROFILE_MAIN_STILL_PIC = 0x00000004,
+	HAL_UNUSED_HEVC_PROFILE         = 0x10000000,
+};
+
+enum hal_hevc_level {
+	HAL_HEVC_MAIN_TIER_LEVEL_1      = 0x10000001,
+	HAL_HEVC_MAIN_TIER_LEVEL_2      = 0x10000002,
+	HAL_HEVC_MAIN_TIER_LEVEL_2_1    = 0x10000004,
+	HAL_HEVC_MAIN_TIER_LEVEL_3      = 0x10000008,
+	HAL_HEVC_MAIN_TIER_LEVEL_3_1    = 0x10000010,
+	HAL_HEVC_MAIN_TIER_LEVEL_4      = 0x10000020,
+	HAL_HEVC_MAIN_TIER_LEVEL_4_1    = 0x10000040,
+	HAL_HEVC_MAIN_TIER_LEVEL_5      = 0x10000080,
+	HAL_HEVC_MAIN_TIER_LEVEL_5_1    = 0x10000100,
+	HAL_HEVC_MAIN_TIER_LEVEL_5_2    = 0x10000200,
+	HAL_HEVC_MAIN_TIER_LEVEL_6      = 0x10000400,
+	HAL_HEVC_MAIN_TIER_LEVEL_6_1    = 0x10000800,
+	HAL_HEVC_MAIN_TIER_LEVEL_6_2    = 0x10001000,
+	HAL_HEVC_HIGH_TIER_LEVEL_1      = 0x20000001,
+	HAL_HEVC_HIGH_TIER_LEVEL_2      = 0x20000002,
+	HAL_HEVC_HIGH_TIER_LEVEL_2_1    = 0x20000004,
+	HAL_HEVC_HIGH_TIER_LEVEL_3      = 0x20000008,
+	HAL_HEVC_HIGH_TIER_LEVEL_3_1    = 0x20000010,
+	HAL_HEVC_HIGH_TIER_LEVEL_4      = 0x20000020,
+	HAL_HEVC_HIGH_TIER_LEVEL_4_1    = 0x20000040,
+	HAL_HEVC_HIGH_TIER_LEVEL_5      = 0x20000080,
+	HAL_HEVC_HIGH_TIER_LEVEL_5_1    = 0x20000100,
+	HAL_HEVC_HIGH_TIER_LEVEL_5_2    = 0x20000200,
+	HAL_HEVC_HIGH_TIER_LEVEL_6      = 0x20000400,
+	HAL_HEVC_HIGH_TIER_LEVEL_6_1    = 0x20000800,
+	HAL_HEVC_HIGH_TIER_LEVEL_6_2    = 0x20001000,
+	HAL_UNUSED_HEVC_TIER_LEVEL      = 0x80000000,
+};
+
+enum hal_hevc_tier {
+	HAL_HEVC_TIER_MAIN   = 0x00000001,
+	HAL_HEVC_TIER_HIGH   = 0x00000002,
+	HAL_UNUSED_HEVC_TIER = 0x10000000,
+};
+
+enum hal_vpx_profile {
+	HAL_VPX_PROFILE_SIMPLE    = 0x00000001,
+	HAL_VPX_PROFILE_ADVANCED  = 0x00000002,
+	HAL_VPX_PROFILE_VERSION_0 = 0x00000004,
+	HAL_VPX_PROFILE_VERSION_1 = 0x00000008,
+	HAL_VPX_PROFILE_VERSION_2 = 0x00000010,
+	HAL_VPX_PROFILE_VERSION_3 = 0x00000020,
+	HAL_VPX_PROFILE_UNUSED = 0x10000000,
+};
+
+enum hal_vc1_profile {
+	HAL_VC1_PROFILE_SIMPLE   = 0x00000001,
+	HAL_VC1_PROFILE_MAIN     = 0x00000002,
+	HAL_VC1_PROFILE_ADVANCED = 0x00000004,
+	HAL_UNUSED_VC1_PROFILE = 0x10000000,
+};
+
+enum hal_vc1_level {
+	HAL_VC1_LEVEL_LOW    = 0x00000001,
+	HAL_VC1_LEVEL_MEDIUM = 0x00000002,
+	HAL_VC1_LEVEL_HIGH   = 0x00000004,
+	HAL_VC1_LEVEL_0      = 0x00000008,
+	HAL_VC1_LEVEL_1      = 0x00000010,
+	HAL_VC1_LEVEL_2      = 0x00000020,
+	HAL_VC1_LEVEL_3      = 0x00000040,
+	HAL_VC1_LEVEL_4      = 0x00000080,
+	HAL_UNUSED_VC1_LEVEL = 0x10000000,
+};
+
+enum hal_divx_format {
+	HAL_DIVX_FORMAT_4,
+	HAL_DIVX_FORMAT_5,
+	HAL_DIVX_FORMAT_6,
+	HAL_UNUSED_DIVX_FORMAT = 0x10000000,
+};
+
+enum hal_divx_profile {
+	HAL_DIVX_PROFILE_QMOBILE  = 0x00000001,
+	HAL_DIVX_PROFILE_MOBILE   = 0x00000002,
+	HAL_DIVX_PROFILE_MT       = 0x00000004,
+	HAL_DIVX_PROFILE_HT       = 0x00000008,
+	HAL_DIVX_PROFILE_HD       = 0x00000010,
+	HAL_UNUSED_DIVX_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_profile {
+	HAL_MVC_PROFILE_STEREO_HIGH  = 0x00001000,
+	HAL_UNUSED_MVC_PROFILE = 0x10000000,
+};
+
+enum hal_mvc_level {
+	HAL_MVC_LEVEL_1  = 0x00000001,
+	HAL_MVC_LEVEL_1b = 0x00000002,
+	HAL_MVC_LEVEL_11 = 0x00000004,
+	HAL_MVC_LEVEL_12 = 0x00000008,
+	HAL_MVC_LEVEL_13 = 0x00000010,
+	HAL_MVC_LEVEL_2  = 0x00000020,
+	HAL_MVC_LEVEL_21 = 0x00000040,
+	HAL_MVC_LEVEL_22 = 0x00000080,
+	HAL_MVC_LEVEL_3  = 0x00000100,
+	HAL_MVC_LEVEL_31 = 0x00000200,
+	HAL_MVC_LEVEL_32 = 0x00000400,
+	HAL_MVC_LEVEL_4  = 0x00000800,
+	HAL_MVC_LEVEL_41 = 0x00001000,
+	HAL_MVC_LEVEL_42 = 0x00002000,
+	HAL_MVC_LEVEL_5  = 0x00004000,
+	HAL_MVC_LEVEL_51 = 0x00008000,
+	HAL_UNUSED_MVC_LEVEL = 0x10000000,
+};
+
+struct hal_frame_rate {
+	enum hal_buffer buffer_type;
+	u32 frame_rate;
+};
+
+enum hal_uncompressed_format {
+	HAL_COLOR_FORMAT_MONOCHROME     = 0x00000001,
+	HAL_COLOR_FORMAT_NV12           = 0x00000002,
+	HAL_COLOR_FORMAT_NV21           = 0x00000004,
+	HAL_COLOR_FORMAT_NV12_4x4TILE   = 0x00000008,
+	HAL_COLOR_FORMAT_NV21_4x4TILE   = 0x00000010,
+	HAL_COLOR_FORMAT_YUYV           = 0x00000020,
+	HAL_COLOR_FORMAT_YVYU           = 0x00000040,
+	HAL_COLOR_FORMAT_UYVY           = 0x00000080,
+	HAL_COLOR_FORMAT_VYUY           = 0x00000100,
+	HAL_COLOR_FORMAT_RGB565         = 0x00000200,
+	HAL_COLOR_FORMAT_BGR565         = 0x00000400,
+	HAL_COLOR_FORMAT_RGB888         = 0x00000800,
+	HAL_COLOR_FORMAT_BGR888         = 0x00001000,
+	HAL_COLOR_FORMAT_NV12_UBWC      = 0x00002000,
+	HAL_COLOR_FORMAT_NV12_TP10_UBWC = 0x00004000,
+	HAL_COLOR_FORMAT_RGBA8888       = 0x00008000,
+	HAL_COLOR_FORMAT_RGBA8888_UBWC  = 0x00010000,
+	HAL_UNUSED_COLOR                = 0x10000000,
+};
+
+enum hal_statistics_mode_type {
+	HAL_STATISTICS_MODE_DEFAULT	= 0x00000001,
+	HAL_STATISTICS_MODE_1		= 0x00000002,
+	HAL_STATISTICS_MODE_2		= 0x00000004,
+	HAL_STATISTICS_MODE_3		= 0x00000008,
+};
+
+enum hal_ssr_trigger_type {
+	SSR_ERR_FATAL = 1,
+	SSR_SW_DIV_BY_ZERO,
+	SSR_HW_WDOG_IRQ,
+};
+
+struct hal_uncompressed_format_select {
+	enum hal_buffer buffer_type;
+	enum hal_uncompressed_format format;
+};
+
+struct hal_uncompressed_plane_actual {
+	int actual_stride;
+	u32 actual_plane_buffer_height;
+};
+
+struct hal_uncompressed_plane_actual_info {
+	enum hal_buffer buffer_type;
+	u32 num_planes;
+	struct hal_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hal_uncompressed_plane_constraints {
+	u32 stride_multiples;
+	u32 max_stride;
+	u32 min_plane_buffer_height_multiple;
+	u32 buffer_alignment;
+};
+
+struct hal_uncompressed_plane_actual_constraints_info {
+	enum hal_buffer buffer_type;
+	u32 num_planes;
+	struct hal_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hal_extra_data_header_config {
+	u32 type;
+	enum hal_buffer buffer_type;
+	u32 version;
+	u32 port_index;
+	u32 client_extradata_id;
+};
+
+struct hal_frame_size {
+	enum hal_buffer buffer_type;
+	u32 width;
+	u32 height;
+};
+
+struct hal_enable {
+	bool enable;
+};
+
+struct hal_buffer_count_actual {
+	enum hal_buffer buffer_type;
+	u32 buffer_count_actual;
+};
+
+struct hal_buffer_size_minimum {
+	enum hal_buffer buffer_type;
+	u32 buffer_size;
+};
+
+struct hal_buffer_display_hold_count_actual {
+	enum hal_buffer buffer_type;
+	u32 hold_count;
+};
+
+enum hal_nal_stream_format {
+	HAL_NAL_FORMAT_STARTCODES         = 0x00000001,
+	HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002,
+	HAL_NAL_FORMAT_ONE_BYTE_LENGTH    = 0x00000004,
+	HAL_NAL_FORMAT_TWO_BYTE_LENGTH    = 0x00000008,
+	HAL_NAL_FORMAT_FOUR_BYTE_LENGTH   = 0x00000010,
+};
+
+enum hal_output_order {
+	HAL_OUTPUT_ORDER_DISPLAY,
+	HAL_OUTPUT_ORDER_DECODE,
+	HAL_UNUSED_OUTPUT = 0x10000000,
+};
+
+enum hal_picture {
+	HAL_PICTURE_I = 0x01,
+	HAL_PICTURE_P = 0x02,
+	HAL_PICTURE_B = 0x04,
+	HAL_PICTURE_IDR = 0x08,
+	HAL_PICTURE_CRA = 0x10,
+	HAL_FRAME_NOTCODED = 0x7F002000,
+	HAL_FRAME_YUV = 0x7F004000,
+	HAL_UNUSED_PICT = 0x10000000,
+};
+
+struct hal_extradata_enable {
+	u32 enable;
+	enum hal_extradata_id index;
+};
+
+struct hal_enable_picture {
+	u32 picture_type;
+};
+
+struct hal_multi_stream {
+	enum hal_buffer buffer_type;
+	u32 enable;
+	u32 width;
+	u32 height;
+};
+
+struct hal_display_picture_buffer_count {
+	u32 enable;
+	u32 count;
+};
+
+struct hal_mb_error_map {
+	u32 error_map_size;
+	u8 rg_error_map[1];
+};
+
+struct hal_request_iframe {
+	u32 enable;
+};
+
+struct hal_bitrate {
+	u32 bit_rate;
+	u32 layer_id;
+};
+
+struct hal_profile_level {
+	u32 profile;
+	u32 level;
+};
+
+struct hal_profile_level_supported {
+	u32 profile_count;
+	struct hal_profile_level profile_level[MAX_PROFILE_COUNT];
+};
+
+enum hal_h264_entropy {
+	HAL_H264_ENTROPY_CAVLC = 1,
+	HAL_H264_ENTROPY_CABAC = 2,
+	HAL_UNUSED_ENTROPY = 0x10000000,
+};
+
+enum hal_h264_cabac_model {
+	HAL_H264_CABAC_MODEL_0 = 1,
+	HAL_H264_CABAC_MODEL_1 = 2,
+	HAL_H264_CABAC_MODEL_2 = 4,
+	HAL_UNUSED_CABAC = 0x10000000,
+};
+
+struct hal_h264_entropy_control {
+	enum hal_h264_entropy entropy_mode;
+	enum hal_h264_cabac_model cabac_model;
+};
+
+enum hal_rate_control {
+	HAL_RATE_CONTROL_OFF,
+	HAL_RATE_CONTROL_VBR_VFR,
+	HAL_RATE_CONTROL_VBR_CFR,
+	HAL_RATE_CONTROL_CBR_VFR,
+	HAL_RATE_CONTROL_CBR_CFR,
+	HAL_RATE_CONTROL_MBR_CFR,
+	HAL_RATE_CONTROL_MBR_VFR,
+	HAL_UNUSED_RC = 0x10000000,
+};
+
+struct hal_mpeg4_time_resolution {
+	u32 time_increment_resolution;
+};
+
+struct hal_mpeg4_header_extension {
+	u32 header_extension;
+};
+
+enum hal_h264_db_mode {
+	HAL_H264_DB_MODE_DISABLE,
+	HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
+	HAL_H264_DB_MODE_ALL_BOUNDARY,
+	HAL_UNUSED_H264_DB = 0x10000000,
+};
+
+struct hal_h264_db_control {
+	enum hal_h264_db_mode mode;
+	int slice_alpha_offset;
+	int slice_beta_offset;
+};
+
+struct hal_temporal_spatial_tradeoff {
+	u32 ts_factor;
+};
+
+struct hal_quantization {
+	u32 qpi;
+	u32 qpp;
+	u32 qpb;
+	u32 layer_id;
+};
+
+struct hal_initial_quantization {
+	u32 qpi;
+	u32 qpp;
+	u32 qpb;
+	u32 init_qp_enable;
+};
+
+struct hal_quantization_range {
+	u32 min_qp;
+	u32 max_qp;
+	u32 layer_id;
+};
+
+struct hal_intra_period {
+	u32 pframes;
+	u32 bframes;
+};
+
+struct hal_idr_period {
+	u32 idr_period;
+};
+
+enum hal_rotate {
+	HAL_ROTATE_NONE,
+	HAL_ROTATE_90,
+	HAL_ROTATE_180,
+	HAL_ROTATE_270,
+	HAL_UNUSED_ROTATE = 0x10000000,
+};
+
+enum hal_flip {
+	HAL_FLIP_NONE,
+	HAL_FLIP_HORIZONTAL,
+	HAL_FLIP_VERTICAL,
+	HAL_UNUSED_FLIP = 0x10000000,
+};
+
+struct hal_operations {
+	enum hal_rotate rotate;
+	enum hal_flip flip;
+};
+
+enum hal_intra_refresh_mode {
+	HAL_INTRA_REFRESH_NONE,
+	HAL_INTRA_REFRESH_CYCLIC,
+	HAL_INTRA_REFRESH_ADAPTIVE,
+	HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE,
+	HAL_INTRA_REFRESH_RANDOM,
+	HAL_UNUSED_INTRA = 0x10000000,
+};
+
+struct hal_intra_refresh {
+	enum hal_intra_refresh_mode mode;
+	u32 air_mbs;
+	u32 air_ref;
+	u32 cir_mbs;
+};
+
+enum hal_multi_slice {
+	HAL_MULTI_SLICE_OFF,
+	HAL_MULTI_SLICE_BY_MB_COUNT,
+	HAL_MULTI_SLICE_BY_BYTE_COUNT,
+	HAL_MULTI_SLICE_GOB,
+	HAL_UNUSED_SLICE = 0x10000000,
+};
+
+struct hal_multi_slice_control {
+	enum hal_multi_slice multi_slice;
+	u32 slice_size;
+};
+
+struct hal_debug_config {
+	u32 debug_config;
+};
+
+struct hal_buffer_requirements {
+	enum hal_buffer buffer_type;
+	u32 buffer_size;
+	u32 buffer_region_size;
+	u32 buffer_hold_count;
+	u32 buffer_count_min;
+	u32 buffer_count_actual;
+	u32 contiguous;
+	u32 buffer_alignment;
+};
+
+enum hal_priority {/* Priority increases with number */
+	HAL_PRIORITY_LOW = 10,
+	HAL_PRIOIRTY_MEDIUM = 20,
+	HAL_PRIORITY_HIGH = 30,
+	HAL_UNUSED_PRIORITY = 0x10000000,
+};
+
+struct hal_batch_info {
+	u32 input_batch_count;
+	u32 output_batch_count;
+};
+
+struct hal_metadata_pass_through {
+	u32 enable;
+	u32 size;
+};
+
+struct hal_uncompressed_format_supported {
+	enum hal_buffer buffer_type;
+	u32 format_entries;
+	u32 rg_format_info[1];
+};
+
+enum hal_interlace_format {
+	HAL_INTERLACE_FRAME_PROGRESSIVE                 = 0x01,
+	HAL_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST    = 0x02,
+	HAL_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04,
+	HAL_INTERLACE_FRAME_TOPFIELDFIRST               = 0x08,
+	HAL_INTERLACE_FRAME_BOTTOMFIELDFIRST            = 0x10,
+	HAL_UNUSED_INTERLACE = 0x10000000,
+};
+
+struct hal_interlace_format_supported {
+	enum hal_buffer buffer_type;
+	enum hal_interlace_format format;
+};
+
+enum hal_chroma_site {
+	HAL_CHROMA_SITE_0,
+	HAL_CHROMA_SITE_1,
+	HAL_UNUSED_CHROMA = 0x10000000,
+};
+
+struct hal_properties_supported {
+	u32 num_properties;
+	u32 rg_properties[1];
+};
+
+enum hal_capability {
+	HAL_CAPABILITY_FRAME_WIDTH = 0x1,
+	HAL_CAPABILITY_FRAME_HEIGHT,
+	HAL_CAPABILITY_MBS_PER_FRAME,
+	HAL_CAPABILITY_MBS_PER_SECOND,
+	HAL_CAPABILITY_FRAMERATE,
+	HAL_CAPABILITY_SCALE_X,
+	HAL_CAPABILITY_SCALE_Y,
+	HAL_CAPABILITY_BITRATE,
+	HAL_CAPABILITY_BFRAME,
+	HAL_CAPABILITY_PEAKBITRATE,
+	HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS,
+	HAL_CAPABILITY_ENC_LTR_COUNT,
+	HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD,
+	HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS,
+	HAL_CAPABILITY_LCU_SIZE,
+	HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS,
+	HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE,
+	HAL_UNUSED_CAPABILITY = 0x10000000,
+};
+
+struct hal_capability_supported {
+	enum hal_capability capability_type;
+	u32 min;
+	u32 max;
+	u32 step_size;
+};
+
+struct hal_capability_supported_info {
+	u32 num_capabilities;
+	struct hal_capability_supported rg_data[1];
+};
+
+struct hal_nal_stream_format_supported {
+	u32 nal_stream_format_supported;
+};
+
+struct hal_nal_stream_format_select {
+	u32 nal_stream_format_select;
+};
+
+struct hal_multi_view_format {
+	u32 views;
+	u32 rg_view_order[1];
+};
+
+enum hal_buffer_layout_type {
+	HAL_BUFFER_LAYOUT_TOP_BOTTOM,
+	HAL_BUFFER_LAYOUT_SEQ,
+	HAL_UNUSED_BUFFER_LAYOUT = 0x10000000,
+};
+
+struct hal_mvc_buffer_layout {
+	enum hal_buffer_layout_type layout_type;
+	u32 bright_view_first;
+	u32 ngap;
+};
+
+struct hal_seq_header_info {
+	u32 nax_header_len;
+};
+
+struct hal_aspect_ratio {
+	u32 aspect_width;
+	u32 aspect_height;
+};
+
+struct hal_codec_supported {
+	u32 decoder_codec_supported;
+	u32 encoder_codec_supported;
+};
+
+struct hal_multi_view_select {
+	u32 view_index;
+};
+
+struct hal_timestamp_scale {
+	u32 time_stamp_scale;
+};
+
+
+struct hal_h264_vui_timing_info {
+	u32 enable;
+	u32 fixed_frame_rate;
+	u32 time_scale;
+};
+
+struct hal_h264_vui_bitstream_restrc {
+	u32 enable;
+};
+
+struct hal_preserve_text_quality {
+	u32 enable;
+};
+
+struct hal_vc1e_perf_cfg_type {
+	struct {
+		u32 x_subsampled;
+		u32 y_subsampled;
+	} i_frame, p_frame, b_frame;
+};
+
+struct hal_vpe_color_space_conversion {
+	u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
+	u32 csc_bias[HAL_MAX_BIAS_COEFFS];
+	u32 csc_limit[HAL_MAX_LIMIT_COEFFS];
+};
+
+struct hal_video_signal_info {
+	u32 color_space;
+	u32 transfer_chars;
+	u32 matrix_coeffs;
+	bool full_range;
+};
+
+enum hal_iframesize_type {
+	HAL_IFRAMESIZE_TYPE_DEFAULT,
+	HAL_IFRAMESIZE_TYPE_MEDIUM,
+	HAL_IFRAMESIZE_TYPE_HUGE,
+	HAL_IFRAMESIZE_TYPE_UNLIMITED,
+};
+
+enum vidc_resource_id {
+	VIDC_RESOURCE_NONE,
+	VIDC_RESOURCE_OCMEM,
+	VIDC_RESOURCE_VMEM,
+	VIDC_UNUSED_RESOURCE = 0x10000000,
+};
+
+struct vidc_resource_hdr {
+	enum vidc_resource_id resource_id;
+	void *resource_handle;
+	u32 size;
+};
+
+struct vidc_buffer_addr_info {
+	enum hal_buffer buffer_type;
+	u32 buffer_size;
+	u32 num_buffers;
+	ion_phys_addr_t align_device_addr;
+	ion_phys_addr_t extradata_addr;
+	u32 extradata_size;
+	u32 response_required;
+};
+
+/* Needs to be exactly the same as hfi_buffer_info */
+struct hal_buffer_info {
+	u32 buffer_addr;
+	u32 extra_data_addr;
+};
+
+struct vidc_frame_plane_config {
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+	u32 stride;
+	u32 scan_lines;
+};
+
+struct vidc_uncompressed_frame_config {
+	struct vidc_frame_plane_config luma_plane;
+	struct vidc_frame_plane_config chroma_plane;
+};
+
+struct vidc_frame_data {
+	enum hal_buffer buffer_type;
+	ion_phys_addr_t device_addr;
+	ion_phys_addr_t extradata_addr;
+	int64_t timestamp;
+	u32 flags;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	u32 mark_target;
+	u32 mark_data;
+	u32 clnt_data;
+	u32 extradata_size;
+};
+
+struct vidc_seq_hdr {
+	ion_phys_addr_t seq_hdr;
+	u32 seq_hdr_len;
+};
+
+struct hal_fw_info {
+	char version[VENUS_VERSION_LENGTH];
+	phys_addr_t base_addr;
+	int register_base;
+	int register_size;
+	int irq;
+};
+
+enum hal_flush {
+	HAL_FLUSH_INPUT,
+	HAL_FLUSH_OUTPUT,
+	HAL_FLUSH_ALL,
+	HAL_UNUSED_FLUSH = 0x10000000,
+};
+
+enum hal_event_type {
+	HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
+	HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+	HAL_EVENT_RELEASE_BUFFER_REFERENCE,
+	HAL_UNUSED_SEQCHG = 0x10000000,
+};
+
+enum buffer_mode_type {
+	HAL_BUFFER_MODE_STATIC = 0x001,
+	HAL_BUFFER_MODE_RING = 0x010,
+	HAL_BUFFER_MODE_DYNAMIC = 0x100,
+};
+
+struct hal_buffer_alloc_mode {
+	enum hal_buffer buffer_type;
+	enum buffer_mode_type buffer_mode;
+};
+
+enum ltr_mode {
+	HAL_LTR_MODE_DISABLE,
+	HAL_LTR_MODE_MANUAL,
+	HAL_LTR_MODE_PERIODIC,
+};
+
+struct hal_ltr_mode {
+	enum ltr_mode mode;
+	u32 count;
+	u32 trust_mode;
+};
+
+struct hal_ltr_use {
+	u32 ref_ltr;
+	u32 use_constraint;
+	u32 frames;
+};
+
+struct hal_ltr_mark {
+	u32 mark_frame;
+};
+
+enum hal_perf_mode {
+	HAL_PERF_MODE_POWER_SAVE,
+	HAL_PERF_MODE_POWER_MAX_QUALITY,
+};
+
+struct hal_hybrid_hierp {
+	u32 layers;
+};
+
+struct hal_scs_threshold {
+	u32 threshold_value;
+};
+
+struct buffer_requirements {
+	struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
+};
+
+union hal_get_property {
+	struct hal_frame_rate frame_rate;
+	struct hal_uncompressed_format_select format_select;
+	struct hal_uncompressed_plane_actual plane_actual;
+	struct hal_uncompressed_plane_actual_info plane_actual_info;
+	struct hal_uncompressed_plane_constraints plane_constraints;
+	struct hal_uncompressed_plane_actual_constraints_info
+						plane_constraints_info;
+	struct hal_extra_data_header_config extra_data_header_config;
+	struct hal_frame_size frame_size;
+	struct hal_enable enable;
+	struct hal_buffer_count_actual buffer_count_actual;
+	struct hal_extradata_enable extradata_enable;
+	struct hal_enable_picture enable_picture;
+	struct hal_multi_stream multi_stream;
+	struct hal_display_picture_buffer_count display_picture_buffer_count;
+	struct hal_mb_error_map mb_error_map;
+	struct hal_request_iframe request_iframe;
+	struct hal_bitrate bitrate;
+	struct hal_profile_level profile_level;
+	struct hal_profile_level_supported profile_level_supported;
+	struct hal_mpeg4_time_resolution mpeg4_time_resolution;
+	struct hal_mpeg4_header_extension mpeg4_header_extension;
+	struct hal_h264_db_control h264_db_control;
+	struct hal_temporal_spatial_tradeoff temporal_spatial_tradeoff;
+	struct hal_quantization quantization;
+	struct hal_quantization_range quantization_range;
+	struct hal_intra_period intra_period;
+	struct hal_idr_period idr_period;
+	struct hal_operations operations;
+	struct hal_intra_refresh intra_refresh;
+	struct hal_multi_slice_control multi_slice_control;
+	struct hal_debug_config debug_config;
+	struct hal_batch_info batch_info;
+	struct hal_metadata_pass_through metadata_pass_through;
+	struct hal_uncompressed_format_supported uncompressed_format_supported;
+	struct hal_interlace_format_supported interlace_format_supported;
+	struct hal_properties_supported properties_supported;
+	struct hal_capability_supported capability_supported;
+	struct hal_capability_supported_info capability_supported_info;
+	struct hal_nal_stream_format_supported nal_stream_format_supported;
+	struct hal_nal_stream_format_select nal_stream_format_select;
+	struct hal_multi_view_format multi_view_format;
+	struct hal_seq_header_info seq_header_info;
+	struct hal_codec_supported codec_supported;
+	struct hal_multi_view_select multi_view_select;
+	struct hal_timestamp_scale timestamp_scale;
+	struct hal_h264_vui_timing_info h264_vui_timing_info;
+	struct hal_h264_vui_bitstream_restrc h264_vui_bitstream_restrc;
+	struct hal_preserve_text_quality preserve_text_quality;
+	struct hal_buffer_info buffer_info;
+	struct hal_buffer_alloc_mode buffer_alloc_mode;
+	struct buffer_requirements buf_req;
+	enum hal_h264_entropy h264_entropy;
+};
+
+/* HAL Response */
+#define IS_HAL_SYS_CMD(cmd) ((cmd) >= HAL_SYS_INIT_DONE && \
+		(cmd) <= HAL_SYS_ERROR)
+#define IS_HAL_SESSION_CMD(cmd) ((cmd) >= HAL_SESSION_EVENT_CHANGE && \
+		(cmd) <= HAL_SESSION_ERROR)
+enum hal_command_response {
+	/* SYSTEM COMMANDS_DONE*/
+	HAL_SYS_INIT_DONE,
+	HAL_SYS_SET_RESOURCE_DONE,
+	HAL_SYS_RELEASE_RESOURCE_DONE,
+	HAL_SYS_PING_ACK_DONE,
+	HAL_SYS_PC_PREP_DONE,
+	HAL_SYS_IDLE,
+	HAL_SYS_DEBUG,
+	HAL_SYS_WATCHDOG_TIMEOUT,
+	HAL_SYS_ERROR,
+	/* SESSION COMMANDS_DONE */
+	HAL_SESSION_EVENT_CHANGE,
+	HAL_SESSION_LOAD_RESOURCE_DONE,
+	HAL_SESSION_INIT_DONE,
+	HAL_SESSION_END_DONE,
+	HAL_SESSION_ABORT_DONE,
+	HAL_SESSION_START_DONE,
+	HAL_SESSION_STOP_DONE,
+	HAL_SESSION_ETB_DONE,
+	HAL_SESSION_FTB_DONE,
+	HAL_SESSION_FLUSH_DONE,
+	HAL_SESSION_SUSPEND_DONE,
+	HAL_SESSION_RESUME_DONE,
+	HAL_SESSION_SET_PROP_DONE,
+	HAL_SESSION_GET_PROP_DONE,
+	HAL_SESSION_PARSE_SEQ_HDR_DONE,
+	HAL_SESSION_GET_SEQ_HDR_DONE,
+	HAL_SESSION_RELEASE_BUFFER_DONE,
+	HAL_SESSION_RELEASE_RESOURCE_DONE,
+	HAL_SESSION_PROPERTY_INFO,
+	HAL_SESSION_ERROR,
+	HAL_RESPONSE_UNUSED = 0x10000000,
+};
+
+struct vidc_hal_ebd {
+	u32 timestamp_hi;
+	u32 timestamp_lo;
+	u32 flags;
+	enum vidc_status status;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 offset;
+	u32 alloc_len;
+	u32 filled_len;
+	enum hal_picture picture_type;
+	ion_phys_addr_t packet_buffer;
+	ion_phys_addr_t extra_data_buffer;
+};
+
+struct vidc_hal_fbd {
+	u32 stream_id;
+	u32 view_id;
+	u32 timestamp_hi;
+	u32 timestamp_lo;
+	u32 flags1;
+	u32 mark_target;
+	u32 mark_data;
+	u32 stats;
+	u32 alloc_len1;
+	u32 filled_len1;
+	u32 offset1;
+	u32 frame_width;
+	u32 frame_height;
+	u32 start_x_coord;
+	u32 start_y_coord;
+	u32 input_tag;
+	u32 input_tag1;
+	enum hal_picture picture_type;
+	ion_phys_addr_t packet_buffer1;
+	ion_phys_addr_t extra_data_buffer;
+	u32 flags2;
+	u32 alloc_len2;
+	u32 filled_len2;
+	u32 offset2;
+	ion_phys_addr_t packet_buffer2;
+	u32 flags3;
+	u32 alloc_len3;
+	u32 filled_len3;
+	u32 offset3;
+	ion_phys_addr_t packet_buffer3;
+	enum hal_buffer buffer_type;
+};
+
+struct msm_vidc_capability {
+	enum hal_domain domain;
+	enum hal_video_codec codec;
+	struct hal_capability_supported width;
+	struct hal_capability_supported height;
+	struct hal_capability_supported mbs_per_frame;
+	struct hal_capability_supported mbs_per_sec;
+	struct hal_capability_supported frame_rate;
+	struct hal_capability_supported scale_x;
+	struct hal_capability_supported scale_y;
+	struct hal_capability_supported bitrate;
+	struct hal_capability_supported bframe;
+	struct hal_capability_supported peakbitrate;
+	struct hal_capability_supported hier_p;
+	struct hal_capability_supported ltr_count;
+	struct hal_capability_supported secure_output2_threshold;
+	struct hal_capability_supported hier_b;
+	struct hal_capability_supported lcu_size;
+	struct hal_capability_supported hier_p_hybrid;
+	struct hal_capability_supported mbs_per_sec_power_save;
+	struct hal_profile_level_supported profile_level;
+	struct hal_uncompressed_format_supported uncomp_format;
+	struct hal_interlace_format_supported HAL_format;
+	struct hal_nal_stream_format_supported nal_stream_format;
+	struct hal_intra_refresh intra_refresh;
+	enum buffer_mode_type alloc_mode_out;
+	enum buffer_mode_type alloc_mode_in;
+	u32 pixelprocess_capabilities;
+};
+
+struct vidc_hal_sys_init_done {
+	u32 dec_codec_supported;
+	u32 enc_codec_supported;
+	u32 codec_count;
+	struct msm_vidc_capability *capabilities;
+	u32 max_sessions_supported;
+};
+
+struct vidc_hal_session_init_done {
+	struct msm_vidc_capability capability;
+};
+
+struct msm_vidc_cb_cmd_done {
+	u32 device_id;
+	void *session_id;
+	enum vidc_status status;
+	u32 size;
+	union {
+		struct vidc_resource_hdr resource_hdr;
+		struct vidc_buffer_addr_info buffer_addr_info;
+		struct vidc_frame_plane_config frame_plane_config;
+		struct vidc_uncompressed_frame_config uncompressed_frame_config;
+		struct vidc_frame_data frame_data;
+		struct vidc_seq_hdr seq_hdr;
+		struct vidc_hal_ebd ebd;
+		struct vidc_hal_fbd fbd;
+		struct vidc_hal_sys_init_done sys_init_done;
+		struct vidc_hal_session_init_done session_init_done;
+		struct hal_buffer_info buffer_info;
+		union hal_get_property property;
+		enum hal_flush flush_type;
+	} data;
+};
+
+struct msm_vidc_cb_event {
+	u32 device_id;
+	void *session_id;
+	enum vidc_status status;
+	u32 height;
+	u32 width;
+	enum msm_vidc_pixel_depth bit_depth;
+	u32 hal_event_type;
+	ion_phys_addr_t packet_buffer;
+	ion_phys_addr_t extra_data_buffer;
+	u32 pic_struct;
+	u32 colour_space;
+};
+
+struct msm_vidc_cb_data_done {
+	u32 device_id;
+	void *session_id;
+	enum vidc_status status;
+	u32 size;
+	u32 clnt_data;
+	union {
+		struct vidc_hal_ebd input_done;
+		struct vidc_hal_fbd output_done;
+	};
+};
+
+struct msm_vidc_cb_info {
+	enum hal_command_response response_type;
+	union {
+		struct msm_vidc_cb_cmd_done cmd;
+		struct msm_vidc_cb_event event;
+		struct msm_vidc_cb_data_done data;
+	} response;
+};
+
+enum msm_vidc_hfi_type {
+	VIDC_HFI_VENUS,
+};
+
+enum msm_vidc_thermal_level {
+	VIDC_THERMAL_NORMAL = 0,
+	VIDC_THERMAL_LOW,
+	VIDC_THERMAL_HIGH,
+	VIDC_THERMAL_CRITICAL
+};
+
+enum vidc_vote_data_session {
+	VIDC_BUS_VOTE_DATA_SESSION_INVALID = 0,
+	/* No declarations exist. Values generated by VIDC_VOTE_DATA_SESSION_VAL
+	 * describe the enumerations e.g.:
+	 *
+	 * enum vidc_bus_vote_data_session_type h264_decoder_session =
+	 *        VIDC_VOTE_DATA_SESSION_VAL(HAL_VIDEO_CODEC_H264,
+	 *                 HAL_VIDEO_DOMAIN_DECODER);
+	 */
+};
+
+/* Careful modifying VIDC_VOTE_DATA_SESSION_VAL().
+ *
+ * This macro assigns two bits to each codec: the lower bit denoting the codec
+ * type, and the higher bit denoting session type.
+ */
+static inline enum vidc_vote_data_session VIDC_VOTE_DATA_SESSION_VAL(
+		enum hal_video_codec c, enum hal_domain d) {
+	if (d != HAL_VIDEO_DOMAIN_ENCODER && d != HAL_VIDEO_DOMAIN_DECODER)
+		return VIDC_BUS_VOTE_DATA_SESSION_INVALID;
+
+	return (1 << ilog2(c) * 2) | ((d - 1) << (ilog2(c) * 2 + 1));
+}
+
+struct msm_vidc_gov_data {
+	struct vidc_bus_vote_data *data;
+	u32 data_count;
+	int imem_size;
+};
+
+enum msm_vidc_power_mode {
+	VIDC_POWER_NORMAL = 0,
+	VIDC_POWER_LOW,
+	VIDC_POWER_TURBO
+};
+
+
+struct vidc_bus_vote_data {
+	enum hal_domain domain;
+	enum hal_video_codec codec;
+	enum hal_uncompressed_format color_formats[2];
+	int num_formats; /* 1 = DPB-OPB unified; 2 = split */
+	int height, width, fps;
+	enum msm_vidc_power_mode power_mode;
+	struct imem_ab_table *imem_ab_tbl;
+	u32 imem_ab_tbl_size;
+	unsigned long core_freq;
+};
+
+
+struct vidc_clk_scale_data {
+	enum vidc_vote_data_session session[VIDC_MAX_SESSIONS];
+	enum msm_vidc_power_mode power_mode[VIDC_MAX_SESSIONS];
+	u32 load[VIDC_MAX_SESSIONS];
+	int num_sessions;
+};
+
+struct hal_index_extradata_input_crop_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+};
+
+struct hal_cmd_sys_get_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+#define call_hfi_op(q, op, args...)			\
+	(((q) && (q)->op) ? ((q)->op(args)) : 0)
+
+struct hfi_device {
+	void *hfi_device_data;
+
+	/*Add function pointers for all the hfi functions below*/
+	int (*core_init)(void *device);
+	int (*core_release)(void *device);
+	int (*core_ping)(void *device);
+	int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type);
+	int (*session_init)(void *device, void *session_id,
+		enum hal_domain session_type, enum hal_video_codec codec_type,
+		void **new_session);
+	int (*session_end)(void *session);
+	int (*session_abort)(void *session);
+	int (*session_set_buffers)(void *sess,
+				struct vidc_buffer_addr_info *buffer_info);
+	int (*session_release_buffers)(void *sess,
+				struct vidc_buffer_addr_info *buffer_info);
+	int (*session_load_res)(void *sess);
+	int (*session_release_res)(void *sess);
+	int (*session_start)(void *sess);
+	int (*session_continue)(void *sess);
+	int (*session_stop)(void *sess);
+	int (*session_etb)(void *sess, struct vidc_frame_data *input_frame);
+	int (*session_ftb)(void *sess, struct vidc_frame_data *output_frame);
+	int (*session_process_batch)(void *sess,
+		int num_etbs, struct vidc_frame_data etbs[],
+		int num_ftbs, struct vidc_frame_data ftbs[]);
+	int (*session_parse_seq_hdr)(void *sess,
+			struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_seq_hdr)(void *sess,
+			struct vidc_seq_hdr *seq_hdr);
+	int (*session_get_buf_req)(void *sess);
+	int (*session_flush)(void *sess, enum hal_flush flush_mode);
+	int (*session_set_property)(void *sess, enum hal_property ptype,
+			void *pdata);
+	int (*session_get_property)(void *sess, enum hal_property ptype);
+	int (*scale_clocks)(void *dev, int load,
+			struct vidc_clk_scale_data *data,
+			unsigned long instant_bitrate);
+	int (*vote_bus)(void *dev, struct vidc_bus_vote_data *data,
+			int num_data);
+	int (*get_fw_info)(void *dev, struct hal_fw_info *fw_info);
+	int (*session_clean)(void *sess);
+	int (*get_core_capabilities)(void *dev);
+	int (*suspend)(void *dev);
+	unsigned long (*get_core_clock_rate)(void *dev, bool actual_rate);
+	enum hal_default_properties (*get_default_properties)(void *dev);
+};
+
+typedef void (*hfi_cmd_response_callback) (enum hal_command_response cmd,
+			void *data);
+typedef void (*msm_vidc_callback) (u32 response, void *callback);
+
+struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type,
+		u32 device_id, struct msm_vidc_platform_resources *res,
+		hfi_cmd_response_callback callback);
+void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
+			struct hfi_device *hdev);
+u32 vidc_get_hfi_domain(enum hal_domain hal_domain);
+u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec);
+enum hal_domain vidc_get_hal_domain(u32 hfi_domain);
+enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec);
+
+#endif /*__VIDC_HFI_API_H__ */
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h
new file mode 100644
index 0000000..39904a5
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_helper.h
@@ -0,0 +1,1180 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __H_VIDC_HFI_HELPER_H__
+#define __H_VIDC_HFI_HELPER_H__
+
+#define HFI_COMMON_BASE				(0)
+#define HFI_OX_BASE					(0x01000000)
+
+#define HFI_VIDEO_DOMAIN_ENCODER	(HFI_COMMON_BASE + 0x1)
+#define HFI_VIDEO_DOMAIN_DECODER	(HFI_COMMON_BASE + 0x2)
+#define HFI_VIDEO_DOMAIN_VPE		(HFI_COMMON_BASE + 0x4)
+#define HFI_VIDEO_DOMAIN_MBI		(HFI_COMMON_BASE + 0x8)
+
+#define HFI_DOMAIN_BASE_COMMON		(HFI_COMMON_BASE + 0)
+#define HFI_DOMAIN_BASE_VDEC		(HFI_COMMON_BASE + 0x01000000)
+#define HFI_DOMAIN_BASE_VENC		(HFI_COMMON_BASE + 0x02000000)
+#define HFI_DOMAIN_BASE_VPE			(HFI_COMMON_BASE + 0x03000000)
+
+#define HFI_VIDEO_ARCH_OX			(HFI_COMMON_BASE + 0x1)
+
+#define HFI_ARCH_COMMON_OFFSET		(0)
+#define HFI_ARCH_OX_OFFSET			(0x00200000)
+
+#define  HFI_CMD_START_OFFSET		(0x00010000)
+#define  HFI_MSG_START_OFFSET		(0x00020000)
+
+#define HFI_ERR_NONE						HFI_COMMON_BASE
+#define HFI_ERR_SYS_FATAL				(HFI_COMMON_BASE + 0x1)
+#define HFI_ERR_SYS_INVALID_PARAMETER		(HFI_COMMON_BASE + 0x2)
+#define HFI_ERR_SYS_VERSION_MISMATCH		(HFI_COMMON_BASE + 0x3)
+#define HFI_ERR_SYS_INSUFFICIENT_RESOURCES	(HFI_COMMON_BASE + 0x4)
+#define HFI_ERR_SYS_MAX_SESSIONS_REACHED	(HFI_COMMON_BASE + 0x5)
+#define HFI_ERR_SYS_UNSUPPORTED_CODEC		(HFI_COMMON_BASE + 0x6)
+#define HFI_ERR_SYS_SESSION_IN_USE			(HFI_COMMON_BASE + 0x7)
+#define HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE	(HFI_COMMON_BASE + 0x8)
+#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN		(HFI_COMMON_BASE + 0x9)
+
+#define HFI_ERR_SESSION_FATAL			(HFI_COMMON_BASE + 0x1001)
+#define HFI_ERR_SESSION_INVALID_PARAMETER	(HFI_COMMON_BASE + 0x1002)
+#define HFI_ERR_SESSION_BAD_POINTER		(HFI_COMMON_BASE + 0x1003)
+#define HFI_ERR_SESSION_INVALID_SESSION_ID	(HFI_COMMON_BASE + 0x1004)
+#define HFI_ERR_SESSION_INVALID_STREAM_ID	(HFI_COMMON_BASE + 0x1005)
+#define HFI_ERR_SESSION_INCORRECT_STATE_OPERATION		\
+	(HFI_COMMON_BASE + 0x1006)
+#define HFI_ERR_SESSION_UNSUPPORTED_PROPERTY	(HFI_COMMON_BASE + 0x1007)
+
+#define HFI_ERR_SESSION_UNSUPPORTED_SETTING	(HFI_COMMON_BASE + 0x1008)
+
+#define HFI_ERR_SESSION_INSUFFICIENT_RESOURCES	(HFI_COMMON_BASE + 0x1009)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED	\
+	(HFI_COMMON_BASE + 0x100A)
+
+#define HFI_ERR_SESSION_STREAM_CORRUPT		(HFI_COMMON_BASE + 0x100B)
+#define HFI_ERR_SESSION_ENC_OVERFLOW		(HFI_COMMON_BASE + 0x100C)
+#define HFI_ERR_SESSION_UNSUPPORTED_STREAM	(HFI_COMMON_BASE + 0x100D)
+#define HFI_ERR_SESSION_CMDSIZE			(HFI_COMMON_BASE + 0x100E)
+#define HFI_ERR_SESSION_UNSUPPORT_CMD		(HFI_COMMON_BASE + 0x100F)
+#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE	(HFI_COMMON_BASE + 0x1010)
+#define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL	(HFI_COMMON_BASE + 0x1011)
+#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR	(HFI_COMMON_BASE + 0x1012)
+#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED	(HFI_COMMON_BASE + 0x1013)
+
+#define HFI_EVENT_SYS_ERROR				(HFI_COMMON_BASE + 0x1)
+#define HFI_EVENT_SESSION_ERROR			(HFI_COMMON_BASE + 0x2)
+
+#define HFI_VIDEO_CODEC_H264				0x00000002
+#define HFI_VIDEO_CODEC_H263				0x00000004
+#define HFI_VIDEO_CODEC_MPEG1				0x00000008
+#define HFI_VIDEO_CODEC_MPEG2				0x00000010
+#define HFI_VIDEO_CODEC_MPEG4				0x00000020
+#define HFI_VIDEO_CODEC_DIVX_311			0x00000040
+#define HFI_VIDEO_CODEC_DIVX				0x00000080
+#define HFI_VIDEO_CODEC_VC1				0x00000100
+#define HFI_VIDEO_CODEC_SPARK				0x00000200
+#define HFI_VIDEO_CODEC_VP8				0x00001000
+#define HFI_VIDEO_CODEC_HEVC				0x00002000
+#define HFI_VIDEO_CODEC_VP9				0x00004000
+#define HFI_VIDEO_CODEC_HEVC_HYBRID			0x80000000
+
+#define HFI_H264_PROFILE_BASELINE			0x00000001
+#define HFI_H264_PROFILE_MAIN				0x00000002
+#define HFI_H264_PROFILE_HIGH				0x00000004
+#define HFI_H264_PROFILE_STEREO_HIGH		0x00000008
+#define HFI_H264_PROFILE_MULTIVIEW_HIGH		0x00000010
+#define HFI_H264_PROFILE_CONSTRAINED_BASE	0x00000020
+#define HFI_H264_PROFILE_CONSTRAINED_HIGH	0x00000040
+
+#define HFI_H264_LEVEL_1					0x00000001
+#define HFI_H264_LEVEL_1b					0x00000002
+#define HFI_H264_LEVEL_11					0x00000004
+#define HFI_H264_LEVEL_12					0x00000008
+#define HFI_H264_LEVEL_13					0x00000010
+#define HFI_H264_LEVEL_2					0x00000020
+#define HFI_H264_LEVEL_21					0x00000040
+#define HFI_H264_LEVEL_22					0x00000080
+#define HFI_H264_LEVEL_3					0x00000100
+#define HFI_H264_LEVEL_31					0x00000200
+#define HFI_H264_LEVEL_32					0x00000400
+#define HFI_H264_LEVEL_4					0x00000800
+#define HFI_H264_LEVEL_41					0x00001000
+#define HFI_H264_LEVEL_42					0x00002000
+#define HFI_H264_LEVEL_5					0x00004000
+#define HFI_H264_LEVEL_51					0x00008000
+#define HFI_H264_LEVEL_52                                       0x00010000
+
+#define HFI_H263_PROFILE_BASELINE			0x00000001
+
+#define HFI_H263_LEVEL_10					0x00000001
+#define HFI_H263_LEVEL_20					0x00000002
+#define HFI_H263_LEVEL_30					0x00000004
+#define HFI_H263_LEVEL_40					0x00000008
+#define HFI_H263_LEVEL_45					0x00000010
+#define HFI_H263_LEVEL_50					0x00000020
+#define HFI_H263_LEVEL_60					0x00000040
+#define HFI_H263_LEVEL_70					0x00000080
+
+#define HFI_MPEG2_PROFILE_SIMPLE			0x00000001
+#define HFI_MPEG2_PROFILE_MAIN				0x00000002
+#define HFI_MPEG2_PROFILE_422				0x00000004
+#define HFI_MPEG2_PROFILE_SNR				0x00000008
+#define HFI_MPEG2_PROFILE_SPATIAL			0x00000010
+#define HFI_MPEG2_PROFILE_HIGH				0x00000020
+
+#define HFI_MPEG2_LEVEL_LL					0x00000001
+#define HFI_MPEG2_LEVEL_ML					0x00000002
+#define HFI_MPEG2_LEVEL_H14					0x00000004
+#define HFI_MPEG2_LEVEL_HL					0x00000008
+
+#define HFI_MPEG4_PROFILE_SIMPLE			0x00000001
+#define HFI_MPEG4_PROFILE_ADVANCEDSIMPLE	0x00000002
+
+#define HFI_MPEG4_LEVEL_0					0x00000001
+#define HFI_MPEG4_LEVEL_0b					0x00000002
+#define HFI_MPEG4_LEVEL_1					0x00000004
+#define HFI_MPEG4_LEVEL_2					0x00000008
+#define HFI_MPEG4_LEVEL_3					0x00000010
+#define HFI_MPEG4_LEVEL_4					0x00000020
+#define HFI_MPEG4_LEVEL_4a					0x00000040
+#define HFI_MPEG4_LEVEL_5					0x00000080
+#define HFI_MPEG4_LEVEL_6					0x00000100
+#define HFI_MPEG4_LEVEL_7					0x00000200
+#define HFI_MPEG4_LEVEL_8					0x00000400
+#define HFI_MPEG4_LEVEL_9					0x00000800
+#define HFI_MPEG4_LEVEL_3b					0x00001000
+
+#define HFI_VC1_PROFILE_SIMPLE				0x00000001
+#define HFI_VC1_PROFILE_MAIN				0x00000002
+#define HFI_VC1_PROFILE_ADVANCED			0x00000004
+
+#define HFI_VC1_LEVEL_LOW					0x00000001
+#define HFI_VC1_LEVEL_MEDIUM				0x00000002
+#define HFI_VC1_LEVEL_HIGH					0x00000004
+#define HFI_VC1_LEVEL_0						0x00000008
+#define HFI_VC1_LEVEL_1						0x00000010
+#define HFI_VC1_LEVEL_2						0x00000020
+#define HFI_VC1_LEVEL_3						0x00000040
+#define HFI_VC1_LEVEL_4						0x00000080
+
+#define HFI_VPX_PROFILE_SIMPLE				0x00000001
+#define HFI_VPX_PROFILE_ADVANCED			0x00000002
+#define HFI_VPX_PROFILE_VERSION_0			0x00000004
+#define HFI_VPX_PROFILE_VERSION_1			0x00000008
+#define HFI_VPX_PROFILE_VERSION_2			0x00000010
+#define HFI_VPX_PROFILE_VERSION_3			0x00000020
+
+#define HFI_DIVX_FORMAT_4				(HFI_COMMON_BASE + 0x1)
+#define HFI_DIVX_FORMAT_5				(HFI_COMMON_BASE + 0x2)
+#define HFI_DIVX_FORMAT_6				(HFI_COMMON_BASE + 0x3)
+
+#define HFI_DIVX_PROFILE_QMOBILE		0x00000001
+#define HFI_DIVX_PROFILE_MOBILE			0x00000002
+#define HFI_DIVX_PROFILE_MT				0x00000004
+#define HFI_DIVX_PROFILE_HT				0x00000008
+#define HFI_DIVX_PROFILE_HD				0x00000010
+
+#define  HFI_HEVC_PROFILE_MAIN			0x00000001
+#define  HFI_HEVC_PROFILE_MAIN10		0x00000002
+#define  HFI_HEVC_PROFILE_MAIN_STILL_PIC	0x00000004
+
+#define  HFI_HEVC_LEVEL_1	0x00000001
+#define  HFI_HEVC_LEVEL_2	0x00000002
+#define  HFI_HEVC_LEVEL_21	0x00000004
+#define  HFI_HEVC_LEVEL_3	0x00000008
+#define  HFI_HEVC_LEVEL_31	0x00000010
+#define  HFI_HEVC_LEVEL_4	0x00000020
+#define  HFI_HEVC_LEVEL_41	0x00000040
+#define  HFI_HEVC_LEVEL_5	0x00000080
+#define  HFI_HEVC_LEVEL_51	0x00000100
+#define  HFI_HEVC_LEVEL_52	0x00000200
+#define  HFI_HEVC_LEVEL_6	0x00000400
+#define  HFI_HEVC_LEVEL_61	0x00000800
+#define  HFI_HEVC_LEVEL_62	0x00001000
+
+#define HFI_HEVC_TIER_MAIN	0x1
+#define HFI_HEVC_TIER_HIGH0	0x2
+
+#define HFI_BUFFER_INPUT				(HFI_COMMON_BASE + 0x1)
+#define HFI_BUFFER_OUTPUT				(HFI_COMMON_BASE + 0x2)
+#define HFI_BUFFER_OUTPUT2				(HFI_COMMON_BASE + 0x3)
+#define HFI_BUFFER_INTERNAL_PERSIST		(HFI_COMMON_BASE + 0x4)
+#define HFI_BUFFER_INTERNAL_PERSIST_1		(HFI_COMMON_BASE + 0x5)
+
+#define  HFI_BITDEPTH_8				(HFI_COMMON_BASE + 0x0)
+#define  HFI_BITDEPTH_9				(HFI_COMMON_BASE + 0x1)
+#define  HFI_BITDEPTH_10			(HFI_COMMON_BASE + 0x2)
+
+#define HFI_VENC_PERFMODE_MAX_QUALITY	0x1
+#define HFI_VENC_PERFMODE_POWER_SAVE	0x2
+
+struct hfi_buffer_info {
+	u32 buffer_addr;
+	u32 extra_data_addr;
+};
+
+#define HFI_PROPERTY_SYS_COMMON_START		\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000)
+#define HFI_PROPERTY_SYS_DEBUG_CONFIG		\
+	(HFI_PROPERTY_SYS_COMMON_START + 0x001)
+#define HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO	\
+	(HFI_PROPERTY_SYS_COMMON_START + 0x002)
+#define HFI_PROPERTY_SYS_CONFIG_VCODEC_CLKFREQ				\
+	(HFI_PROPERTY_SYS_COMMON_START + 0x003)
+#define HFI_PROPERTY_SYS_IDLE_INDICATOR         \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x004)
+#define  HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL     \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x005)
+#define  HFI_PROPERTY_SYS_IMAGE_VERSION    \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x006)
+#define  HFI_PROPERTY_SYS_CONFIG_COVERAGE    \
+	(HFI_PROPERTY_SYS_COMMON_START + 0x007)
+
+#define HFI_PROPERTY_PARAM_COMMON_START	\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000)
+#define HFI_PROPERTY_PARAM_FRAME_SIZE		\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO	\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT		\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED	\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x004)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED				\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x007)
+#define HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED				\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_CODEC_SUPPORTED			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED		\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT			\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00B)
+#define HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT				\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00C)
+#define  HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE        \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00D)
+#define  HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED            \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
+#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x00F)
+#define  HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED	    \
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x010)
+
+#define HFI_PROPERTY_CONFIG_COMMON_START				\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
+#define HFI_PROPERTY_CONFIG_FRAME_RATE					\
+	(HFI_PROPERTY_CONFIG_COMMON_START + 0x001)
+
+#define HFI_PROPERTY_PARAM_VDEC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000)
+#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x003)
+#define  HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x007)
+#define  HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x009)
+#define  HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE				\
+	(HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x00A)
+
+
+#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x4000)
+
+#define HFI_PROPERTY_PARAM_VENC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x5000)
+#define HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004)
+#define  HFI_PROPERTY_PARAM_VENC_H264_PICORDER_CNT_TYPE     \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_PARAM_VENC_SESSION_QP				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x006)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x007)
+#define  HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE           \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x008)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00A)
+#define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00B)
+#define  HFI_PROPERTY_PARAM_VENC_OPEN_GOP                   \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00C)
+#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00D)
+#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00E)
+#define  HFI_PROPERTY_PARAM_VENC_VBV_HRD_BUF_SIZE           \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00F)
+#define  HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED           \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010)
+#define HFI_PROPERTY_PARAM_VENC_ADVANCED				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x012)
+#define  HFI_PROPERTY_PARAM_VENC_H264_SPS_ID                \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x014)
+#define  HFI_PROPERTY_PARAM_VENC_H264_PPS_ID               \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x015)
+#define HFI_PROPERTY_PARAM_VENC_GENERATE_AUDNAL	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x016)
+#define HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x017)
+#define HFI_PROPERTY_PARAM_VENC_NUMREF					\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x018)
+#define HFI_PROPERTY_PARAM_VENC_MULTIREF_P				\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x019)
+#define HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B)
+#define HFI_PROPERTY_PARAM_VENC_LTRMODE		\
+	 (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C)
+#define HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D)
+#define HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E)
+#define HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01F)
+#define  HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
+#define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x021)
+#define HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x022)
+#define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x023)
+#define HFI_PROPERTY_PARAM_VENC_H264_8X8_TRANSFORM \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x025)
+#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x026)
+#define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP \
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x027)
+#define HFI_PROPERTY_PARAM_VENC_INITIAL_QP	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x028)
+#define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x029)
+#define HFI_PROPERTY_PARAM_VENC_CONSTRAINED_INTRA_PRED	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02B)
+#define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02C)
+#define  HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE	\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02F)
+#define  HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x031)
+#define  HFI_PROPERTY_PARAM_VENC_VQZIP_SEI_TYPE		\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x033)
+#define  HFI_PROPERTY_PARAM_VENC_IFRAMESIZE			\
+	(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x034)
+
+#define HFI_PROPERTY_CONFIG_VENC_COMMON_START				\
+	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000)
+#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x002)
+#define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x003)
+#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004)
+#define  HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE                \
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005)
+#define HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE				\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x007)
+
+#define HFI_PROPERTY_PARAM_VPE_COMMON_START				\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
+#define  HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER	\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008)
+#define  HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x009)
+#define  HFI_PROPERTY_CONFIG_VENC_USELTRFRAME			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00A)
+#define  HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER		\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00B)
+#define  HFI_PROPERTY_CONFIG_VENC_LTRPERIOD			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00C)
+#define  HFI_PROPERTY_CONFIG_VENC_PERF_MODE			\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00E)
+#define HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID		\
+	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00F)
+
+#define HFI_PROPERTY_CONFIG_VPE_COMMON_START				\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
+#define  HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE		\
+	(HFI_PROPERTY_CONFIG_COMMON_START + 0x010)
+#define HFI_PROPERTY_CONFIG_VPE_DEINTERLACE				\
+	(HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VPE_OPERATIONS				\
+	(HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x002)
+
+struct hfi_pic_struct {
+	u32 progressive_only;
+};
+
+struct hfi_bitrate {
+	u32 bit_rate;
+	u32 layer_id;
+};
+
+struct hfi_colour_space {
+	u32 colour_space;
+};
+
+#define HFI_CAPABILITY_FRAME_WIDTH			(HFI_COMMON_BASE + 0x1)
+#define HFI_CAPABILITY_FRAME_HEIGHT			(HFI_COMMON_BASE + 0x2)
+#define HFI_CAPABILITY_MBS_PER_FRAME			(HFI_COMMON_BASE + 0x3)
+#define HFI_CAPABILITY_MBS_PER_SECOND			(HFI_COMMON_BASE + 0x4)
+#define HFI_CAPABILITY_FRAMERATE			(HFI_COMMON_BASE + 0x5)
+#define HFI_CAPABILITY_SCALE_X				(HFI_COMMON_BASE + 0x6)
+#define HFI_CAPABILITY_SCALE_Y				(HFI_COMMON_BASE + 0x7)
+#define HFI_CAPABILITY_BITRATE				(HFI_COMMON_BASE + 0x8)
+#define HFI_CAPABILITY_BFRAME				(HFI_COMMON_BASE + 0x9)
+#define HFI_CAPABILITY_PEAKBITRATE			(HFI_COMMON_BASE + 0xa)
+#define HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS		(HFI_COMMON_BASE + 0x10)
+#define HFI_CAPABILITY_ENC_LTR_COUNT			(HFI_COMMON_BASE + 0x11)
+#define HFI_CAPABILITY_CP_OUTPUT2_THRESH		(HFI_COMMON_BASE + 0x12)
+#define HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS	(HFI_COMMON_BASE + 0x13)
+#define HFI_CAPABILITY_LCU_SIZE				(HFI_COMMON_BASE + 0x14)
+#define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS	(HFI_COMMON_BASE + 0x15)
+#define HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE		(HFI_COMMON_BASE + 0x16)
+
+struct hfi_capability_supported {
+	u32 capability_type;
+	u32 min;
+	u32 max;
+	u32 step_size;
+};
+
+struct hfi_capability_supported_info {
+	u32 num_capabilities;
+	struct hfi_capability_supported rg_data[1];
+};
+
+#define HFI_DEBUG_MSG_LOW					0x00000001
+#define HFI_DEBUG_MSG_MEDIUM					0x00000002
+#define HFI_DEBUG_MSG_HIGH					0x00000004
+#define HFI_DEBUG_MSG_ERROR					0x00000008
+#define HFI_DEBUG_MSG_FATAL					0x00000010
+#define HFI_DEBUG_MSG_PERF					0x00000020
+
+#define HFI_DEBUG_MODE_QUEUE					0x00000001
+#define HFI_DEBUG_MODE_QDSS					0x00000002
+
+struct hfi_debug_config {
+	u32 debug_config;
+	u32 debug_mode;
+};
+
+struct hfi_enable {
+	u32 enable;
+};
+
+#define HFI_H264_DB_MODE_DISABLE			(HFI_COMMON_BASE + 0x1)
+#define HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY	\
+	(HFI_COMMON_BASE + 0x2)
+#define HFI_H264_DB_MODE_ALL_BOUNDARY		(HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_db_control {
+	u32 mode;
+	u32 slice_alpha_offset;
+	u32 slice_beta_offset;
+};
+
+#define HFI_H264_ENTROPY_CAVLC				(HFI_COMMON_BASE + 0x1)
+#define HFI_H264_ENTROPY_CABAC				(HFI_COMMON_BASE + 0x2)
+
+#define HFI_H264_CABAC_MODEL_0				(HFI_COMMON_BASE + 0x1)
+#define HFI_H264_CABAC_MODEL_1				(HFI_COMMON_BASE + 0x2)
+#define HFI_H264_CABAC_MODEL_2				(HFI_COMMON_BASE + 0x3)
+
+struct hfi_h264_entropy_control {
+	u32 entropy_mode;
+	u32 cabac_model;
+};
+
+struct hfi_frame_rate {
+	u32 buffer_type;
+	u32 frame_rate;
+};
+
+#define HFI_INTRA_REFRESH_NONE				(HFI_COMMON_BASE + 0x1)
+#define HFI_INTRA_REFRESH_CYCLIC			(HFI_COMMON_BASE + 0x2)
+#define HFI_INTRA_REFRESH_ADAPTIVE			(HFI_COMMON_BASE + 0x3)
+#define HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE	(HFI_COMMON_BASE + 0x4)
+#define HFI_INTRA_REFRESH_RANDOM			(HFI_COMMON_BASE + 0x5)
+
+struct hfi_intra_refresh {
+	u32 mode;
+	u32 air_mbs;
+	u32 air_ref;
+	u32 cir_mbs;
+};
+
+struct hfi_3x_intra_refresh {
+	u32 mode;
+	u32 mbs;
+};
+
+struct hfi_idr_period {
+	u32 idr_period;
+};
+
+struct hfi_operations_type {
+	u32 rotation;
+	u32 flip;
+};
+
+struct hfi_max_num_b_frames {
+	u32 max_num_b_frames;
+};
+
+struct hfi_vc1e_perf_cfg_type {
+	u32 search_range_x_subsampled[3];
+	u32 search_range_y_subsampled[3];
+};
+
+struct hfi_conceal_color {
+	u32 conceal_color;
+};
+
+struct hfi_intra_period {
+	u32 pframes;
+	u32 bframes;
+};
+
+struct hfi_mpeg4_header_extension {
+	u32 header_extension;
+};
+
+struct hfi_mpeg4_time_resolution {
+	u32 time_increment_resolution;
+};
+
+struct hfi_multi_stream {
+	u32 buffer_type;
+	u32 enable;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_3x_multi_stream {
+	u32 buffer_type;
+	u32 enable;
+};
+
+struct hfi_multi_view_format {
+	u32 views;
+	u32 rg_view_order[1];
+};
+
+#define HFI_MULTI_SLICE_OFF				(HFI_COMMON_BASE + 0x1)
+#define HFI_MULTI_SLICE_BY_MB_COUNT		(HFI_COMMON_BASE + 0x2)
+#define HFI_MULTI_SLICE_BY_BYTE_COUNT	(HFI_COMMON_BASE + 0x3)
+#define HFI_MULTI_SLICE_GOB				(HFI_COMMON_BASE + 0x4)
+
+struct hfi_multi_slice_control {
+	u32 multi_slice;
+	u32 slice_size;
+};
+
+#define HFI_NAL_FORMAT_STARTCODES			0x00000001
+#define HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER	0x00000002
+#define HFI_NAL_FORMAT_ONE_BYTE_LENGTH		0x00000004
+#define HFI_NAL_FORMAT_TWO_BYTE_LENGTH		0x00000008
+#define HFI_NAL_FORMAT_FOUR_BYTE_LENGTH		0x00000010
+
+struct hfi_nal_stream_format_supported {
+	u32 nal_stream_format_supported;
+};
+
+struct hfi_nal_stream_format_select {
+	u32 nal_stream_format_select;
+};
+#define HFI_PICTURE_TYPE_I					0x01
+#define HFI_PICTURE_TYPE_P					0x02
+#define HFI_PICTURE_TYPE_B					0x04
+#define HFI_PICTURE_TYPE_IDR					0x08
+#define HFI_PICTURE_TYPE_CRA					0x10
+
+struct hfi_profile_level {
+	u32 profile;
+	u32 level;
+};
+
+struct hfi_profile_level_supported {
+	u32 profile_count;
+	struct hfi_profile_level rg_profile_level[1];
+};
+
+struct hfi_quality_vs_speed {
+	u32 quality_vs_speed;
+};
+
+struct hfi_quantization {
+	u32 qp_i;
+	u32 qp_p;
+	u32 qp_b;
+	u32 layer_id;
+};
+
+struct hfi_initial_quantization {
+	u32 qp_i;
+	u32 qp_p;
+	u32 qp_b;
+	u32 init_qp_enable;
+};
+
+struct hfi_quantization_range {
+	u32 min_qp;
+	u32 max_qp;
+	u32 layer_id;
+};
+
+#define HFI_LTR_MODE_DISABLE	0x0
+#define HFI_LTR_MODE_MANUAL		0x1
+#define HFI_LTR_MODE_PERIODIC	0x2
+
+struct hfi_ltr_mode {
+	u32 ltr_mode;
+	u32 ltr_count;
+	u32 trust_mode;
+};
+
+struct hfi_ltr_use {
+	u32 ref_ltr;
+	u32 use_constrnt;
+	u32 frames;
+};
+
+struct hfi_ltr_mark {
+	u32 mark_frame;
+};
+
+struct hfi_frame_size {
+	u32 buffer_type;
+	u32 width;
+	u32 height;
+};
+
+struct hfi_video_signal_metadata {
+	u32 enable;
+	u32 video_format;
+	u32 video_full_range;
+	u32 color_description;
+	u32 color_primaries;
+	u32 transfer_characteristics;
+	u32 matrix_coeffs;
+};
+
+struct hfi_h264_vui_timing_info {
+	u32 enable;
+	u32 fixed_frame_rate;
+	u32 time_scale;
+};
+
+struct hfi_bit_depth {
+	u32 buffer_type;
+	u32 bit_depth;
+};
+
+struct hfi_picture_type {
+	u32 is_sync_frame;
+	u32 picture_type;
+};
+
+/* Base Offset for UBWC color formats  */
+#define HFI_COLOR_FORMAT_UBWC_BASE        (0x8000)
+/* Base Offset for 10-bit color formats */
+#define HFI_COLOR_FORMAT_10_BIT_BASE      (0x4000)
+
+#define HFI_COLOR_FORMAT_MONOCHROME			(HFI_COMMON_BASE + 0x1)
+#define HFI_COLOR_FORMAT_NV12				(HFI_COMMON_BASE + 0x2)
+#define HFI_COLOR_FORMAT_NV21				(HFI_COMMON_BASE + 0x3)
+#define HFI_COLOR_FORMAT_NV12_4x4TILE		(HFI_COMMON_BASE + 0x4)
+#define HFI_COLOR_FORMAT_NV21_4x4TILE		(HFI_COMMON_BASE + 0x5)
+#define HFI_COLOR_FORMAT_YUYV				(HFI_COMMON_BASE + 0x6)
+#define HFI_COLOR_FORMAT_YVYU				(HFI_COMMON_BASE + 0x7)
+#define HFI_COLOR_FORMAT_UYVY				(HFI_COMMON_BASE + 0x8)
+#define HFI_COLOR_FORMAT_VYUY				(HFI_COMMON_BASE + 0x9)
+#define HFI_COLOR_FORMAT_RGB565				(HFI_COMMON_BASE + 0xA)
+#define HFI_COLOR_FORMAT_BGR565				(HFI_COMMON_BASE + 0xB)
+#define HFI_COLOR_FORMAT_RGB888				(HFI_COMMON_BASE + 0xC)
+#define HFI_COLOR_FORMAT_BGR888				(HFI_COMMON_BASE + 0xD)
+#define HFI_COLOR_FORMAT_YUV444				(HFI_COMMON_BASE + 0xE)
+#define HFI_COLOR_FORMAT_RGBA8888			(HFI_COMMON_BASE + 0x10)
+
+#define HFI_COLOR_FORMAT_YUV420_TP10					\
+		(HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12)
+
+#define HFI_COLOR_FORMAT_NV12_UBWC					\
+		(HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_NV12)
+
+#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC				\
+		(HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_YUV420_TP10)
+
+#define  HFI_COLOR_FORMAT_RGBA8888_UBWC					\
+		(HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_RGBA8888)
+
+#define HFI_MAX_MATRIX_COEFFS 9
+#define HFI_MAX_BIAS_COEFFS 3
+#define HFI_MAX_LIMIT_COEFFS 6
+
+#define HFI_STATISTICS_MODE_DEFAULT 0x10
+#define HFI_STATISTICS_MODE_1 0x11
+#define HFI_STATISTICS_MODE_2 0x12
+#define HFI_STATISTICS_MODE_3 0x13
+
+struct hfi_uncompressed_format_select {
+	u32 buffer_type;
+	u32 format;
+};
+
+struct hfi_uncompressed_format_supported {
+	u32 buffer_type;
+	u32 format_entries;
+	u32 rg_format_info[1];
+};
+
+struct hfi_uncompressed_plane_actual {
+	u32 actual_stride;
+	u32 actual_plane_buffer_height;
+};
+
+struct hfi_uncompressed_plane_actual_info {
+	u32 buffer_type;
+	u32 num_planes;
+	struct hfi_uncompressed_plane_actual rg_plane_format[1];
+};
+
+struct hfi_uncompressed_plane_constraints {
+	u32 stride_multiples;
+	u32 max_stride;
+	u32 min_plane_buffer_height_multiple;
+	u32 buffer_alignment;
+};
+
+struct hfi_uncompressed_plane_info {
+	u32 format;
+	u32 num_planes;
+	struct hfi_uncompressed_plane_constraints rg_plane_format[1];
+};
+
+struct hfi_codec_supported {
+	u32 decoder_codec_supported;
+	u32 encoder_codec_supported;
+};
+
+struct hfi_properties_supported {
+	u32 num_properties;
+	u32 rg_properties[1];
+};
+
+struct hfi_max_sessions_supported {
+	u32 max_sessions;
+};
+
+struct hfi_vpe_color_space_conversion {
+	u32 csc_matrix[HFI_MAX_MATRIX_COEFFS];
+	u32 csc_bias[HFI_MAX_BIAS_COEFFS];
+	u32 csc_limit[HFI_MAX_LIMIT_COEFFS];
+};
+
+struct hfi_scs_threshold {
+	u32 threshold_value;
+};
+
+#define HFI_ROTATE_NONE					(HFI_COMMON_BASE + 0x1)
+#define HFI_ROTATE_90					(HFI_COMMON_BASE + 0x2)
+#define HFI_ROTATE_180					(HFI_COMMON_BASE + 0x3)
+#define HFI_ROTATE_270					(HFI_COMMON_BASE + 0x4)
+
+#define HFI_FLIP_NONE					(HFI_COMMON_BASE + 0x1)
+#define HFI_FLIP_HORIZONTAL				(HFI_COMMON_BASE + 0x2)
+#define HFI_FLIP_VERTICAL				(HFI_COMMON_BASE + 0x3)
+
+struct hfi_operations {
+	u32 rotate;
+	u32 flip;
+};
+
+#define HFI_RESOURCE_OCMEM 0x00000001
+
+struct hfi_resource_ocmem {
+	u32 size;
+	u32 mem;
+};
+
+struct hfi_resource_ocmem_requirement {
+	u32 session_domain;
+	u32 width;
+	u32 height;
+	u32 size;
+};
+
+struct hfi_resource_ocmem_requirement_info {
+	u32 num_entries;
+	struct hfi_resource_ocmem_requirement rg_requirements[1];
+};
+
+struct hfi_property_sys_image_version_info_type {
+	u32 string_size;
+	u8  str_image_version[1];
+};
+
+struct hfi_venc_config_advanced {
+	u8 pipe2d;
+	u8 hw_mode;
+	u8 low_delay_enforce;
+	u8 worker_vppsg_delay;
+	u32 close_gop;
+	u32 h264_constrain_intra_pred;
+	u32 h264_transform_8x8_flag;
+	u32 mpeg4_qpel_enable;
+	u32 multi_refp_en;
+	u32 qmatrix_en;
+	u8 vpp_info_packet_mode;
+	u8 ref_tile_mode;
+	u8 bitstream_flush_mode;
+	u32 vppsg_vspap_fb_sync_delay;
+	u32 rc_initial_delay;
+	u32 peak_bitrate_constraint;
+	u32 ds_display_frame_width;
+	u32 ds_display_frame_height;
+	u32 perf_tune_param_ptr;
+	u32 input_x_offset;
+	u32 input_y_offset;
+	u32 input_roi_width;
+	u32 input_roi_height;
+	u32 vsp_fifo_dma_sel;
+	u32 h264_num_ref_frames;
+};
+
+struct hfi_vbv_hrd_bufsize {
+	u32 buffer_size;
+};
+
+struct hfi_codec_mask_supported {
+	u32 codecs;
+	u32 video_domains;
+};
+
+struct hfi_seq_header_info {
+	u32 max_hader_len;
+};
+
+struct hfi_aspect_ratio {
+	u32 aspect_width;
+	u32 aspect_height;
+};
+
+#define HFI_IFRAME_SIZE_DEFAULT			(HFI_COMMON_BASE + 0x1)
+#define HFI_IFRAME_SIZE_MEDIUM			(HFI_COMMON_BASE + 0x2)
+#define HFI_IFRAME_SIZE_HIGH			(HFI_COMMON_BASE + 0x3)
+#define HFI_IFRAME_SIZE_UNLIMITED		(HFI_COMMON_BASE + 0x4)
+struct hfi_iframe_size {
+	u32 type;
+};
+
+#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM  (0)
+#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE  (1)
+#define HFI_MVC_BUFFER_LAYOUT_SEQ         (2)
+struct hfi_mvc_buffer_layout_descp_type {
+	u32    layout_type;
+	u32    bright_view_first;
+	u32    ngap;
+};
+
+
+#define HFI_CMD_SYS_COMMON_START			\
+(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \
+	+ 0x0000)
+#define HFI_CMD_SYS_INIT		(HFI_CMD_SYS_COMMON_START + 0x001)
+#define HFI_CMD_SYS_PC_PREP		(HFI_CMD_SYS_COMMON_START + 0x002)
+#define HFI_CMD_SYS_SET_RESOURCE	(HFI_CMD_SYS_COMMON_START + 0x003)
+#define HFI_CMD_SYS_RELEASE_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x004)
+#define HFI_CMD_SYS_SET_PROPERTY	(HFI_CMD_SYS_COMMON_START + 0x005)
+#define HFI_CMD_SYS_GET_PROPERTY	(HFI_CMD_SYS_COMMON_START + 0x006)
+#define HFI_CMD_SYS_SESSION_INIT	(HFI_CMD_SYS_COMMON_START + 0x007)
+#define HFI_CMD_SYS_SESSION_END		(HFI_CMD_SYS_COMMON_START + 0x008)
+#define HFI_CMD_SYS_SET_BUFFERS		(HFI_CMD_SYS_COMMON_START + 0x009)
+#define HFI_CMD_SYS_TEST_START		(HFI_CMD_SYS_COMMON_START + 0x100)
+
+#define HFI_CMD_SESSION_COMMON_START		\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET +	\
+	HFI_CMD_START_OFFSET + 0x1000)
+#define HFI_CMD_SESSION_SET_PROPERTY		\
+	(HFI_CMD_SESSION_COMMON_START + 0x001)
+#define HFI_CMD_SESSION_SET_BUFFERS			\
+	(HFI_CMD_SESSION_COMMON_START + 0x002)
+#define HFI_CMD_SESSION_GET_SEQUENCE_HEADER	\
+	(HFI_CMD_SESSION_COMMON_START + 0x003)
+
+#define HFI_MSG_SYS_COMMON_START			\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET +	\
+	HFI_MSG_START_OFFSET + 0x0000)
+#define HFI_MSG_SYS_INIT_DONE			(HFI_MSG_SYS_COMMON_START + 0x1)
+#define HFI_MSG_SYS_PC_PREP_DONE		(HFI_MSG_SYS_COMMON_START + 0x2)
+#define HFI_MSG_SYS_RELEASE_RESOURCE	(HFI_MSG_SYS_COMMON_START + 0x3)
+#define HFI_MSG_SYS_DEBUG			(HFI_MSG_SYS_COMMON_START + 0x4)
+#define HFI_MSG_SYS_SESSION_INIT_DONE	(HFI_MSG_SYS_COMMON_START + 0x6)
+#define HFI_MSG_SYS_SESSION_END_DONE	(HFI_MSG_SYS_COMMON_START + 0x7)
+#define HFI_MSG_SYS_IDLE		(HFI_MSG_SYS_COMMON_START + 0x8)
+#define HFI_MSG_SYS_COV                 (HFI_MSG_SYS_COMMON_START + 0x9)
+#define HFI_MSG_SYS_PROPERTY_INFO	(HFI_MSG_SYS_COMMON_START + 0xA)
+#define HFI_MSG_SESSION_SYNC_DONE      (HFI_MSG_SESSION_OX_START + 0xD)
+
+#define HFI_MSG_SESSION_COMMON_START		\
+	(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET +	\
+	HFI_MSG_START_OFFSET + 0x1000)
+#define HFI_MSG_EVENT_NOTIFY	(HFI_MSG_SESSION_COMMON_START + 0x1)
+#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE	\
+	(HFI_MSG_SESSION_COMMON_START + 0x2)
+
+#define HFI_CMD_SYS_TEST_SSR	(HFI_CMD_SYS_TEST_START + 0x1)
+#define HFI_TEST_SSR_SW_ERR_FATAL	0x1
+#define HFI_TEST_SSR_SW_DIV_BY_ZERO	0x2
+#define HFI_TEST_SSR_HW_WDOG_IRQ	0x3
+
+struct vidc_hal_cmd_pkt_hdr {
+	u32 size;
+	u32 packet_type;
+};
+
+struct vidc_hal_msg_pkt_hdr {
+	u32 size;
+	u32 packet;
+};
+
+struct vidc_hal_session_cmd_pkt {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_sys_init_packet {
+	u32 size;
+	u32 packet_type;
+	u32 arch_type;
+};
+
+struct hfi_cmd_sys_pc_prep_packet {
+	u32 size;
+	u32 packet_type;
+};
+
+struct hfi_cmd_sys_set_resource_packet {
+	u32 size;
+	u32 packet_type;
+	u32 resource_handle;
+	u32 resource_type;
+	u32 rg_resource_data[1];
+};
+
+struct hfi_cmd_sys_release_resource_packet {
+	u32 size;
+	u32 packet_type;
+	u32 resource_type;
+	u32 resource_handle;
+};
+
+struct hfi_cmd_sys_set_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_get_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_cmd_sys_session_init_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 session_domain;
+	u32 session_codec;
+};
+
+struct hfi_cmd_sys_session_end_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+};
+
+struct hfi_cmd_sys_set_buffers_packet {
+	u32 size;
+	u32 packet_type;
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 num_buffers;
+	u32 rg_buffer_addr[1];
+};
+
+struct hfi_cmd_session_set_property_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 num_properties;
+	u32 rg_property_data[0];
+};
+
+struct hfi_cmd_session_set_buffers_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 buffer_type;
+	u32 buffer_size;
+	u32 extra_data_size;
+	u32 min_buffer_size;
+	u32 num_buffers;
+	u32 rg_buffer_info[1];
+};
+
+struct hfi_cmd_session_get_sequence_header_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 buffer_len;
+	u32 packet_buffer;
+};
+
+struct hfi_cmd_session_sync_process_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 sync_id;
+	u32 rg_data[1];
+};
+
+struct hfi_msg_event_notify_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 event_id;
+	u32 event_data1;
+	u32 event_data2;
+	u32 rg_ext_event_data[1];
+};
+
+struct hfi_msg_release_buffer_ref_event_packet {
+	u32 packet_buffer;
+	u32 extra_data_buffer;
+	u32 output_tag;
+};
+
+struct hfi_msg_sys_init_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 error_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_pc_prep_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 error_type;
+};
+
+struct hfi_msg_sys_release_resource_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 resource_handle;
+	u32 error_type;
+};
+
+struct hfi_msg_sys_session_init_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 num_properties;
+	u32 rg_property_data[1];
+};
+
+struct hfi_msg_sys_session_end_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+};
+
+struct hfi_msg_session_get_sequence_header_done_packet {
+	u32 size;
+	u32 packet_type;
+	u32 session_id;
+	u32 error_type;
+	u32 header_len;
+	u32 sequence_header;
+};
+
+struct hfi_msg_sys_debug_packet {
+	u32 size;
+	u32 packet_type;
+	u32 msg_type;
+	u32 msg_size;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u8 rg_msg_data[1];
+};
+
+struct hfi_msg_sys_coverage_packet {
+	u32 size;
+	u32 packet_type;
+	u32 msg_size;
+	u32 time_stamp_hi;
+	u32 time_stamp_lo;
+	u8 rg_msg_data[1];
+};
+
+enum HFI_VENUS_QTBL_STATUS {
+	HFI_VENUS_QTBL_DISABLED = 0x00,
+	HFI_VENUS_QTBL_ENABLED = 0x01,
+	HFI_VENUS_QTBL_INITIALIZING = 0x02,
+	HFI_VENUS_QTBL_DEINITIALIZING = 0x03
+};
+
+enum HFI_VENUS_CTRL_INIT_STATUS {
+	HFI_VENUS_CTRL_NOT_INIT = 0x0,
+	HFI_VENUS_CTRL_READY = 0x1,
+	HFI_VENUS_CTRL_ERROR_FATAL = 0x2
+};
+
+struct hfi_sfr_struct {
+	u32 bufSize;
+	u8 rg_data[1];
+};
+
+struct hfi_cmd_sys_test_ssr_packet {
+	u32 size;
+	u32 packet_type;
+	u32 trigger_type;
+};
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_io.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_io.h
new file mode 100644
index 0000000..75f44ec
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_io.h
@@ -0,0 +1,195 @@
+/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __VIDC_HFI_IO_H__
+#define __VIDC_HFI_IO_H__
+
+#include <linux/io.h>
+
+#define VENUS_VCODEC_SS_CLOCK_HALT     0x0000000C
+#define VENUS_VPP_CORE_SW_RESET        0x00042004
+#define VENUS_VPP_CTRL_CTRL_RESET      0x00041008
+
+#define VIDC_VBIF_BASE_OFFS			0x00080000
+#define VIDC_VBIF_VERSION			(VIDC_VBIF_BASE_OFFS + 0x00)
+#define VIDC_VENUS_VBIF_DDR_OUT_MAX_BURST		\
+			(VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VENUS_VBIF_OCMEM_OUT_MAX_BURST		\
+			(VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VENUS_VBIF_ROUND_ROBIN_QOS_ARB		\
+			(VIDC_VBIF_BASE_OFFS + 0x124)
+
+#define VIDC_CPU_BASE_OFFS			0x000C0000
+#define VIDC_CPU_CS_BASE_OFFS		(VIDC_CPU_BASE_OFFS + 0x00012000)
+#define VIDC_CPU_IC_BASE_OFFS		(VIDC_CPU_BASE_OFFS + 0x0001F000)
+
+#define VIDC_CPU_CS_REMAP_OFFS		(VIDC_CPU_CS_BASE_OFFS + 0x00)
+#define VIDC_CPU_CS_TIMER_CONTROL	(VIDC_CPU_CS_BASE_OFFS + 0x04)
+#define VIDC_CPU_CS_A2HSOFTINTEN	(VIDC_CPU_CS_BASE_OFFS + 0x10)
+#define VIDC_CPU_CS_A2HSOFTINTENCLR	(VIDC_CPU_CS_BASE_OFFS + 0x14)
+#define VIDC_CPU_CS_A2HSOFTINT		(VIDC_CPU_CS_BASE_OFFS + 0x18)
+#define VIDC_CPU_CS_A2HSOFTINTCLR	(VIDC_CPU_CS_BASE_OFFS + 0x1C)
+#define VIDC_CPU_CS_SCIACMD			(VIDC_CPU_CS_BASE_OFFS + 0x48)
+
+/* HFI_CTRL_STATUS */
+#define VIDC_CPU_CS_SCIACMDARG0		(VIDC_CPU_CS_BASE_OFFS + 0x4C)
+#define VIDC_CPU_CS_SCIACMDARG0_BMSK	0xff
+#define VIDC_CPU_CS_SCIACMDARG0_SHFT	0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK	0xfe
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT	0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK	0x1
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT	0x0
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY           0x100
+#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK     0x40000000
+
+/* HFI_QTBL_INFO */
+#define VIDC_CPU_CS_SCIACMDARG1		(VIDC_CPU_CS_BASE_OFFS + 0x50)
+
+/* HFI_QTBL_ADDR */
+#define VIDC_CPU_CS_SCIACMDARG2		(VIDC_CPU_CS_BASE_OFFS + 0x54)
+
+/* HFI_VERSION_INFO */
+#define VIDC_CPU_CS_SCIACMDARG3		(VIDC_CPU_CS_BASE_OFFS + 0x58)
+#define VIDC_CPU_IC_IRQSTATUS		(VIDC_CPU_IC_BASE_OFFS + 0x00)
+#define VIDC_CPU_IC_FIQSTATUS		(VIDC_CPU_IC_BASE_OFFS + 0x04)
+#define VIDC_CPU_IC_RAWINTR			(VIDC_CPU_IC_BASE_OFFS + 0x08)
+#define VIDC_CPU_IC_INTSELECT		(VIDC_CPU_IC_BASE_OFFS + 0x0C)
+#define VIDC_CPU_IC_INTENABLE		(VIDC_CPU_IC_BASE_OFFS + 0x10)
+#define VIDC_CPU_IC_INTENACLEAR		(VIDC_CPU_IC_BASE_OFFS + 0x14)
+#define VIDC_CPU_IC_SOFTINT			(VIDC_CPU_IC_BASE_OFFS + 0x18)
+#define VIDC_CPU_IC_SOFTINT_H2A_BMSK	0x8000
+#define VIDC_CPU_IC_SOFTINT_H2A_SHFT	0xF
+#define VIDC_CPU_IC_SOFTINTCLEAR	(VIDC_CPU_IC_BASE_OFFS + 0x1C)
+
+/*---------------------------------------------------------------------------
+ * MODULE: vidc_wrapper
+ *--------------------------------------------------------------------------
+ */
+#define VIDC_WRAPPER_BASE_OFFS		0x000E0000
+
+#define VIDC_WRAPPER_HW_VERSION		(VIDC_WRAPPER_BASE_OFFS + 0x00)
+#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_MASK  0x78000000
+#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT 28
+#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_MASK  0xFFF0000
+#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT 16
+#define VIDC_WRAPPER_HW_VERSION_STEP_VERSION_MASK   0xFFFF
+#define VIDC_WRAPPER_CLOCK_CONFIG	(VIDC_WRAPPER_BASE_OFFS + 0x04)
+
+#define VIDC_WRAPPER_INTR_STATUS	(VIDC_WRAPPER_BASE_OFFS + 0x0C)
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK	0x10
+#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT	0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK	0x4
+#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT	0x2
+
+#define VIDC_WRAPPER_INTR_MASK		(VIDC_WRAPPER_BASE_OFFS + 0x10)
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK	0x10
+#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT	0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK	0x8
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_SHFT	0x3
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK	0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT	0x2
+
+#define VIDC_WRAPPER_INTR_CLEAR		(VIDC_WRAPPER_BASE_OFFS + 0x14)
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK	0x10
+#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT	0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK	0x4
+#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT	0x2
+
+#define VIDC_WRAPPER_VBIF_XIN_SW_RESET	(VIDC_WRAPPER_BASE_OFFS + 0x18)
+#define VIDC_WRAPPER_VBIF_XIN_STATUS	(VIDC_WRAPPER_BASE_OFFS + 0x1C)
+#define VIDC_WRAPPER_CPU_CLOCK_CONFIG	(VIDC_WRAPPER_BASE_OFFS + 0x2000)
+#define VIDC_WRAPPER_VBIF_XIN_CPU_SW_RESET	\
+				(VIDC_WRAPPER_BASE_OFFS + 0x2004)
+#define VIDC_WRAPPER_AXI_HALT		(VIDC_WRAPPER_BASE_OFFS + 0x2008)
+#define VIDC_WRAPPER_AXI_HALT_STATUS	(VIDC_WRAPPER_BASE_OFFS + 0x200C)
+#define VIDC_WRAPPER_CPU_CGC_DIS	(VIDC_WRAPPER_BASE_OFFS + 0x2010)
+#define VIDC_WRAPPER_CPU_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x2014)
+#define VIDC_VENUS_VBIF_CLK_ON		(VIDC_VBIF_BASE_OFFS + 0x4)
+#define VIDC_VBIF_IN_RD_LIM_CONF0       (VIDC_VBIF_BASE_OFFS + 0xB0)
+#define VIDC_VBIF_IN_RD_LIM_CONF1       (VIDC_VBIF_BASE_OFFS + 0xB4)
+#define VIDC_VBIF_IN_RD_LIM_CONF2       (VIDC_VBIF_BASE_OFFS + 0xB8)
+#define VIDC_VBIF_IN_RD_LIM_CONF3       (VIDC_VBIF_BASE_OFFS + 0xBC)
+#define VIDC_VBIF_IN_WR_LIM_CONF0       (VIDC_VBIF_BASE_OFFS + 0xC0)
+#define VIDC_VBIF_IN_WR_LIM_CONF1       (VIDC_VBIF_BASE_OFFS + 0xC4)
+#define VIDC_VBIF_IN_WR_LIM_CONF2       (VIDC_VBIF_BASE_OFFS + 0xC8)
+#define VIDC_VBIF_IN_WR_LIM_CONF3       (VIDC_VBIF_BASE_OFFS + 0xCC)
+#define VIDC_VBIF_OUT_RD_LIM_CONF0      (VIDC_VBIF_BASE_OFFS + 0xD0)
+#define VIDC_VBIF_OUT_WR_LIM_CONF0      (VIDC_VBIF_BASE_OFFS + 0xD4)
+#define VIDC_VBIF_DDR_OUT_MAX_BURST     (VIDC_VBIF_BASE_OFFS + 0xD8)
+#define VIDC_VBIF_OCMEM_OUT_MAX_BURST   (VIDC_VBIF_BASE_OFFS + 0xDC)
+#define VIDC_VBIF_DDR_ARB_CONF0         (VIDC_VBIF_BASE_OFFS + 0xF4)
+#define VIDC_VBIF_DDR_ARB_CONF1         (VIDC_VBIF_BASE_OFFS + 0xF8)
+#define VIDC_VBIF_ROUND_ROBIN_QOS_ARB   (VIDC_VBIF_BASE_OFFS + 0x124)
+#define VIDC_VBIF_OUT_AXI_AOOO_EN       (VIDC_VBIF_BASE_OFFS + 0x178)
+#define VIDC_VBIF_OUT_AXI_AOOO          (VIDC_VBIF_BASE_OFFS + 0x17C)
+#define VIDC_VBIF_ARB_CTL               (VIDC_VBIF_BASE_OFFS + 0xF0)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF0 (VIDC_VBIF_BASE_OFFS + 0x160)
+#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF1 (VIDC_VBIF_BASE_OFFS + 0x164)
+#define VIDC_VBIF_ADDR_TRANS_EN         (VIDC_VBIF_BASE_OFFS + 0xC00)
+#define VIDC_VBIF_AT_OLD_BASE           (VIDC_VBIF_BASE_OFFS + 0xC04)
+#define VIDC_VBIF_AT_OLD_HIGH           (VIDC_VBIF_BASE_OFFS + 0xC08)
+#define VIDC_VBIF_AT_NEW_BASE           (VIDC_VBIF_BASE_OFFS + 0xC10)
+#define VIDC_VBIF_AT_NEW_HIGH           (VIDC_VBIF_BASE_OFFS + 0xC18)
+#define VENUS_VBIF_XIN_HALT_CTRL1   (VIDC_VBIF_BASE_OFFS + 0x204)
+#define VENUS_VBIF_AXI_HALT_CTRL0   (VIDC_VBIF_BASE_OFFS + 0x208)
+#define VENUS_VBIF_AXI_HALT_CTRL1   (VIDC_VBIF_BASE_OFFS + 0x20C)
+
+#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ		BIT(0)
+#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK		BIT(0)
+#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US		500000
+
+#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
+	(VIDC_WRAPPER_BASE_OFFS + 0x20)
+#define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \
+	(VIDC_WRAPPER_BASE_OFFS + 0x24)
+#define VIDC_VENUS_WRAPPER_MMCC_VENUS0_POWER_STATUS \
+	(VIDC_WRAPPER_BASE_OFFS + 0x44)
+
+#define VIDC_CTRL_INIT 0x000D2048
+#define VIDC_CTRL_INIT_RESERVED_BITS31_1__M 0xFFFFFFFE
+#define VIDC_CTRL_INIT_RESERVED_BITS31_1__S 1
+#define VIDC_CTRL_INIT_CTRL__M 0x00000001
+#define VIDC_CTRL_INIT_CTRL__S 0
+
+#define VIDC_CTRL_STATUS 0x000D204C
+#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__M 0xFFFFFF00
+#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__S 8
+#define VIDC_CTRL_ERROR_STATUS__M             0x000000FE
+#define VIDC_CTRL_ERROR_STATUS__S             1
+#define VIDC_CTRL_INIT_STATUS__M              0x00000001
+#define VIDC_CTRL_INIT_STATUS__S              0
+
+#define VIDC_QTBL_INFO 0x000D2050
+#define VIDC_QTBL_HOSTID__M 0xFF000000
+#define VIDC_QTBL_HOSTID__S 24
+#define VIDC_QTBL_INFO_RESERVED_BITS23_8__M 0x00FFFF00
+#define VIDC_QTBL_INFO_RESERVED_BITS23_8__S 8
+#define VIDC_QTBL_STATUS__M 0x000000FF
+#define VIDC_QTBL_STATUS__S 0
+
+#define VIDC_QTBL_ADDR 0x000D2054
+
+#define VIDC_VERSION_INFO 0x000D2058
+#define VIDC_VERSION_INFO_MAJOR__M  0xF0000000
+#define VIDC_VERSION_INFO_MAJOR__S  28
+#define VIDC_VERSION_INFO_MINOR__M  0x0FFFFFE0
+#define VIDC_VERSION_INFO_MINOR__S  5
+#define VIDC_VERSION_INFO_BRANCH__M 0x0000001F
+#define VIDC_VERSION_INFO_BRANCH__S 0
+
+#define VIDC_SFR_ADDR 0x000D205C
+#define VIDC_MMAP_ADDR 0x000D2060
+#define VIDC_UC_REGION_ADDR 0x000D2064
+#define VIDC_UC_REGION_SIZE 0x000D2068
+
+#endif
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/Kconfig b/drivers/media/platform/msm/vidc_3x/vmem/Kconfig
new file mode 100644
index 0000000..26a609e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/Kconfig
@@ -0,0 +1,3 @@
+menuconfig MSM_VIDC_VMEM
+	bool "Qualcomm Technologies Inc MSM VMEM driver"
+	depends on ARCH_MSM && MSM_VIDC_V4L2
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/Makefile b/drivers/media/platform/msm/vidc_3x/vmem/Makefile
new file mode 100644
index 0000000..713b92e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MSM_VIDC_VMEM) := vmem.o \
+				vmem_debugfs.o
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/vmem.c b/drivers/media/platform/msm/vidc_3x/vmem/vmem.c
new file mode 100644
index 0000000..f4f8977
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem.c
@@ -0,0 +1,698 @@
+/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/msm-bus.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "vmem.h"
+#include "vmem_debugfs.h"
+
+/* Registers */
+#define OCIMEM_BASE(v)               ((uint8_t *)(v)->reg.base)
+#define OCIMEM_HW_VERSION(v)         (OCIMEM_BASE(v) + 0x00)
+#define OCIMEM_HW_PROFILE(v)         (OCIMEM_BASE(v) + 0x04)
+#define OCIMEM_GEN_CTL(v)            (OCIMEM_BASE(v) + 0x08)
+#define OCIMEM_GEN_STAT(v)           (OCIMEM_BASE(v) + 0x0C)
+#define OCIMEM_INTC_CLR(v)           (OCIMEM_BASE(v) + 0x10)
+#define OCIMEM_INTC_MASK(v)          (OCIMEM_BASE(v) + 0x14)
+#define OCIMEM_INTC_STAT(v)          (OCIMEM_BASE(v) + 0x18)
+#define OCIMEM_OSW_STATUS(v)         (OCIMEM_BASE(v) + 0x1C)
+#define OCIMEM_PSCGC_TIMERS(v)       (OCIMEM_BASE(v) + 0x34)
+#define OCIMEM_PSCGC_STAT(v)         (OCIMEM_BASE(v) + 0x38)
+#define OCIMEM_PSCGC_M0_M7_CTL(v)    (OCIMEM_BASE(v) + 0x3C)
+#define OCIMEM_ERR_ADDRESS(v)        (OCIMEM_BASE(v) + 0x60)
+#define OCIMEM_AXI_ERR_SYNDROME(v)   (OCIMEM_BASE(v) + 0x64)
+#define OCIMEM_DEBUG_CTL(v)          (OCIMEM_BASE(v) + 0x68)
+
+/*
+ * Helper macro to help out with masks and shifts for values packed into
+ * registers.
+ */
+#define DECLARE_TYPE(__type, __end, __start)                                   \
+	static const unsigned int __type##_BITS = (__end) - (__start) + 1;     \
+	static const unsigned int __type##_SHIFT = (__start);                  \
+	static const unsigned int __type##_MASK = GENMASK((__end), (__start)); \
+	static inline unsigned int __type(uint32_t val)                        \
+	{                                                                      \
+		return (val & __type##_MASK) >> __type##_SHIFT;                \
+	}                                                                      \
+	static inline uint32_t __type##_UPDATE(unsigned int val)               \
+	{                                                                      \
+		return (val << __type##_SHIFT) & __type##_MASK;                \
+	}
+
+/* Register masks */
+/* OCIMEM_PSCGC_M0_M7_CTL */
+DECLARE_TYPE(BANK0_STATE, 3, 0);
+DECLARE_TYPE(BANK1_STATE, 7, 4);
+DECLARE_TYPE(BANK2_STATE, 11, 8);
+DECLARE_TYPE(BANK3_STATE, 15, 12);
+/* OCIMEM_PSCGC_TIMERS */
+DECLARE_TYPE(TIMERS_WAKEUP, 3, 0);
+DECLARE_TYPE(TIMERS_SLEEP, 11, 8);
+/* OCIMEM_HW_VERSION */
+DECLARE_TYPE(VERSION_STEP, 15, 0);
+DECLARE_TYPE(VERSION_MINOR, 27, 16);
+DECLARE_TYPE(VERSION_MAJOR, 31, 28);
+/* OCIMEM_HW_PROFILE */
+DECLARE_TYPE(PROFILE_BANKS, 16, 12);
+/* OCIMEM_AXI_ERR_SYNDROME */
+DECLARE_TYPE(ERR_SYN_ATID, 14, 8);
+DECLARE_TYPE(ERR_SYN_AMID, 23, 16);
+DECLARE_TYPE(ERR_SYN_APID, 28, 24);
+DECLARE_TYPE(ERR_SYN_ABID, 31, 29);
+/* OCIMEM_INTC_MASK */
+DECLARE_TYPE(AXI_ERR_INT, 0, 0);
+
+/* Internal stuff */
+#define MAX_BANKS 4
+
+enum bank_state {
+	BANK_STATE_NORM_PASSTHRU = 0,
+	BANK_STATE_NORM_FORCE_CORE_ON = 2,
+	BANK_STATE_NORM_FORCE_PERIPH_ON = 1,
+	BANK_STATE_NORM_FORCE_ALL_ON = 3,
+	BANK_STATE_SLEEP_RET = 6,
+	BANK_STATE_SLEEP_RET_PERIPH_ON = 7,
+	BANK_STATE_SLEEP_NO_RET = 4,
+};
+
+struct vmem {
+	int irq;
+	int num_banks;
+	int bank_size;
+	struct {
+		struct resource *resource;
+		void __iomem *base;
+	} reg, mem;
+	struct regulator *vdd;
+	struct {
+		const char *name;
+		struct clk *clk;
+	} *clocks;
+	int num_clocks;
+	struct {
+		struct msm_bus_scale_pdata *pdata;
+		uint32_t priv;
+	} bus;
+	atomic_t alloc_count;
+	struct dentry *debugfs_root;
+};
+
+static struct vmem *vmem;
+
+static inline u32 __readl(void * __iomem addr)
+{
+	u32 value = 0;
+
+	pr_debug("read %pK ", addr);
+	value = readl_relaxed(addr);
+	pr_debug("-> %08x\n", value);
+
+	return value;
+}
+
+static inline void __writel(u32 val, void * __iomem addr)
+{
+	pr_debug("write %08x -> %pK\n", val, addr);
+	writel_relaxed(val, addr);
+	/*
+	 * Commit all writes via a mem barrier, as subsequent __readl()
+	 * will depend on the state that's set via __writel().
+	 */
+	mb();
+}
+
+static inline void __wait_timer(struct vmem *v, bool wakeup)
+{
+	uint32_t ticks = 0;
+	unsigned int (*timer)(uint32_t) = wakeup ?
+		TIMERS_WAKEUP : TIMERS_SLEEP;
+
+	ticks = timer(__readl(OCIMEM_PSCGC_TIMERS(v)));
+
+	/* Sleep for `ticks` nanoseconds as per h/w spec */
+	ndelay(ticks);
+}
+
+static inline void __wait_wakeup(struct vmem *v)
+{
+	return __wait_timer(v, true);
+}
+
+static inline void __wait_sleep(struct vmem *v)
+{
+	return __wait_timer(v, false);
+}
+
+static inline int __power_on(struct vmem *v)
+{
+	int rc = 0, c = 0;
+
+	rc = msm_bus_scale_client_update_request(v->bus.priv, 1);
+	if (rc) {
+		pr_err("Failed to vote for buses (%d)\n", rc);
+		goto exit;
+	}
+	pr_debug("Voted for buses\n");
+
+	rc = regulator_enable(v->vdd);
+	if (rc) {
+		pr_err("Failed to power on gdsc (%d)", rc);
+		goto unvote_bus;
+	}
+	pr_debug("Enabled regulator vdd\n");
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		rc = clk_prepare_enable(v->clocks[c].clk);
+		if (rc) {
+			pr_err("Failed to enable %s clock (%d)\n",
+					v->clocks[c].name, rc);
+			goto disable_clocks;
+		}
+
+		pr_debug("Enabled clock %s\n", v->clocks[c].name);
+	}
+
+	return 0;
+disable_clocks:
+	for (--c; c >= 0; c--)
+		clk_disable_unprepare(v->clocks[c].clk);
+	regulator_disable(v->vdd);
+unvote_bus:
+	msm_bus_scale_client_update_request(v->bus.priv, 0);
+exit:
+	return rc;
+}
+
+static inline int __power_off(struct vmem *v)
+{
+	int c = 0;
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		clk_disable_unprepare(v->clocks[c].clk);
+		pr_debug("Disabled clock %s\n", v->clocks[c].name);
+	}
+
+	regulator_disable(v->vdd);
+	pr_debug("Disabled regulator vdd\n");
+
+	msm_bus_scale_client_update_request(v->bus.priv, 0);
+	pr_debug("Unvoted for buses\n");
+
+	return 0;
+}
+
+static inline enum bank_state __bank_get_state(struct vmem *v,
+		unsigned int bank)
+{
+	unsigned int (*func[MAX_BANKS])(uint32_t) = {
+		BANK0_STATE, BANK1_STATE, BANK2_STATE, BANK3_STATE
+	};
+
+	WARN_ON(bank >= ARRAY_SIZE(func));
+	return func[bank](__readl(OCIMEM_PSCGC_M0_M7_CTL(v)));
+}
+
+static inline void __bank_set_state(struct vmem *v, unsigned int bank,
+		enum bank_state state)
+{
+	uint32_t bank_state = 0;
+	struct {
+		uint32_t (*update)(unsigned int);
+		uint32_t mask;
+	} banks[MAX_BANKS] = {
+		{BANK0_STATE_UPDATE, BANK0_STATE_MASK},
+		{BANK1_STATE_UPDATE, BANK1_STATE_MASK},
+		{BANK2_STATE_UPDATE, BANK2_STATE_MASK},
+		{BANK3_STATE_UPDATE, BANK3_STATE_MASK},
+	};
+
+	WARN_ON(bank >= ARRAY_SIZE(banks));
+
+	bank_state = __readl(OCIMEM_PSCGC_M0_M7_CTL(v));
+	bank_state &= ~banks[bank].mask;
+	bank_state |= banks[bank].update(state);
+
+	__writel(bank_state, OCIMEM_PSCGC_M0_M7_CTL(v));
+}
+
+static inline void __toggle_interrupts(struct vmem *v, bool enable)
+{
+	uint32_t ints = __readl(OCIMEM_INTC_MASK(v)),
+		mask = AXI_ERR_INT_MASK,
+		update = AXI_ERR_INT_UPDATE(!enable);
+
+	ints &= ~mask;
+	ints |= update;
+
+	__writel(ints, OCIMEM_INTC_MASK(v));
+}
+
+static void __enable_interrupts(struct vmem *v)
+{
+	pr_debug("Enabling interrupts\n");
+	enable_irq(v->irq);
+	__toggle_interrupts(v, true);
+}
+
+static void __disable_interrupts(struct vmem *v)
+{
+	pr_debug("Disabling interrupts\n");
+	__toggle_interrupts(v, false);
+	disable_irq_nosync(v->irq);
+}
+
+/**
+ * vmem_allocate: - Allocates memory from VMEM.  Allocations have a few
+ * restrictions: only allocations of the entire VMEM memory are allowed, and
+ * , as a result, only single outstanding allocations are allowed.
+ *
+ * @size: amount of bytes to allocate
+ * @addr: A pointer to phys_addr_t where the physical address of the memory
+ * allocated is stored.
+ *
+ * Return: 0 in case of successful allocation (i.e. *addr != NULL). -ENOTSUPP,
+ * if platform doesn't support VMEM. -EEXIST, if there are outstanding VMEM
+ * allocations.  -ENOMEM, if platform can't support allocation of `size` bytes.
+ * -EAGAIN, if `size` does not allocate the entire VMEM region.  -EIO in case of
+ * internal errors.
+ */
+int vmem_allocate(size_t size, phys_addr_t *addr)
+{
+	int rc = 0, c = 0;
+	resource_size_t max_size = 0;
+
+	if (!vmem) {
+		pr_err("No vmem, try rebooting your device\n");
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+	if (!size) {
+		pr_err("%s Invalid size %ld\n", __func__, size);
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	max_size = resource_size(vmem->mem.resource);
+
+	if (atomic_read(&vmem->alloc_count)) {
+		pr_err("Only single allocations allowed for vmem\n");
+		rc = -EEXIST;
+		goto exit;
+	} else if (size > max_size) {
+		pr_err("Out of memory, have max %pa\n", &max_size);
+		rc = -ENOMEM;
+		goto exit;
+	} else if (size != max_size) {
+		pr_err("Only support allocations of size %pa\n", &max_size);
+		rc = -EAGAIN;
+		goto exit;
+	}
+
+	rc = __power_on(vmem);
+	if (rc) {
+		pr_err("Failed power on (%d)\n", rc);
+		goto exit;
+	}
+
+	WARN_ON(vmem->num_banks != DIV_ROUND_UP(size, vmem->bank_size));
+
+	/* Turn on the necessary banks */
+	for (c = 0; c < vmem->num_banks; ++c) {
+		__bank_set_state(vmem, c, BANK_STATE_NORM_FORCE_CORE_ON);
+		__wait_wakeup(vmem);
+	}
+
+	/* Enable interrupts to detect faults */
+	__enable_interrupts(vmem);
+
+	atomic_inc(&vmem->alloc_count);
+	*addr = (phys_addr_t)vmem->mem.resource->start;
+	return 0;
+exit:
+	return rc;
+}
+
+/**
+ * vmem_free: - Frees the memory allocated via vmem_allocate.  Undefined
+ * behaviour if to_free is a not a pointer returned via vmem_allocate
+ */
+void vmem_free(phys_addr_t to_free)
+{
+	int c = 0;
+
+	if (!to_free || !vmem)
+		return;
+
+	WARN_ON(atomic_read(&vmem->alloc_count) == 0);
+
+	for (c = 0; c < vmem->num_banks; ++c) {
+		enum bank_state curr_state = __bank_get_state(vmem, c);
+
+		if (curr_state != BANK_STATE_NORM_FORCE_CORE_ON) {
+			pr_warn("When freeing, expected bank state to be %d, was instead %d\n",
+					BANK_STATE_NORM_FORCE_CORE_ON,
+					curr_state);
+		}
+
+		__bank_set_state(vmem, c, BANK_STATE_SLEEP_NO_RET);
+	}
+
+	__disable_interrupts(vmem);
+	__power_off(vmem);
+	atomic_dec(&vmem->alloc_count);
+}
+
+struct vmem_interrupt_cookie {
+	struct vmem *vmem;
+	struct work_struct work;
+};
+
+static void __irq_helper(struct work_struct *work)
+{
+	struct vmem_interrupt_cookie *cookie = container_of(work,
+			struct vmem_interrupt_cookie, work);
+	struct vmem *v = cookie->vmem;
+	unsigned int stat, gen_stat, pscgc_stat, err_addr_abs,
+		err_addr_rel, err_syn;
+
+	stat = __readl(OCIMEM_INTC_STAT(v));
+	gen_stat = __readl(OCIMEM_GEN_CTL(v));
+	pscgc_stat = __readl(OCIMEM_PSCGC_STAT(v));
+
+	err_addr_abs = __readl(OCIMEM_ERR_ADDRESS(v));
+	err_addr_rel = v->mem.resource->start - err_addr_abs;
+
+	err_syn = __readl(OCIMEM_AXI_ERR_SYNDROME(v));
+
+	pr_crit("Detected a fault on VMEM:\n");
+	pr_cont("\tinterrupt status: %x\n", stat);
+	pr_cont("\tgeneral status: %x\n", gen_stat);
+	pr_cont("\tmemory status: %x\n", pscgc_stat);
+	pr_cont("\tfault address: %x (absolute), %x (relative)\n",
+			err_addr_abs, err_addr_rel);
+	pr_cont("\tfault bank: %x\n", err_addr_rel / v->bank_size);
+	pr_cont("\tfault core: %u (mid), %u (pid), %u (bid)\n",
+			ERR_SYN_AMID(err_syn), ERR_SYN_APID(err_syn),
+			ERR_SYN_ABID(err_syn));
+
+	/* Clear the interrupt */
+	__writel(0, OCIMEM_INTC_CLR(v));
+
+	__enable_interrupts(v);
+}
+
+static struct vmem_interrupt_cookie interrupt_cookie;
+
+static irqreturn_t __irq_handler(int irq, void *cookie)
+{
+	struct vmem *v = cookie;
+	irqreturn_t status = __readl(OCIMEM_INTC_STAT(vmem)) ?
+		IRQ_HANDLED : IRQ_NONE;
+
+	if (status != IRQ_NONE) {
+		/* Mask further interrupts while handling this one */
+		__disable_interrupts(v);
+
+		interrupt_cookie.vmem = v;
+		INIT_WORK(&interrupt_cookie.work, __irq_helper);
+		schedule_work(&interrupt_cookie.work);
+	}
+
+	return status;
+}
+
+static inline int __init_resources(struct vmem *v,
+		struct platform_device *pdev)
+{
+	int rc = 0, c = 0;
+
+	v->irq = platform_get_irq(pdev, 0);
+	if (v->irq < 0) {
+		rc = v->irq;
+		pr_err("Failed to get irq (%d)\n", rc);
+		v->irq = 0;
+		goto exit;
+	}
+
+	/* Registers and memory */
+	v->reg.resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"reg-base");
+	if (!v->reg.resource) {
+		pr_err("Failed to find register base\n");
+		rc = -ENOENT;
+		goto exit;
+	}
+
+	v->reg.base = devm_ioremap_resource(&pdev->dev, v->reg.resource);
+	if (IS_ERR_OR_NULL(v->reg.base)) {
+		rc = PTR_ERR(v->reg.base) ?: -EIO;
+		pr_err("Failed to map register base into kernel (%d)\n", rc);
+		v->reg.base = NULL;
+		goto exit;
+	}
+
+	pr_debug("Register range: %pa -> %pa\n", &v->reg.resource->start,
+			&v->reg.resource->end);
+
+	v->mem.resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"mem-base");
+	if (!v->mem.resource) {
+		pr_err("Failed to find memory base\n");
+		rc = -ENOENT;
+		goto exit;
+	}
+
+	v->mem.base = NULL;
+	pr_debug("Memory range: %pa -> %pa\n", &v->mem.resource->start,
+			&v->mem.resource->end);
+
+	/* Buses, Clocks & Regulators*/
+	v->num_clocks = of_property_count_strings(pdev->dev.of_node,
+			"clock-names");
+	if (v->num_clocks <= 0) {
+		pr_err("Can't find any clocks\n");
+		goto exit;
+	}
+
+	v->clocks = devm_kzalloc(&pdev->dev, sizeof(*v->clocks) * v->num_clocks,
+			GFP_KERNEL);
+	if (!v->clocks) {
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		const char *name = NULL;
+		struct clk *temp = NULL;
+
+		of_property_read_string_index(pdev->dev.of_node, "clock-names",
+				c, &name);
+		temp = devm_clk_get(&pdev->dev, name);
+		if (IS_ERR_OR_NULL(temp)) {
+			rc = PTR_ERR(temp) ?: -ENOENT;
+			pr_err("Failed to find %s (%d)\n", name, rc);
+			goto exit;
+		}
+
+		v->clocks[c].clk = temp;
+		v->clocks[c].name = name;
+	}
+
+	v->vdd = devm_regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR_OR_NULL(v->vdd)) {
+		rc = PTR_ERR(v->vdd) ?: -ENOENT;
+		pr_err("Failed to find regulator (vdd) (%d)\n", rc);
+		goto exit;
+	}
+
+	v->bus.pdata = msm_bus_cl_get_pdata(pdev);
+	if (IS_ERR_OR_NULL(v->bus.pdata)) {
+		rc = PTR_ERR(v->bus.pdata) ?: -ENOENT;
+		pr_err("Failed to find bus vectors (%d)\n", rc);
+		goto exit;
+	}
+
+	v->bus.priv = msm_bus_scale_register_client(v->bus.pdata);
+	if (!v->bus.priv) {
+		rc = -EBADHANDLE;
+		pr_err("Failed to register bus client\n");
+		goto free_pdata;
+	}
+
+	/* Misc. */
+	rc = of_property_read_u32(pdev->dev.of_node, "qcom,bank-size",
+			&v->bank_size);
+	if (rc || !v->bank_size) {
+		pr_err("Failed reading (or found invalid) qcom,bank-size in %s (%d)\n",
+				of_node_full_name(pdev->dev.of_node), rc);
+		rc = -ENOENT;
+		goto free_pdata;
+	}
+
+	v->num_banks = resource_size(v->mem.resource) / v->bank_size;
+
+	pr_debug("Found configuration with %d banks with size %d\n",
+			v->num_banks, v->bank_size);
+
+	return 0;
+free_pdata:
+	msm_bus_cl_clear_pdata(v->bus.pdata);
+exit:
+	return rc;
+}
+
+static inline void __uninit_resources(struct vmem *v,
+		struct platform_device *pdev)
+{
+	int c = 0;
+
+	msm_bus_cl_clear_pdata(v->bus.pdata);
+	v->bus.pdata = NULL;
+	v->bus.priv = 0;
+
+	for (c = 0; c < v->num_clocks; ++c) {
+		v->clocks[c].clk = NULL;
+		v->clocks[c].name = NULL;
+	}
+
+	v->vdd = NULL;
+}
+
+static int vmem_probe(struct platform_device *pdev)
+{
+	uint32_t version = 0, num_banks = 0, rc = 0;
+	struct vmem *v = NULL;
+
+	if (vmem) {
+		pr_err("Only one instance of %s allowed", pdev->name);
+		return -EEXIST;
+	}
+
+	v = devm_kzalloc(&pdev->dev, sizeof(*v), GFP_KERNEL);
+	if (!v)
+		return -ENOMEM;
+
+	rc = __init_resources(v, pdev);
+	if (rc) {
+		pr_err("Failed to read resources\n");
+		goto exit;
+	}
+
+	/*
+	 * For now, only support up to 4 banks. It's unrealistic that VMEM has
+	 * more banks than that (even in the future).
+	 */
+	if (v->num_banks > MAX_BANKS) {
+		pr_err("Number of banks (%d) exceeds what's supported (%d)\n",
+			v->num_banks, MAX_BANKS);
+		rc = -ENOTSUPP;
+		goto exit;
+	}
+
+	/* Cross check the platform resources with what's available on chip */
+	rc = __power_on(v);
+	if (rc) {
+		pr_err("Failed to power on (%d)\n", rc);
+		goto exit;
+	}
+
+	version = __readl(OCIMEM_HW_VERSION(v));
+	pr_debug("v%d.%d.%d\n", VERSION_MAJOR(version), VERSION_MINOR(version),
+			VERSION_STEP(version));
+
+	num_banks = PROFILE_BANKS(__readl(OCIMEM_HW_PROFILE(v)));
+	pr_debug("Found %d banks on chip\n", num_banks);
+	if (v->num_banks != num_banks) {
+		pr_err("Platform configuration of %d banks differs from what's available on chip (%d)\n",
+				v->num_banks, num_banks);
+		rc = -EINVAL;
+		goto disable_clocks;
+	}
+
+	rc = devm_request_irq(&pdev->dev, v->irq, __irq_handler,
+			IRQF_TRIGGER_HIGH, "vmem", v);
+	if (rc) {
+		pr_err("Failed to setup irq (%d)\n", rc);
+		goto disable_clocks;
+	}
+
+	__disable_interrupts(v);
+
+	/* Everything good so far, set up the global context and debug hooks */
+	pr_info("Up and running with %d banks of memory from %pR\n",
+			v->num_banks, &v->mem.resource);
+	v->debugfs_root = vmem_debugfs_init(pdev);
+	platform_set_drvdata(pdev, v);
+	vmem = v;
+
+disable_clocks:
+	__power_off(v);
+exit:
+	return rc;
+}
+
+static int vmem_remove(struct platform_device *pdev)
+{
+	struct vmem *v = platform_get_drvdata(pdev);
+
+	WARN_ON(v != vmem);
+
+	__uninit_resources(v, pdev);
+	vmem_debugfs_deinit(v->debugfs_root);
+	vmem = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id vmem_of_match[] = {
+	{.compatible = "qcom,msm-vmem"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, vmem_of_match);
+
+static struct platform_driver vmem_driver = {
+	.probe = vmem_probe,
+	.remove = vmem_remove,
+	.driver = {
+		.name = "msm_vidc_vmem",
+		.owner = THIS_MODULE,
+		.of_match_table = vmem_of_match,
+	},
+};
+
+static int __init vmem_init(void)
+{
+	return platform_driver_register(&vmem_driver);
+}
+
+static void __exit vmem_exit(void)
+{
+	platform_driver_unregister(&vmem_driver);
+}
+
+module_init(vmem_init);
+module_exit(vmem_exit);
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/vmem.h b/drivers/media/platform/msm/vidc_3x/vmem/vmem.h
new file mode 100644
index 0000000..f874aa5
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __VMEM_H__
+#define __VMEM_H__
+
+#ifdef CONFIG_MSM_VIDC_VMEM
+
+int vmem_allocate(size_t size, phys_addr_t *addr);
+void vmem_free(phys_addr_t to_free);
+
+#else
+
+static inline int vmem_allocate(size_t size, phys_addr_t *addr)
+{
+	return -ENODEV;
+}
+
+static inline void vmem_free(phys_addr_t to_free)
+{
+}
+
+#endif
+
+#endif /* __VMEM_H__ */
diff --git a/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.c b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.c
new file mode 100644
index 0000000..358b75e
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include "vmem.h"
+
+struct vmem_debugfs_cookie {
+	phys_addr_t addr;
+	size_t size;
+};
+
+static int __vmem_alloc_get(void *priv, u64 *val)
+{
+	struct vmem_debugfs_cookie *cookie = priv;
+
+	*val = cookie->size;
+	return 0;
+}
+
+static int __vmem_alloc_set(void *priv, u64 val)
+{
+	struct vmem_debugfs_cookie *cookie = priv;
+	int rc = 0;
+
+	switch (val) {
+	case 0: /* free */
+		vmem_free(cookie->addr);
+		cookie->size = 0;
+		break;
+	default:
+		rc = vmem_allocate(val, &cookie->addr);
+		cookie->size = val;
+		break;
+	}
+
+	return rc;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_vmem_alloc, __vmem_alloc_get,
+		__vmem_alloc_set, "%llu");
+
+struct dentry *vmem_debugfs_init(struct platform_device *pdev)
+{
+	struct vmem_debugfs_cookie *alloc_cookie = NULL;
+	struct dentry *debugfs_root = NULL;
+
+	alloc_cookie = devm_kzalloc(&pdev->dev, sizeof(*alloc_cookie),
+			GFP_KERNEL);
+	if (!alloc_cookie)
+		goto exit;
+
+	debugfs_root = debugfs_create_dir("vmem", NULL);
+	if (IS_ERR_OR_NULL(debugfs_root)) {
+		pr_warn("Failed to create '<debugfs>/vmem'\n");
+		debugfs_root = NULL;
+		goto exit;
+	}
+
+	debugfs_create_file("alloc", 0600, debugfs_root,
+			alloc_cookie, &fops_vmem_alloc);
+
+exit:
+	return debugfs_root;
+}
+
+void vmem_debugfs_deinit(struct dentry *debugfs_root)
+{
+	debugfs_remove_recursive(debugfs_root);
+}
+
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.h
similarity index 60%
copy from arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
copy to drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.h
index 194bfeb..1aa764b 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
+++ b/drivers/media/platform/msm/vidc_3x/vmem/vmem_debugfs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -10,15 +10,12 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+#ifndef __VMEM_DEBUGFS_H__
+#define __VMEM_DEBUGFS_H__
 
-/dts-v1/;
+#include <linux/debugfs.h>
 
-#include "qcs605.dtsi"
-#include "qcs605-lc-mtp.dtsi"
+struct dentry *vmem_debugfs_init(struct platform_device *pdev);
+void vmem_debugfs_deinit(struct dentry *debugfs_root);
 
-/ {
-	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
-	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
-	qcom,board-id = <8 4>;
-
-};
+#endif /* __VMEM_DEBUGFS_H__ */
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index dc76fd4..0324633 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -141,6 +141,7 @@
 
 static struct usb_device_id usbtv_id_table[] = {
 	{ USB_DEVICE(0x1b71, 0x3002) },
+	{ USB_DEVICE(0x1f71, 0x3301) },
 	{}
 };
 MODULE_DEVICE_TABLE(usb, usbtv_id_table);
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index eab93cc..a86d9f1 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2216,13 +2216,24 @@
 	}
 
 	*data->hdcp_ctx = handle;
-	/* Cache the client ctx to be used later
-	 * HDCP driver probe happens earlier than
+
+	/* Cache the client ctx to be used later if
+	 * Misc HDCP driver probe happens later than
 	 * SDE driver probe hence caching it to
 	 * be used later.
 	 */
-
 	drv_client_handle = handle;
+
+	/* if misc HDCP driver probe happens earlier
+	 * than SDE driver probe store the client
+	 * handle to be used to sysfs notifications.
+	 */
+
+	if (hdcp_drv_mgr && !hdcp_drv_mgr->handle) {
+		if (drv_client_handle)
+			hdcp_drv_mgr->handle = drv_client_handle;
+	}
+
 	handle->thread = kthread_run(kthread_worker_fn,
 				     &handle->worker, "hdcp_tz_lib");
 
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 146ca6f..232b4ae 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,7 +1,7 @@
 /*
  * QTI Secure Execution Environment Communicator (QSEECOM) driver
  *
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1848,7 +1848,7 @@
 	return ret;
 }
 
-static int __qseecom_process_blocked_on_listener_legacy(
+static int __qseecom_process_reentrancy_blocked_on_listener(
 				struct qseecom_command_scm_resp *resp,
 				struct qseecom_registered_app_list *ptr_app,
 				struct qseecom_dev_handle *data)
@@ -1857,8 +1857,11 @@
 	int ret = 0;
 	struct qseecom_continue_blocked_request_ireq ireq;
 	struct qseecom_command_scm_resp continue_resp;
-	bool found_app = false;
+	unsigned int session_id;
+	sigset_t new_sigset;
+	sigset_t old_sigset;
 	unsigned long flags;
+	bool found_app = false;
 
 	if (!resp || !data) {
 		pr_err("invalid resp or data pointer\n");
@@ -1889,137 +1892,81 @@
 		}
 	}
 
-	list_ptr = __qseecom_find_svc(resp->data);
-	if (!list_ptr) {
-		pr_err("Invalid listener ID\n");
-		ret = -ENODATA;
-		goto exit;
-	}
-	pr_debug("lsntr %d in_use = %d\n",
-			resp->data, list_ptr->listener_in_use);
-	ptr_app->blocked_on_listener_id = resp->data;
-
-	/* sleep until listener is available */
 	do {
-		qseecom.app_block_ref_cnt++;
-		ptr_app->app_blocked = true;
-		mutex_unlock(&app_access_lock);
-		if (wait_event_freezable(
-			list_ptr->listener_block_app_wq,
-			!list_ptr->listener_in_use)) {
-			pr_err("Interrupted: listener_id %d, app_id %d\n",
-				resp->data, ptr_app->app_id);
-			ret = -ERESTARTSYS;
+		session_id = resp->resp_type;
+		list_ptr = __qseecom_find_svc(resp->data);
+		if (!list_ptr) {
+			pr_err("Invalid listener ID %d\n", resp->data);
+			ret = -ENODATA;
 			goto exit;
 		}
-		mutex_lock(&app_access_lock);
-		ptr_app->app_blocked = false;
-		qseecom.app_block_ref_cnt--;
-	}  while (list_ptr->listener_in_use);
+		ptr_app->blocked_on_listener_id = resp->data;
 
-	ptr_app->blocked_on_listener_id = 0;
-	/* notify the blocked app that listener is available */
-	pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n",
-		resp->data, data->client.app_id,
-		data->client.app_name);
-	ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
-	ireq.app_or_session_id = data->client.app_id;
-	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-	if (ret) {
-		pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n",
-			data->client.app_id,
-			data->client.app_name, ret);
-		goto exit;
-	}
-	/*
-	 * After TZ app is unblocked, then continue to next case
-	 * for incomplete request processing
-	 */
-	resp->result = QSEOS_RESULT_INCOMPLETE;
-exit:
-	return ret;
-}
+		pr_warn("Lsntr %d in_use %d, block session(%d) app(%d)\n",
+			resp->data, list_ptr->listener_in_use,
+			session_id, data->client.app_id);
 
-static int __qseecom_process_blocked_on_listener_smcinvoke(
-			struct qseecom_command_scm_resp *resp, uint32_t app_id)
-{
-	struct qseecom_registered_listener_list *list_ptr;
-	int ret = 0;
-	struct qseecom_continue_blocked_request_ireq ireq;
-	struct qseecom_command_scm_resp continue_resp;
-	unsigned int session_id;
+		/* sleep until listener is available */
+		sigfillset(&new_sigset);
+		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
 
-	if (!resp) {
-		pr_err("invalid resp pointer\n");
-		ret = -EINVAL;
-		goto exit;
-	}
-	session_id = resp->resp_type;
-	list_ptr = __qseecom_find_svc(resp->data);
-	if (!list_ptr) {
-		pr_err("Invalid listener ID\n");
-		ret = -ENODATA;
-		goto exit;
-	}
-	pr_debug("lsntr %d in_use = %d\n",
-			resp->data, list_ptr->listener_in_use);
-	/* sleep until listener is available */
-	do {
-		qseecom.app_block_ref_cnt++;
-		mutex_unlock(&app_access_lock);
-		if (wait_event_freezable(
-			list_ptr->listener_block_app_wq,
-			!list_ptr->listener_in_use)) {
-			pr_err("Interrupted: listener_id %d, session_id %d\n",
-				resp->data, session_id);
-			ret = -ERESTARTSYS;
-			goto exit;
-		}
-		mutex_lock(&app_access_lock);
-		qseecom.app_block_ref_cnt--;
-	}  while (list_ptr->listener_in_use);
+		do {
+			qseecom.app_block_ref_cnt++;
+			ptr_app->app_blocked = true;
+			mutex_unlock(&app_access_lock);
+			wait_event_freezable(
+				list_ptr->listener_block_app_wq,
+				!list_ptr->listener_in_use);
+			mutex_lock(&app_access_lock);
+			ptr_app->app_blocked = false;
+			qseecom.app_block_ref_cnt--;
+		}  while (list_ptr->listener_in_use);
 
-	/* notify TZ that listener is available */
-	pr_warn("Lsntr %d is available, unblock session(%d) in TZ\n",
-			resp->data, session_id);
-	ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
-	ireq.app_or_session_id = session_id;
-	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
-			&ireq, sizeof(ireq),
-			&continue_resp, sizeof(continue_resp));
-	if (ret) {
-		/* retry with legacy cmd */
-		qseecom.smcinvoke_support = false;
-		ireq.app_or_session_id = app_id;
+		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+
+		ptr_app->blocked_on_listener_id = 0;
+		pr_warn("Lsntr %d is available, unblock session(%d) app(%d)\n",
+			resp->data, session_id, data->client.app_id);
+
+		/* notify TZ that listener is available */
+		ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
+
+		if (qseecom.smcinvoke_support)
+			ireq.app_or_session_id = session_id;
+		else
+			ireq.app_or_session_id = data->client.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;
+					&ireq, sizeof(ireq),
+					&continue_resp, sizeof(continue_resp));
+		if (ret && qseecom.smcinvoke_support) {
+			/* retry with legacy cmd */
+			qseecom.smcinvoke_support = false;
+			ireq.app_or_session_id = data->client.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("unblock app %d or session %d fail\n",
+					data->client.app_id, session_id);
+				goto exit;
+			}
 		}
+		resp->result = continue_resp.result;
+		resp->resp_type = continue_resp.resp_type;
+		resp->data = continue_resp.data;
+		pr_debug("unblock resp = %d\n", resp->result);
+	} while (resp->result == QSEOS_RESULT_BLOCKED_ON_LISTENER);
+
+	if (resp->result != QSEOS_RESULT_INCOMPLETE) {
+		pr_err("Unexpected unblock resp %d\n", resp->result);
+		ret = -EINVAL;
 	}
-	resp->result = QSEOS_RESULT_INCOMPLETE;
 exit:
 	return ret;
 }
 
-static int __qseecom_process_reentrancy_blocked_on_listener(
-				struct qseecom_command_scm_resp *resp,
-				struct qseecom_registered_app_list *ptr_app,
-				struct qseecom_dev_handle *data)
-{
-	if (!qseecom.smcinvoke_support)
-		return __qseecom_process_blocked_on_listener_legacy(
-			resp, ptr_app, data);
-	else
-		return __qseecom_process_blocked_on_listener_smcinvoke(
-			resp, data->client.app_id);
-}
 static int __qseecom_reentrancy_process_incomplete_cmd(
 					struct qseecom_dev_handle *data,
 					struct qseecom_command_scm_resp *resp)
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index 55ce946..01811d9 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -357,7 +357,7 @@
 	if (!cq_host->desc_base || !cq_host->trans_desc_base)
 		return -ENOMEM;
 
-	pr_info("desc-base: 0x%p trans-base: 0x%p\n desc_dma 0x%llx trans_dma: 0x%llx\n",
+	pr_debug("desc-base: 0x%pK trans-base: 0x%pK\n desc_dma 0x%llx trans_dma: 0x%llx\n",
 		 cq_host->desc_base, cq_host->trans_desc_base,
 		(unsigned long long)cq_host->desc_dma_base,
 		(unsigned long long) cq_host->trans_desc_dma_base);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 367c84f..0abc7a3 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2,7 +2,7 @@
  * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform
  * driver source file
  *
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,7 @@
 #include <linux/iopoll.h>
 #include <linux/msm-bus.h>
 #include <linux/pm_runtime.h>
+#include <linux/nvmem-consumer.h>
 #include <trace/events/mmc.h>
 
 #include "sdhci-msm.h"
@@ -1885,6 +1886,69 @@
 	}
 }
 
+#ifdef CONFIG_NVMEM
+/* Parse qfprom data for deciding on errata work-arounds */
+static long qfprom_read(struct device *dev, const char *name)
+{
+	struct nvmem_cell *cell;
+	ssize_t len = 0;
+	u32 *buf, val = 0;
+	long err = 0;
+
+	cell = nvmem_cell_get(dev, name);
+	if (IS_ERR(cell)) {
+		err = PTR_ERR(cell);
+		dev_err(dev, "failed opening nvmem cell err : %ld\n", err);
+		/* If entry does not exist, then that is not an error */
+		if (err == -ENOENT)
+			err = 0;
+		return err;
+	}
+
+	buf = (u32 *)nvmem_cell_read(cell, &len);
+	if (IS_ERR(buf) || !len) {
+		dev_err(dev, "Failed reading nvmem cell, err: %u, bytes fetched: %zd\n",
+				*buf, len);
+		if (!IS_ERR(buf)) {
+			kfree(buf);
+			err = -EINVAL;
+		} else {
+			err = PTR_ERR(buf);
+		}
+	} else {
+		/*
+		 * 30 bits from bit offset 0 would be read.
+		 * We're interested in bits 28:29
+		 */
+		val = (*buf >> 28) & 0x3;
+		kfree(buf);
+	}
+
+	nvmem_cell_put(cell);
+	return err ? err : (long) val;
+}
+
+/* Reads the SoC version */
+static int sdhci_msm_get_socrev(struct device *dev,
+				struct sdhci_msm_host *msm_host)
+{
+
+	msm_host->soc_min_rev  = qfprom_read(dev, "minor_rev");
+
+	if (msm_host->soc_min_rev < 0)
+		dev_err(dev, "failed getting soc_min_rev, err : %d\n",
+				msm_host->soc_min_rev);
+	return msm_host->soc_min_rev;
+}
+#else
+/* Reads the SoC version */
+static int sdhci_msm_get_socrev(struct device *dev,
+				struct sdhci_msm_host *msm_host)
+{
+	return 0;
+}
+#endif
+
 /* Parse platform data */
 static
 struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
@@ -2062,6 +2126,13 @@
 	if (!of_property_read_u32(np, "qcom,ddr-config", &pdata->ddr_config))
 		pdata->rclk_wa = true;
 
+	/*
+	 * rclk_wa is not required if soc version is mentioned and
+	 * is not base version.
+	 */
+	if (msm_host->soc_min_rev != 0)
+		pdata->rclk_wa = false;
+
 	return pdata;
 out:
 	return NULL;
@@ -4170,11 +4241,10 @@
 		group->latency = PM_QOS_DEFAULT_VALUE;
 		pm_qos_add_request(&group->req, PM_QOS_CPU_DMA_LATENCY,
 			group->latency);
-		pr_info("%s (): voted for group #%d (mask=0x%lx) latency=%d (0x%p)\n",
+		pr_info("%s (): voted for group #%d (mask=0x%lx) latency=%d\n",
 			__func__, i,
 			group->req.cpus_affine.bits[0],
-			group->latency,
-			&latency[i].latency[SDHCI_PERFORMANCE_MODE]);
+			group->latency);
 	}
 	msm_host->pm_qos_prev_cpu = -1;
 	msm_host->pm_qos_group_enable = true;
@@ -4530,6 +4600,12 @@
 	msm_host->mmc = host->mmc;
 	msm_host->pdev = pdev;
 
+	ret = sdhci_msm_get_socrev(&pdev->dev, msm_host);
+	if (ret == -EPROBE_DEFER) {
+		dev_err(&pdev->dev, "SoC version rd: fail: defer for now\n");
+		goto pltfm_free;
+	}
+
 	/* get the ice device vops if present */
 	ret = sdhci_msm_ice_get_dev(host);
 	if (ret == -EPROBE_DEFER) {
@@ -4735,8 +4811,6 @@
 			goto vreg_deinit;
 		}
 		writel_relaxed(readl_relaxed(tlmm_mem) | 0x2, tlmm_mem);
-		dev_dbg(&pdev->dev, "tlmm reg %pa value 0x%08x\n",
-				&tlmm_memres->start, readl_relaxed(tlmm_mem));
 	}
 
 	/*
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index 7c737cc..9c2442d 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -255,6 +255,7 @@
 	bool core_3_0v_support;
 	bool pltfm_init_done;
 	struct sdhci_msm_regs_restore regs_restore;
+	int soc_min_rev;
 };
 
 extern char *saved_command_line;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 566be69..b674b38 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3068,13 +3068,13 @@
 		struct sdhci_adma2_64_desc *dma_desc = desc;
 
 		if (host->flags & SDHCI_USE_64_BIT_DMA)
-			DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+			DBG("%s: %pK: DMA 0x%08x%08x, LEN 0x%04x,Attr=0x%02x\n",
 			    name, desc, le32_to_cpu(dma_desc->addr_hi),
 			    le32_to_cpu(dma_desc->addr_lo),
 			    le16_to_cpu(dma_desc->len),
 			    le16_to_cpu(dma_desc->cmd));
 		else
-			DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+			DBG("%s: %pK: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
 			    name, desc, le32_to_cpu(dma_desc->addr_lo),
 			    le16_to_cpu(dma_desc->len),
 			    le16_to_cpu(dma_desc->cmd));
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
index de31514..d38527e 100644
--- a/drivers/mtd/nand/denali_pci.c
+++ b/drivers/mtd/nand/denali_pci.c
@@ -119,3 +119,7 @@
 };
 
 module_pci_driver(denali_pci_driver);
+
+MODULE_DESCRIPTION("PCI driver for Denali NAND controller");
+MODULE_AUTHOR("Intel Corporation and its suppliers");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index 3047325..7f5ec40 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -184,7 +184,7 @@
 	void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
 	int err = 0;
 	u8 *packet_ptr;
-	int i, n = 1, packet_len;
+	int packet_len;
 	ptrdiff_t cmd_len;
 
 	/* usb device unregistered? */
@@ -201,17 +201,13 @@
 	}
 
 	packet_ptr = cmd_head;
+	packet_len = cmd_len;
 
 	/* firmware is not able to re-assemble 512 bytes buffer in full-speed */
-	if ((dev->udev->speed != USB_SPEED_HIGH) &&
-	    (cmd_len > PCAN_UFD_LOSPD_PKT_SIZE)) {
-		packet_len = PCAN_UFD_LOSPD_PKT_SIZE;
-		n += cmd_len / packet_len;
-	} else {
-		packet_len = cmd_len;
-	}
+	if (unlikely(dev->udev->speed != USB_SPEED_HIGH))
+		packet_len = min(packet_len, PCAN_UFD_LOSPD_PKT_SIZE);
 
-	for (i = 0; i < n; i++) {
+	do {
 		err = usb_bulk_msg(dev->udev,
 				   usb_sndbulkpipe(dev->udev,
 						   PCAN_USBPRO_EP_CMDOUT),
@@ -224,7 +220,12 @@
 		}
 
 		packet_ptr += packet_len;
-	}
+		cmd_len -= packet_len;
+
+		if (cmd_len < PCAN_UFD_LOSPD_PKT_SIZE)
+			packet_len = cmd_len;
+
+	} while (packet_len > 0);
 
 	return err;
 }
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index a7e04ff..cde4b96 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -1843,8 +1843,8 @@
 	/* Read A2 portion of the EEPROM */
 	if (length) {
 		start -= ETH_MODULE_SFF_8436_LEN;
-		bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 1, start,
-						 length, data);
+		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 1,
+						      start, length, data);
 	}
 	return rc;
 }
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 1644896..b2eeecb 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4733,6 +4733,15 @@
 
 	be_schedule_worker(adapter);
 
+	/*
+	 * The IF was destroyed and re-created. We need to clear
+	 * all promiscuous flags valid for the destroyed IF.
+	 * Without this promisc mode is not restored during
+	 * be_open() because the driver thinks that it is
+	 * already enabled in HW.
+	 */
+	adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS;
+
 	if (netif_running(netdev))
 		status = be_open(netdev);
 
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ca54f76..3a61491 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -3273,7 +3273,7 @@
 
 int igb_close(struct net_device *netdev)
 {
-	if (netif_device_present(netdev))
+	if (netif_device_present(netdev) || netdev->dismantle)
 		return __igb_close(netdev, false);
 	return 0;
 }
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 8aa91dd..1655601 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -765,11 +765,8 @@
 	dipn = htonl(dip);
 	dev = mlxsw_sp->rifs[rif]->dev;
 	n = neigh_lookup(&arp_tbl, &dipn, dev);
-	if (!n) {
-		netdev_err(dev, "Failed to find matching neighbour for IP=%pI4h\n",
-			   &dip);
+	if (!n)
 		return;
-	}
 
 	netdev_dbg(dev, "Updating neighbour with IP=%pI4h\n", &dip);
 	neigh_event_send(n, NULL);
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 2c4350a..298b74e 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -2222,19 +2222,14 @@
 	void __iomem *ioaddr = tp->mmio_addr;
 	dma_addr_t paddr = tp->counters_phys_addr;
 	u32 cmd;
-	bool ret;
 
 	RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
+	RTL_R32(CounterAddrHigh);
 	cmd = (u64)paddr & DMA_BIT_MASK(32);
 	RTL_W32(CounterAddrLow, cmd);
 	RTL_W32(CounterAddrLow, cmd | counter_cmd);
 
-	ret = rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000);
-
-	RTL_W32(CounterAddrLow, 0);
-	RTL_W32(CounterAddrHigh, 0);
-
-	return ret;
+	return rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000);
 }
 
 static bool rtl8169_reset_counters(struct net_device *dev)
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 6d68c8a..da4ec57 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -34,6 +34,7 @@
 config XILINX_LL_TEMAC
 	tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
 	depends on (PPC || MICROBLAZE)
+	depends on !64BIT || BROKEN
 	select PHYLIB
 	---help---
 	  This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index b883af9..fc4c2cc 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1002,17 +1002,18 @@
 	if (!ifname_is_set)
 		snprintf(ppp->dev->name, IFNAMSIZ, "ppp%i", ppp->file.index);
 
+	mutex_unlock(&pn->all_ppp_mutex);
+
 	ret = register_netdevice(ppp->dev);
 	if (ret < 0)
 		goto err_unit;
 
 	atomic_inc(&ppp_unit_count);
 
-	mutex_unlock(&pn->all_ppp_mutex);
-
 	return 0;
 
 err_unit:
+	mutex_lock(&pn->all_ppp_mutex);
 	unit_put(&pn->units_idr, ppp->file.index);
 err:
 	mutex_unlock(&pn->all_ppp_mutex);
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 4ddae81..dc36c2e 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -842,6 +842,7 @@
 	struct pppoe_hdr *ph;
 	struct net_device *dev;
 	char *start;
+	int hlen;
 
 	lock_sock(sk);
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {
@@ -860,16 +861,16 @@
 	if (total_len > (dev->mtu + dev->hard_header_len))
 		goto end;
 
-
-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
-			   0, GFP_KERNEL);
+	hlen = LL_RESERVED_SPACE(dev);
+	skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len +
+			   dev->needed_tailroom, 0, GFP_KERNEL);
 	if (!skb) {
 		error = -ENOMEM;
 		goto end;
 	}
 
 	/* Reserve space for headers. */
-	skb_reserve(skb, dev->hard_header_len);
+	skb_reserve(skb, hlen);
 	skb_reset_network_header(skb);
 
 	skb->dev = dev;
@@ -930,7 +931,7 @@
 	/* Copy the data if there is no space for the header or if it's
 	 * read-only.
 	 */
-	if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
+	if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph)))
 		goto abort;
 
 	__skb_push(skb, sizeof(*ph));
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 6f9fc27..9babe04 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -525,6 +525,14 @@
 	skb_queue_purge(&tfile->sk.sk_error_queue);
 }
 
+static void tun_cleanup_tx_array(struct tun_file *tfile)
+{
+	if (tfile->tx_array.ring.queue) {
+		skb_array_cleanup(&tfile->tx_array);
+		memset(&tfile->tx_array, 0, sizeof(tfile->tx_array));
+	}
+}
+
 static void __tun_detach(struct tun_file *tfile, bool clean)
 {
 	struct tun_file *ntfile;
@@ -566,8 +574,7 @@
 			    tun->dev->reg_state == NETREG_REGISTERED)
 				unregister_netdevice(tun->dev);
 		}
-		if (tun)
-			skb_array_cleanup(&tfile->tx_array);
+		tun_cleanup_tx_array(tfile);
 		sock_put(&tfile->sk);
 	}
 }
@@ -606,11 +613,13 @@
 		/* Drop read queue */
 		tun_queue_purge(tfile);
 		sock_put(&tfile->sk);
+		tun_cleanup_tx_array(tfile);
 	}
 	list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
 		tun_enable_queue(tfile);
 		tun_queue_purge(tfile);
 		sock_put(&tfile->sk);
+		tun_cleanup_tx_array(tfile);
 	}
 	BUG_ON(tun->numdisabled != 0);
 
@@ -2373,6 +2382,8 @@
 
 	sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
 
+	memset(&tfile->tx_array, 0, sizeof(tfile->tx_array));
+
 	return 0;
 }
 
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 9c257ff..c53385a 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -2197,6 +2197,7 @@
 		buf = DEFAULT_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
 		dev->rx_urb_size = DEFAULT_BURST_CAP_SIZE;
 		dev->rx_qlen = 4;
+		dev->tx_qlen = 4;
 	}
 
 	ret = lan78xx_write_reg(dev, BURST_CAP, buf);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index ef83ae3..4afba17 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1616,7 +1616,6 @@
 					  rq->rx_ring[i].basePA);
 			rq->rx_ring[i].base = NULL;
 		}
-		rq->buf_info[i] = NULL;
 	}
 
 	if (rq->data_ring.base) {
@@ -1638,6 +1637,7 @@
 			(rq->rx_ring[0].size + rq->rx_ring[1].size);
 		dma_free_coherent(&adapter->pdev->dev, sz, rq->buf_info[0],
 				  rq->buf_info_pa);
+		rq->buf_info[0] = rq->buf_info[1] = NULL;
 	}
 }
 
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 75faeb1..bb2270b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -108,20 +108,8 @@
 	 for it's internal usage and release it to back to pre allocated pool.
 	 This memory is allocated at the cold boot time.
 
-config CLD_LL_CORE
-       tristate "QTI core WLAN driver for QCA6174 chipset"
-       select NL80211_TESTMODE
-       select WEXT_CORE
-       select WEXT_PRIV
-       select WEXT_SPY
-       select WIRELESS_EXT
-       ---help---
-         This section contains the necessary modules needed to enable the
-	 core WLAN driver for QTI QCA6174 chipset.
-	 Select Y to compile the driver in order to have WLAN functionality
-	 support.
-
 source "drivers/net/wireless/cnss2/Kconfig"
+source "drivers/net/wireless/cnss/Kconfig"
 source "drivers/net/wireless/cnss_utils/Kconfig"
 source "drivers/net/wireless/cnss_genl/Kconfig"
 
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 4ffbd10..5c33140 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -27,8 +27,7 @@
 obj-$(CONFIG_MAC80211_HWSIM)	+= mac80211_hwsim.o
 
 obj-$(CONFIG_CNSS2)	+= cnss2/
-
+obj-$(CONFIG_CNSS)              += cnss/
 obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
-
 obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/
diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h
index c131b5e..d32c1f4 100644
--- a/drivers/net/wireless/ath/wil6210/boot_loader.h
+++ b/drivers/net/wireless/ath/wil6210/boot_loader.h
@@ -1,4 +1,5 @@
 /* Copyright (c) 2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -39,7 +40,8 @@
 	/* valid only for version 2 and above */
 	__le32  bl_assert_code;         /* 0x880A58 BL Assert code */
 	__le32  bl_assert_blink;        /* 0x880A5C BL Assert Branch */
-	__le32  bl_reserved[22];        /* 0x880A60 - 0x880AB4 */
+	__le32  bl_shutdown_handshake;  /* 0x880A60 BL cleaner shutdown */
+	__le32  bl_reserved[21];        /* 0x880A64 - 0x880AB4 */
 	__le32  bl_magic_number;        /* 0x880AB8 BL Magic number */
 } __packed;
 
@@ -58,4 +60,9 @@
 	u8	mac_address[6];			/* 0x880A4c BL mac address */
 } __packed;
 
+/* bits for bl_shutdown_handshake */
+#define BL_SHUTDOWN_HS_GRTD		BIT(0)
+#define BL_SHUTDOWN_HS_RTD		BIT(1)
+#define BL_SHUTDOWN_HS_PROT_VER(x) WIL_GET_BITS(x, 28, 31)
+
 #endif /* BOOT_LOADER_EXPORT_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
index 2f2b910..2c7b24f 100644
--- a/drivers/net/wireless/ath/wil6210/fw.h
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014,2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -58,15 +59,30 @@
 	u8 data[0]; /* free-form data [data_size], see above */
 } __packed;
 
+/* Comment header - common for all comment record types */
+struct wil_fw_record_comment_hdr {
+	__le32 magic;
+};
+
 /* FW capabilities encoded inside a comment record */
 #define WIL_FW_CAPABILITIES_MAGIC (0xabcddcba)
 struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
 	/* identifies capabilities record */
-	__le32 magic;
+	struct wil_fw_record_comment_hdr hdr;
 	/* capabilities (variable size), see enum wmi_fw_capability */
 	u8 capabilities[0];
 };
 
+/* brd file info encoded inside a comment record */
+#define WIL_BRD_FILE_MAGIC (0xabcddcbb)
+struct wil_fw_record_brd_file { /* type == wil_fw_type_comment */
+	/* identifies brd file record */
+	struct wil_fw_record_comment_hdr hdr;
+	__le32 version;
+	__le32 base_addr;
+	__le32 max_size_bytes;
+} __packed;
+
 /* perform action
  * data_size = @head.size - offsetof(struct wil_fw_record_action, data)
  */
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 77d1902..914c010 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -128,14 +129,13 @@
 }
 
 static int
-fw_handle_comment(struct wil6210_priv *wil, const void *data,
-		  size_t size)
+fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
+		       size_t size)
 {
 	const struct wil_fw_record_capabilities *rec = data;
 	size_t capa_size;
 
-	if (size < sizeof(*rec) ||
-	    le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
+	if (size < sizeof(*rec)) {
 		wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
 				data, size, true);
 		return 0;
@@ -151,8 +151,56 @@
 	return 0;
 }
 
-static int fw_handle_data(struct wil6210_priv *wil, const void *data,
-			  size_t size)
+static int
+fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
+		   size_t size)
+{
+	const struct wil_fw_record_brd_file *rec = data;
+
+	if (size < sizeof(*rec)) {
+		wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
+				data, size, true);
+		return 0;
+	}
+
+	wil->brd_file_addr = le32_to_cpu(rec->base_addr);
+	wil->brd_file_max_size = le32_to_cpu(rec->max_size_bytes);
+
+	wil_dbg_fw(wil, "brd_file_addr 0x%x, brd_file_max_size %d\n",
+		   wil->brd_file_addr, wil->brd_file_max_size);
+
+	return 0;
+}
+
+static int
+fw_handle_comment(struct wil6210_priv *wil, const void *data,
+		  size_t size)
+{
+	const struct wil_fw_record_comment_hdr *hdr = data;
+	u32 magic;
+	int rc = 0;
+
+	if (size < sizeof(*hdr))
+		return 0;
+
+	magic = le32_to_cpu(hdr->magic);
+
+	switch (magic) {
+	case WIL_FW_CAPABILITIES_MAGIC:
+		wil_dbg_fw(wil, "magic is WIL_FW_CAPABILITIES_MAGIC\n");
+		rc = fw_handle_capabilities(wil, data, size);
+		break;
+	case WIL_BRD_FILE_MAGIC:
+		wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
+		rc = fw_handle_brd_file(wil, data, size);
+		break;
+	}
+
+	return rc;
+}
+
+static int __fw_handle_data(struct wil6210_priv *wil, const void *data,
+			    size_t size, __le32 addr)
 {
 	const struct wil_fw_record_data *d = data;
 	void __iomem *dst;
@@ -163,16 +211,23 @@
 		return -EINVAL;
 	}
 
-	if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
+	if (!wil_fw_addr_check(wil, &dst, addr, s, "address"))
 		return -EINVAL;
-	wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
-		   s);
+	wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(addr), s);
 	wil_memcpy_toio_32(dst, d->data, s);
 	wmb(); /* finish before processing next record */
 
 	return 0;
 }
 
+static int fw_handle_data(struct wil6210_priv *wil, const void *data,
+			  size_t size)
+{
+	const struct wil_fw_record_data *d = data;
+
+	return __fw_handle_data(wil, data, size, d->addr);
+}
+
 static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
 			  size_t size)
 {
@@ -552,6 +607,100 @@
 }
 
 /**
+ * wil_brd_process - process section from BRD file
+ *
+ * Return error code
+ */
+static int wil_brd_process(struct wil6210_priv *wil, const void *data,
+			   size_t size)
+{
+	int rc = 0;
+	const struct wil_fw_record_head *hdr = data;
+	size_t s, hdr_sz;
+	u16 type;
+
+	/* Assuming the board file includes only one header record and one data
+	 * record. Each record starts with wil_fw_record_head.
+	 */
+	if (size < sizeof(*hdr))
+		return -EINVAL;
+	s = sizeof(*hdr) + le32_to_cpu(hdr->size);
+	if (s > size)
+		return -EINVAL;
+
+	/* Skip the header record and handle the data record */
+	hdr = (const void *)hdr + s;
+	size -= s;
+	if (size < sizeof(*hdr))
+		return -EINVAL;
+	hdr_sz = le32_to_cpu(hdr->size);
+
+	if (wil->brd_file_max_size && hdr_sz > wil->brd_file_max_size)
+		return -EINVAL;
+	if (sizeof(*hdr) + hdr_sz > size)
+		return -EINVAL;
+	if (hdr_sz % 4) {
+		wil_err_fw(wil, "unaligned record size: %zu\n",
+			   hdr_sz);
+		return -EINVAL;
+	}
+	type = le16_to_cpu(hdr->type);
+	if (type != wil_fw_type_data) {
+		wil_err_fw(wil, "invalid record type for board file: %d\n",
+			   type);
+		return -EINVAL;
+	}
+	if (hdr_sz < sizeof(struct wil_fw_record_data)) {
+		wil_err_fw(wil, "data record too short: %zu\n", hdr_sz);
+		return -EINVAL;
+	}
+
+	wil_dbg_fw(wil, "using addr from fw file: [0x%08x]\n",
+		   wil->brd_file_addr);
+
+	rc = __fw_handle_data(wil, &hdr[1], hdr_sz,
+			      cpu_to_le32(wil->brd_file_addr));
+
+	return rc;
+}
+
+/**
+ * wil_request_board - Request board file
+ *
+ * Request board image from the file
+ * board file address and max size are read from FW file
+ * during initialization.
+ * brd file shall include one header and one data section.
+ *
+ * Return error code
+ */
+int wil_request_board(struct wil6210_priv *wil, const char *name)
+{
+	int rc, dlen;
+	const struct firmware *brd;
+
+	rc = request_firmware(&brd, name, wil_to_dev(wil));
+	if (rc) {
+		wil_err_fw(wil, "Failed to load brd %s\n", name);
+		return rc;
+	}
+	wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, brd->size);
+
+	/* Verify the header */
+	dlen = wil_fw_verify(wil, brd->data, brd->size);
+	if (dlen < 0) {
+		rc = dlen;
+		goto out;
+	}
+	/* Process the data record */
+	rc = wil_brd_process(wil, brd->data, dlen);
+
+out:
+	release_firmware(brd);
+	return rc;
+}
+
+/**
  * wil_fw_verify_file_exists - checks if firmware file exist
  *
  * @wil: driver context
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index dcf87a7..1835187 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -395,8 +396,9 @@
 	wil6210_mask_irq_misc(wil, false);
 
 	if (isr & ISR_MISC_FW_ERROR) {
-		u32 fw_assert_code = wil_r(wil, RGF_FW_ASSERT_CODE);
-		u32 ucode_assert_code = wil_r(wil, RGF_UCODE_ASSERT_CODE);
+		u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr);
+		u32 ucode_assert_code =
+			wil_r(wil, wil->rgf_ucode_assert_code_addr);
 
 		wil_err(wil,
 			"Firmware error detected, assert codes FW 0x%08x, UCODE 0x%08x\n",
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 8e13f24..9cef0f0 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -642,6 +643,98 @@
 	destroy_workqueue(wil->wmi_wq);
 }
 
+static void wil_shutdown_bl(struct wil6210_priv *wil)
+{
+	u32 val;
+
+	wil_s(wil, RGF_USER_BL +
+	      offsetof(struct bl_dedicated_registers_v1,
+		       bl_shutdown_handshake), BL_SHUTDOWN_HS_GRTD);
+
+	usleep_range(100, 150);
+
+	val = wil_r(wil, RGF_USER_BL +
+		    offsetof(struct bl_dedicated_registers_v1,
+			     bl_shutdown_handshake));
+	if (val & BL_SHUTDOWN_HS_RTD) {
+		wil_dbg_misc(wil, "BL is ready for halt\n");
+		return;
+	}
+
+	wil_err(wil, "BL did not report ready for halt\n");
+}
+
+/* this format is used by ARC embedded CPU for instruction memory */
+static inline u32 ARC_me_imm32(u32 d)
+{
+	return ((d & 0xffff0000) >> 16) | ((d & 0x0000ffff) << 16);
+}
+
+/* defines access to interrupt vectors for wil_freeze_bl */
+#define ARC_IRQ_VECTOR_OFFSET(N)	((N) * 8)
+/* ARC long jump instruction */
+#define ARC_JAL_INST			(0x20200f80)
+
+static void wil_freeze_bl(struct wil6210_priv *wil)
+{
+	u32 jal, upc, saved;
+	u32 ivt3 = ARC_IRQ_VECTOR_OFFSET(3);
+
+	jal = wil_r(wil, wil->iccm_base + ivt3);
+	if (jal != ARC_me_imm32(ARC_JAL_INST)) {
+		wil_dbg_misc(wil, "invalid IVT entry found, skipping\n");
+		return;
+	}
+
+	/* prevent the target from entering deep sleep
+	 * and disabling memory access
+	 */
+	saved = wil_r(wil, RGF_USER_USAGE_8);
+	wil_w(wil, RGF_USER_USAGE_8, saved | BIT_USER_PREVENT_DEEP_SLEEP);
+	usleep_range(20, 25); /* let the BL process the bit */
+
+	/* redirect to endless loop in the INT_L1 context and let it trap */
+	wil_w(wil, wil->iccm_base + ivt3 + 4, ARC_me_imm32(ivt3));
+	usleep_range(20, 25); /* let the BL get into the trap */
+
+	/* verify the BL is frozen */
+	upc = wil_r(wil, RGF_USER_CPU_PC);
+	if (upc < ivt3 || (upc > (ivt3 + 8)))
+		wil_dbg_misc(wil, "BL freeze failed, PC=0x%08X\n", upc);
+
+	wil_w(wil, RGF_USER_USAGE_8, saved);
+}
+
+static void wil_bl_prepare_halt(struct wil6210_priv *wil)
+{
+	u32 tmp, ver;
+
+	/* before halting device CPU driver must make sure BL is not accessing
+	 * host memory. This is done differently depending on BL version:
+	 * 1. For very old BL versions the procedure is skipped
+	 * (not supported).
+	 * 2. For old BL version we use a special trick to freeze the BL
+	 * 3. For new BL versions we shutdown the BL using handshake procedure.
+	 */
+	tmp = wil_r(wil, RGF_USER_BL +
+		    offsetof(struct bl_dedicated_registers_v0,
+			     boot_loader_struct_version));
+	if (!tmp) {
+		wil_dbg_misc(wil, "old BL, skipping halt preperation\n");
+		return;
+	}
+
+	tmp = wil_r(wil, RGF_USER_BL +
+		    offsetof(struct bl_dedicated_registers_v1,
+			     bl_shutdown_handshake));
+	ver = BL_SHUTDOWN_HS_PROT_VER(tmp);
+
+	if (ver > 0)
+		wil_shutdown_bl(wil);
+	else
+		wil_freeze_bl(wil);
+}
+
 static inline void wil_halt_cpu(struct wil6210_priv *wil)
 {
 	wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST);
@@ -675,7 +768,7 @@
 	}
 }
 
-static int wil_target_reset(struct wil6210_priv *wil)
+static int wil_target_reset(struct wil6210_priv *wil, int no_flash)
 {
 	int delay = 0;
 	u32 x, x1 = 0;
@@ -689,9 +782,16 @@
 
 	wil_halt_cpu(wil);
 
-	/* clear all boot loader "ready" bits */
-	wil_w(wil, RGF_USER_BL +
-	      offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0);
+	if (!no_flash) {
+		/* clear all boot loader "ready" bits */
+		wil_w(wil, RGF_USER_BL +
+		      offsetof(struct bl_dedicated_registers_v0,
+			       boot_loader_ready), 0);
+		/* this should be safe to write even with old BLs */
+		wil_w(wil, RGF_USER_BL +
+		      offsetof(struct bl_dedicated_registers_v1,
+			       bl_shutdown_handshake), 0);
+	}
 	/* Clear Fw Download notification */
 	wil_c(wil, RGF_USER_USAGE_6, BIT(0));
 
@@ -732,21 +832,33 @@
 	wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
 
 	/* wait until device ready. typical time is 20..80 msec */
-	do {
-		msleep(RST_DELAY);
-		x = wil_r(wil, RGF_USER_BL +
-			  offsetof(struct bl_dedicated_registers_v0,
-				   boot_loader_ready));
-		if (x1 != x) {
-			wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
-			x1 = x;
-		}
-		if (delay++ > RST_COUNT) {
-			wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
-				x);
-			return -ETIME;
-		}
-	} while (x != BL_READY);
+	if (no_flash)
+		do {
+			msleep(RST_DELAY);
+			x = wil_r(wil, USER_EXT_USER_PMU_3);
+			if (delay++ > RST_COUNT) {
+				wil_err(wil, "Reset not completed, PMU_3 0x%08x\n",
+					x);
+				return -ETIME;
+			}
+		} while ((x & BIT_PMU_DEVICE_RDY) == 0);
+	else
+		do {
+			msleep(RST_DELAY);
+			x = wil_r(wil, RGF_USER_BL +
+				  offsetof(struct bl_dedicated_registers_v0,
+					   boot_loader_ready));
+			if (x1 != x) {
+				wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n",
+					     x1, x);
+				x1 = x;
+			}
+			if (delay++ > RST_COUNT) {
+				wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
+					x);
+				return -ETIME;
+			}
+		} while (x != BL_READY);
 
 	wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
 
@@ -754,6 +866,21 @@
 	wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN |
 	      BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC);
 
+	if (no_flash) {
+		/* Reset OTP HW vectors to fit 40MHz */
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME1, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME2, 0x20027);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME3, 0x1);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME4, 0x20027);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME5, 0x30003);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME6, 0x20002);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME7, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME8, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME9, 0x60001);
+		wil_w(wil, RGF_USER_XPM_IFC_RD_TIME10, 0x60001);
+		wil_w(wil, RGF_USER_XPM_RD_DOUT_SAMPLE_TIME, 0x57);
+	}
+
 	wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
 	return 0;
 }
@@ -911,6 +1038,27 @@
 	}
 }
 
+static int wil_get_otp_info(struct wil6210_priv *wil)
+{
+	struct net_device *ndev = wil_to_ndev(wil);
+	struct wiphy *wiphy = wil_to_wiphy(wil);
+	u8 mac[8];
+
+	wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(RGF_OTP_MAC),
+			     sizeof(mac));
+	if (!is_valid_ether_addr(mac)) {
+		wil_err(wil, "Invalid MAC %pM\n", mac);
+		return -EINVAL;
+	}
+
+	ether_addr_copy(ndev->perm_addr, mac);
+	ether_addr_copy(wiphy->perm_addr, mac);
+	if (!is_valid_ether_addr(ndev->dev_addr))
+		ether_addr_copy(ndev->dev_addr, mac);
+
+	return 0;
+}
+
 static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
 {
 	ulong to = msecs_to_jiffies(1000);
@@ -1004,6 +1152,7 @@
 {
 	int rc;
 	unsigned long status_flags = BIT(wil_status_resetting);
+	int no_flash;
 
 	wil_dbg_misc(wil, "reset\n");
 
@@ -1082,20 +1231,28 @@
 	flush_workqueue(wil->wq_service);
 	flush_workqueue(wil->wmi_wq);
 
-	wil_bl_crash_info(wil, false);
+	no_flash = test_bit(hw_capa_no_flash, wil->hw_capa);
+	if (!no_flash)
+		wil_bl_crash_info(wil, false);
 	wil_disable_irq(wil);
-	rc = wil_target_reset(wil);
+	rc = wil_target_reset(wil, no_flash);
 	wil6210_clear_irq(wil);
 	wil_enable_irq(wil);
 	wil_rx_fini(wil);
 	if (rc) {
-		wil_bl_crash_info(wil, true);
+		if (!no_flash)
+			wil_bl_crash_info(wil, true);
 		goto out;
 	}
 
-	rc = wil_get_bl_info(wil);
-	if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
-		rc = 0;
+	if (no_flash) {
+		rc = wil_get_otp_info(wil);
+	} else {
+		rc = wil_get_bl_info(wil);
+		if (rc == -EAGAIN && !load_fw)
+			/* ignore RF error if not going up */
+			rc = 0;
+	}
 	if (rc)
 		goto out;
 
@@ -1104,13 +1261,21 @@
 		wil_info(wil, "Use firmware <%s> + board <%s>\n",
 			 wil->wil_fw_name, WIL_BOARD_FILE_NAME);
 
+		if (!no_flash)
+			wil_bl_prepare_halt(wil);
+
 		wil_halt_cpu(wil);
 		memset(wil->fw_version, 0, sizeof(wil->fw_version));
 		/* Loading f/w from the file */
 		rc = wil_request_firmware(wil, wil->wil_fw_name, true);
 		if (rc)
 			goto out;
-		rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
+		if (wil->brd_file_addr)
+			rc = wil_request_board(wil, WIL_BOARD_FILE_NAME);
+		else
+			rc = wil_request_firmware(wil,
+						  WIL_BOARD_FILE_NAME,
+						  true);
 		if (rc)
 			goto out;
 
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 025bdd3..1875387 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -39,15 +40,16 @@
 #endif /* CONFIG_PM */
 
 static
-void wil_set_capabilities(struct wil6210_priv *wil)
+int wil_set_capabilities(struct wil6210_priv *wil)
 {
 	const char *wil_fw_name;
 	u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
 	u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
 			    RGF_USER_REVISION_ID_MASK);
 	int platform_capa;
+	struct fw_map *iccm_section, *sct;
 
-	bitmap_zero(wil->hw_capabilities, hw_capability_last);
+	bitmap_zero(wil->hw_capa, hw_capa_last);
 	bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
 	bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX);
 	wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
@@ -56,6 +58,8 @@
 
 	switch (jtag_id) {
 	case JTAG_DEV_ID_SPARROW:
+		memcpy(fw_mapping, sparrow_fw_mapping,
+		       sizeof(sparrow_fw_mapping));
 		switch (chip_revision) {
 		case REVISION_ID_SPARROW_D0:
 			wil->hw_name = "Sparrow D0";
@@ -65,6 +69,12 @@
 
 			if (wil_fw_verify_file_exists(wil, wil_fw_name))
 				wil->wil_fw_name = wil_fw_name;
+			sct = wil_find_fw_mapping("mac_rgf_ext");
+			if (!sct) {
+				wil_err(wil, "mac_rgf_ext section not found in fw_mapping\n");
+				return -EINVAL;
+			}
+			memcpy(sct, &sparrow_d0_mac_rgf_ext, sizeof(*sct));
 			break;
 		case REVISION_ID_SPARROW_B0:
 			wil->hw_name = "Sparrow B0";
@@ -75,15 +85,36 @@
 			wil->hw_version = HW_VER_UNKNOWN;
 			break;
 		}
+		wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE;
+		wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE;
+		break;
+	case JTAG_DEV_ID_TALYN:
+		wil->hw_name = "Talyn";
+		wil->hw_version = HW_VER_TALYN;
+		memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping));
+		wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE;
+		wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE;
+		if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) &
+		    BIT_NO_FLASH_INDICATION)
+			set_bit(hw_capa_no_flash, wil->hw_capa);
 		break;
 	default:
 		wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
 			jtag_id, chip_revision);
 		wil->hw_name = "Unknown";
 		wil->hw_version = HW_VER_UNKNOWN;
+		return -EINVAL;
 	}
 
-	wil_info(wil, "Board hardware is %s\n", wil->hw_name);
+	iccm_section = wil_find_fw_mapping("fw_code");
+	if (!iccm_section) {
+		wil_err(wil, "fw_code section not found in fw_mapping\n");
+		return -EINVAL;
+	}
+	wil->iccm_base = iccm_section->host;
+
+	wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name,
+		 test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : "");
 
 	/* Get platform capabilities */
 	if (wil->platform_ops.get_capa) {
@@ -96,6 +127,8 @@
 	/* extract FW capabilities from file without loading the FW */
 	wil_request_firmware(wil, wil->wil_fw_name, false);
 	wil_refresh_fw_capabilities(wil);
+
+	return 0;
 }
 
 void wil_disable_irq(struct wil6210_priv *wil)
@@ -299,7 +332,11 @@
 	/* rollback to err_iounmap */
 	wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr);
 
-	wil_set_capabilities(wil);
+	rc = wil_set_capabilities(wil);
+	if (rc) {
+		wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc);
+		goto err_iounmap;
+	}
 	wil6210_clear_irq(wil);
 
 	/* FW should raise IRQ when ready */
@@ -385,6 +422,7 @@
 static const struct pci_device_id wil6210_pcie_ids[] = {
 	{ PCI_DEVICE(0x1ae9, 0x0310) },
 	{ PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
+	{ PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */
 	{ /* end: all zeroes */	},
 };
 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 33df230..2f6d6c9 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -170,6 +171,7 @@
 	#define HW_MACHINE_BOOT_DONE	(0x3fffffd)
 #define RGF_USER_USER_CPU_0		(0x8801e0)
 	#define BIT_USER_USER_CPU_MAN_RST	BIT(1) /* user_cpu_man_rst */
+#define RGF_USER_CPU_PC			(0x8801e8)
 #define RGF_USER_MAC_CPU_0		(0x8801fc)
 	#define BIT_USER_MAC_CPU_MAN_RST	BIT(1) /* mac_cpu_man_rst */
 #define RGF_USER_USER_SCRATCH_PAD	(0x8802bc)
@@ -195,6 +197,19 @@
 #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1	(0x880c2c)
 #define RGF_USER_SPARROW_M_4			(0x880c50) /* Sparrow */
 	#define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF	BIT(2)
+#define RGF_USER_OTP_HW_RD_MACHINE_1	(0x880ce0)
+	#define BIT_NO_FLASH_INDICATION		BIT(8)
+#define RGF_USER_XPM_IFC_RD_TIME1	(0x880cec)
+#define RGF_USER_XPM_IFC_RD_TIME2	(0x880cf0)
+#define RGF_USER_XPM_IFC_RD_TIME3	(0x880cf4)
+#define RGF_USER_XPM_IFC_RD_TIME4	(0x880cf8)
+#define RGF_USER_XPM_IFC_RD_TIME5	(0x880cfc)
+#define RGF_USER_XPM_IFC_RD_TIME6	(0x880d00)
+#define RGF_USER_XPM_IFC_RD_TIME7	(0x880d04)
+#define RGF_USER_XPM_IFC_RD_TIME8	(0x880d08)
+#define RGF_USER_XPM_IFC_RD_TIME9	(0x880d0c)
+#define RGF_USER_XPM_IFC_RD_TIME10	(0x880d10)
+#define RGF_USER_XPM_RD_DOUT_SAMPLE_TIME (0x880d64)
 
 #define RGF_DMA_EP_TX_ICR		(0x881bb4) /* struct RGF_ICR */
 	#define BIT_DMA_EP_TX_ICR_TX_DONE	BIT(0)
@@ -285,22 +300,33 @@
 #define RGF_CAF_PLL_LOCK_STATUS		(0x88afec)
 	#define BIT_CAF_OSC_DIG_XTAL_STABLE	BIT(0)
 
+#define USER_EXT_USER_PMU_3		(0x88d00c)
+	#define BIT_PMU_DEVICE_RDY		BIT(0)
+
 #define RGF_USER_JTAG_DEV_ID	(0x880b34) /* device ID */
 	#define JTAG_DEV_ID_SPARROW	(0x2632072f)
+	#define JTAG_DEV_ID_TALYN	(0x7e0e1)
 
 #define RGF_USER_REVISION_ID		(0x88afe4)
 #define RGF_USER_REVISION_ID_MASK	(3)
 	#define REVISION_ID_SPARROW_B0	(0x0)
 	#define REVISION_ID_SPARROW_D0	(0x3)
 
+#define RGF_OTP_MAC			(0x8a0620)
+
 /* crash codes for FW/Ucode stored here */
-#define RGF_FW_ASSERT_CODE		(0x91f020)
-#define RGF_UCODE_ASSERT_CODE		(0x91f028)
+
+/* ASSERT RGFs */
+#define SPARROW_RGF_FW_ASSERT_CODE	(0x91f020)
+#define SPARROW_RGF_UCODE_ASSERT_CODE	(0x91f028)
+#define TALYN_RGF_FW_ASSERT_CODE	(0xa37020)
+#define TALYN_RGF_UCODE_ASSERT_CODE	(0xa37028)
 
 enum {
 	HW_VER_UNKNOWN,
 	HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */
 	HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */
+	HW_VER_TALYN,	/* JTAG_DEV_ID_TALYN */
 };
 
 /* popular locations */
@@ -316,6 +342,10 @@
 #define WIL_DATA_COMPLETION_TO_MS 200
 
 /* Hardware definitions end */
+#define SPARROW_FW_MAPPING_TABLE_SIZE 10
+#define TALYN_FW_MAPPING_TABLE_SIZE 13
+#define MAX_FW_MAPPING_TABLE_SIZE 13
+
 struct fw_map {
 	u32 from; /* linker address - from, inclusive */
 	u32 to;   /* linker address - to, exclusive */
@@ -325,7 +355,10 @@
 };
 
 /* array size should be in sync with actual definition in the wmi.c */
-extern const struct fw_map fw_mapping[10];
+extern const struct fw_map sparrow_fw_mapping[SPARROW_FW_MAPPING_TABLE_SIZE];
+extern const struct fw_map sparrow_d0_mac_rgf_ext;
+extern const struct fw_map talyn_fw_mapping[TALYN_FW_MAPPING_TABLE_SIZE];
+extern struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
 
 /**
  * mk_cidxtid - construct @cidxtid field
@@ -572,7 +605,8 @@
 };
 
 enum {
-	hw_capability_last
+	hw_capa_no_flash,
+	hw_capa_last
 };
 
 struct wil_probe_client_req {
@@ -648,7 +682,10 @@
 	u8 chip_revision;
 	const char *hw_name;
 	const char *wil_fw_name;
-	DECLARE_BITMAP(hw_capabilities, hw_capability_last);
+	char *board_file;
+	u32 brd_file_addr;
+	u32 brd_file_max_size;
+	DECLARE_BITMAP(hw_capa, hw_capa_last);
 	DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
 	DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
 	u8 n_mids; /* number of additional MIDs as reported by FW */
@@ -722,7 +759,7 @@
 	atomic_t isr_count_rx, isr_count_tx;
 	/* debugfs */
 	struct dentry *debug;
-	struct wil_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
+	struct wil_blob_wrapper blobs[MAX_FW_MAPPING_TABLE_SIZE];
 	u8 discovery_mode;
 	u8 abft_len;
 	u8 wakeup_trigger;
@@ -770,6 +807,10 @@
 	bool suspend_resp_comp;
 	u32 bus_request_kbps;
 	u32 bus_request_kbps_pre_suspend;
+
+	u32 rgf_fw_assert_code_addr;
+	u32 rgf_ucode_assert_code_addr;
+	u32 iccm_base;
 };
 
 #define wil_to_wiphy(i) (i->wdev->wiphy)
@@ -895,6 +936,7 @@
 int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
 void wil_set_ethtoolops(struct net_device *ndev);
 
+struct fw_map *wil_find_fw_mapping(const char *section);
 void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size);
 void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
 void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
@@ -1034,6 +1076,7 @@
 int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
 int wil_request_firmware(struct wil6210_priv *wil, const char *name,
 			 bool load);
+int wil_request_board(struct wil6210_priv *wil, const char *name);
 bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
 
 void wil_pm_runtime_allow(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 07659b12..f2dba31 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -71,23 +72,23 @@
  * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
  * AHB addresses starting from 0x880000
  *
- * Internally, firmware uses addresses that allows faster access but
+ * Internally, firmware uses addresses that allow faster access but
  * are invisible from the host. To read from these addresses, alternative
  * AHB address must be used.
- *
- * Memory mapping
- * Linker address         PCI/Host address
- *                        0x880000 .. 0xa80000  2Mb BAR0
- * 0x800000 .. 0x807000   0x900000 .. 0x907000  28k DCCM
- * 0x840000 .. 0x857000   0x908000 .. 0x91f000  92k PERIPH
  */
 
 /**
- * @fw_mapping provides memory remapping table
+ * @sparrow_fw_mapping provides memory remapping table for sparrow
  *
  * array size should be in sync with the declaration in the wil6210.h
+ *
+ * Sparrow memory mapping:
+ * Linker address         PCI/Host address
+ *                        0x880000 .. 0xa80000  2Mb BAR0
+ * 0x800000 .. 0x808000   0x900000 .. 0x908000  32k DCCM
+ * 0x840000 .. 0x860000   0x908000 .. 0x928000  128k PERIPH
  */
-const struct fw_map fw_mapping[] = {
+const struct fw_map sparrow_fw_mapping[] = {
 	/* FW code RAM 256k */
 	{0x000000, 0x040000, 0x8c0000, "fw_code", true},
 	/* FW data RAM 32k */
@@ -113,6 +114,59 @@
 	{0x800000, 0x804000, 0x940000, "uc_data", false},
 };
 
+/**
+ * @sparrow_d0_mac_rgf_ext - mac_rgf_ext section for Sparrow D0
+ * it is a bit larger to support extra features
+ */
+const struct fw_map sparrow_d0_mac_rgf_ext = {
+	0x88c000, 0x88c500, 0x88c000, "mac_rgf_ext", true
+};
+
+/**
+ * @talyn_fw_mapping provides memory remapping table for Talyn
+ *
+ * array size should be in sync with the declaration in the wil6210.h
+ *
+ * Talyn memory mapping:
+ * Linker address         PCI/Host address
+ *                        0x880000 .. 0xc80000  4Mb BAR0
+ * 0x800000 .. 0x820000   0xa00000 .. 0xa20000  128k DCCM
+ * 0x840000 .. 0x858000   0xa20000 .. 0xa38000  96k PERIPH
+ */
+const struct fw_map talyn_fw_mapping[] = {
+	/* FW code RAM 1M */
+	{0x000000, 0x100000, 0x900000, "fw_code", true},
+	/* FW data RAM 128k */
+	{0x800000, 0x820000, 0xa00000, "fw_data", true},
+	/* periph. data RAM 96k */
+	{0x840000, 0x858000, 0xa20000, "fw_peri", true},
+	/* various RGF 40k */
+	{0x880000, 0x88a000, 0x880000, "rgf", true},
+	/* AGC table 4k */
+	{0x88a000, 0x88b000, 0x88a000, "AGC_tbl", true},
+	/* Pcie_ext_rgf 4k */
+	{0x88b000, 0x88c000, 0x88b000, "rgf_ext", true},
+	/* mac_ext_rgf 1344b */
+	{0x88c000, 0x88c540, 0x88c000, "mac_rgf_ext", true},
+	/* ext USER RGF 4k */
+	{0x88d000, 0x88e000, 0x88d000, "ext_user_rgf", true},
+	/* OTP 4k */
+	{0x8a0000, 0x8a1000, 0x8a0000, "otp", true},
+	/* DMA EXT RGF 64k */
+	{0x8b0000, 0x8c0000, 0x8b0000, "dma_ext_rgf", true},
+	/* upper area 1536k */
+	{0x900000, 0xa80000, 0x900000, "upper", true},
+	/* UCODE areas - accessible by debugfs blobs but not by
+	 * wmi_addr_remap. UCODE areas MUST be added AFTER FW areas!
+	 */
+	/* ucode code RAM 256k */
+	{0x000000, 0x040000, 0xa38000, "uc_code", false},
+	/* ucode data RAM 32k */
+	{0x800000, 0x808000, 0xa78000, "uc_data", false},
+};
+
+struct fw_map fw_mapping[MAX_FW_MAPPING_TABLE_SIZE];
+
 struct blink_on_off_time led_blink_time[] = {
 	{WIL_LED_BLINK_ON_SLOW_MS, WIL_LED_BLINK_OFF_SLOW_MS},
 	{WIL_LED_BLINK_ON_MED_MS, WIL_LED_BLINK_OFF_MED_MS},
@@ -140,6 +194,24 @@
 }
 
 /**
+ * find fw_mapping entry by section name
+ * @section - section name
+ *
+ * Return pointer to section or NULL if not found
+ */
+struct fw_map *wil_find_fw_mapping(const char *section)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++)
+		if (fw_mapping[i].name &&
+		    !strcmp(section, fw_mapping[i].name))
+			return &fw_mapping[i];
+
+	return NULL;
+}
+
+/**
  * Check address validity for WMI buffer; remap if needed
  * @ptr - internal (linker) fw/ucode address
  * @size - if non zero, validate the block does not
diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig
new file mode 100644
index 0000000..0b37af6
--- /dev/null
+++ b/drivers/net/wireless/cnss/Kconfig
@@ -0,0 +1,116 @@
+config CNSS
+	tristate "CNSS driver for wifi module"
+	select CNSS_UTILS
+	select CRYPTO
+	select CRYPTO_HASH
+	select CRYPTO_BLKCIPHER
+	---help---
+	 This module adds support for the CNSS connectivity subsystem used
+	 for wifi devices based on the QCA AR6320 chipset.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework.
+
+config CNSS_SDIO
+	bool "Enable/disable cnss sdio platform driver for wifi module"
+	depends on CNSS
+	depends on MMC
+	---help---
+	 This module adds support for the CNSS wlan module interfaced
+	 with SDIO bus.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework, power on WLAN chip and registered the WLAN module
+	 as a SDIO client device.
+
+config CNSS_PCI
+	bool "Enable/disable cnss pci platform driver for wifi module"
+	depends on CNSS
+	depends on PCI
+	---help---
+	 This module adds support for the CNSS wlan module interfaced
+	 with PCIe bus.
+	 This driver also adds support to integrate WLAN module to subsystem
+	 restart framework, power on WLAN chip and registered the WLAN module
+	 as a PCIe client device.
+
+config CNSS_ASYNC
+	bool "Enable/disable cnss pci platform driver asynchronous probe"
+	depends on CNSS_PCI
+	---help---
+	 If enabled, CNSS PCI platform driver would do asynchronous probe.
+	 Using asynchronous probe will allow CNSS PCI platform driver to
+	 probe in parallel with other device drivers and will help to
+	 reduce kernel boot time.
+
+config CNSS_MAC_BUG
+	bool "Enable/disable 0-4K memory initialization for QCA6174"
+	depends on CNSS
+	---help---
+	  If enabled, 0-4K memory is reserved for QCA6174 to address
+	  a MAC HW bug. MAC would do an invalid pointer fetch based on
+	  the data, that was read from 0 to 4K. So fill it with zero's;
+	  to an address for which PCIe root complex would honor the read
+	  without any errors.
+
+config CLD_DEBUG
+	bool "Enable/disable CLD debug features"
+	help
+	 WLAN CLD driver uses this config to enable certain debug features.
+	 Some of the debug features may affect performance or may compromise
+	 on security.
+
+	  Say N, if you are building a release kernel for production use.
+	  Only say Y, if you are building a kernel with debug support.
+
+config CLD_HL_SDIO_CORE
+	tristate "Qualcomm Technologies Inc. Core wlan driver for QCA SDIO interface"
+	select WIRELESS_EXT
+	select WEXT_PRIV
+	select WEXT_CORE
+	select WEXT_SPY
+	select NL80211_TESTMODE
+	depends on ARCH_QCOM
+	depends on MMC
+
+config CLD_LL_CORE
+	tristate "Qualcomm Technologies Inc. Core wlan driver"
+	select NL80211_TESTMODE
+	select WEXT_CORE
+	select WEXT_PRIV
+	select WEXT_SPY
+	select WIRELESS_EXT
+	---help---
+	  This section contains the necessary modules needed to enable the
+	  core WLAN driver for Qualcomm Technologies Inc QCA6174 chipset.
+	  Select Y to compile the driver in order to have WLAN functionality
+	  support.
+
+config CNSS_SECURE_FW
+	bool "Enable/Disable Memory Allocation for Secure Firmware Feature"
+	depends on CNSS
+	---help---
+	  CLD Driver can use this for holding local copy of firmware
+	  binaries which is used for sha crypto computation.
+	  The Memory Allocation is done only if this Config Parameter is
+	  enabled
+
+config BUS_AUTO_SUSPEND
+	bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers"
+	depends on CNSS
+	depends on PCI
+	---help---
+	  Runtime Power Management is supported for PCIe based WLAN Drivers.
+	  The features enable cld wlan driver to suspend pcie bus when APPS
+	  is awake based on the driver inactivity with the Firmware.
+	  The Feature uses runtime power management framework from kernel to
+	  track bus access clients and to synchronize the driver activity
+	  during system pm.
+	  This config flag controls the feature per target based. The feature
+	  requires CNSS driver support.
+
+source "drivers/net/wireless/cnss/logger/Kconfig"
+
+config WLAN_FEATURE_RX_WAKELOCK
+	bool "Enable RX wake lock feature"
+	help
+	Enable WLAN_FEATURE_HOLD_RX_WAKELOCK which is required to take rx
+	wakelock when driver receives packets from fw.
diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile
new file mode 100644
index 0000000..38ad562
--- /dev/null
+++ b/drivers/net/wireless/cnss/Makefile
@@ -0,0 +1,6 @@
+# Makefile for CNSS platform driver
+
+obj-$(CONFIG_CNSS_PCI)	+= cnss_pci.o
+obj-$(CONFIG_CNSS_SDIO)	+= cnss_sdio.o
+obj-$(CONFIG_CNSS)	+= cnss_common.o
+obj-$(CONFIG_CNSS_LOGGER)	+= logger/
diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c
new file mode 100644
index 0000000..a1731b0
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.c
@@ -0,0 +1,450 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <net/cfg80211.h>
+
+#define AR6320_REV1_VERSION             0x5000000
+#define AR6320_REV1_1_VERSION           0x5000001
+#define AR6320_REV1_3_VERSION           0x5000003
+#define AR6320_REV2_1_VERSION           0x5010000
+#define AR6320_REV3_VERSION             0x5020000
+#define AR6320_REV3_2_VERSION           0x5030000
+#define AR900B_DEV_VERSION              0x1000000
+#define QCA9377_REV1_1_VERSION          0x5020001
+
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_1 = {
+	"qwlan11.bin", "bdwlan11.bin", "otp11.bin", "utf11.bin",
+	"utfbd11.bin", "epping11.bin", "evicted11.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_2_0 = {
+	"qwlan20.bin", "bdwlan20.bin", "otp20.bin", "utf20.bin",
+	"utfbd20.bin", "epping20.bin", "evicted20.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_1_3 = {
+	"qwlan13.bin", "bdwlan13.bin", "otp13.bin", "utf13.bin",
+	"utfbd13.bin", "epping13.bin", "evicted13.bin"};
+static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
+	"qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
+	"utfbd30.bin", "epping30.bin", "evicted30.bin"};
+static struct cnss_fw_files FW_FILES_DEFAULT = {
+	"qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin",
+	"utfbd.bin", "epping.bin", "evicted.bin"};
+
+enum cnss_dev_bus_type {
+	CNSS_BUS_NONE = -1,
+	CNSS_BUS_PCI,
+	CNSS_BUS_SDIO
+};
+
+static DEFINE_MUTEX(unsafe_channel_list_lock);
+static DEFINE_MUTEX(dfs_nol_info_lock);
+
+static struct cnss_unsafe_channel_list {
+	u16 unsafe_ch_count;
+	u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
+} unsafe_channel_list;
+
+static struct cnss_dfs_nol_info {
+	void *dfs_nol_info;
+	u16 dfs_nol_info_len;
+} dfs_nol_info;
+
+static enum cnss_cc_src cnss_cc_source = CNSS_SOURCE_CORE;
+
+int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	unsafe_channel_list.unsafe_ch_count = ch_count;
+
+	if (ch_count != 0) {
+		memcpy(
+			(char *)unsafe_channel_list.unsafe_ch_list,
+			(char *)unsafe_ch_list, ch_count * sizeof(u16));
+	}
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_set_wlan_unsafe_channel);
+
+int cnss_get_wlan_unsafe_channel(
+			u16 *unsafe_ch_list,
+			u16 *ch_count, u16 buf_len)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if (!unsafe_ch_list || !ch_count) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -ENOMEM;
+	}
+
+	*ch_count = unsafe_channel_list.unsafe_ch_count;
+	memcpy(
+		(char *)unsafe_ch_list,
+		(char *)unsafe_channel_list.unsafe_ch_list,
+		unsafe_channel_list.unsafe_ch_count * sizeof(u16));
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel);
+
+int cnss_wlan_set_dfs_nol(const void *info, u16 info_len)
+{
+	void *temp;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	temp = kmalloc(info_len, GFP_KERNEL);
+	if (!temp) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOMEM;
+	}
+
+	memcpy(temp, info, info_len);
+	dfs_info = &dfs_nol_info;
+	kfree(dfs_info->dfs_nol_info);
+
+	dfs_info->dfs_nol_info = temp;
+	dfs_info->dfs_nol_info_len = info_len;
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_wlan_set_dfs_nol);
+
+int cnss_wlan_get_dfs_nol(void *info, u16 info_len)
+{
+	int len;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	dfs_info = &dfs_nol_info;
+
+	if (!dfs_info->dfs_nol_info || dfs_info->dfs_nol_info_len == 0) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOENT;
+	}
+
+	len = min(info_len, dfs_info->dfs_nol_info_len);
+
+	memcpy(info, dfs_info->dfs_nol_info, len);
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return len;
+}
+EXPORT_SYMBOL(cnss_wlan_get_dfs_nol);
+
+void cnss_init_work(struct work_struct *work, work_func_t func)
+{
+	INIT_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_work);
+
+void cnss_flush_work(void *work)
+{
+	struct work_struct *cnss_work = work;
+
+	cancel_work_sync(cnss_work);
+}
+EXPORT_SYMBOL(cnss_flush_work);
+
+void cnss_flush_delayed_work(void *dwork)
+{
+	struct delayed_work *cnss_dwork = dwork;
+
+	cancel_delayed_work_sync(cnss_dwork);
+}
+EXPORT_SYMBOL(cnss_flush_delayed_work);
+
+void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name)
+{
+	wakeup_source_init(ws, name);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_init);
+
+void cnss_pm_wake_lock(struct wakeup_source *ws)
+{
+	__pm_stay_awake(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock);
+
+void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec)
+{
+	__pm_wakeup_event(ws, msec);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_timeout);
+
+void cnss_pm_wake_lock_release(struct wakeup_source *ws)
+{
+	__pm_relax(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_release);
+
+void cnss_pm_wake_lock_destroy(struct wakeup_source *ws)
+{
+	wakeup_source_trash(ws);
+}
+EXPORT_SYMBOL(cnss_pm_wake_lock_destroy);
+
+void cnss_get_monotonic_boottime(struct timespec *ts)
+{
+	get_monotonic_boottime(ts);
+}
+EXPORT_SYMBOL(cnss_get_monotonic_boottime);
+
+void cnss_get_boottime(struct timespec *ts)
+{
+	ktime_get_ts(ts);
+}
+EXPORT_SYMBOL(cnss_get_boottime);
+
+void cnss_init_delayed_work(struct delayed_work *work, work_func_t func)
+{
+	INIT_DELAYED_WORK(work, func);
+}
+EXPORT_SYMBOL(cnss_init_delayed_work);
+
+int cnss_vendor_cmd_reply(struct sk_buff *skb)
+{
+	return cfg80211_vendor_cmd_reply(skb);
+}
+EXPORT_SYMBOL(cnss_vendor_cmd_reply);
+
+int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu)
+{
+	return set_cpus_allowed_ptr(task, cpumask_of(cpu));
+}
+EXPORT_SYMBOL(cnss_set_cpus_allowed_ptr);
+
+/* wlan prop driver cannot invoke show_stack
+ * function directly, so to invoke this function it
+ * call wcnss_dump_stack function
+ */
+void cnss_dump_stack(struct task_struct *task)
+{
+	show_stack(task, NULL);
+}
+EXPORT_SYMBOL(cnss_dump_stack);
+
+struct cnss_dev_platform_ops *cnss_get_platform_ops(struct device *dev)
+{
+	if (!dev)
+		return NULL;
+	else
+		return dev->platform_data;
+}
+
+int cnss_common_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->request_bus_bandwidth)
+		return pf_ops->request_bus_bandwidth(bandwidth);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_request_bus_bandwidth);
+
+void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->get_virt_ramdump_mem)
+		return pf_ops->get_virt_ramdump_mem(size);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_virt_ramdump_mem);
+
+void cnss_common_device_self_recovery(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->device_self_recovery)
+		pf_ops->device_self_recovery();
+}
+EXPORT_SYMBOL(cnss_common_device_self_recovery);
+
+void cnss_common_schedule_recovery_work(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->schedule_recovery_work)
+		pf_ops->schedule_recovery_work();
+}
+EXPORT_SYMBOL(cnss_common_schedule_recovery_work);
+
+void cnss_common_device_crashed(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->device_crashed)
+		pf_ops->device_crashed();
+}
+EXPORT_SYMBOL(cnss_common_device_crashed);
+
+u8 *cnss_common_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->get_wlan_mac_address)
+		return pf_ops->get_wlan_mac_address(num);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(cnss_common_get_wlan_mac_address);
+
+int cnss_common_set_wlan_mac_address(
+		struct device *dev, const u8 *in, u32 len)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->set_wlan_mac_address)
+		return pf_ops->set_wlan_mac_address(in, len);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_set_wlan_mac_address);
+
+int cnss_power_up(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->power_up)
+		return pf_ops->power_up(dev);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_up);
+
+int cnss_power_down(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->power_down)
+		return pf_ops->power_down(dev);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_power_down);
+
+void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+			       u32 size, u32 tufello_dual_fw)
+{
+	if (tufello_dual_fw)
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+	else
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+}
+EXPORT_SYMBOL(cnss_get_qca9377_fw_files);
+
+int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+				 u32 target_type, u32 target_version)
+{
+	if (!pfw_files)
+		return -ENODEV;
+
+	switch (target_version) {
+	case AR6320_REV1_VERSION:
+	case AR6320_REV1_1_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_1, sizeof(*pfw_files));
+		break;
+	case AR6320_REV1_3_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_1_3, sizeof(*pfw_files));
+		break;
+	case AR6320_REV2_1_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_2_0, sizeof(*pfw_files));
+		break;
+	case AR6320_REV3_VERSION:
+	case AR6320_REV3_2_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+		break;
+	default:
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+		pr_err("%s default version 0x%X 0x%X", __func__,
+		       target_type, target_version);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files_for_target);
+
+void cnss_set_cc_source(enum cnss_cc_src cc_source)
+{
+	cnss_cc_source = cc_source;
+}
+EXPORT_SYMBOL(cnss_set_cc_source);
+
+enum cnss_cc_src cnss_get_cc_source(void)
+{
+	return cnss_cc_source;
+}
+EXPORT_SYMBOL(cnss_get_cc_source);
+
+const char *cnss_wlan_get_evicted_data_file(void)
+{
+	return FW_FILES_QCA6174_FW_3_0.evicted_data;
+}
+
+int cnss_common_register_tsf_captured_handler(struct device *dev,
+					      irq_handler_t handler, void *ctx)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->register_tsf_captured_handler)
+		return pf_ops->register_tsf_captured_handler(handler, ctx);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_register_tsf_captured_handler);
+
+int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+						void *ctx)
+{
+	struct cnss_dev_platform_ops *pf_ops = cnss_get_platform_ops(dev);
+
+	if (pf_ops && pf_ops->unregister_tsf_captured_handler)
+		return pf_ops->unregister_tsf_captured_handler(ctx);
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_common_unregister_tsf_captured_handler);
diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h
new file mode 100644
index 0000000..7013aba
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _NET_CNSS_COMMON_H_
+#define _NET_CNSS_COMMON_H_
+
+/* max 20mhz channel count */
+#define CNSS_MAX_CH_NUM		45
+
+struct cnss_cap_tsf_info {
+	int irq_num;
+	void *context;
+	irq_handler_t irq_handler;
+};
+
+struct cnss_dev_platform_ops {
+	int (*request_bus_bandwidth)(int bandwidth);
+	void* (*get_virt_ramdump_mem)(unsigned long *size);
+	void (*device_self_recovery)(void);
+	void (*schedule_recovery_work)(void);
+	void (*device_crashed)(void);
+	u8 * (*get_wlan_mac_address)(u32 *num);
+	int (*set_wlan_mac_address)(const u8 *in, u32 len);
+	int (*power_up)(struct device *dev);
+	int (*power_down)(struct device *dev);
+	int (*register_tsf_captured_handler)(irq_handler_t handler,
+					     void *adapter);
+	int (*unregister_tsf_captured_handler)(void *adapter);
+};
+
+int cnss_pci_request_bus_bandwidth(int bandwidth);
+int cnss_sdio_request_bus_bandwidth(int bandwidth);
+
+void cnss_sdio_device_crashed(void);
+void cnss_pci_device_crashed(void);
+
+void cnss_pci_device_self_recovery(void);
+void cnss_sdio_device_self_recovery(void);
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size);
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size);
+
+void cnss_sdio_schedule_recovery_work(void);
+void cnss_pci_schedule_recovery_work(void);
+
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len);
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len);
+
+u8 *cnss_pci_get_wlan_mac_address(u32 *num);
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num);
+int cnss_sdio_power_up(struct device *dev);
+int cnss_sdio_power_down(struct device *dev);
+int cnss_pcie_power_up(struct device *dev);
+int cnss_pcie_power_down(struct device *dev);
+const char *cnss_wlan_get_evicted_data_file(void);
+#endif /* _NET_CNSS_COMMON_H_ */
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
new file mode 100644
index 0000000..8797e68
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -0,0 +1,3835 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/sched.h>
+#include <linux/pm_qos.h>
+#include <linux/pm_runtime.h>
+#include <linux/esoc_client.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/spinlock.h>
+#include <linux/suspend.h>
+#include <linux/rwsem.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/log2.h>
+#include <linux/etherdevice.h>
+#include <linux/msm_pcie.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <net/cfg80211.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include <net/cnss_prealloc.h>
+#endif
+
+#define subsys_to_drv(d) container_of(d, struct cnss_data, subsys_desc)
+
+#define VREG_ON			1
+#define VREG_OFF		0
+#define WLAN_EN_HIGH		1
+#define WLAN_EN_LOW		0
+#define PCIE_LINK_UP		1
+#define PCIE_LINK_DOWN		0
+#define WLAN_BOOTSTRAP_HIGH	1
+#define WLAN_BOOTSTRAP_LOW	0
+#define CNSS_DUMP_FORMAT_VER	0x11
+#define CNSS_DUMP_MAGIC_VER_V2	0x42445953
+#define CNSS_DUMP_NAME		"CNSS_WLAN"
+
+#define QCA6174_VENDOR_ID	(0x168C)
+#define QCA6174_DEVICE_ID	(0x003E)
+#define BEELINER_DEVICE_ID      (0x0040)
+#define QCA6174_REV_ID_OFFSET	(0x08)
+#define QCA6174_FW_1_1	(0x11)
+#define QCA6174_FW_1_3	(0x13)
+#define QCA6174_FW_2_0	(0x20)
+#define QCA6174_FW_3_0	(0x30)
+#define QCA6174_FW_3_2	(0x32)
+#define BEELINER_FW	(0x00)
+
+#define QCA6180_VENDOR_ID	(0x168C)
+#define QCA6180_DEVICE_ID	(0x0041)
+#define QCA6180_REV_ID_OFFSET	(0x08)
+
+#define WLAN_EN_VREG_NAME	"vdd-wlan-en"
+#define WLAN_VREG_NAME		"vdd-wlan"
+#define WLAN_VREG_IO_NAME	"vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME	"vdd-wlan-xtal"
+#define WLAN_VREG_XTAL_AON_NAME	"vdd-wlan-xtal-aon"
+#define WLAN_VREG_CORE_NAME	"vdd-wlan-core"
+#define WLAN_VREG_SP2T_NAME	"vdd-wlan-sp2t"
+#define WLAN_SWREG_NAME		"wlan-soc-swreg"
+#define WLAN_ANT_SWITCH_NAME	"wlan-ant-switch"
+#define WLAN_EN_GPIO_NAME	"wlan-en-gpio"
+#define WLAN_BOOTSTRAP_GPIO_NAME "wlan-bootstrap-gpio"
+#define PM_OPTIONS		0
+#define PM_OPTIONS_SUSPEND_LINK_DOWN \
+	(MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN)
+#define PM_OPTIONS_RESUME_LINK_DOWN \
+	(MSM_PCIE_CONFIG_NO_CFG_RESTORE)
+
+#define SOC_SWREG_VOLT_MAX	1200000
+#define SOC_SWREG_VOLT_MIN	1200000
+#define WLAN_ANT_SWITCH_VOLT_MAX	2700000
+#define WLAN_ANT_SWITCH_VOLT_MIN	2700000
+#define WLAN_ANT_SWITCH_CURR	20000
+#define WLAN_VREG_IO_MAX	1800000
+#define WLAN_VREG_IO_MIN	1800000
+#define WLAN_VREG_XTAL_MAX	1800000
+#define WLAN_VREG_XTAL_MIN	1800000
+#define WLAN_VREG_CORE_MAX	1300000
+#define WLAN_VREG_CORE_MIN	1300000
+#define WLAN_VREG_SP2T_MAX	2700000
+#define WLAN_VREG_SP2T_MIN	2700000
+
+#define POWER_ON_DELAY		2
+#define WLAN_VREG_IO_DELAY_MIN	100
+#define WLAN_VREG_IO_DELAY_MAX	1000
+#define WLAN_ENABLE_DELAY	10
+#define PCIE_SWITCH_DELAY       20
+#define WLAN_RECOVERY_DELAY	1
+#define PCIE_ENABLE_DELAY	100
+#define WLAN_BOOTSTRAP_DELAY	10
+#define EVICT_BIN_MAX_SIZE      (512 * 1024)
+
+static DEFINE_SPINLOCK(pci_link_down_lock);
+
+#define FW_NAME_FIXED_LEN	(6)
+#define MAX_NUM_OF_SEGMENTS	(16)
+#define MAX_INDEX_FILE_SIZE	(512)
+#define FW_FILENAME_LENGTH	(13)
+#define TYPE_LENGTH		(4)
+#define PER_FILE_DATA		(21)
+#define MAX_IMAGE_SIZE		(2 * 1024 * 1024)
+#define FW_IMAGE_FTM		(0x01)
+#define FW_IMAGE_MISSION	(0x02)
+#define FW_IMAGE_BDATA		(0x03)
+#define FW_IMAGE_PRINT		(0x04)
+
+#define SEG_METADATA		(0x01)
+#define SEG_NON_PAGED		(0x02)
+#define SEG_LOCKED_PAGE		(0x03)
+#define SEG_UNLOCKED_PAGE	(0x04)
+#define SEG_NON_SECURE_DATA	(0x05)
+
+#define BMI_TEST_SETUP		(0x09)
+
+struct cnss_wlan_gpio_info {
+	char *name;
+	u32 num;
+	bool state;
+	bool init;
+	bool prop;
+};
+
+struct cnss_wlan_vreg_info {
+	struct regulator *wlan_en_reg;
+	struct regulator *wlan_reg;
+	struct regulator *soc_swreg;
+	struct regulator *ant_switch;
+	struct regulator *wlan_reg_io;
+	struct regulator *wlan_reg_xtal;
+	struct regulator *wlan_reg_xtal_aon;
+	struct regulator *wlan_reg_core;
+	struct regulator *wlan_reg_sp2t;
+	bool state;
+};
+
+struct segment_memory {
+	dma_addr_t dma_region;
+	void *cpu_region;
+	u32 size;
+};
+
+/* FW image descriptor lists */
+struct image_desc_hdr {
+	u8 image_id;
+	u8 reserved[3];
+	u32 segments_cnt;
+};
+
+struct segment_desc {
+	u8 segment_id;
+	u8 segment_idx;
+	u8 flags[2];
+	u32 addr_count;
+	u32 addr_low;
+	u32 addr_high;
+};
+
+struct region_desc {
+	u32 addr_low;
+	u32 addr_high;
+	u32 size;
+	u32 reserved;
+};
+
+struct index_file {
+	u32 type;
+	u32 segment_idx;
+	u8 file_name[13];
+};
+
+struct cnss_dual_wifi {
+	bool is_dual_wifi_enabled;
+};
+
+/**
+ * struct wlan_mac_addr - Structure to hold WLAN MAC Address
+ * @mac_addr: MAC address
+ */
+#define MAX_NO_OF_MAC_ADDR 4
+struct cnss_wlan_mac_addr {
+	u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
+	u32 no_of_mac_addr_set;
+};
+
+/* device_info is expected to be fully populated after cnss_config is invoked.
+ * The function pointer callbacks are expected to be non null as well.
+ */
+static struct cnss_data {
+	struct platform_device *pldev;
+	struct subsys_device *subsys;
+	struct subsys_desc    subsysdesc;
+	struct cnss_wlan_mac_addr wlan_mac_addr;
+	bool is_wlan_mac_set;
+	bool ramdump_dynamic;
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_addr;
+	phys_addr_t ramdump_phys;
+	struct msm_dump_data dump_data;
+	struct cnss_wlan_driver *driver;
+	struct pci_dev *pdev;
+	const struct pci_device_id *id;
+	struct dma_iommu_mapping *smmu_mapping;
+	dma_addr_t smmu_iova_start;
+	size_t smmu_iova_len;
+	struct cnss_wlan_vreg_info vreg_info;
+	bool wlan_en_vreg_support;
+	struct cnss_wlan_gpio_info gpio_info;
+	bool pcie_link_state;
+	bool pcie_link_down_ind;
+	bool pci_register_again;
+	bool notify_modem_status;
+	struct pci_saved_state *saved_state;
+	u16 revision_id;
+	bool recovery_in_progress;
+	atomic_t fw_available;
+	struct codeswap_codeseg_info *cnss_seg_info;
+	/* Virtual Address of the DMA page */
+	void *codeseg_cpuaddr[CODESWAP_MAX_CODESEGS];
+	struct cnss_fw_files fw_files;
+	struct pm_qos_request qos_request;
+	void *modem_notify_handler;
+	int modem_current_status;
+	struct msm_bus_scale_pdata *bus_scale_table;
+	u32 bus_client;
+	int current_bandwidth_vote;
+	void *subsys_handle;
+	struct esoc_desc *esoc_desc;
+	struct cnss_platform_cap cap;
+	struct msm_pcie_register_event event_reg;
+	struct wakeup_source ws;
+	u32 recovery_count;
+	enum cnss_driver_status driver_status;
+#ifdef CONFIG_CNSS_SECURE_FW
+	void *fw_mem;
+#endif
+	u32 device_id;
+	int fw_image_setup;
+	u32 bmi_test;
+	void *fw_cpu;
+	dma_addr_t fw_dma;
+	u32 fw_dma_size;
+	u32 fw_seg_count;
+	struct segment_memory fw_seg_mem[MAX_NUM_OF_SEGMENTS];
+	/* Firmware setup complete lock */
+	struct mutex fw_setup_stat_lock;
+	void *bdata_cpu;
+	dma_addr_t bdata_dma;
+	u32 bdata_dma_size;
+	u32 bdata_seg_count;
+	struct segment_memory bdata_seg_mem[MAX_NUM_OF_SEGMENTS];
+	int wlan_bootstrap_gpio;
+	atomic_t auto_suspended;
+	bool monitor_wake_intr;
+	struct cnss_dual_wifi dual_wifi_info;
+	struct cnss_dev_platform_ops platform_ops;
+} *penv;
+
+static unsigned int pcie_link_down_panic;
+module_param(pcie_link_down_panic, uint, 0600);
+MODULE_PARM_DESC(pcie_link_down_panic,
+		 "Trigger kernel panic when PCIe link down is detected");
+
+static void cnss_put_wlan_enable_gpio(void)
+{
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_en_vreg_support)
+		regulator_put(vreg_info->wlan_en_reg);
+	else
+		gpio_free(gpio_info->num);
+}
+
+static int cnss_wlan_vreg_on(struct cnss_wlan_vreg_info *vreg_info)
+{
+	int ret;
+
+	if (vreg_info->wlan_reg_core) {
+		ret = regulator_enable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_core\n",
+			       __func__);
+			goto error_enable_reg_core;
+		}
+	}
+
+	if (vreg_info->wlan_reg_io) {
+		ret = regulator_enable(vreg_info->wlan_reg_io);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_io\n",
+			       __func__);
+			goto error_enable_reg_io;
+		}
+
+		usleep_range(WLAN_VREG_IO_DELAY_MIN, WLAN_VREG_IO_DELAY_MAX);
+	}
+
+	if (vreg_info->wlan_reg_xtal_aon) {
+		ret = regulator_enable(vreg_info->wlan_reg_xtal_aon);
+		if (ret) {
+			pr_err("%s: wlan_reg_xtal_aon enable failed\n",
+			       __func__);
+			goto error_enable_reg_xtal_aon;
+		}
+	}
+
+	if (vreg_info->wlan_reg_xtal) {
+		ret = regulator_enable(vreg_info->wlan_reg_xtal);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_xtal\n",
+			       __func__);
+			goto error_enable_reg_xtal;
+		}
+	}
+
+	ret = regulator_enable(vreg_info->wlan_reg);
+	if (ret) {
+		pr_err("%s: regulator enable failed for WLAN power\n",
+		       __func__);
+		goto error_enable;
+	}
+
+	if (vreg_info->wlan_reg_sp2t) {
+		ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+		if (ret) {
+			pr_err("%s: regulator enable failed for wlan_reg_sp2t\n",
+			       __func__);
+			goto error_enable_reg_sp2t;
+		}
+	}
+
+	if (vreg_info->ant_switch) {
+		ret = regulator_enable(vreg_info->ant_switch);
+		if (ret) {
+			pr_err("%s: regulator enable failed for ant_switch\n",
+			       __func__);
+			goto error_enable_ant_switch;
+		}
+	}
+
+	if (vreg_info->soc_swreg) {
+		ret = regulator_enable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: regulator enable failed for external soc-swreg\n",
+			       __func__);
+			goto error_enable_soc_swreg;
+		}
+	}
+
+	return ret;
+
+error_enable_soc_swreg:
+	if (vreg_info->ant_switch)
+		regulator_disable(vreg_info->ant_switch);
+error_enable_ant_switch:
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_disable(vreg_info->wlan_reg_sp2t);
+error_enable_reg_sp2t:
+	regulator_disable(vreg_info->wlan_reg);
+error_enable:
+	if (vreg_info->wlan_reg_xtal)
+		regulator_disable(vreg_info->wlan_reg_xtal);
+error_enable_reg_xtal:
+	if (vreg_info->wlan_reg_xtal_aon)
+		regulator_disable(vreg_info->wlan_reg_xtal_aon);
+error_enable_reg_xtal_aon:
+	if (vreg_info->wlan_reg_io)
+		regulator_disable(vreg_info->wlan_reg_io);
+error_enable_reg_io:
+	if (vreg_info->wlan_reg_core)
+		regulator_disable(vreg_info->wlan_reg_core);
+error_enable_reg_core:
+	return ret;
+}
+
+static int cnss_wlan_vreg_off(struct cnss_wlan_vreg_info *vreg_info)
+{
+	int ret;
+
+	if (vreg_info->soc_swreg) {
+		ret = regulator_disable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: regulator disable failed for external soc-swreg\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->ant_switch) {
+		ret = regulator_disable(vreg_info->ant_switch);
+		if (ret) {
+			pr_err("%s: regulator disable failed for ant_switch\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_sp2t) {
+		ret = regulator_disable(vreg_info->wlan_reg_sp2t);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_sp2t\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	ret = regulator_disable(vreg_info->wlan_reg);
+	if (ret) {
+		pr_err("%s: regulator disable failed for WLAN power\n",
+		       __func__);
+		goto error_disable;
+	}
+
+	if (vreg_info->wlan_reg_xtal) {
+		ret = regulator_disable(vreg_info->wlan_reg_xtal);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_xtal\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_xtal_aon) {
+		ret = regulator_disable(vreg_info->wlan_reg_xtal_aon);
+		if (ret) {
+			pr_err("%s: wlan_reg_xtal_aon disable failed\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_io) {
+		ret = regulator_disable(vreg_info->wlan_reg_io);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_io\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+	if (vreg_info->wlan_reg_core) {
+		ret = regulator_disable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: regulator disable failed for wlan_reg_core\n",
+			       __func__);
+			goto error_disable;
+		}
+	}
+
+error_disable:
+	return ret;
+}
+
+static int cnss_wlan_vreg_set(struct cnss_wlan_vreg_info *vreg_info, bool state)
+{
+	int ret = 0;
+
+	if (vreg_info->state == state) {
+		pr_debug("Already wlan vreg state is %s\n",
+			 state ? "enabled" : "disabled");
+		goto out;
+	}
+
+	if (state)
+		ret = cnss_wlan_vreg_on(vreg_info);
+	else
+		ret = cnss_wlan_vreg_off(vreg_info);
+
+	if (ret)
+		goto out;
+
+	pr_debug("%s: wlan vreg is now %s\n", __func__,
+		 state ? "enabled" : "disabled");
+	vreg_info->state = state;
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_gpio_init(struct cnss_wlan_gpio_info *info)
+{
+	int ret = 0;
+
+	ret = gpio_request(info->num, info->name);
+
+	if (ret) {
+		pr_err("can't get gpio %s ret %d\n", info->name, ret);
+		goto err_gpio_req;
+	}
+
+	ret = gpio_direction_output(info->num, info->init);
+
+	if (ret) {
+		pr_err("can't set gpio direction %s ret %d\n", info->name, ret);
+		goto err_gpio_dir;
+	}
+	info->state = info->init;
+
+	return ret;
+
+err_gpio_dir:
+	gpio_free(info->num);
+
+err_gpio_req:
+
+	return ret;
+}
+
+static int cnss_wlan_bootstrap_gpio_init(void)
+{
+	int ret = 0;
+
+	ret = gpio_request(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_GPIO_NAME);
+	if (ret) {
+		pr_err("%s: Can't get GPIO %s, ret = %d\n",
+		       __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+		goto out;
+	}
+
+	ret = gpio_direction_output(penv->wlan_bootstrap_gpio,
+				    WLAN_BOOTSTRAP_HIGH);
+	if (ret) {
+		pr_err("%s: Can't set GPIO %s direction, ret = %d\n",
+		       __func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+		gpio_free(penv->wlan_bootstrap_gpio);
+		goto out;
+	}
+
+	msleep(WLAN_BOOTSTRAP_DELAY);
+out:
+	return ret;
+}
+
+static void cnss_wlan_gpio_set(struct cnss_wlan_gpio_info *info, bool state)
+{
+	if (!info->prop)
+		return;
+
+	if (info->state == state) {
+		pr_debug("Already %s gpio is %s\n",
+			 info->name, state ? "high" : "low");
+		return;
+	}
+
+	gpio_set_value(info->num, state);
+	info->state = state;
+
+	pr_debug("%s: %s gpio is now %s\n", __func__,
+		 info->name, info->state ? "enabled" : "disabled");
+}
+
+static int cnss_configure_wlan_en_gpio(bool state)
+{
+	int ret = 0;
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_en_vreg_support) {
+		if (state)
+			ret = regulator_enable(vreg_info->wlan_en_reg);
+		else
+			ret = regulator_disable(vreg_info->wlan_en_reg);
+	} else {
+		cnss_wlan_gpio_set(gpio_info, state);
+	}
+
+	msleep(WLAN_ENABLE_DELAY);
+	return ret;
+}
+
+static void cnss_disable_xtal_ldo(struct platform_device *pdev)
+{
+	struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+	if (info->wlan_reg_xtal) {
+		regulator_disable(info->wlan_reg_xtal);
+		regulator_put(info->wlan_reg_xtal);
+	}
+
+	if (info->wlan_reg_xtal_aon) {
+		regulator_disable(info->wlan_reg_xtal_aon);
+		regulator_put(info->wlan_reg_xtal_aon);
+	}
+}
+
+static int cnss_enable_xtal_ldo(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct cnss_wlan_vreg_info *info = &penv->vreg_info;
+
+	if (!of_get_property(pdev->dev.of_node,
+			     WLAN_VREG_XTAL_AON_NAME "-supply", NULL))
+		goto enable_xtal;
+
+	info->wlan_reg_xtal_aon = regulator_get(&pdev->dev,
+						WLAN_VREG_XTAL_AON_NAME);
+	if (IS_ERR(info->wlan_reg_xtal_aon)) {
+		ret = PTR_ERR(info->wlan_reg_xtal_aon);
+		pr_err("%s: XTAL AON Regulator get failed err:%d\n", __func__,
+		       ret);
+		return ret;
+	}
+
+	ret = regulator_enable(info->wlan_reg_xtal_aon);
+	if (ret) {
+		pr_err("%s: VREG_XTAL_ON enable failed\n", __func__);
+		goto end;
+	}
+
+enable_xtal:
+
+	if (!of_get_property(pdev->dev.of_node,
+			     WLAN_VREG_XTAL_NAME "-supply", NULL))
+		goto out_disable_xtal_aon;
+
+	info->wlan_reg_xtal = regulator_get(&pdev->dev, WLAN_VREG_XTAL_NAME);
+
+	if (IS_ERR(info->wlan_reg_xtal)) {
+		ret = PTR_ERR(info->wlan_reg_xtal);
+		pr_err("%s XTAL Regulator get failed err:%d\n", __func__, ret);
+		goto out_disable_xtal_aon;
+	}
+
+	ret = regulator_set_voltage(info->wlan_reg_xtal, WLAN_VREG_XTAL_MIN,
+				    WLAN_VREG_XTAL_MAX);
+	if (ret) {
+		pr_err("%s: Set wlan_vreg_xtal failed\n", __func__);
+		goto out_put_xtal;
+	}
+
+	ret = regulator_enable(info->wlan_reg_xtal);
+	if (ret) {
+		pr_err("%s: Enable wlan_vreg_xtal failed\n", __func__);
+		goto out_put_xtal;
+	}
+
+	return 0;
+
+out_put_xtal:
+	if (info->wlan_reg_xtal)
+		regulator_put(info->wlan_reg_xtal);
+
+out_disable_xtal_aon:
+	if (info->wlan_reg_xtal_aon)
+		regulator_disable(info->wlan_reg_xtal_aon);
+
+end:
+	if (info->wlan_reg_xtal_aon)
+		regulator_put(info->wlan_reg_xtal_aon);
+
+	return ret;
+}
+
+static int cnss_get_wlan_enable_gpio(
+	struct cnss_wlan_gpio_info *gpio_info,
+	struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device *dev = &pdev->dev;
+
+	if (!of_find_property(dev->of_node, gpio_info->name, NULL)) {
+		gpio_info->prop = false;
+		return -ENODEV;
+	}
+
+	gpio_info->prop = true;
+	ret = of_get_named_gpio(dev->of_node, gpio_info->name, 0);
+	if (ret >= 0) {
+		gpio_info->num = ret;
+	} else {
+		if (ret == -EPROBE_DEFER)
+			pr_debug("get WLAN_EN GPIO probe defer\n");
+		else
+			pr_err(
+			"can't get gpio %s ret %d", gpio_info->name, ret);
+	}
+
+	ret = cnss_wlan_gpio_init(gpio_info);
+	if (ret)
+		pr_err("gpio init failed\n");
+
+	return ret;
+}
+
+static int cnss_get_wlan_bootstrap_gpio(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device_node *node = (&pdev->dev)->of_node;
+
+	if (!of_find_property(node, WLAN_BOOTSTRAP_GPIO_NAME, NULL))
+		return ret;
+
+	penv->wlan_bootstrap_gpio =
+		of_get_named_gpio(node, WLAN_BOOTSTRAP_GPIO_NAME, 0);
+	if (penv->wlan_bootstrap_gpio > 0) {
+		ret = cnss_wlan_bootstrap_gpio_init();
+	} else {
+		ret = penv->wlan_bootstrap_gpio;
+		pr_err(
+		"%s: Can't get GPIO %s, ret = %d",
+		__func__, WLAN_BOOTSTRAP_GPIO_NAME, ret);
+	}
+
+	return ret;
+}
+
+static int cnss_wlan_get_resources(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+	struct device_node *node = pdev->dev.of_node;
+
+	if (of_get_property(node, WLAN_VREG_CORE_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_core = regulator_get(&pdev->dev,
+			WLAN_VREG_CORE_NAME);
+		if (IS_ERR(vreg_info->wlan_reg_core)) {
+			ret = PTR_ERR(vreg_info->wlan_reg_core);
+
+			if (ret == -EPROBE_DEFER) {
+				pr_err("%s: wlan_reg_core probe deferred\n",
+				       __func__);
+			} else {
+				pr_err("%s: Get wlan_reg_core failed\n",
+				       __func__);
+			}
+			goto err_reg_core_get;
+		}
+
+		ret = regulator_set_voltage(vreg_info->wlan_reg_core,
+					    WLAN_VREG_CORE_MIN,
+					    WLAN_VREG_CORE_MAX);
+		if (ret) {
+			pr_err("%s: Set wlan_reg_core failed\n", __func__);
+			goto err_reg_core_set;
+		}
+
+		ret = regulator_enable(vreg_info->wlan_reg_core);
+		if (ret) {
+			pr_err("%s: Enable wlan_reg_core failed\n", __func__);
+			goto err_reg_core_enable;
+		}
+	}
+
+	if (of_get_property(node, WLAN_VREG_IO_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_io = regulator_get(&pdev->dev,
+			WLAN_VREG_IO_NAME);
+		if (!IS_ERR(vreg_info->wlan_reg_io)) {
+			ret = regulator_set_voltage(vreg_info->wlan_reg_io,
+						    WLAN_VREG_IO_MIN,
+						    WLAN_VREG_IO_MAX);
+			if (ret) {
+				pr_err("%s: Set wlan_vreg_io failed\n",
+				       __func__);
+				goto err_reg_io_set;
+			}
+
+			ret = regulator_enable(vreg_info->wlan_reg_io);
+			if (ret) {
+				pr_err("%s: Enable wlan_vreg_io failed\n",
+				       __func__);
+				goto err_reg_io_enable;
+			}
+
+			usleep_range(WLAN_VREG_IO_DELAY_MIN,
+				     WLAN_VREG_IO_DELAY_MAX);
+		}
+	}
+
+	if (cnss_enable_xtal_ldo(pdev))
+		goto err_reg_xtal_enable;
+
+	vreg_info->wlan_reg = regulator_get(&pdev->dev, WLAN_VREG_NAME);
+
+	if (IS_ERR(vreg_info->wlan_reg)) {
+		if (PTR_ERR(vreg_info->wlan_reg) == -EPROBE_DEFER)
+			pr_err("%s: vreg probe defer\n", __func__);
+		else
+			pr_err("%s: vreg regulator get failed\n", __func__);
+		ret = PTR_ERR(vreg_info->wlan_reg);
+		goto err_reg_get;
+	}
+
+	ret = regulator_enable(vreg_info->wlan_reg);
+
+	if (ret) {
+		pr_err("%s: vreg initial vote failed\n", __func__);
+		goto err_reg_enable;
+	}
+
+	if (of_get_property(node, WLAN_VREG_SP2T_NAME "-supply", NULL)) {
+		vreg_info->wlan_reg_sp2t =
+			regulator_get(&pdev->dev, WLAN_VREG_SP2T_NAME);
+		if (!IS_ERR(vreg_info->wlan_reg_sp2t)) {
+			ret = regulator_set_voltage(vreg_info->wlan_reg_sp2t,
+						    WLAN_VREG_SP2T_MIN,
+						    WLAN_VREG_SP2T_MAX);
+			if (ret) {
+				pr_err("%s: Set wlan_vreg_sp2t failed\n",
+				       __func__);
+				goto err_reg_sp2t_set;
+			}
+
+			ret = regulator_enable(vreg_info->wlan_reg_sp2t);
+			if (ret) {
+				pr_err("%s: Enable wlan_vreg_sp2t failed\n",
+				       __func__);
+				goto err_reg_sp2t_enable;
+			}
+		}
+	}
+
+	if (of_get_property(node, WLAN_ANT_SWITCH_NAME "-supply", NULL)) {
+		vreg_info->ant_switch =
+			regulator_get(&pdev->dev, WLAN_ANT_SWITCH_NAME);
+		if (!IS_ERR(vreg_info->ant_switch)) {
+			ret = regulator_set_voltage(vreg_info->ant_switch,
+						    WLAN_ANT_SWITCH_VOLT_MIN,
+						    WLAN_ANT_SWITCH_VOLT_MAX);
+			if (ret < 0) {
+				pr_err("%s: Set ant_switch voltage failed\n",
+				       __func__);
+				goto err_ant_switch_set;
+			}
+
+			ret = regulator_set_load(vreg_info->ant_switch,
+						 WLAN_ANT_SWITCH_CURR);
+			if (ret < 0) {
+				pr_err("%s: Set ant_switch current failed\n",
+				       __func__);
+				goto err_ant_switch_set;
+			}
+
+			ret = regulator_enable(vreg_info->ant_switch);
+			if (ret < 0) {
+				pr_err("%s: Enable ant_switch failed\n",
+				       __func__);
+				goto err_ant_switch_enable;
+			}
+		}
+	}
+
+	if (of_find_property(node, "qcom,wlan-uart-access", NULL))
+		penv->cap.cap_flag |= CNSS_HAS_UART_ACCESS;
+
+	if (of_get_property(node, WLAN_SWREG_NAME "-supply", NULL)) {
+		vreg_info->soc_swreg = regulator_get(&pdev->dev,
+			WLAN_SWREG_NAME);
+		if (IS_ERR(vreg_info->soc_swreg)) {
+			pr_err("%s: soc-swreg node not found\n",
+			       __func__);
+			goto err_reg_get2;
+		}
+		ret = regulator_set_voltage(vreg_info->soc_swreg,
+					    SOC_SWREG_VOLT_MIN,
+					    SOC_SWREG_VOLT_MAX);
+		if (ret) {
+			pr_err("%s: vreg initial voltage set failed on soc-swreg\n",
+			       __func__);
+			goto err_reg_set;
+		}
+		ret = regulator_enable(vreg_info->soc_swreg);
+		if (ret) {
+			pr_err("%s: vreg initial vote failed\n", __func__);
+			goto err_reg_enable2;
+		}
+		penv->cap.cap_flag |= CNSS_HAS_EXTERNAL_SWREG;
+	}
+
+	penv->wlan_en_vreg_support =
+		of_property_read_bool(node, "qcom,wlan-en-vreg-support");
+	if (penv->wlan_en_vreg_support) {
+		vreg_info->wlan_en_reg =
+			regulator_get(&pdev->dev, WLAN_EN_VREG_NAME);
+		if (IS_ERR(vreg_info->wlan_en_reg)) {
+			pr_err("%s:wlan_en vreg get failed\n", __func__);
+			ret = PTR_ERR(vreg_info->wlan_en_reg);
+			goto err_wlan_en_reg_get;
+		}
+	}
+
+	if (!penv->wlan_en_vreg_support) {
+		ret = cnss_get_wlan_enable_gpio(gpio_info, pdev);
+		if (ret) {
+			pr_err(
+			"%s:Failed to config the WLAN_EN gpio\n", __func__);
+			goto err_gpio_wlan_en;
+		}
+	}
+	vreg_info->state = VREG_ON;
+
+	ret = cnss_get_wlan_bootstrap_gpio(pdev);
+	if (ret) {
+		pr_err("%s: Failed to enable wlan bootstrap gpio\n", __func__);
+		goto err_gpio_wlan_bootstrap;
+	}
+
+	return ret;
+
+err_gpio_wlan_bootstrap:
+	cnss_put_wlan_enable_gpio();
+err_gpio_wlan_en:
+err_wlan_en_reg_get:
+	vreg_info->wlan_en_reg = NULL;
+	if (vreg_info->soc_swreg)
+		regulator_disable(vreg_info->soc_swreg);
+	vreg_info->state = VREG_OFF;
+
+err_reg_enable2:
+err_reg_set:
+	if (vreg_info->soc_swreg)
+		regulator_put(vreg_info->soc_swreg);
+
+err_reg_get2:
+	if (vreg_info->ant_switch)
+		regulator_disable(vreg_info->ant_switch);
+
+err_ant_switch_enable:
+err_ant_switch_set:
+	if (vreg_info->ant_switch)
+		regulator_put(vreg_info->ant_switch);
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_disable(vreg_info->wlan_reg_sp2t);
+
+err_reg_sp2t_enable:
+err_reg_sp2t_set:
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_put(vreg_info->wlan_reg_sp2t);
+	regulator_disable(vreg_info->wlan_reg);
+
+err_reg_enable:
+	regulator_put(vreg_info->wlan_reg);
+err_reg_get:
+	cnss_disable_xtal_ldo(pdev);
+
+err_reg_xtal_enable:
+	if (vreg_info->wlan_reg_io)
+		regulator_disable(vreg_info->wlan_reg_io);
+
+err_reg_io_enable:
+err_reg_io_set:
+	if (vreg_info->wlan_reg_io)
+		regulator_put(vreg_info->wlan_reg_io);
+	if (vreg_info->wlan_reg_core)
+		regulator_disable(vreg_info->wlan_reg_core);
+
+err_reg_core_enable:
+err_reg_core_set:
+	if (vreg_info->wlan_reg_core)
+		regulator_put(vreg_info->wlan_reg_core);
+
+err_reg_core_get:
+	return ret;
+}
+
+static void cnss_wlan_release_resources(void)
+{
+	struct cnss_wlan_gpio_info *gpio_info = &penv->gpio_info;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_free(penv->wlan_bootstrap_gpio);
+	cnss_put_wlan_enable_gpio();
+	gpio_info->state = WLAN_EN_LOW;
+	gpio_info->prop = false;
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (vreg_info->soc_swreg)
+		regulator_put(vreg_info->soc_swreg);
+	if (vreg_info->ant_switch)
+		regulator_put(vreg_info->ant_switch);
+	if (vreg_info->wlan_reg_sp2t)
+		regulator_put(vreg_info->wlan_reg_sp2t);
+	regulator_put(vreg_info->wlan_reg);
+	if (vreg_info->wlan_reg_xtal)
+		regulator_put(vreg_info->wlan_reg_xtal);
+	if (vreg_info->wlan_reg_xtal_aon)
+		regulator_put(vreg_info->wlan_reg_xtal_aon);
+	if (vreg_info->wlan_reg_io)
+		regulator_put(vreg_info->wlan_reg_io);
+	if (vreg_info->wlan_reg_core)
+		regulator_put(vreg_info->wlan_reg_core);
+	vreg_info->state = VREG_OFF;
+}
+
+static u8 cnss_get_pci_dev_bus_number(struct pci_dev *pdev)
+{
+	return pdev->bus->number;
+}
+
+void cnss_setup_fw_files(u16 revision)
+{
+	switch (revision) {
+	case QCA6174_FW_1_1:
+		strlcpy(penv->fw_files.image_file, "qwlan11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf11.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd11.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_1_3:
+		strlcpy(penv->fw_files.image_file, "qwlan13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf13.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd13.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_2_0:
+		strlcpy(penv->fw_files.image_file, "qwlan20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf20.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd20.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	case QCA6174_FW_3_0:
+	case QCA6174_FW_3_2:
+		strlcpy(penv->fw_files.image_file, "qwlan30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf30.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd30.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+
+	default:
+		strlcpy(penv->fw_files.image_file, "qwlan.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.board_data, "bdwlan.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.otp_data, "otp.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_file, "utf.bin",
+			CNSS_MAX_FILE_NAME);
+		strlcpy(penv->fw_files.utf_board_data, "utfbd.bin",
+			CNSS_MAX_FILE_NAME);
+		break;
+	}
+}
+
+int cnss_get_fw_files(struct cnss_fw_files *pfw_files)
+{
+	if (!penv || !pfw_files)
+		return -ENODEV;
+
+	*pfw_files = penv->fw_files;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+	penv->fw_mem = devm_kzalloc(&pdev->dev, MAX_FIRMWARE_SIZE, GFP_KERNEL);
+}
+#else
+static void cnss_wlan_fw_mem_alloc(struct pci_dev *pdev)
+{
+}
+#endif
+
+static int get_image_file(const u8 *index_info, u8 *file_name,
+			  u32 *type, u32 *segment_idx)
+{
+	if (!file_name || !index_info || !type)
+		return -EINVAL;
+
+	memcpy(type, index_info, TYPE_LENGTH);
+	memcpy(segment_idx, index_info + TYPE_LENGTH, TYPE_LENGTH);
+	memcpy(file_name, index_info + TYPE_LENGTH + TYPE_LENGTH,
+	       FW_FILENAME_LENGTH);
+
+	pr_debug("%u: %u: %s", *type, *segment_idx, file_name);
+
+	return PER_FILE_DATA;
+}
+
+static void print_allocated_image_table(void)
+{
+	u32 seg = 0, count = 0;
+	u8 *dump_addr;
+	struct segment_memory *pseg_mem = penv->fw_seg_mem;
+	struct segment_memory *p_bdata_seg_mem = penv->bdata_seg_mem;
+
+	pr_debug("%s: Dumping FW IMAGE\n", __func__);
+	while (seg++ < penv->fw_seg_count) {
+		dump_addr = (u8 *)pseg_mem->cpu_region +
+			sizeof(struct region_desc);
+		for (count = 0; count < pseg_mem->size -
+				sizeof(struct region_desc); count++)
+			pr_debug("%02x", dump_addr[count]);
+
+		pseg_mem++;
+	}
+
+	seg = 0;
+	pr_debug("%s: Dumping BOARD DATA\n", __func__);
+	while (seg++ < penv->bdata_seg_count) {
+		dump_addr = (u8 *)p_bdata_seg_mem->cpu_region +
+			sizeof(struct region_desc);
+		for (count = 0; count < p_bdata_seg_mem->size -
+			     sizeof(struct region_desc); count++)
+			pr_debug("%02x ", dump_addr[count]);
+
+		p_bdata_seg_mem++;
+	}
+}
+
+static void free_allocated_image_table(void)
+{
+	struct device *dev = &penv->pdev->dev;
+	struct segment_memory *pseg_mem;
+	u32 seg = 0;
+
+	/* free fw memroy */
+	pseg_mem = penv->fw_seg_mem;
+	while (seg++ < penv->fw_seg_count) {
+		dma_free_coherent(dev, pseg_mem->size,
+				  pseg_mem->cpu_region, pseg_mem->dma_region);
+		pseg_mem++;
+	}
+	if (penv->fw_cpu)
+		dma_free_coherent(dev,
+				  sizeof(struct segment_desc) *
+				  MAX_NUM_OF_SEGMENTS,
+				  penv->fw_cpu, penv->fw_dma);
+	penv->fw_seg_count = 0;
+	penv->fw_dma = 0;
+	penv->fw_cpu = NULL;
+	penv->fw_dma_size = 0;
+
+	/* free bdata memory */
+	seg = 0;
+	pseg_mem = penv->bdata_seg_mem;
+	while (seg++ < penv->bdata_seg_count) {
+		dma_free_coherent(dev, pseg_mem->size,
+				  pseg_mem->cpu_region,
+				  pseg_mem->dma_region);
+		pseg_mem++;
+	}
+	if (penv->bdata_cpu)
+		dma_free_coherent(dev,
+				  sizeof(struct segment_desc) *
+				  MAX_NUM_OF_SEGMENTS,
+				  penv->bdata_cpu, penv->bdata_dma);
+	penv->bdata_seg_count = 0;
+	penv->bdata_dma = 0;
+	penv->bdata_cpu = NULL;
+	penv->bdata_dma_size = 0;
+}
+
+static int cnss_setup_fw_image_table(int mode)
+{
+	struct image_desc_hdr *image_hdr;
+	struct segment_desc *pseg = NULL;
+	const struct firmware *fw_index, *fw_image;
+	struct device *dev = NULL;
+	char reserved[3] = "";
+	u8 image_file[FW_FILENAME_LENGTH] = "";
+	u8 index_file[FW_FILENAME_LENGTH] = "";
+	u8 index_info[MAX_INDEX_FILE_SIZE] = "";
+	size_t image_desc_size = 0, file_size = 0;
+	size_t index_pos = 0, image_pos = 0;
+	struct region_desc *reg_desc = NULL;
+	u32 type = 0;
+	u32 segment_idx = 0;
+	uintptr_t address;
+	int ret = 0;
+	dma_addr_t dma_addr;
+	void *vaddr = NULL;
+	dma_addr_t paddr;
+	struct segment_memory *pseg_mem;
+	u32 *pseg_count;
+
+	if (!penv || !penv->pdev) {
+		pr_err("cnss: invalid penv or pdev or dev\n");
+		ret = -EINVAL;
+		goto err;
+	}
+	dev = &penv->pdev->dev;
+
+	/*  meta data file has image details */
+	switch (mode) {
+	case FW_IMAGE_FTM:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qftm.bin");
+		pseg_mem = penv->fw_seg_mem;
+		pseg_count = &penv->fw_seg_count;
+		break;
+	case FW_IMAGE_MISSION:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "qwlan.bin");
+		pseg_mem = penv->fw_seg_mem;
+		pseg_count = &penv->fw_seg_count;
+		break;
+	case FW_IMAGE_BDATA:
+		ret = scnprintf(index_file, FW_FILENAME_LENGTH, "bdwlan.bin");
+		pseg_mem = penv->bdata_seg_mem;
+		pseg_count = &penv->bdata_seg_count;
+		break;
+	default:
+		pr_err("%s: Unknown meta data file type 0x%x\n",
+		       __func__, mode);
+		ret = -EINVAL;
+	}
+	if (ret < 0)
+		goto err;
+
+	image_desc_size = sizeof(struct image_desc_hdr) +
+		sizeof(struct segment_desc) * MAX_NUM_OF_SEGMENTS;
+
+	vaddr = dma_alloc_coherent(dev, image_desc_size,
+				   &paddr, GFP_KERNEL);
+
+	if (!vaddr) {
+		pr_err("cnss: image desc allocation failure\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memset(vaddr, 0, image_desc_size);
+
+	image_hdr = (struct image_desc_hdr *)vaddr;
+	image_hdr->image_id = mode;
+	memcpy(image_hdr->reserved, reserved, 3);
+
+	pr_err("cnss: request meta data file %s\n", index_file);
+	ret = request_firmware(&fw_index, index_file, dev);
+	if (ret || !fw_index || !fw_index->data || !fw_index->size) {
+		pr_err("cnss: meta data file open failure %s\n", index_file);
+		goto err_free;
+	}
+
+	if (fw_index->size > MAX_INDEX_FILE_SIZE) {
+		pr_err("cnss: meta data file has invalid size %s: %zu\n",
+		       index_file, fw_index->size);
+		release_firmware(fw_index);
+		goto err_free;
+	}
+
+	memcpy(index_info, fw_index->data, fw_index->size);
+	file_size = fw_index->size;
+	release_firmware(fw_index);
+
+	while (file_size >= PER_FILE_DATA  && image_pos < image_desc_size &&
+	       image_hdr->segments_cnt < MAX_NUM_OF_SEGMENTS) {
+		ret = get_image_file(index_info + index_pos,
+				     image_file, &type, &segment_idx);
+		if (ret == -EINVAL)
+			goto err_free;
+
+		file_size -= ret;
+		index_pos += ret;
+		pseg = vaddr + image_pos +
+				sizeof(struct image_desc_hdr);
+
+		switch (type) {
+		case SEG_METADATA:
+		case SEG_NON_PAGED:
+		case SEG_LOCKED_PAGE:
+		case SEG_UNLOCKED_PAGE:
+		case SEG_NON_SECURE_DATA:
+
+			image_hdr->segments_cnt++;
+			pseg->segment_id = type;
+			pseg->segment_idx = (u8)(segment_idx & 0xff);
+			memcpy(pseg->flags, reserved, 2);
+
+			ret = request_firmware(&fw_image, image_file, dev);
+			if (ret || !fw_image || !fw_image->data ||
+			    !fw_image->size) {
+				pr_err("cnss: image file read failed %s",
+				       image_file);
+				goto err_free;
+			}
+			if (fw_image->size > MAX_IMAGE_SIZE) {
+				pr_err("cnss: %s: image file invalid size %zu\n",
+				       image_file, fw_image->size);
+				release_firmware(fw_image);
+				ret = -EINVAL;
+				goto err_free;
+			}
+			reg_desc =
+				dma_alloc_coherent(dev,
+						   sizeof(struct region_desc) +
+						   fw_image->size,
+						   &dma_addr, GFP_KERNEL);
+			if (!reg_desc) {
+				pr_err("cnss: region allocation failure\n");
+				ret = -ENOMEM;
+				release_firmware(fw_image);
+				goto err_free;
+			}
+			address = (uintptr_t)dma_addr;
+			pseg->addr_low = address & 0xFFFFFFFF;
+			pseg->addr_high = 0x00;
+			/* one region for one image file */
+			pseg->addr_count = 1;
+			memcpy((u8 *)reg_desc + sizeof(struct region_desc),
+			       fw_image->data, fw_image->size);
+			address += sizeof(struct region_desc);
+			reg_desc->addr_low = address & 0xFFFFFFFF;
+			reg_desc->addr_high = 0x00;
+			reg_desc->reserved = 0;
+			reg_desc->size = fw_image->size;
+
+			pseg_mem[*pseg_count].dma_region = dma_addr;
+			pseg_mem[*pseg_count].cpu_region = reg_desc;
+			pseg_mem[*pseg_count].size =
+				sizeof(struct region_desc) + fw_image->size;
+
+			release_firmware(fw_image);
+			(*pseg_count)++;
+			break;
+
+		default:
+			pr_err("cnss: Unknown segment %d", type);
+			ret = -EINVAL;
+			goto err_free;
+		}
+		image_pos += sizeof(struct segment_desc);
+	}
+	if (mode != FW_IMAGE_BDATA) {
+		penv->fw_cpu = vaddr;
+		penv->fw_dma = paddr;
+		penv->fw_dma_size = sizeof(struct image_desc_hdr) +
+			sizeof(struct segment_desc) * image_hdr->segments_cnt;
+	} else {
+		penv->bdata_cpu = vaddr;
+		penv->bdata_dma = paddr;
+		penv->bdata_dma_size = sizeof(struct image_desc_hdr) +
+			sizeof(struct segment_desc) * image_hdr->segments_cnt;
+	}
+	pr_info("%s: Mode %d: Image setup table built on host", __func__, mode);
+
+	return file_size;
+err_free:
+	free_allocated_image_table();
+err:
+	pr_err("cnss: image file setup failed %d\n", ret);
+	return ret;
+}
+
+int cnss_get_fw_image(struct image_desc_info *image_desc_info)
+{
+	if (!image_desc_info || !penv ||
+	    !penv->fw_seg_count || !penv->bdata_seg_count)
+		return -EINVAL;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	image_desc_info->fw_addr = penv->fw_dma;
+	image_desc_info->fw_size = penv->fw_dma_size;
+	image_desc_info->bdata_addr = penv->bdata_dma;
+	image_desc_info->bdata_size = penv->bdata_dma_size;
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_image);
+
+static ssize_t wlan_setup_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", penv->revision_id);
+}
+
+static DEVICE_ATTR(wlan_setup, 0400,
+			wlan_setup_show, NULL);
+
+static int cnss_wlan_is_codeswap_supported(u16 revision)
+{
+	switch (revision) {
+	case QCA6174_FW_3_0:
+	case QCA6174_FW_3_2:
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+static int cnss_smmu_init(struct device *dev)
+{
+	struct dma_iommu_mapping *mapping;
+	int atomic_ctx = 1;
+	int ret;
+
+	mapping = arm_iommu_create_mapping(&platform_bus_type,
+					   penv->smmu_iova_start,
+					   penv->smmu_iova_len);
+	if (IS_ERR(mapping)) {
+		ret = PTR_ERR(mapping);
+		pr_err("%s: create mapping failed, err = %d\n", __func__, ret);
+		goto map_fail;
+	}
+
+	ret = iommu_domain_set_attr(mapping->domain,
+				    DOMAIN_ATTR_ATOMIC,
+				    &atomic_ctx);
+	if (ret) {
+		pr_err("%s: set atomic_ctx attribute failed, err = %d\n",
+		       __func__, ret);
+		goto set_attr_fail;
+	}
+
+	ret = arm_iommu_attach_device(dev, mapping);
+	if (ret) {
+		pr_err("%s: attach device failed, err = %d\n", __func__, ret);
+		goto attach_fail;
+	}
+
+	penv->smmu_mapping = mapping;
+
+	return ret;
+
+attach_fail:
+set_attr_fail:
+	arm_iommu_release_mapping(mapping);
+map_fail:
+	return ret;
+}
+
+static void cnss_smmu_remove(struct device *dev)
+{
+	arm_iommu_detach_device(dev);
+	arm_iommu_release_mapping(penv->smmu_mapping);
+
+	penv->smmu_mapping = NULL;
+}
+
+#ifdef CONFIG_PCI_MSM
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+	return pci_store_saved_state(dev);
+}
+
+int cnss_msm_pcie_pm_control(
+		enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+		struct pci_dev *pdev, u32 options)
+{
+	return msm_pcie_pm_control(pm_opt, bus_num, pdev, NULL, options);
+}
+
+int cnss_pci_load_and_free_saved_state(
+	struct pci_dev *dev, struct pci_saved_state **state)
+{
+	return pci_load_and_free_saved_state(dev, state);
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return msm_pcie_shadow_control(dev, enable);
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+	return msm_pcie_deregister_event(reg);
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+	return msm_pcie_recover_config(dev);
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+	return msm_pcie_register_event(reg);
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+	return msm_pcie_enumerate(rc_idx);
+}
+#else /* !defined CONFIG_PCI_MSM */
+
+struct pci_saved_state *cnss_pci_store_saved_state(struct pci_dev *dev)
+{
+	return NULL;
+}
+
+int cnss_msm_pcie_pm_control(
+		enum msm_pcie_pm_opt pm_opt, u32 bus_num,
+		struct pci_dev *pdev, u32 options)
+{
+	return -ENODEV;
+}
+
+int cnss_pci_load_and_free_saved_state(
+	struct pci_dev *dev, struct pci_saved_state **state)
+{
+	return 0;
+}
+
+int cnss_msm_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_deregister_event(struct msm_pcie_register_event *reg)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_recover_config(struct pci_dev *dev)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_register_event(struct msm_pcie_register_event *reg)
+{
+	return -ENODEV;
+}
+
+int cnss_msm_pcie_enumerate(u32 rc_idx)
+{
+	return -EPROBE_DEFER;
+}
+#endif
+
+static void cnss_pcie_set_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+	pf_ops->request_bus_bandwidth = cnss_pci_request_bus_bandwidth;
+	pf_ops->get_virt_ramdump_mem = cnss_pci_get_virt_ramdump_mem;
+	pf_ops->device_self_recovery = cnss_pci_device_self_recovery;
+	pf_ops->schedule_recovery_work = cnss_pci_schedule_recovery_work;
+	pf_ops->device_crashed = cnss_pci_device_crashed;
+	pf_ops->get_wlan_mac_address = cnss_pci_get_wlan_mac_address;
+	pf_ops->set_wlan_mac_address = cnss_pcie_set_wlan_mac_address;
+	pf_ops->power_up = cnss_pcie_power_up;
+	pf_ops->power_down = cnss_pcie_power_down;
+
+	dev->platform_data = pf_ops;
+}
+
+static void cnss_pcie_reset_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &penv->platform_ops;
+
+	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+	dev->platform_data = NULL;
+}
+
+static int cnss_wlan_pci_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	int ret = 0;
+	struct cnss_wlan_vreg_info *vreg_info = &penv->vreg_info;
+	void *cpu_addr;
+	dma_addr_t dma_handle;
+	struct codeswap_codeseg_info *cnss_seg_info = NULL;
+	struct device *dev = &pdev->dev;
+
+	cnss_pcie_set_platform_ops(dev);
+	penv->pdev = pdev;
+	penv->id = id;
+	atomic_set(&penv->fw_available, 0);
+	penv->device_id = pdev->device;
+
+	if (penv->smmu_iova_len) {
+		ret = cnss_smmu_init(&pdev->dev);
+		if (ret) {
+			pr_err("%s: SMMU init failed, err = %d\n",
+			       __func__, ret);
+			goto smmu_init_fail;
+		}
+	}
+
+	if (penv->pci_register_again) {
+		pr_debug("%s: PCI re-registration complete\n", __func__);
+		penv->pci_register_again = false;
+		return 0;
+	}
+
+	switch (pdev->device) {
+	case QCA6180_DEVICE_ID:
+		pci_read_config_word(pdev, QCA6180_REV_ID_OFFSET,
+				     &penv->revision_id);
+		break;
+
+	case QCA6174_DEVICE_ID:
+		pci_read_config_word(pdev, QCA6174_REV_ID_OFFSET,
+				     &penv->revision_id);
+		cnss_setup_fw_files(penv->revision_id);
+		break;
+
+	default:
+		pr_err("cnss: unknown device found %d\n", pdev->device);
+		ret = -EPROBE_DEFER;
+		goto err_unknown;
+	}
+
+	if (penv->pcie_link_state) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		if (ret) {
+			pr_err("Failed to shutdown PCIe link\n");
+			goto err_pcie_suspend;
+		}
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+
+	if (ret) {
+		pr_err("can't turn off wlan vreg\n");
+		goto err_pcie_suspend;
+	}
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	cnss_wlan_fw_mem_alloc(pdev);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	ret = device_create_file(&penv->pldev->dev, &dev_attr_wlan_setup);
+
+	if (ret) {
+		pr_err("Can't Create Device file\n");
+		goto err_pcie_suspend;
+	}
+
+	if (cnss_wlan_is_codeswap_supported(penv->revision_id)) {
+		pr_debug("Code-swap not enabled: %d\n", penv->revision_id);
+		goto err_pcie_suspend;
+	}
+
+	cpu_addr = dma_alloc_coherent(dev, EVICT_BIN_MAX_SIZE,
+				      &dma_handle, GFP_KERNEL);
+	if (!cpu_addr || !dma_handle) {
+		pr_err("cnss: Memory Alloc failed for codeswap feature\n");
+		goto err_pcie_suspend;
+	}
+
+	memset(cpu_addr, 0, EVICT_BIN_MAX_SIZE);
+	cnss_seg_info = devm_kzalloc(dev, sizeof(*cnss_seg_info),
+				     GFP_KERNEL);
+	if (!cnss_seg_info)
+		goto end_dma_alloc;
+
+	memset(cnss_seg_info, 0, sizeof(*cnss_seg_info));
+	cnss_seg_info->codeseg_busaddr[0]   = (void *)dma_handle;
+	penv->codeseg_cpuaddr[0]            = cpu_addr;
+	cnss_seg_info->codeseg_size         = EVICT_BIN_MAX_SIZE;
+	cnss_seg_info->codeseg_total_bytes  = EVICT_BIN_MAX_SIZE;
+	cnss_seg_info->num_codesegs         = 1;
+	cnss_seg_info->codeseg_size_log2    = ilog2(EVICT_BIN_MAX_SIZE);
+
+	penv->cnss_seg_info = cnss_seg_info;
+	pr_debug("%s: Successfully allocated memory for CODESWAP\n", __func__);
+
+	return ret;
+
+end_dma_alloc:
+	dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle);
+err_unknown:
+err_pcie_suspend:
+smmu_init_fail:
+	cnss_pcie_reset_platform_ops(dev);
+	return ret;
+}
+
+static void cnss_wlan_pci_remove(struct pci_dev *pdev)
+{
+	struct device *dev;
+
+	if (!penv)
+		return;
+
+	dev = &penv->pldev->dev;
+	cnss_pcie_reset_platform_ops(dev);
+	device_remove_file(dev, &dev_attr_wlan_setup);
+
+	if (penv->smmu_mapping)
+		cnss_smmu_remove(&pdev->dev);
+}
+
+static int cnss_wlan_pci_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdriver;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+	if (!penv)
+		goto out;
+
+	if (!penv->pcie_link_state)
+		goto out;
+
+	wdriver = penv->driver;
+	if (!wdriver)
+		goto out;
+
+	if (wdriver->suspend) {
+		ret = wdriver->suspend(pdev, state);
+
+		if (penv->pcie_link_state) {
+			pci_save_state(pdev);
+			penv->saved_state = cnss_pci_store_saved_state(pdev);
+		}
+	}
+	penv->monitor_wake_intr = false;
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_pci_resume(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdriver;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (!penv)
+		goto out;
+
+	if (!penv->pcie_link_state)
+		goto out;
+
+	wdriver = penv->driver;
+	if (!wdriver)
+		goto out;
+
+	if (wdriver->resume && !penv->pcie_link_down_ind) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+		pci_restore_state(pdev);
+
+		ret = wdriver->resume(pdev);
+	}
+
+out:
+	return ret;
+}
+
+static int cnss_wlan_runtime_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_wlan_driver *wdrv;
+
+	if (!penv)
+		return -EAGAIN;
+
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress\n");
+		return -EAGAIN;
+	}
+
+	pr_debug("cnss: runtime suspend start\n");
+
+	wdrv = penv->driver;
+
+	if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_suspend)
+		ret = wdrv->runtime_ops->runtime_suspend(to_pci_dev(dev));
+
+	pr_info("cnss: runtime suspend status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_wlan_runtime_resume(struct device *dev)
+{
+	struct cnss_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!penv)
+		return -EAGAIN;
+
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress\n");
+		return -EAGAIN;
+	}
+
+	pr_debug("cnss: runtime resume start\n");
+
+	wdrv = penv->driver;
+
+	if (wdrv && wdrv->runtime_ops && wdrv->runtime_ops->runtime_resume)
+		ret = wdrv->runtime_ops->runtime_resume(to_pci_dev(dev));
+
+	pr_info("cnss: runtime resume status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_wlan_runtime_idle(struct device *dev)
+{
+	pr_debug("cnss: runtime idle\n");
+
+	pm_request_autosuspend(dev);
+
+	return -EBUSY;
+}
+
+static DECLARE_RWSEM(cnss_pm_sem);
+
+static int cnss_pm_notify(struct notifier_block *b,
+			  unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&cnss_pm_sem);
+		break;
+
+	case PM_POST_SUSPEND:
+		up_write(&cnss_pm_sem);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cnss_pm_notifier = {
+	.notifier_call = cnss_pm_notify,
+};
+
+static const struct pci_device_id cnss_wlan_pci_id_table[] = {
+	{ QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6174_VENDOR_ID, BEELINER_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6180_VENDOR_ID, QCA6180_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, cnss_wlan_pci_id_table);
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops cnss_wlan_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(cnss_wlan_pci_suspend, cnss_wlan_pci_resume)
+	SET_RUNTIME_PM_OPS(cnss_wlan_runtime_suspend, cnss_wlan_runtime_resume,
+			   cnss_wlan_runtime_idle)
+};
+#endif
+
+struct pci_driver cnss_wlan_pci_driver = {
+	.name     = "cnss_wlan_pci",
+	.id_table = cnss_wlan_pci_id_table,
+	.probe    = cnss_wlan_pci_probe,
+	.remove   = cnss_wlan_pci_remove,
+#ifdef CONFIG_PM
+	.driver = {
+		.pm = &cnss_wlan_pm_ops,
+	},
+#endif
+};
+
+static ssize_t fw_image_setup_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", penv->fw_image_setup);
+}
+
+static ssize_t fw_image_setup_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	int val;
+	int ret;
+
+	if (!penv)
+		return -ENODEV;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	pr_info("%s: Firmware setup in progress\n", __func__);
+
+	if (kstrtoint(buf, 0, &val)) {
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -EINVAL;
+	}
+
+	if (val == FW_IMAGE_FTM || val == FW_IMAGE_MISSION ||
+	    val == FW_IMAGE_BDATA) {
+		pr_info("%s: fw image setup triggered %d\n", __func__, val);
+		ret = cnss_setup_fw_image_table(val);
+		if (ret != 0) {
+			pr_err("%s: Invalid parsing of FW image files %d\n",
+			       __func__, ret);
+			mutex_unlock(&penv->fw_setup_stat_lock);
+			return -EINVAL;
+		}
+		penv->fw_image_setup = val;
+	} else if (val == FW_IMAGE_PRINT) {
+		print_allocated_image_table();
+	} else if (val == BMI_TEST_SETUP) {
+		penv->bmi_test = val;
+	}
+
+	pr_info("%s: Firmware setup completed\n", __func__);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+	return count;
+}
+
+static DEVICE_ATTR(fw_image_setup, 0600,
+	fw_image_setup_show, fw_image_setup_store);
+
+void cnss_pci_recovery_work_handler(struct work_struct *recovery)
+{
+	cnss_pci_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_pci_recovery_work, cnss_pci_recovery_work_handler);
+
+void cnss_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_schedule_recovery_work);
+
+static inline void __cnss_disable_irq(void *data)
+{
+	struct pci_dev *pdev = data;
+
+	disable_irq(pdev->irq);
+}
+
+void cnss_pci_events_cb(struct msm_pcie_notify *notify)
+{
+	unsigned long flags;
+
+	if (!notify)
+		return;
+
+	switch (notify->event) {
+	case MSM_PCIE_EVENT_LINKDOWN:
+		if (pcie_link_down_panic)
+			panic("PCIe link is down\n");
+
+		spin_lock_irqsave(&pci_link_down_lock, flags);
+		if (penv->pcie_link_down_ind) {
+			pr_debug("PCI link down recovery is in progress, ignore\n");
+			spin_unlock_irqrestore(&pci_link_down_lock, flags);
+			return;
+		}
+		penv->pcie_link_down_ind = true;
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+		pr_err("PCI link down, schedule recovery\n");
+		__cnss_disable_irq(notify->user);
+		schedule_work(&cnss_pci_recovery_work);
+		break;
+
+	case MSM_PCIE_EVENT_WAKEUP:
+		if (penv->monitor_wake_intr &&
+		    atomic_read(&penv->auto_suspended)) {
+			penv->monitor_wake_intr = false;
+			pm_request_resume(&penv->pdev->dev);
+		}
+		break;
+
+	default:
+		pr_err("cnss: invalid event from PCIe callback %d\n",
+		       notify->event);
+	}
+}
+
+void cnss_wlan_pci_link_down(void)
+{
+	unsigned long flags;
+
+	if (pcie_link_down_panic)
+		panic("PCIe link is down\n");
+
+	spin_lock_irqsave(&pci_link_down_lock, flags);
+	if (penv->pcie_link_down_ind) {
+		pr_debug("PCI link down recovery is in progress, ignore\n");
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+		return;
+	}
+	penv->pcie_link_down_ind = true;
+	spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+	pr_err("PCI link down detected by host driver, schedule recovery\n");
+	schedule_work(&cnss_pci_recovery_work);
+}
+EXPORT_SYMBOL(cnss_wlan_pci_link_down);
+
+int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable)
+{
+	return cnss_msm_pcie_shadow_control(dev, enable);
+}
+EXPORT_SYMBOL(cnss_pcie_shadow_control);
+
+int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg)
+{
+	struct codeswap_codeseg_info *cnss_seg_info = penv->cnss_seg_info;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	if (!cnss_seg_info) {
+		swap_seg = NULL;
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -ENOENT;
+	}
+
+	if (!atomic_read(&penv->fw_available)) {
+		pr_debug("%s: fw is not available\n", __func__);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		return -ENOENT;
+	}
+
+	*swap_seg = *cnss_seg_info;
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_codeswap_struct);
+
+static void cnss_wlan_memory_expansion(void)
+{
+	struct device *dev;
+	const struct firmware *fw_entry;
+	const char *filename;
+	u32 fw_entry_size, size_left, dma_size_left, length;
+	char *fw_temp;
+	char *fw_data;
+	char *dma_virt_addr;
+	struct codeswap_codeseg_info *cnss_seg_info;
+	u32 total_length = 0;
+	struct pci_dev *pdev;
+
+	mutex_lock(&penv->fw_setup_stat_lock);
+	filename = cnss_wlan_get_evicted_data_file();
+	pdev = penv->pdev;
+	dev = &pdev->dev;
+	cnss_seg_info = penv->cnss_seg_info;
+
+	if (!cnss_seg_info) {
+		pr_debug("cnss: cnss_seg_info is NULL\n");
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (atomic_read(&penv->fw_available)) {
+		pr_debug("cnss: fw code already copied to host memory\n");
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (request_firmware(&fw_entry, filename, dev) != 0) {
+		pr_debug("cnss: failed to get fw: %s\n", filename);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto end;
+	}
+
+	if (!fw_entry || !fw_entry->data) {
+		pr_err("%s: INVALID FW entries\n", __func__);
+		mutex_unlock(&penv->fw_setup_stat_lock);
+		goto release_fw;
+	}
+
+	dma_virt_addr = (char *)penv->codeseg_cpuaddr[0];
+	fw_data = (u8 *)fw_entry->data;
+	fw_temp = fw_data;
+	fw_entry_size = fw_entry->size;
+	if (fw_entry_size > EVICT_BIN_MAX_SIZE)
+		fw_entry_size = EVICT_BIN_MAX_SIZE;
+	size_left = fw_entry_size;
+	dma_size_left = EVICT_BIN_MAX_SIZE;
+	while ((size_left && fw_temp) && (dma_size_left > 0)) {
+		fw_temp = fw_temp + 4;
+		size_left = size_left - 4;
+		length = *(int *)fw_temp;
+		if ((length > size_left || length <= 0) ||
+		    (dma_size_left <= 0 || length > dma_size_left)) {
+			pr_err("cnss: wrong length read:%d\n",
+			       length);
+			break;
+		}
+		fw_temp = fw_temp + 4;
+		size_left = size_left - 4;
+		memcpy(dma_virt_addr, fw_temp, length);
+		dma_size_left = dma_size_left - length;
+		size_left = size_left - length;
+		fw_temp = fw_temp + length;
+		dma_virt_addr = dma_virt_addr + length;
+		total_length += length;
+		pr_debug("cnss: bytes_left to copy: fw:%d; dma_page:%d\n",
+			 size_left, dma_size_left);
+	}
+	pr_debug("cnss: total_bytes copied: %d\n", total_length);
+	cnss_seg_info->codeseg_total_bytes = total_length;
+
+	atomic_set(&penv->fw_available, 1);
+	mutex_unlock(&penv->fw_setup_stat_lock);
+
+release_fw:
+	release_firmware(fw_entry);
+end:
+	return;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_pci_get_wlan_mac_address(u32 *num)
+{
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform Driver Context\n", __func__);
+		goto end;
+	}
+
+	if (!penv->is_wlan_mac_set) {
+		pr_info("%s: Platform Driver doesn't have any mac address\n",
+			__func__);
+		goto end;
+	}
+
+	addr = &penv->wlan_mac_addr;
+	*num = addr->no_of_mac_addr_set;
+	return &addr->mac_addr[0][0];
+
+end:
+	*num = 0;
+	return NULL;
+}
+
+/**
+ * cnss_get_wlan_mac_address() - API to return MAC addresses buffer
+ * @dev: struct device pointer
+ * @num: buffer for number of mac addresses supported
+ *
+ * API returns the pointer to the buffer filled with mac addresses and
+ * updates num with the number of mac addresses the buffer contains.
+ *
+ * Return: pointer to mac address buffer.
+ */
+u8 *cnss_get_wlan_mac_address(struct device *dev, u32 *num)
+{
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform Driver Context\n", __func__);
+		goto end;
+	}
+
+	if (!penv->is_wlan_mac_set) {
+		pr_info("%s: Platform Driver doesn't have any mac address\n",
+			__func__);
+		goto end;
+	}
+
+	addr = &penv->wlan_mac_addr;
+	*num = addr->no_of_mac_addr_set;
+	return &addr->mac_addr[0][0];
+end:
+	*num = 0;
+	return NULL;
+}
+EXPORT_SYMBOL(cnss_get_wlan_mac_address);
+
+/**
+ * cnss_pcie_set_wlan_mac_address() - API to get two wlan mac address
+ * @in: Input buffer with wlan mac addresses
+ * @len: Size of the buffer passed
+ *
+ * API to store wlan mac address passed by the caller. The stored mac
+ * addresses are used by the wlan functional driver to program wlan HW.
+ *
+ * Return: kernel error code.
+ */
+int cnss_pcie_set_wlan_mac_address(const u8 *in, u32 len)
+{
+	u32 no_of_mac_addr;
+	struct cnss_wlan_mac_addr *addr = NULL;
+	int iter = 0;
+	u8 *temp = NULL;
+
+	if (len == 0 || (len % ETH_ALEN) != 0) {
+		pr_err("%s: Invalid Length:%d\n", __func__, len);
+		return -EINVAL;
+	}
+
+	no_of_mac_addr = len / ETH_ALEN;
+
+	if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
+		pr_err("%s: Num of supported MAC  addresses are:%d given:%d\n",
+		       __func__, MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
+		return -EINVAL;
+	}
+
+	if (!penv) {
+		pr_err("%s: Invalid CNSS Platform Context\n", __func__);
+		return -ENOENT;
+	}
+
+	if (penv->is_wlan_mac_set) {
+		pr_info("%s: Already MAC address are configured\n", __func__);
+		return 0;
+	}
+
+	penv->is_wlan_mac_set = true;
+	addr = &penv->wlan_mac_addr;
+	addr->no_of_mac_addr_set = no_of_mac_addr;
+	temp = &addr->mac_addr[0][0];
+
+	for (; iter < no_of_mac_addr; ++iter, temp += ETH_ALEN, in +=
+	     ETH_ALEN) {
+		ether_addr_copy(temp, in);
+		pr_debug("%s MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+			 __func__, temp[0], temp[1], temp[2], temp[3], temp[4],
+			 temp[5]);
+	}
+	return 0;
+}
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver)
+{
+	int ret = 0;
+	int probe_again = 0;
+	struct cnss_wlan_driver *wdrv;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return -ENODEV;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+	pdev = penv->pdev;
+
+	if (!penv->driver) {
+		penv->driver = driver;
+		wdrv = penv->driver;
+	} else {
+		pr_err("driver already registered\n");
+		return -EEXIST;
+	}
+
+again:
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("wlan vreg ON failed\n");
+		goto err_wlan_vreg_on;
+	}
+
+	msleep(POWER_ON_DELAY);
+
+	if (penv->wlan_bootstrap_gpio > 0) {
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+		msleep(WLAN_BOOTSTRAP_DELAY);
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+
+	if (!pdev) {
+		pr_debug("%s: invalid pdev. register pci device\n", __func__);
+		ret = pci_register_driver(&cnss_wlan_pci_driver);
+
+		if (ret) {
+			pr_err("%s: pci registration failed\n", __func__);
+			goto err_pcie_reg;
+		}
+		pdev = penv->pdev;
+		if (!pdev) {
+			pr_err("%s: pdev is still invalid\n", __func__);
+			goto err_pcie_reg;
+		}
+	}
+
+	penv->event_reg.events = MSM_PCIE_EVENT_LINKDOWN |
+			MSM_PCIE_EVENT_WAKEUP;
+	penv->event_reg.user = pdev;
+	penv->event_reg.mode = MSM_PCIE_TRIGGER_CALLBACK;
+	penv->event_reg.callback = cnss_pci_events_cb;
+	penv->event_reg.options = MSM_PCIE_CONFIG_NO_RECOVERY;
+	ret = cnss_msm_pcie_register_event(&penv->event_reg);
+	if (ret)
+		pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+	if (!penv->pcie_link_state && !penv->pcie_link_down_ind) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		if (ret) {
+			pr_err("PCIe link bring-up failed\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+	} else if (!penv->pcie_link_state && penv->pcie_link_down_ind) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+		if (ret) {
+			pr_err("PCIe link bring-up failed (link down option)\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+
+		ret = cnss_msm_pcie_recover_config(pdev);
+		if (ret) {
+			pr_err("cnss: PCI link failed to recover\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_down_ind = false;
+	}
+
+	if (!cnss_wlan_is_codeswap_supported(penv->revision_id))
+		cnss_wlan_memory_expansion();
+
+	if (wdrv->probe) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+
+		pci_restore_state(pdev);
+
+		ret = wdrv->probe(pdev, penv->id);
+		if (ret) {
+			wcnss_prealloc_check_memory_leak();
+			wcnss_pre_alloc_reset();
+
+			if (probe_again > 3) {
+				pr_err("Failed to probe WLAN\n");
+				goto err_wlan_probe;
+			}
+			pci_save_state(pdev);
+			penv->saved_state = cnss_pci_store_saved_state(pdev);
+			cnss_msm_pcie_deregister_event(&penv->event_reg);
+			cnss_msm_pcie_pm_control(
+				MSM_PCIE_SUSPEND,
+				cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS);
+			penv->pcie_link_state = PCIE_LINK_DOWN;
+			cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+			cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+			msleep(POWER_ON_DELAY);
+			probe_again++;
+			goto again;
+		}
+	}
+
+	if (penv->notify_modem_status && wdrv->modem_status)
+		wdrv->modem_status(pdev, penv->modem_current_status);
+
+	return ret;
+
+err_wlan_probe:
+	pci_save_state(pdev);
+	penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+err_pcie_link_up:
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+	if (penv->pcie_link_state) {
+		cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+err_pcie_reg:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (penv->pdev) {
+		pr_err("%d: Unregistering PCI device\n", __LINE__);
+		pci_unregister_driver(&cnss_wlan_pci_driver);
+		penv->pdev = NULL;
+		penv->pci_register_again = true;
+	}
+
+err_wlan_vreg_on:
+	penv->driver = NULL;
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return;
+
+	wdrv = penv->driver;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+	pdev = penv->pdev;
+
+	if (!wdrv) {
+		pr_err("driver not registered\n");
+		return;
+	}
+
+	if (penv->bus_client)
+		msm_bus_scale_client_update_request(penv->bus_client,
+						    CNSS_BUS_WIDTH_NONE);
+
+	if (!pdev) {
+		pr_err("%d: invalid pdev\n", __LINE__);
+		goto cut_power;
+	}
+
+	if (wdrv->remove)
+		wdrv->remove(pdev);
+
+	wcnss_prealloc_check_memory_leak();
+	wcnss_pre_alloc_reset();
+
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+
+	if (penv->pcie_link_state && !penv->pcie_link_down_ind) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS)) {
+			pr_err("Failed to shutdown PCIe link\n");
+			return;
+		}
+	} else if (penv->pcie_link_state && penv->pcie_link_down_ind) {
+		penv->saved_state = NULL;
+
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+			pr_err("Failed to shutdown PCIe link (with linkdown option)\n");
+			return;
+		}
+	}
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+	penv->driver_status = CNSS_UNINITIALIZED;
+	penv->monitor_wake_intr = false;
+	atomic_set(&penv->auto_suspended, 0);
+
+cut_power:
+	penv->driver = NULL;
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+		pr_err("wlan vreg OFF failed\n");
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+#ifdef CONFIG_PCI_MSM
+int cnss_wlan_pm_control(bool vote)
+{
+	if (!penv || !penv->pdev)
+		return -ENODEV;
+
+	return cnss_msm_pcie_pm_control(
+		vote ? MSM_PCIE_DISABLE_PC : MSM_PCIE_ENABLE_PC,
+		cnss_get_pci_dev_bus_number(penv->pdev),
+		penv->pdev, PM_OPTIONS);
+}
+EXPORT_SYMBOL(cnss_wlan_pm_control);
+#endif
+
+void cnss_lock_pm_sem(void)
+{
+	down_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_lock_pm_sem);
+
+void cnss_release_pm_sem(void)
+{
+	up_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_release_pm_sem);
+
+void cnss_pci_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_pci_recovery_work);
+}
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!penv || !penv->pldev)
+		return NULL;
+
+	*size = penv->ramdump_size;
+
+	return penv->ramdump_addr;
+}
+
+void cnss_pci_device_crashed(void)
+{
+	if (penv && penv->subsys) {
+		subsys_set_crash_status(penv->subsys, true);
+		subsystem_restart_dev(penv->subsys);
+	}
+}
+
+void *cnss_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!penv || !penv->pldev)
+		return NULL;
+
+	*size = penv->ramdump_size;
+
+	return penv->ramdump_addr;
+}
+EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
+
+void cnss_device_crashed(void)
+{
+	if (penv && penv->subsys) {
+		subsys_set_crash_status(penv->subsys, true);
+		subsystem_restart_dev(penv->subsys);
+	}
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+
+static int cnss_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	penv->recovery_in_progress = true;
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	if (!pdev) {
+		ret = -EINVAL;
+		goto cut_power;
+	}
+
+	if (wdrv && wdrv->shutdown)
+		wdrv->shutdown(pdev);
+
+	if (penv->pcie_link_state) {
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS_SUSPEND_LINK_DOWN)) {
+			pr_debug("cnss: Failed to shutdown PCIe link\n");
+			ret = -EFAULT;
+		}
+		penv->saved_state = NULL;
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+	}
+
+cut_power:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (cnss_wlan_vreg_set(vreg_info, VREG_OFF))
+		pr_err("cnss: Failed to set WLAN VREG_OFF\n");
+
+	return ret;
+}
+
+static int cnss_powerup(const struct subsys_desc *subsys)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->driver)
+		goto out;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("cnss: Failed to set WLAN VREG_ON\n");
+		goto err_wlan_vreg_on;
+	}
+
+	msleep(POWER_ON_DELAY);
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	/**
+	 *  Some platforms have wifi and other PCIE card attached with PCIE
+	 *  switch on the same RC like P5459 board(ROME 3.2 PCIE card + Ethernet
+	 *  PCI), it will need extra time to stable the signals when do SSR,
+	 *  otherwise fail to create the PCIE link, so add PCIE_SWITCH_DELAY.
+	 */
+	msleep(PCIE_SWITCH_DELAY);
+
+	if (!pdev) {
+		pr_err("%d: invalid pdev\n", __LINE__);
+		goto err_pcie_link_up;
+	}
+
+	if (!penv->pcie_link_state) {
+		ret = cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME,
+			cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS_RESUME_LINK_DOWN);
+
+		if (ret) {
+			pr_err("cnss: Failed to bring-up PCIe link\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_state = PCIE_LINK_UP;
+		ret = cnss_msm_pcie_recover_config(penv->pdev);
+		if (ret) {
+			pr_err("cnss: PCI link failed to recover\n");
+			goto err_pcie_link_up;
+		}
+		penv->pcie_link_down_ind = false;
+	}
+
+	if (wdrv && wdrv->reinit) {
+		if (penv->saved_state)
+			cnss_pci_load_and_free_saved_state(
+				pdev, &penv->saved_state);
+
+		pci_restore_state(pdev);
+
+		ret = wdrv->reinit(pdev, penv->id);
+		if (ret) {
+			pr_err("%d: Failed to do reinit\n", __LINE__);
+			goto err_wlan_reinit;
+		}
+	} else {
+		pr_err("%d: wdrv->reinit is invalid\n", __LINE__);
+			goto err_pcie_link_up;
+	}
+
+	if (penv->notify_modem_status && wdrv->modem_status)
+		wdrv->modem_status(pdev, penv->modem_current_status);
+
+out:
+	penv->recovery_in_progress = false;
+	return ret;
+
+err_wlan_reinit:
+	pci_save_state(pdev);
+	penv->saved_state = cnss_pci_store_saved_state(pdev);
+	cnss_msm_pcie_pm_control(
+			MSM_PCIE_SUSPEND,
+			cnss_get_pci_dev_bus_number(pdev),
+			pdev, PM_OPTIONS);
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+err_pcie_link_up:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (penv->pdev) {
+		pr_err("%d: Unregistering pci device\n", __LINE__);
+		pci_unregister_driver(&cnss_wlan_pci_driver);
+		penv->pdev = NULL;
+		penv->pci_register_again = true;
+	}
+
+err_wlan_vreg_on:
+	return ret;
+}
+
+void cnss_pci_device_self_recovery(void)
+{
+	if (!penv)
+		return;
+
+	if (penv->recovery_in_progress) {
+		pr_err("cnss: Recovery already in progress\n");
+		return;
+	}
+
+	if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+		pr_err("cnss: load unload in progress\n");
+		return;
+	}
+
+	penv->recovery_count++;
+	penv->recovery_in_progress = true;
+	cnss_pm_wake_lock(&penv->ws);
+	cnss_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_powerup(NULL);
+	cnss_pm_wake_lock_release(&penv->ws);
+	penv->recovery_in_progress = false;
+}
+
+static int cnss_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct ramdump_segment segment;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->ramdump_size)
+		return -ENOENT;
+
+	if (!enable)
+		return 0;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = penv->ramdump_addr;
+	segment.size = penv->ramdump_size;
+
+	return do_ramdump(penv->ramdump_dev, &segment, 1);
+}
+
+static void cnss_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+
+	if (!penv)
+		return;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+
+	if (pdev && wdrv && wdrv->crash_shutdown)
+		wdrv->crash_shutdown(pdev);
+}
+
+void cnss_device_self_recovery(void)
+{
+	if (!penv)
+		return;
+
+	if (penv->recovery_in_progress) {
+		pr_err("cnss: Recovery already in progress\n");
+		return;
+	}
+	if (penv->driver_status == CNSS_LOAD_UNLOAD) {
+		pr_err("cnss: load unload in progress\n");
+		return;
+	}
+	penv->recovery_count++;
+	penv->recovery_in_progress = true;
+	cnss_pm_wake_lock(&penv->ws);
+	cnss_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_powerup(NULL);
+	cnss_pm_wake_lock_release(&penv->ws);
+	penv->recovery_in_progress = false;
+}
+EXPORT_SYMBOL(cnss_device_self_recovery);
+
+static int cnss_modem_notifier_nb(struct notifier_block *this,
+				  unsigned long code,
+				  void *ss_handle)
+{
+	struct cnss_wlan_driver *wdrv;
+	struct pci_dev *pdev;
+
+	pr_debug("%s: Modem-Notify: event %lu\n", __func__, code);
+
+	if (!penv)
+		return NOTIFY_DONE;
+
+	if (code == SUBSYS_AFTER_POWERUP)
+		penv->modem_current_status = 1;
+	else if (code == SUBSYS_BEFORE_SHUTDOWN)
+		penv->modem_current_status = 0;
+	else
+		return NOTIFY_DONE;
+
+	wdrv = penv->driver;
+	pdev = penv->pdev;
+
+	if (!wdrv || !pdev || !wdrv->modem_status)
+		return NOTIFY_DONE;
+
+	wdrv->modem_status(pdev, penv->modem_current_status);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mnb = {
+	.notifier_call = cnss_modem_notifier_nb,
+};
+
+static int cnss_init_dump_entry(void)
+{
+	struct msm_dump_entry dump_entry;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->ramdump_dynamic)
+		return 0;
+
+	penv->dump_data.addr = penv->ramdump_phys;
+	penv->dump_data.len = penv->ramdump_size;
+	penv->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	penv->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(penv->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(penv->dump_data.name));
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&penv->dump_data);
+
+	return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+}
+
+static int cnss_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct esoc_desc *desc;
+	const char *client_desc;
+	struct device *dev = &pdev->dev;
+	u32 rc_num;
+	struct resource *res;
+	u32 ramdump_size = 0;
+	u32 smmu_iova_address[2];
+
+	if (penv)
+		return -ENODEV;
+
+	penv = devm_kzalloc(&pdev->dev, sizeof(*penv), GFP_KERNEL);
+	if (!penv)
+		return -ENOMEM;
+
+	penv->pldev = pdev;
+	penv->esoc_desc = NULL;
+
+	penv->gpio_info.name = WLAN_EN_GPIO_NAME;
+	penv->gpio_info.num = 0;
+	penv->gpio_info.state = WLAN_EN_LOW;
+	penv->gpio_info.init = WLAN_EN_LOW;
+	penv->gpio_info.prop = false;
+	penv->vreg_info.wlan_reg = NULL;
+	penv->vreg_info.state = VREG_OFF;
+	penv->pci_register_again = false;
+	mutex_init(&penv->fw_setup_stat_lock);
+
+	ret = cnss_wlan_get_resources(pdev);
+	if (ret)
+		goto err_get_wlan_res;
+
+	ret = cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	if (ret) {
+		pr_err("%s: Failed to enable WLAN enable gpio\n", __func__);
+		goto err_get_rc;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num);
+	if (ret) {
+		pr_err("%s: Failed to find PCIe RC number\n", __func__);
+		goto err_get_rc;
+	}
+
+	ret = cnss_msm_pcie_enumerate(rc_num);
+	if (ret) {
+		pr_err("%s: Failed to enable PCIe RC%x\n", __func__, rc_num);
+		goto err_pcie_enumerate;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	penv->notify_modem_status =
+		of_property_read_bool(dev->of_node,
+				      "qcom,notify-modem-status");
+
+	if (penv->notify_modem_status) {
+		ret = of_property_read_string_index(dev->of_node, "esoc-names",
+						    0, &client_desc);
+		if (ret) {
+			pr_debug("%s: esoc-names is not defined in DT, SKIP\n",
+				 __func__);
+		} else {
+			desc = devm_register_esoc_client(dev, client_desc);
+			if (IS_ERR_OR_NULL(desc)) {
+				ret = PTR_RET(desc);
+				pr_err("%s: can't find esoc desc\n", __func__);
+				goto err_esoc_reg;
+			}
+			penv->esoc_desc = desc;
+		}
+	}
+
+	penv->subsysdesc.name = "AR6320";
+	penv->subsysdesc.owner = THIS_MODULE;
+	penv->subsysdesc.shutdown = cnss_shutdown;
+	penv->subsysdesc.powerup = cnss_powerup;
+	penv->subsysdesc.ramdump = cnss_ramdump;
+	penv->subsysdesc.crash_shutdown = cnss_crash_shutdown;
+	penv->subsysdesc.dev = &pdev->dev;
+	penv->subsys = subsys_register(&penv->subsysdesc);
+	if (IS_ERR(penv->subsys)) {
+		ret = PTR_ERR(penv->subsys);
+		goto err_subsys_reg;
+	}
+
+	penv->subsys_handle = subsystem_get(penv->subsysdesc.name);
+
+	if (of_property_read_bool(dev->of_node, "qcom,is-dual-wifi-enabled"))
+		penv->dual_wifi_info.is_dual_wifi_enabled = true;
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0) {
+		penv->ramdump_addr = dma_alloc_coherent(&pdev->dev,
+				ramdump_size, &penv->ramdump_phys, GFP_KERNEL);
+
+		if (penv->ramdump_addr)
+			penv->ramdump_size = ramdump_size;
+		penv->ramdump_dynamic = true;
+	} else {
+		res = platform_get_resource_byname(penv->pldev,
+						   IORESOURCE_MEM, "ramdump");
+		if (res) {
+			penv->ramdump_phys = res->start;
+			ramdump_size = resource_size(res);
+			penv->ramdump_addr = ioremap(penv->ramdump_phys,
+					ramdump_size);
+
+			if (penv->ramdump_addr)
+				penv->ramdump_size = ramdump_size;
+
+			penv->ramdump_dynamic = false;
+		}
+	}
+
+	pr_debug("%s: ramdump addr: %p, phys: %pa\n", __func__,
+		 penv->ramdump_addr, &penv->ramdump_phys);
+
+	if (penv->ramdump_size == 0) {
+		pr_info("%s: CNSS ramdump will not be collected\n", __func__);
+		goto skip_ramdump;
+	}
+
+	ret = cnss_init_dump_entry();
+	if (ret) {
+		pr_err("%s: Dump table setup failed: %d\n", __func__, ret);
+		goto err_ramdump_create;
+	}
+
+	penv->ramdump_dev = create_ramdump_device(penv->subsysdesc.name,
+				penv->subsysdesc.dev);
+	if (!penv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump_create;
+	}
+
+skip_ramdump:
+	penv->modem_current_status = 0;
+
+	if (penv->notify_modem_status) {
+		penv->modem_notify_handler =
+			subsys_notif_register_notifier(penv->esoc_desc ?
+						       penv->esoc_desc->name :
+						       "modem", &mnb);
+		if (IS_ERR(penv->modem_notify_handler)) {
+			ret = PTR_ERR(penv->modem_notify_handler);
+			pr_err("%s: Register notifier Failed\n", __func__);
+			goto err_notif_modem;
+		}
+	}
+
+	if (of_property_read_u32_array(dev->of_node,
+				       "qcom,wlan-smmu-iova-address",
+				       smmu_iova_address, 2) == 0) {
+		penv->smmu_iova_start = smmu_iova_address[0];
+		penv->smmu_iova_len = smmu_iova_address[1];
+	}
+
+	ret = pci_register_driver(&cnss_wlan_pci_driver);
+	if (ret)
+		goto err_pci_reg;
+
+	penv->bus_scale_table = 0;
+	penv->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+
+	if (penv->bus_scale_table)  {
+		penv->bus_client =
+			msm_bus_scale_register_client(penv->bus_scale_table);
+
+		if (!penv->bus_client) {
+			pr_err("Failed to register with bus_scale client\n");
+			goto err_bus_reg;
+		}
+	}
+	cnss_pm_wake_lock_init(&penv->ws, "cnss_wlock");
+
+	register_pm_notifier(&cnss_pm_notifier);
+
+#ifdef CONFIG_CNSS_MAC_BUG
+	/* 0-4K memory is reserved for QCA6174 to address a MAC HW bug.
+	 * MAC would do an invalid pointer fetch based on the data
+	 * that was read from 0 to 4K. So fill it with zero's (to an
+	 * address for which PCIe RC honored the read without any errors).
+	 */
+	memset(phys_to_virt(0), 0, SZ_4K);
+#endif
+
+	ret = device_create_file(dev, &dev_attr_fw_image_setup);
+	if (ret) {
+		pr_err("cnss: fw_image_setup sys file creation failed\n");
+		goto err_bus_reg;
+	}
+	pr_debug("cnss: Platform driver probed successfully.\n");
+	return ret;
+
+err_bus_reg:
+	if (penv->bus_scale_table)
+		msm_bus_cl_clear_pdata(penv->bus_scale_table);
+	pci_unregister_driver(&cnss_wlan_pci_driver);
+
+err_pci_reg:
+	if (penv->notify_modem_status)
+		subsys_notif_unregister_notifier
+			(penv->modem_notify_handler, &mnb);
+
+err_notif_modem:
+	if (penv->ramdump_dev)
+		destroy_ramdump_device(penv->ramdump_dev);
+
+err_ramdump_create:
+	if (penv->ramdump_addr) {
+		if (penv->ramdump_dynamic) {
+			dma_free_coherent(&pdev->dev, penv->ramdump_size,
+					  penv->ramdump_addr,
+					  penv->ramdump_phys);
+		} else {
+			iounmap(penv->ramdump_addr);
+		}
+	}
+
+	if (penv->subsys_handle)
+		subsystem_put(penv->subsys_handle);
+
+	subsys_unregister(penv->subsys);
+
+err_subsys_reg:
+	if (penv->esoc_desc)
+		devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+
+err_esoc_reg:
+err_pcie_enumerate:
+err_get_rc:
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	cnss_wlan_release_resources();
+
+err_get_wlan_res:
+	penv = NULL;
+
+	return ret;
+}
+
+static int cnss_remove(struct platform_device *pdev)
+{
+	unregister_pm_notifier(&cnss_pm_notifier);
+	device_remove_file(&pdev->dev, &dev_attr_fw_image_setup);
+
+	cnss_pm_wake_lock_destroy(&penv->ws);
+
+	if (penv->bus_client)
+		msm_bus_scale_unregister_client(penv->bus_client);
+
+	if (penv->bus_scale_table)
+		msm_bus_cl_clear_pdata(penv->bus_scale_table);
+
+	if (penv->ramdump_addr) {
+		if (penv->ramdump_dynamic) {
+			dma_free_coherent(&pdev->dev, penv->ramdump_size,
+					  penv->ramdump_addr,
+					  penv->ramdump_phys);
+		} else {
+			iounmap(penv->ramdump_addr);
+		}
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+	cnss_wlan_release_resources();
+
+	return 0;
+}
+
+static const struct of_device_id cnss_dt_match[] = {
+	{.compatible = "qcom,cnss"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cnss_dt_match);
+
+static struct platform_driver cnss_driver = {
+	.probe  = cnss_probe,
+	.remove = cnss_remove,
+	.driver = {
+		.name = "cnss",
+		.owner = THIS_MODULE,
+		.of_match_table = cnss_dt_match,
+#ifdef CONFIG_CNSS_ASYNC
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+	},
+};
+
+static int __init cnss_initialize(void)
+{
+	return platform_driver_register(&cnss_driver);
+}
+
+static void __exit cnss_exit(void)
+{
+	struct platform_device *pdev = penv->pldev;
+
+	if (penv->ramdump_dev)
+		destroy_ramdump_device(penv->ramdump_dev);
+	if (penv->notify_modem_status)
+		subsys_notif_unregister_notifier(penv->modem_notify_handler,
+						 &mnb);
+	subsys_unregister(penv->subsys);
+	if (penv->esoc_desc)
+		devm_unregister_esoc_client(&pdev->dev, penv->esoc_desc);
+	platform_driver_unregister(&cnss_driver);
+}
+
+void cnss_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos_type);
+
+void cnss_request_pm_qos(u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos);
+
+void cnss_remove_pm_qos(void)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_remove_pm_qos);
+
+void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos_type);
+
+void cnss_pci_request_pm_qos(u32 qos_val)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_add_request(&penv->qos_request, PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_pci_request_pm_qos);
+
+void cnss_pci_remove_pm_qos(void)
+{
+	if (!penv) {
+		pr_err("%s: penv is NULL\n", __func__);
+		return;
+	}
+
+	pm_qos_remove_request(&penv->qos_request);
+}
+EXPORT_SYMBOL(cnss_pci_remove_pm_qos);
+
+int cnss_pci_request_bus_bandwidth(int bandwidth)
+{
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+				penv->bus_client, bandwidth);
+		if (!ret) {
+			penv->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+			       __func__, bandwidth, ret);
+		}
+		break;
+
+	default:
+		pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+int cnss_request_bus_bandwidth(int bandwidth)
+{
+	int ret = 0;
+
+	if (!penv)
+		return -ENODEV;
+
+	if (!penv->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+				penv->bus_client, bandwidth);
+		if (!ret) {
+			penv->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_err("%s: could not set bus bandwidth %d, ret = %d\n",
+			       __func__, bandwidth, ret);
+		}
+		break;
+
+	default:
+		pr_err("%s: Invalid request %d\n", __func__, bandwidth);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+EXPORT_SYMBOL(cnss_request_bus_bandwidth);
+
+int cnss_get_platform_cap(struct cnss_platform_cap *cap)
+{
+	if (!penv)
+		return -ENODEV;
+
+	if (cap)
+		*cap = penv->cap;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_platform_cap);
+
+void cnss_set_driver_status(enum cnss_driver_status driver_status)
+{
+	penv->driver_status = driver_status;
+}
+EXPORT_SYMBOL(cnss_set_driver_status);
+
+int cnss_get_bmi_setup(void)
+{
+	if (!penv)
+		return -ENODEV;
+
+	return penv->bmi_test;
+}
+EXPORT_SYMBOL(cnss_get_bmi_setup);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+int cnss_get_sha_hash(const u8 *data, u32 data_len, u8 *hash_idx, u8 *out)
+{
+	struct scatterlist sg;
+	struct hash_desc desc;
+	int ret = 0;
+
+	if (!out) {
+		pr_err("memory for output buffer is not allocated\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	desc.tfm   = crypto_alloc_hash(hash_idx, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(desc.tfm)) {
+		pr_err("crypto_alloc_hash failed:%ld\n", PTR_ERR(desc.tfm));
+		ret = PTR_ERR(desc.tfm);
+		goto end;
+	}
+
+	sg_init_one(&sg, data, data_len);
+	ret = crypto_hash_digest(&desc, &sg, sg.length, out);
+	crypto_free_hash(desc.tfm);
+end:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_get_sha_hash);
+
+void *cnss_get_fw_ptr(void)
+{
+	if (!penv)
+		return NULL;
+
+	return penv->fw_mem;
+}
+EXPORT_SYMBOL(cnss_get_fw_ptr);
+#endif
+
+int cnss_auto_suspend(void)
+{
+	int ret = 0;
+	struct pci_dev *pdev;
+
+	if (!penv || !penv->driver)
+		return -ENODEV;
+
+	pdev = penv->pdev;
+
+	if (penv->pcie_link_state) {
+		pci_save_state(pdev);
+		penv->saved_state = cnss_pci_store_saved_state(pdev);
+		pci_disable_device(pdev);
+		ret = pci_set_power_state(pdev, PCI_D3hot);
+		if (ret)
+			pr_err("%s: Set D3Hot failed: %d\n", __func__, ret);
+		if (cnss_msm_pcie_pm_control(
+				MSM_PCIE_SUSPEND,
+				cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS)) {
+			pr_err("%s: Failed to shutdown PCIe link\n", __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+	}
+	atomic_set(&penv->auto_suspended, 1);
+	penv->monitor_wake_intr = true;
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	msm_bus_scale_client_update_request(penv->bus_client,
+					    CNSS_BUS_WIDTH_NONE);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_suspend);
+
+int cnss_auto_resume(void)
+{
+	int ret = 0;
+	struct pci_dev *pdev;
+
+	if (!penv || !penv->driver)
+		return -ENODEV;
+
+	pdev = penv->pdev;
+	if (!penv->pcie_link_state) {
+		if (cnss_msm_pcie_pm_control(
+			MSM_PCIE_RESUME, cnss_get_pci_dev_bus_number(pdev),
+				pdev, PM_OPTIONS)) {
+			pr_err("%s: Failed to resume PCIe link\n", __func__);
+			ret = -EAGAIN;
+			goto out;
+		}
+		ret = pci_enable_device(pdev);
+		if (ret)
+			pr_err("%s: enable device failed: %d\n", __func__, ret);
+		penv->pcie_link_state = PCIE_LINK_UP;
+	}
+
+	if (penv->saved_state)
+		cnss_pci_load_and_free_saved_state(pdev, &penv->saved_state);
+
+	pci_restore_state(pdev);
+	pci_set_master(pdev);
+
+	atomic_set(&penv->auto_suspended, 0);
+
+	msm_bus_scale_client_update_request(penv->bus_client,
+					    penv->current_bandwidth_vote);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_resume);
+
+int cnss_pm_runtime_request(struct device *dev,
+			    enum cnss_runtime_request request)
+{
+	int ret = 0;
+
+	switch (request) {
+	case CNSS_PM_RUNTIME_GET:
+		ret = pm_runtime_get(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT:
+		ret = pm_runtime_put(dev);
+		break;
+	case CNSS_PM_RUNTIME_MARK_LAST_BUSY:
+		pm_runtime_mark_last_busy(dev);
+		break;
+	case CNSS_PM_RUNTIME_RESUME:
+		ret = pm_runtime_resume(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT_AUTO:
+		ret = pm_runtime_put_autosuspend(dev);
+		break;
+	case CNSS_PM_RUNTIME_PUT_NOIDLE:
+		pm_runtime_put_noidle(dev);
+		break;
+	case CNSS_PM_REQUEST_RESUME:
+		ret = pm_request_resume(dev);
+		break;
+	case CNSS_PM_GET_NORESUME:
+		pm_runtime_get_noresume(dev);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_pm_runtime_request);
+
+void cnss_runtime_init(struct device *dev, int auto_delay)
+{
+	pm_runtime_set_autosuspend_delay(dev, auto_delay);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_allow(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_noidle(dev);
+	pm_suspend_ignore_children(dev, true);
+}
+EXPORT_SYMBOL(cnss_runtime_init);
+
+void cnss_runtime_exit(struct device *dev)
+{
+	pm_runtime_get_noresume(dev);
+	pm_runtime_set_active(dev);
+}
+EXPORT_SYMBOL(cnss_runtime_exit);
+
+static void __cnss_set_pcie_monitor_intr(struct device *dev, bool val)
+{
+	penv->monitor_wake_intr = val;
+}
+
+static void __cnss_set_auto_suspend(struct device *dev, int val)
+{
+	atomic_set(&penv->auto_suspended, val);
+}
+
+static int __cnss_resume_link(struct device *dev, u32 flags)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+
+	ret = cnss_msm_pcie_pm_control(MSM_PCIE_RESUME, bus_num, pdev, flags);
+	if (ret)
+		pr_err("%s: PCIe link resume failed with flags:%d bus_num:%d\n",
+		       __func__, flags, bus_num);
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	return ret;
+}
+
+static int __cnss_suspend_link(struct device *dev, u32 flags)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	u8 bus_num = cnss_get_pci_dev_bus_number(pdev);
+	int ret;
+
+	if (!penv->pcie_link_state)
+		return 0;
+
+	ret = cnss_msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus_num, pdev, flags);
+	if (ret) {
+		pr_err("%s: Failed to suspend link\n", __func__);
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	return ret;
+}
+
+static int __cnss_pcie_recover_config(struct device *dev)
+{
+	int ret;
+
+	ret = cnss_msm_pcie_recover_config(to_pci_dev(dev));
+	if (ret)
+		pr_err("%s: PCIe Recover config failed\n", __func__);
+
+	return ret;
+}
+
+static int __cnss_event_reg(struct device *dev)
+{
+	int ret;
+	struct msm_pcie_register_event *event_reg;
+
+	event_reg = &penv->event_reg;
+
+	event_reg->events = MSM_PCIE_EVENT_LINKDOWN |
+		MSM_PCIE_EVENT_WAKEUP;
+	event_reg->user = to_pci_dev(dev);
+	event_reg->mode = MSM_PCIE_TRIGGER_CALLBACK;
+	event_reg->callback = cnss_pci_events_cb;
+	event_reg->options = MSM_PCIE_CONFIG_NO_RECOVERY;
+
+	ret = cnss_msm_pcie_register_event(event_reg);
+	if (ret)
+		pr_err("%s: PCIe event register failed %d\n", __func__, ret);
+
+	return ret;
+}
+
+static void __cnss_event_dereg(struct device *dev)
+{
+	cnss_msm_pcie_deregister_event(&penv->event_reg);
+}
+
+static struct pci_dev *__cnss_get_pcie_dev(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = penv->pdev;
+
+	if (pdev)
+		return pdev;
+
+	ret = pci_register_driver(&cnss_wlan_pci_driver);
+	if (ret) {
+		pr_err("%s: pci re-registration failed\n", __func__);
+		return NULL;
+	}
+
+	pdev = penv->pdev;
+
+	return pdev;
+}
+
+static int __cnss_pcie_power_up(struct device *dev)
+{
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_ON);
+	if (ret) {
+		pr_err("%s: WLAN VREG ON Failed\n", __func__);
+		return ret;
+	}
+
+	msleep(POWER_ON_DELAY);
+
+	if (penv->wlan_bootstrap_gpio > 0) {
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_HIGH);
+		msleep(WLAN_BOOTSTRAP_DELAY);
+	}
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_HIGH);
+	return 0;
+}
+
+static int __cnss_pcie_power_down(struct device *dev)
+{
+	struct cnss_wlan_vreg_info *vreg_info;
+	struct cnss_wlan_gpio_info *gpio_info;
+	int ret;
+
+	vreg_info = &penv->vreg_info;
+	gpio_info = &penv->gpio_info;
+
+	cnss_configure_wlan_en_gpio(WLAN_EN_LOW);
+	if (penv->wlan_bootstrap_gpio > 0)
+		gpio_set_value(penv->wlan_bootstrap_gpio, WLAN_BOOTSTRAP_LOW);
+
+	ret = cnss_wlan_vreg_set(vreg_info, VREG_OFF);
+	if (ret)
+		pr_err("%s: Failed to turn off 3.3V regulator\n", __func__);
+
+	return ret;
+}
+
+static int __cnss_suspend_link_state(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int link_ind;
+
+	if (!penv->pcie_link_state) {
+		pr_debug("%s: Link is already suspended\n", __func__);
+		return 0;
+	}
+
+	link_ind = penv->pcie_link_down_ind;
+
+	if (!link_ind)
+		pci_save_state(pdev);
+
+	penv->saved_state = link_ind ? NULL : cnss_pci_store_saved_state(pdev);
+
+	ret = link_ind ? __cnss_suspend_link(dev, PM_OPTIONS_SUSPEND_LINK_DOWN)
+		: __cnss_suspend_link(dev, PM_OPTIONS);
+	if (ret) {
+		pr_err("%s: Link Suspend failed in state:%s\n", __func__,
+		       link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_DOWN;
+
+	return 0;
+}
+
+static int __cnss_restore_pci_config_space(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	int ret = 0;
+
+	if (penv->saved_state)
+		ret = cnss_pci_load_and_free_saved_state(pdev,
+							 &penv->saved_state);
+	pci_restore_state(pdev);
+
+	return ret;
+}
+
+static int __cnss_resume_link_state(struct device *dev)
+{
+	int ret;
+	int link_ind;
+
+	if (penv->pcie_link_state) {
+		pr_debug("%s: Link is already in active state\n", __func__);
+		return 0;
+	}
+
+	link_ind = penv->pcie_link_down_ind;
+
+	ret = link_ind ? __cnss_resume_link(dev, PM_OPTIONS_RESUME_LINK_DOWN) :
+		__cnss_resume_link(dev, PM_OPTIONS);
+
+	if (ret) {
+		pr_err("%s: Resume Link failed in link state:%s\n", __func__,
+		       link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		return ret;
+	}
+
+	penv->pcie_link_state = PCIE_LINK_UP;
+
+	ret = link_ind ?  __cnss_pcie_recover_config(dev) :
+		__cnss_restore_pci_config_space(dev);
+
+	if (ret) {
+		pr_err("%s: Link Recovery Config Failed link_state:%s\n",
+		       __func__, link_ind ? "LINK_DOWN" : "LINK_ACTIVE");
+		penv->pcie_link_state = PCIE_LINK_DOWN;
+		return ret;
+	}
+
+	penv->pcie_link_down_ind  = false;
+	return ret;
+}
+
+int cnss_pcie_power_up(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev;
+
+	if (!penv) {
+		pr_err("%s: platform data is NULL\n", __func__);
+		return -ENODEV;
+	}
+
+	ret = __cnss_pcie_power_up(dev);
+	if (ret) {
+		pr_err("%s: Power UP Failed\n", __func__);
+		return ret;
+	}
+
+	pdev = __cnss_get_pcie_dev(dev);
+	if (!pdev) {
+		pr_err("%s: PCIe Dev is NULL\n", __func__);
+		goto power_down;
+	}
+
+	ret = __cnss_event_reg(dev);
+
+	if (ret)
+		pr_err("%s: PCIe event registration failed\n", __func__);
+
+	ret = __cnss_resume_link_state(dev);
+
+	if (ret) {
+		pr_err("%s: Link Bring Up Failed\n", __func__);
+		goto event_dereg;
+	}
+
+	__cnss_set_pcie_monitor_intr(dev, true);
+
+	return ret;
+
+event_dereg:
+	__cnss_event_dereg(dev);
+power_down:
+	__cnss_pcie_power_down(dev);
+	pr_err("%s: Device Power Up Failed Fatal Error\n", __func__);
+	return ret;
+}
+
+static void __cnss_vote_bus_width(struct device *dev, u32 option)
+{
+	if (penv->bus_client)
+		msm_bus_scale_client_update_request(penv->bus_client, option);
+}
+
+int cnss_pcie_power_down(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	if (!penv) {
+		pr_err("%s: Invalid Platform data\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!pdev) {
+		pr_err("%s: Invalid Pdev, Cut Power to device\n", __func__);
+		__cnss_pcie_power_down(dev);
+		return -ENODEV;
+	}
+
+	__cnss_vote_bus_width(dev, CNSS_BUS_WIDTH_NONE);
+	__cnss_event_dereg(dev);
+
+	ret = __cnss_suspend_link_state(dev);
+
+	if (ret) {
+		pr_err("%s: Suspend Link failed\n", __func__);
+		return ret;
+	}
+
+	__cnss_set_pcie_monitor_intr(dev, false);
+	__cnss_set_auto_suspend(dev, 0);
+
+	ret = __cnss_pcie_power_down(dev);
+	if (ret)
+		pr_err("%s: Power Down Failed\n", __func__);
+
+	return ret;
+}
+
+module_init(cnss_initialize);
+module_exit(cnss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS Driver");
diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c
new file mode 100644
index 0000000..c35ba38
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_sdio.c
@@ -0,0 +1,1564 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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) "cnss_sdio:%s:%d:: " fmt, __func__, __LINE__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/memory_dump.h>
+#include <net/cnss.h>
+#include "cnss_common.h"
+#include <linux/pm_qos.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#define WLAN_VREG_NAME		"vdd-wlan"
+#define WLAN_VREG_DSRC_NAME	"vdd-wlan-dsrc"
+#define WLAN_VREG_IO_NAME	"vdd-wlan-io"
+#define WLAN_VREG_XTAL_NAME	"vdd-wlan-xtal"
+#define WLAN_GPIO_CAPTSF_NAME	"qcom,cap-tsf-gpio"
+
+#define WLAN_VREG_IO_MAX	1800000
+#define WLAN_VREG_IO_MIN	1800000
+#define WLAN_VREG_XTAL_MAX	1800000
+#define WLAN_VREG_XTAL_MIN	1800000
+#define POWER_ON_DELAY		4
+
+/* Values for Dynamic Ramdump Collection*/
+#define CNSS_DUMP_FORMAT_VER	0x11
+#define CNSS_DUMP_MAGIC_VER_V2	0x42445953
+#define CNSS_DUMP_NAME		"CNSS_WLAN_SDIO"
+#define CNSS_PINCTRL_SLEEP_STATE	"sleep"
+#define CNSS_PINCTRL_ACTIVE_STATE	"active"
+
+#define CNSS_HW_SLEEP 0
+#define CNSS_HW_ACTIVE 1
+
+struct cnss_sdio_regulator {
+	struct regulator *wlan_io;
+	struct regulator *wlan_xtal;
+	struct regulator *wlan_vreg;
+	struct regulator *wlan_vreg_dsrc;
+};
+
+struct cnss_sdio_info {
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct sdio_func *func;
+	struct mmc_card *card;
+	struct mmc_host *host;
+	struct device *dev;
+	const struct sdio_device_id *id;
+	bool skip_wlan_en_toggle;
+	bool cnss_hw_state;
+	struct cnss_cap_tsf_info cap_tsf_info;
+};
+
+struct cnss_ssr_info {
+	struct subsys_device *subsys;
+	struct subsys_desc subsysdesc;
+	void *subsys_handle;
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_addr;
+	phys_addr_t ramdump_phys;
+	struct msm_dump_data dump_data;
+	bool ramdump_dynamic;
+	char subsys_name[10];
+};
+
+struct cnss_wlan_pinctrl_info {
+	bool is_antenna_shared;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *sleep;
+	struct pinctrl_state *active;
+};
+
+struct cnss_sdio_bus_bandwidth {
+	struct msm_bus_scale_pdata *bus_scale_table;
+	u32 bus_client;
+	int current_bandwidth_vote;
+};
+
+static struct cnss_sdio_data {
+	struct cnss_sdio_regulator regulator;
+	struct platform_device *pdev;
+	struct cnss_sdio_info cnss_sdio_info;
+	struct cnss_ssr_info ssr_info;
+	struct pm_qos_request qos_request;
+	struct cnss_wlan_pinctrl_info pinctrl_info;
+	struct cnss_sdio_bus_bandwidth bus_bandwidth;
+	struct cnss_dev_platform_ops platform_ops;
+} *cnss_pdata;
+
+#define WLAN_RECOVERY_DELAY 1
+/* cnss sdio subsytem device name, required property */
+#define CNSS_SUBSYS_NAME_KEY "subsys-name"
+
+/* SDIO manufacturer ID and Codes */
+#define MANUFACTURER_ID_AR6320_BASE        0x500
+#define MANUFACTURER_ID_QCA9377_BASE       0x700
+#define MANUFACTURER_CODE                  0x271
+
+static const struct sdio_device_id ar6k_id_table[] = {
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))},
+	{SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))},
+	{},
+};
+MODULE_DEVICE_TABLE(sdio, ar6k_id_table);
+
+void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val)
+{
+	if (!cnss_pdata)
+		return;
+
+	pr_debug("PM QoS value: %d\n", qos_val);
+	pm_qos_add_request(&cnss_pdata->qos_request, latency_type, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos_type);
+
+int cnss_sdio_request_bus_bandwidth(int bandwidth)
+{
+	int ret;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (!bus_bandwidth->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, bandwidth);
+		if (!ret) {
+			bus_bandwidth->current_bandwidth_vote = bandwidth;
+		} else {
+			pr_debug(
+			"could not set bus bandwidth %d, ret = %d\n",
+			 bandwidth, ret);
+		}
+		break;
+	default:
+		pr_debug("Invalid request %d\n", bandwidth);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void cnss_sdio_request_pm_qos(u32 qos_val)
+{
+	if (!cnss_pdata)
+		return;
+
+	pr_debug("PM QoS value: %d\n", qos_val);
+	pm_qos_add_request(
+		&cnss_pdata->qos_request,
+		PM_QOS_CPU_DMA_LATENCY, qos_val);
+}
+EXPORT_SYMBOL(cnss_sdio_request_pm_qos);
+
+void cnss_sdio_remove_pm_qos(void)
+{
+	if (!cnss_pdata)
+		return;
+
+	pm_qos_remove_request(&cnss_pdata->qos_request);
+	pr_debug("PM QoS removed\n");
+}
+EXPORT_SYMBOL(cnss_sdio_remove_pm_qos);
+
+static int cnss_put_hw_resources(struct device *dev)
+{
+	int ret = -EINVAL;
+	struct cnss_sdio_info *info;
+	struct mmc_host *host;
+
+	if (!cnss_pdata)
+		return ret;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	if (info->skip_wlan_en_toggle) {
+		pr_debug("HW doesn't support wlan toggling\n");
+		return 0;
+	}
+
+	if (info->cnss_hw_state == CNSS_HW_SLEEP) {
+		pr_debug("HW resources are already released\n");
+		return 0;
+	}
+
+	host = info->host;
+
+	if (!host) {
+		pr_err("MMC host is invalid\n");
+		return ret;
+	}
+
+	if (!cnss_pdata->regulator.wlan_vreg) {
+		pr_debug("wlan_vreg regulator is invalid\n");
+		return 0;
+	}
+
+	ret = mmc_power_save_host(host);
+	if (ret) {
+		pr_err("Failed to Power Save Host err:%d\n",
+		       ret);
+		return ret;
+	}
+
+	regulator_disable(cnss_pdata->regulator.wlan_vreg);
+	info->cnss_hw_state = CNSS_HW_SLEEP;
+
+	return ret;
+}
+
+static int cnss_get_hw_resources(struct device *dev)
+{
+	int ret = -EINVAL;
+	struct mmc_host *host;
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return ret;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	if (info->skip_wlan_en_toggle) {
+		pr_debug("HW doesn't support wlan toggling\n");
+		return 0;
+	}
+
+	if (info->cnss_hw_state == CNSS_HW_ACTIVE) {
+		pr_debug("HW resources are already active\n");
+		return 0;
+	}
+
+	host = info->host;
+
+	if (!host) {
+		pr_err("MMC Host is Invalid; Enumeration Failed\n");
+		return ret;
+	}
+
+	if (!cnss_pdata->regulator.wlan_vreg) {
+		pr_debug("wlan_vreg regulator is invalid\n");
+		return 0;
+	}
+
+	ret = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+	if (ret) {
+		pr_err("Failed to enable wlan vreg\n");
+		return ret;
+	}
+
+	ret = mmc_power_restore_host(host);
+	if (ret) {
+		pr_err("Failed to restore host power ret:%d\n",
+		       ret);
+		regulator_disable(cnss_pdata->regulator.wlan_vreg);
+		return ret;
+	}
+
+	info->cnss_hw_state = CNSS_HW_ACTIVE;
+	return ret;
+}
+
+static int cnss_sdio_shutdown(const struct subsys_desc *subsys, bool force_stop)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+	if (!wdrv)
+		return 0;
+	if (!wdrv->shutdown)
+		return 0;
+
+	wdrv->shutdown(cnss_info->func);
+	ret = cnss_put_hw_resources(cnss_info->dev);
+
+	if (ret)
+		pr_err("Failed to put hw resources\n");
+
+	return ret;
+}
+
+static int cnss_sdio_powerup(const struct subsys_desc *subsys)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+
+	if (!wdrv)
+		return 0;
+
+	if (!wdrv->reinit)
+		return 0;
+
+	ret = cnss_get_hw_resources(cnss_info->dev);
+	if (ret) {
+		pr_err("Failed to power up HW\n");
+		return ret;
+	}
+
+	ret = wdrv->reinit(cnss_info->func, cnss_info->id);
+	if (ret)
+		pr_err("wlan reinit error=%d\n", ret);
+
+	return ret;
+}
+
+static void cnss_sdio_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_wlan_driver *wdrv;
+
+	if (!cnss_pdata)
+		return;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	wdrv = cnss_info->wdrv;
+	if (wdrv && wdrv->crash_shutdown)
+		wdrv->crash_shutdown(cnss_info->func);
+}
+
+static int cnss_sdio_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct cnss_ssr_info *ssr_info;
+	struct ramdump_segment segment;
+	int ret;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	if (!cnss_pdata->ssr_info.ramdump_size)
+		return -ENOENT;
+
+	if (!enable)
+		return 0;
+
+	ssr_info = &cnss_pdata->ssr_info;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = ssr_info->ramdump_addr;
+	segment.size = ssr_info->ramdump_size;
+	ret = do_ramdump(ssr_info->ramdump_dev, &segment, 1);
+	if (ret)
+		pr_err("do_ramdump failed error=%d\n", ret);
+	return ret;
+}
+
+static int cnss_subsys_init(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int ret = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	ssr_info = &cnss_pdata->ssr_info;
+	ssr_info->subsysdesc.name = ssr_info->subsys_name;
+	ssr_info->subsysdesc.owner = THIS_MODULE;
+	ssr_info->subsysdesc.shutdown = cnss_sdio_shutdown;
+	ssr_info->subsysdesc.powerup = cnss_sdio_powerup;
+	ssr_info->subsysdesc.ramdump = cnss_sdio_ramdump;
+	ssr_info->subsysdesc.crash_shutdown = cnss_sdio_crash_shutdown;
+	ssr_info->subsysdesc.dev = &cnss_pdata->pdev->dev;
+	ssr_info->subsys = subsys_register(&ssr_info->subsysdesc);
+	if (IS_ERR(ssr_info->subsys)) {
+		ret = PTR_ERR(ssr_info->subsys);
+		ssr_info->subsys = NULL;
+		dev_err(&cnss_pdata->pdev->dev, "Failed to subsys_register error=%d\n",
+			ret);
+		goto err_subsys_reg;
+	}
+	ssr_info->subsys_handle = subsystem_get(ssr_info->subsysdesc.name);
+	if (IS_ERR(ssr_info->subsys_handle)) {
+		ret = PTR_ERR(ssr_info->subsys_handle);
+		ssr_info->subsys_handle = NULL;
+		dev_err(&cnss_pdata->pdev->dev, "Failed to subsystem_get error=%d\n",
+			ret);
+		goto err_subsys_get;
+	}
+	return 0;
+err_subsys_get:
+	subsys_unregister(ssr_info->subsys);
+	ssr_info->subsys = NULL;
+err_subsys_reg:
+	return ret;
+}
+
+static void cnss_subsys_exit(void)
+{
+	struct cnss_ssr_info *ssr_info;
+
+	if (!cnss_pdata)
+		return;
+
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->subsys_handle)
+		subsystem_put(ssr_info->subsys_handle);
+	ssr_info->subsys_handle = NULL;
+	if (ssr_info->subsys)
+		subsys_unregister(ssr_info->subsys);
+	ssr_info->subsys = NULL;
+}
+
+static int cnss_configure_dump_table(struct cnss_ssr_info *ssr_info)
+{
+	struct msm_dump_entry dump_entry;
+	int ret;
+
+	ssr_info->dump_data.addr = ssr_info->ramdump_phys;
+	ssr_info->dump_data.len = ssr_info->ramdump_size;
+	ssr_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	ssr_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(ssr_info->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(ssr_info->dump_data.name));
+
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&ssr_info->dump_data);
+
+	ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+	if (ret)
+		pr_err("Dump table setup failed: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_configure_ramdump(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int ret = 0;
+	struct resource *res;
+	const char *name;
+	u32 ramdump_size = 0;
+	struct device *dev;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	dev = &cnss_pdata->pdev->dev;
+
+	ssr_info = &cnss_pdata->ssr_info;
+
+	ret = of_property_read_string(dev->of_node, CNSS_SUBSYS_NAME_KEY,
+				      &name);
+	if (ret) {
+		pr_err("cnss missing DT key '%s'\n",
+		       CNSS_SUBSYS_NAME_KEY);
+		ret = -ENODEV;
+		goto err_subsys_name_query;
+	}
+
+	strlcpy(ssr_info->subsys_name, name, sizeof(ssr_info->subsys_name));
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0) {
+		ssr_info->ramdump_addr = dma_alloc_coherent(dev, ramdump_size,
+							&ssr_info->ramdump_phys,
+							GFP_KERNEL);
+		if (ssr_info->ramdump_addr)
+			ssr_info->ramdump_size = ramdump_size;
+		ssr_info->ramdump_dynamic = true;
+	} else {
+		res = platform_get_resource_byname(cnss_pdata->pdev,
+						   IORESOURCE_MEM, "ramdump");
+		if (res) {
+			ssr_info->ramdump_phys = res->start;
+			ramdump_size = resource_size(res);
+			ssr_info->ramdump_addr = ioremap(ssr_info->ramdump_phys,
+								ramdump_size);
+			if (ssr_info->ramdump_addr)
+				ssr_info->ramdump_size = ramdump_size;
+			ssr_info->ramdump_dynamic = false;
+		}
+	}
+
+	pr_info("ramdump addr: %p, phys: %pa subsys:'%s'\n",
+		ssr_info->ramdump_addr, &ssr_info->ramdump_phys,
+		ssr_info->subsys_name);
+
+	if (ssr_info->ramdump_size == 0) {
+		pr_info("CNSS ramdump will not be collected\n");
+		return 0;
+	}
+
+	if (ssr_info->ramdump_dynamic) {
+		ret = cnss_configure_dump_table(ssr_info);
+		if (ret)
+			goto err_configure_dump_table;
+	}
+
+	ssr_info->ramdump_dev = create_ramdump_device(ssr_info->subsys_name,
+									dev);
+	if (!ssr_info->ramdump_dev) {
+		ret = -ENOMEM;
+		pr_err("ramdump dev create failed: error=%d\n",
+		       ret);
+		goto err_configure_dump_table;
+	}
+
+	return 0;
+
+err_configure_dump_table:
+	if (ssr_info->ramdump_dynamic)
+		dma_free_coherent(dev, ssr_info->ramdump_size,
+				  ssr_info->ramdump_addr,
+				  ssr_info->ramdump_phys);
+	else
+		iounmap(ssr_info->ramdump_addr);
+
+	ssr_info->ramdump_addr = NULL;
+	ssr_info->ramdump_size = 0;
+err_subsys_name_query:
+	return ret;
+}
+
+static void cnss_ramdump_cleanup(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	struct device *dev;
+
+	if (!cnss_pdata)
+		return;
+
+	dev = &cnss_pdata->pdev->dev;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->ramdump_addr) {
+		if (ssr_info->ramdump_dynamic)
+			dma_free_coherent(dev, ssr_info->ramdump_size,
+					  ssr_info->ramdump_addr,
+					  ssr_info->ramdump_phys);
+		else
+			iounmap(ssr_info->ramdump_addr);
+	}
+
+	ssr_info->ramdump_addr = NULL;
+	if (ssr_info->ramdump_dev)
+		destroy_ramdump_device(ssr_info->ramdump_dev);
+	ssr_info->ramdump_dev = NULL;
+}
+
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size)
+{
+	if (!cnss_pdata || !cnss_pdata->pdev)
+		return NULL;
+
+	*size = cnss_pdata->ssr_info.ramdump_size;
+
+	return cnss_pdata->ssr_info.ramdump_addr;
+}
+
+void cnss_sdio_device_self_recovery(void)
+{
+	cnss_sdio_shutdown(NULL, false);
+	msleep(WLAN_RECOVERY_DELAY);
+	cnss_sdio_powerup(NULL);
+}
+
+void cnss_sdio_device_crashed(void)
+{
+	struct cnss_ssr_info *ssr_info;
+
+	if (!cnss_pdata)
+		return;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (ssr_info->subsys) {
+		subsys_set_crash_status(ssr_info->subsys, true);
+		subsystem_restart_dev(ssr_info->subsys);
+	}
+}
+
+static void cnss_sdio_recovery_work_handler(struct work_struct *recovery)
+{
+	cnss_sdio_device_self_recovery();
+}
+
+DECLARE_WORK(cnss_sdio_recovery_work, cnss_sdio_recovery_work_handler);
+
+void cnss_sdio_schedule_recovery_work(void)
+{
+	schedule_work(&cnss_sdio_recovery_work);
+}
+
+/**
+ * cnss_get_restart_level() - cnss get restart level API
+ *
+ * Wlan sdio function driver uses this API to get the current
+ * subsystem restart level.
+ *
+ * Return: CNSS_RESET_SOC - "SYSTEM", restart system
+ *         CNSS_RESET_SUBSYS_COUPLED - "RELATED",restart subsystem
+ */
+int cnss_get_restart_level(void)
+{
+	struct cnss_ssr_info *ssr_info;
+	int level;
+
+	if (!cnss_pdata)
+		return CNSS_RESET_SOC;
+	ssr_info = &cnss_pdata->ssr_info;
+	if (!ssr_info->subsys)
+		return CNSS_RESET_SOC;
+	level = subsys_get_restart_level(ssr_info->subsys);
+	switch (level) {
+	case RESET_SOC:
+		return CNSS_RESET_SOC;
+	case RESET_SUBSYS_COUPLED:
+		return CNSS_RESET_SUBSYS_COUPLED;
+	default:
+		return CNSS_RESET_SOC;
+	}
+}
+EXPORT_SYMBOL(cnss_get_restart_level);
+
+static inline int cnss_get_tsf_cap_irq(struct device *dev)
+{
+	int irq = -EINVAL;
+	int gpio;
+
+	if (!dev)
+		return -ENODEV;
+
+	gpio = of_get_named_gpio(dev->of_node, WLAN_GPIO_CAPTSF_NAME, 0);
+	if (gpio >= 0)
+		irq = gpio_to_irq(gpio);
+
+	return irq;
+}
+
+static int cnss_sdio_register_tsf_captured_handler(irq_handler_t handler,
+						   void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0)
+		return -ENOTSUPP;
+
+	tsf_info->irq_handler = handler;
+	tsf_info->context = ctx;
+	return 0;
+}
+
+static int cnss_sdio_unregister_tsf_captured_handler(void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0)
+		return -ENOTSUPP;
+
+	if (ctx == tsf_info->context) {
+		tsf_info->irq_handler = NULL;
+		tsf_info->context = NULL;
+	}
+	return 0;
+}
+
+static irqreturn_t cnss_sdio_tsf_captured_handler(int irq, void *ctx)
+{
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return IRQ_HANDLED;
+
+	tsf_info = &cnss_pdata->cnss_sdio_info.cap_tsf_info;
+	if (tsf_info->irq_num < 0 || tsf_info->irq_num != irq ||
+	    !tsf_info->irq_handler || !tsf_info->context)
+		return IRQ_HANDLED;
+
+	return tsf_info->irq_handler(irq, tsf_info->context);
+}
+
+static void cnss_sdio_tsf_init(struct device *dev,
+			       struct cnss_cap_tsf_info *tsf_info)
+{
+	int ret, irq;
+
+	tsf_info->irq_num = -EINVAL;
+	tsf_info->irq_handler = NULL;
+	tsf_info->context = NULL;
+
+	irq = cnss_get_tsf_cap_irq(dev);
+	if (irq < 0) {
+		dev_err(dev, "%s: fail to get irq: %d\n", __func__, irq);
+		return;
+	}
+
+	ret = request_irq(irq, cnss_sdio_tsf_captured_handler,
+			  IRQF_SHARED | IRQF_TRIGGER_RISING, dev_name(dev),
+			  (void *)tsf_info);
+	dev_err(dev, "%s: request irq[%d] for dev: %s, result: %d\n",
+		__func__, irq, dev_name(dev), ret);
+	if (!ret)
+		tsf_info->irq_num = irq;
+}
+
+static void cnss_sdio_tsf_deinit(struct cnss_cap_tsf_info *tsf_info)
+{
+	int irq = tsf_info->irq_num;
+
+	if (irq < 0)
+		return;
+
+	free_irq(irq, (void *)tsf_info);
+
+	tsf_info->irq_num = -EINVAL;
+	tsf_info->irq_handler = NULL;
+	tsf_info->context = NULL;
+}
+
+static void cnss_sdio_set_platform_ops(struct device *dev)
+{
+	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+
+	pf_ops->power_up = cnss_sdio_power_up;
+	pf_ops->power_down = cnss_sdio_power_down;
+	pf_ops->device_crashed = cnss_sdio_device_crashed;
+	pf_ops->get_virt_ramdump_mem = cnss_sdio_get_virt_ramdump_mem;
+	pf_ops->device_self_recovery = cnss_sdio_device_self_recovery;
+	pf_ops->get_wlan_mac_address = cnss_sdio_get_wlan_mac_address;
+	pf_ops->set_wlan_mac_address = cnss_sdio_set_wlan_mac_address;
+	pf_ops->schedule_recovery_work = cnss_sdio_schedule_recovery_work;
+	pf_ops->request_bus_bandwidth = cnss_sdio_request_bus_bandwidth;
+	pf_ops->register_tsf_captured_handler =
+		cnss_sdio_register_tsf_captured_handler;
+	pf_ops->unregister_tsf_captured_handler =
+		cnss_sdio_unregister_tsf_captured_handler;
+	dev->platform_data = pf_ops;
+}
+
+static int cnss_sdio_wlan_inserted(struct sdio_func *func,
+				   const struct sdio_device_id *id)
+{
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	info->func = func;
+	info->card = func->card;
+	info->host = func->card->host;
+	info->id = id;
+	info->dev = &func->dev;
+	cnss_sdio_set_platform_ops(info->dev);
+
+	cnss_put_hw_resources(cnss_pdata->cnss_sdio_info.dev);
+
+	pr_info("SDIO Device is Probed\n");
+	return 0;
+}
+
+static void cnss_sdio_wlan_removed(struct sdio_func *func)
+{
+	struct cnss_sdio_info *info;
+
+	if (!cnss_pdata)
+		return;
+
+	info = &cnss_pdata->cnss_sdio_info;
+
+	info->host = NULL;
+	info->card = NULL;
+	info->func = NULL;
+	info->id = NULL;
+}
+
+#if defined(CONFIG_PM)
+static int cnss_sdio_wlan_suspend(struct device *dev)
+{
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	struct sdio_func *func;
+
+	int error = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+	}
+
+	func = cnss_pdata->cnss_sdio_info.func;
+	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+	if (!wdrv) {
+		/* This can happen when no wlan driver loaded (no register to
+		 * platform driver).
+		 */
+		sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+		pr_debug("wlan driver not registered\n");
+		return 0;
+	}
+	if (wdrv->suspend) {
+		error = wdrv->suspend(dev);
+		if (error)
+			pr_err("wlan suspend failed error=%d\n", error);
+	}
+
+	return error;
+}
+
+static int cnss_sdio_wlan_resume(struct device *dev)
+{
+	struct cnss_sdio_wlan_driver *wdrv;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	int error = 0;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client,
+			bus_bandwidth->current_bandwidth_vote);
+	}
+
+	wdrv = cnss_pdata->cnss_sdio_info.wdrv;
+	if (!wdrv) {
+		/* This can happen when no wlan driver loaded (no register to
+		 * platform driver).
+		 */
+		pr_debug("wlan driver not registered\n");
+		return 0;
+	}
+	if (wdrv->resume) {
+		error = wdrv->resume(dev);
+		if (error)
+			pr_err("wlan resume failed error=%d\n", error);
+	}
+	return error;
+}
+#endif
+
+#if defined(CONFIG_PM)
+static const struct dev_pm_ops cnss_ar6k_device_pm_ops = {
+	.suspend = cnss_sdio_wlan_suspend,
+	.resume = cnss_sdio_wlan_resume,
+};
+#endif /* CONFIG_PM */
+
+static struct sdio_driver cnss_ar6k_driver = {
+	.name = "cnss_ar6k_wlan",
+	.id_table = ar6k_id_table,
+	.probe = cnss_sdio_wlan_inserted,
+	.remove = cnss_sdio_wlan_removed,
+#if defined(CONFIG_PM)
+	.drv = {
+		.pm = &cnss_ar6k_device_pm_ops,
+	}
+#endif
+};
+
+static int cnss_set_pinctrl_state(struct cnss_sdio_data *pdata, bool state)
+{
+	struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+	if (!info->is_antenna_shared)
+		return 0;
+
+	if (!info->pinctrl)
+		return -EIO;
+
+	return state ? pinctrl_select_state(info->pinctrl, info->active) :
+		pinctrl_select_state(info->pinctrl, info->sleep);
+}
+
+int cnss_sdio_configure_spdt(bool state)
+{
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	return cnss_set_pinctrl_state(cnss_pdata, state);
+}
+EXPORT_SYMBOL(cnss_sdio_configure_spdt);
+
+/**
+ * cnss_sdio_wlan_register_driver() - cnss wlan register API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to register callback
+ * functions to cnss_sido platform driver. The callback will
+ * be invoked by corresponding wrapper function of this cnss
+ * platform driver.
+ */
+int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct device *dev;
+	int error = -EINVAL;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	dev = cnss_info->dev;
+
+	if (cnss_info->wdrv) {
+		pr_debug("wdrv already existed\n");
+		return error;
+	}
+
+	if (!driver)
+		return error;
+
+	error = cnss_get_hw_resources(dev);
+	if (error) {
+		pr_err("Failed to restore power err:%d\n", error);
+		return error;
+	}
+
+	error = cnss_set_pinctrl_state(cnss_pdata, PINCTRL_ACTIVE);
+	if (error) {
+		pr_err("Fail to set pinctrl to active state\n");
+		cnss_put_hw_resources(dev);
+		goto put_hw;
+	}
+
+	/* The HW resources are released in unregister logic if probe fails */
+	error = driver->probe ? driver->probe(cnss_info->func,
+					      cnss_info->id) : error;
+	if (error) {
+		pr_err("wlan probe failed error=%d\n", error);
+		/**
+		 * Check memory leak in skb pre-alloc memory pool
+		 * Reset the skb memory pool
+		 */
+		goto pinctrl_sleep;
+	}
+
+	cnss_info->wdrv = driver;
+
+	return error;
+
+pinctrl_sleep:
+	cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+put_hw:
+	return error;
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_register_driver);
+
+/**
+ * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API
+ * @driver: sdio wlan driver interface from wlan driver.
+ *
+ * wlan sdio function driver uses this API to detach it from cnss_sido
+ * platform driver.
+ */
+void
+cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver)
+{
+	struct cnss_sdio_info *cnss_info;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	if (!cnss_pdata)
+		return;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(
+			bus_bandwidth->bus_client, CNSS_BUS_WIDTH_NONE);
+	}
+
+	cnss_info = &cnss_pdata->cnss_sdio_info;
+	if (!cnss_info->wdrv) {
+		pr_err("driver not registered\n");
+		return;
+	}
+
+	if (!driver)
+		return;
+
+	if (!driver->remove)
+		return;
+
+	driver->remove(cnss_info->func);
+
+	cnss_info->wdrv = NULL;
+	cnss_set_pinctrl_state(cnss_pdata, PINCTRL_SLEEP);
+	cnss_put_hw_resources(cnss_info->dev);
+}
+EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver);
+
+/**
+ * cnss_wlan_query_oob_status() - cnss wlan query oob status API
+ *
+ * Wlan sdio function driver uses this API to check whether oob is
+ * supported in platform driver.
+ *
+ * Return: 0 means oob is supported, others means unsupported.
+ */
+int cnss_wlan_query_oob_status(void)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_query_oob_status);
+
+/**
+ * cnss_wlan_register_oob_irq_handler() - cnss wlan register oob callback API
+ * @handler: oob callback function pointer which registered to platform driver.
+ * @pm_oob : parameter which registered to platform driver.
+ *
+ * Wlan sdio function driver uses this API to register oob callback
+ * function to platform driver.
+ *
+ * Return: 0 means register successfully, others means failure.
+ */
+int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler, void *pm_oob)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_register_oob_irq_handler);
+
+/**
+ * cnss_wlan_unregister_oob_irq_handler() - unregister oob callback API
+ * @pm_oob: parameter which unregistered from platform driver.
+ *
+ * Wlan sdio function driver uses this API to unregister oob callback
+ * function from platform driver.
+ *
+ * Return: 0 means unregister successfully, others means failure.
+ */
+int cnss_wlan_unregister_oob_irq_handler(void *pm_oob)
+{
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_oob_irq_handler);
+
+static void cnss_sdio_reset_platform_ops(void)
+{
+	struct cnss_dev_platform_ops *pf_ops = &cnss_pdata->platform_ops;
+	struct cnss_sdio_info *sdio_info = &cnss_pdata->cnss_sdio_info;
+
+	memset(pf_ops, 0, sizeof(struct cnss_dev_platform_ops));
+	if (sdio_info->dev)
+		sdio_info->dev->platform_data = NULL;
+}
+
+static int cnss_sdio_wlan_init(void)
+{
+	int error = 0;
+
+	error = sdio_register_driver(&cnss_ar6k_driver);
+	if (error) {
+		cnss_sdio_reset_platform_ops();
+		pr_err("registered fail error=%d\n", error);
+	} else {
+		pr_debug("registered success\n");
+	}
+
+	return error;
+}
+
+static void cnss_sdio_wlan_exit(void)
+{
+	if (!cnss_pdata)
+		return;
+
+	cnss_sdio_reset_platform_ops();
+	sdio_unregister_driver(&cnss_ar6k_driver);
+}
+
+static void cnss_sdio_deinit_bus_bandwidth(void)
+{
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	if (bus_bandwidth->bus_client) {
+		msm_bus_scale_client_update_request(bus_bandwidth->bus_client,
+						    CNSS_BUS_WIDTH_NONE);
+		msm_bus_scale_unregister_client(bus_bandwidth->bus_client);
+	}
+}
+
+static int cnss_sdio_configure_wlan_enable_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_vreg = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_vreg)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_vreg);
+			dev_err(dev, "VDD-VREG get failed error=%d\n", error);
+			return error;
+		}
+
+		error = regulator_enable(cnss_pdata->regulator.wlan_vreg);
+		if (error) {
+			dev_err(dev, "VDD-VREG enable failed error=%d\n",
+				error);
+			goto err_vdd_vreg_regulator;
+		}
+	}
+
+	return 0;
+
+err_vdd_vreg_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_vreg);
+
+	return error;
+}
+
+static int cnss_sdio_configure_wlan_enable_dsrc_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_vreg_dsrc = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_DSRC_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_vreg_dsrc)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_vreg_dsrc);
+			dev_err(dev, "VDD-VREG-DSRC get failed error=%d\n",
+				error);
+			return error;
+		}
+
+		error = regulator_enable(cnss_pdata->regulator.wlan_vreg_dsrc);
+		if (error) {
+			dev_err(dev, "VDD-VREG-DSRC enable failed error=%d\n",
+				error);
+			goto err_vdd_vreg_dsrc_regulator;
+		}
+	}
+
+	return 0;
+
+err_vdd_vreg_dsrc_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+
+	return error;
+}
+
+static int cnss_sdio_configure_regulator(void)
+{
+	int error;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_IO_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_io = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_IO_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_io)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_io);
+			dev_err(dev, "VDD-IO get failed error=%d\n", error);
+			return error;
+		}
+
+		error = regulator_set_voltage(
+			cnss_pdata->regulator.wlan_io,
+			WLAN_VREG_IO_MIN, WLAN_VREG_IO_MAX);
+		if (error) {
+			dev_err(dev, "VDD-IO set failed error=%d\n", error);
+			goto err_vdd_io_regulator;
+		} else {
+			error = regulator_enable(cnss_pdata->regulator.wlan_io);
+			if (error) {
+				dev_err(dev, "VDD-IO enable failed error=%d\n",
+					error);
+				goto err_vdd_io_regulator;
+			}
+		}
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+		WLAN_VREG_XTAL_NAME "-supply", NULL)) {
+		cnss_pdata->regulator.wlan_xtal = regulator_get(
+			&cnss_pdata->pdev->dev, WLAN_VREG_XTAL_NAME);
+		if (IS_ERR(cnss_pdata->regulator.wlan_xtal)) {
+			error = PTR_ERR(cnss_pdata->regulator.wlan_xtal);
+			dev_err(dev, "VDD-XTAL get failed error=%d\n", error);
+			goto err_vdd_xtal_regulator;
+		}
+
+		error = regulator_set_voltage(
+			cnss_pdata->regulator.wlan_xtal,
+			WLAN_VREG_XTAL_MIN, WLAN_VREG_XTAL_MAX);
+		if (error) {
+			dev_err(dev, "VDD-XTAL set failed error=%d\n", error);
+			goto err_vdd_xtal_regulator;
+		} else {
+			error = regulator_enable(
+				cnss_pdata->regulator.wlan_xtal);
+			if (error) {
+				dev_err(dev, "VDD-XTAL enable failed err=%d\n",
+					error);
+				goto err_vdd_xtal_regulator;
+			}
+		}
+	}
+
+	return 0;
+
+err_vdd_xtal_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_xtal);
+err_vdd_io_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_io);
+	return error;
+}
+
+static void cnss_sdio_release_resource(void)
+{
+	if (cnss_pdata->regulator.wlan_xtal)
+		regulator_put(cnss_pdata->regulator.wlan_xtal);
+	if (cnss_pdata->regulator.wlan_vreg)
+		regulator_put(cnss_pdata->regulator.wlan_vreg);
+	if (cnss_pdata->regulator.wlan_io)
+		regulator_put(cnss_pdata->regulator.wlan_io);
+	if (cnss_pdata->regulator.wlan_vreg_dsrc)
+		regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+}
+
+static int cnss_sdio_pinctrl_init(struct cnss_sdio_data *pdata,
+				  struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device *dev = &pdev->dev;
+	struct cnss_wlan_pinctrl_info *info = &pdata->pinctrl_info;
+
+	if (!of_find_property(dev->of_node, "qcom,is-antenna-shared", NULL))
+		return 0;
+
+	info->is_antenna_shared = true;
+	info->pinctrl = devm_pinctrl_get(dev);
+	if ((IS_ERR_OR_NULL(info->pinctrl))) {
+		dev_err(dev, "%s: Failed to get pinctrl\n", __func__);
+		return PTR_ERR(info->pinctrl);
+	}
+
+	info->sleep = pinctrl_lookup_state(info->pinctrl,
+						   CNSS_PINCTRL_SLEEP_STATE);
+	if (IS_ERR_OR_NULL(info->sleep)) {
+		dev_err(dev, "%s: Fail to get sleep state for pin\n", __func__);
+		ret = PTR_ERR(info->sleep);
+		goto release_pinctrl;
+	}
+
+	info->active = pinctrl_lookup_state(info->pinctrl,
+					    CNSS_PINCTRL_ACTIVE_STATE);
+	if (IS_ERR_OR_NULL(info->active)) {
+		dev_err(dev, "%s: Fail to get active state for pin\n",
+			__func__);
+		ret = PTR_ERR(info->active);
+		goto release_pinctrl;
+	}
+
+	ret = cnss_set_pinctrl_state(pdata, PINCTRL_SLEEP);
+
+	if (ret) {
+		dev_err(dev, "%s: Fail to set pin in sleep state\n", __func__);
+		goto release_pinctrl;
+	}
+
+	return ret;
+
+release_pinctrl:
+	devm_pinctrl_put(info->pinctrl);
+	info->is_antenna_shared = false;
+	return ret;
+}
+
+static int cnss_sdio_init_bus_bandwidth(void)
+{
+	int ret = 0;
+	struct cnss_sdio_bus_bandwidth *bus_bandwidth;
+	struct device *dev = &cnss_pdata->pdev->dev;
+
+	bus_bandwidth = &cnss_pdata->bus_bandwidth;
+	bus_bandwidth->bus_scale_table = msm_bus_cl_get_pdata(cnss_pdata->pdev);
+	if (!bus_bandwidth->bus_scale_table) {
+		dev_err(dev, "Failed to get the bus scale platform data\n");
+		ret = -EINVAL;
+	}
+
+	bus_bandwidth->bus_client = msm_bus_scale_register_client(
+			bus_bandwidth->bus_scale_table);
+	if (!bus_bandwidth->bus_client) {
+		dev_err(dev, "Failed to register with bus_scale client\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cnss_sdio_probe(struct platform_device *pdev)
+{
+	int error;
+	struct device *dev = &pdev->dev;
+	struct cnss_sdio_info *info;
+
+	if (pdev->dev.of_node) {
+		cnss_pdata = devm_kzalloc(
+			&pdev->dev, sizeof(*cnss_pdata), GFP_KERNEL);
+		if (!cnss_pdata)
+			return -ENOMEM;
+	} else {
+		cnss_pdata = pdev->dev.platform_data;
+	}
+
+	if (!cnss_pdata)
+		return -EINVAL;
+
+	cnss_pdata->pdev = pdev;
+	info = &cnss_pdata->cnss_sdio_info;
+
+	error = cnss_sdio_pinctrl_init(cnss_pdata, pdev);
+	if (error) {
+		dev_err(&pdev->dev, "Fail to configure pinctrl err:%d\n",
+			error);
+		return error;
+	}
+
+	error = cnss_sdio_configure_regulator();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to configure voltage regulator error=%d\n",
+			error);
+		return error;
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+			WLAN_VREG_NAME "-supply", NULL)) {
+		error = cnss_sdio_configure_wlan_enable_regulator();
+		if (error) {
+			dev_err(&pdev->dev,
+				"Failed to enable wlan enable regulator error=%d\n",
+				error);
+			goto err_wlan_enable_regulator;
+		}
+	}
+
+	if (of_get_property(
+		cnss_pdata->pdev->dev.of_node,
+			WLAN_VREG_DSRC_NAME "-supply", NULL)) {
+		error = cnss_sdio_configure_wlan_enable_dsrc_regulator();
+		if (error) {
+			dev_err(&pdev->dev,
+				"Failed to enable wlan dsrc enable regulator\n");
+			goto err_wlan_dsrc_enable_regulator;
+		}
+	}
+
+	info->skip_wlan_en_toggle = of_property_read_bool(dev->of_node,
+							  "qcom,skip-wlan-en-toggle");
+	info->cnss_hw_state = CNSS_HW_ACTIVE;
+
+	cnss_sdio_tsf_init(dev, &info->cap_tsf_info);
+
+	error = cnss_sdio_wlan_init();
+	if (error) {
+		dev_err(&pdev->dev, "cnss wlan init failed error=%d\n", error);
+		goto err_wlan_dsrc_enable_regulator;
+	}
+
+	error = cnss_configure_ramdump();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to configure ramdump error=%d\n",
+			error);
+		goto err_ramdump_create;
+	}
+
+	error = cnss_subsys_init();
+	if (error) {
+		dev_err(&pdev->dev, "Failed to cnss_subsys_init error=%d\n",
+			error);
+		goto err_subsys_init;
+	}
+
+	if (of_property_read_bool(
+		pdev->dev.of_node, "qcom,cnss-enable-bus-bandwidth")) {
+		error = cnss_sdio_init_bus_bandwidth();
+		if (error) {
+			dev_err(&pdev->dev, "Failed to init bus bandwidth\n");
+			goto err_bus_bandwidth_init;
+		}
+	}
+
+	dev_info(&pdev->dev, "CNSS SDIO Driver registered");
+	return 0;
+
+err_bus_bandwidth_init:
+	cnss_subsys_exit();
+err_subsys_init:
+	cnss_ramdump_cleanup();
+err_ramdump_create:
+	cnss_sdio_wlan_exit();
+err_wlan_dsrc_enable_regulator:
+	info->cnss_hw_state = CNSS_HW_SLEEP;
+	regulator_put(cnss_pdata->regulator.wlan_vreg_dsrc);
+err_wlan_enable_regulator:
+	regulator_put(cnss_pdata->regulator.wlan_xtal);
+	regulator_put(cnss_pdata->regulator.wlan_io);
+	cnss_pdata = NULL;
+	return error;
+}
+
+static int cnss_sdio_remove(struct platform_device *pdev)
+{
+	struct cnss_sdio_info *info;
+	struct cnss_cap_tsf_info *tsf_info;
+
+	if (!cnss_pdata)
+		return -ENODEV;
+
+	info = &cnss_pdata->cnss_sdio_info;
+	tsf_info = &info->cap_tsf_info;
+
+	cnss_sdio_tsf_deinit(tsf_info);
+	cnss_sdio_deinit_bus_bandwidth();
+	cnss_sdio_wlan_exit();
+	cnss_subsys_exit();
+	cnss_ramdump_cleanup();
+	cnss_put_hw_resources(info->dev);
+	cnss_sdio_release_resource();
+	cnss_pdata = NULL;
+	return 0;
+}
+
+int cnss_sdio_set_wlan_mac_address(const u8 *in, u32 len)
+{
+	return 0;
+}
+
+u8 *cnss_sdio_get_wlan_mac_address(u32 *num)
+{
+	*num = 0;
+	return NULL;
+}
+
+int cnss_sdio_power_down(struct device *dev)
+{
+	return 0;
+}
+
+int cnss_sdio_power_up(struct device *dev)
+{
+	return 0;
+}
+
+static const struct of_device_id cnss_sdio_dt_match[] = {
+	{.compatible = "qcom,cnss_sdio"},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cnss_sdio_dt_match);
+
+static struct platform_driver cnss_sdio_driver = {
+	.probe  = cnss_sdio_probe,
+	.remove = cnss_sdio_remove,
+	.driver = {
+		.name = "cnss_sdio",
+		.owner = THIS_MODULE,
+		.of_match_table = cnss_sdio_dt_match,
+	},
+};
+
+static int __init cnss_sdio_init(void)
+{
+	return platform_driver_register(&cnss_sdio_driver);
+}
+
+static void __exit cnss_sdio_exit(void)
+{
+	platform_driver_unregister(&cnss_sdio_driver);
+}
+
+module_init(cnss_sdio_init);
+module_exit(cnss_sdio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(DEVICE "CNSS SDIO Driver");
diff --git a/drivers/net/wireless/cnss/logger/Kconfig b/drivers/net/wireless/cnss/logger/Kconfig
new file mode 100644
index 0000000..85b6992
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Kconfig
@@ -0,0 +1,6 @@
+config CNSS_LOGGER
+	tristate "CNSS Logging Service Driver"
+	---help---
+	  This module adds support for the CNSS Logging Service for CLD
+	  driver, including the netlink socket service registration, transmit,
+	  event receive.
diff --git a/drivers/net/wireless/cnss/logger/Makefile b/drivers/net/wireless/cnss/logger/Makefile
new file mode 100644
index 0000000..1e296a3
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_CNSS_LOGGER) += logger.o
+
+logger-y += main.o	\
+	    nl_service.o
+
+logger-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/net/wireless/cnss/logger/debugfs.c b/drivers/net/wireless/cnss/logger/debugfs.c
new file mode 100644
index 0000000..027d630
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/debugfs.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#include "logger.h"
+
+#define CNSS_LOGGER_STATE_DUMP_BUFFER	(2 * 1024) /* 2KB */
+
+static int logger_state_dump_device(struct logger_device *dev, char *buf,
+				    int buf_len)
+{
+	int len = 0;
+	struct logger_event_handler *cur;
+
+	len += scnprintf(buf + len, buf_len - len,
+			"==============================================\n");
+
+	len += scnprintf(buf + len, buf_len - len,
+			"driver [%s] is registered with radio index: %d\n",
+			dev->name, dev->radio_idx);
+
+	if (list_empty(&dev->event_list)) {
+		len += scnprintf(buf + len, buf_len - len,
+				 "No event registered\n");
+		return len;
+	}
+
+	list_for_each_entry(cur, &dev->event_list, list) {
+		len += scnprintf(buf + len, buf_len - len,
+				"\t event %d\n", cur->event);
+	}
+	len += scnprintf(buf + len, buf_len - len, "\n");
+
+	return len;
+}
+
+static int logger_state_dump(struct logger_context *ctx, char *buf, int buf_len)
+{
+	int len = 0;
+	struct logger_device *cur;
+
+	if (list_empty(&ctx->dev_list)) {
+		len += scnprintf(buf + len, buf_len - len,
+				 "=======================\n");
+		len += scnprintf(buf + len, buf_len - len,
+				 "No driver registered\n");
+		return 0;
+	}
+
+	list_for_each_entry(cur, &ctx->dev_list, list)
+		len += logger_state_dump_device(cur, (buf + len), buf_len);
+
+	return 0;
+}
+
+static int logger_state_open(struct inode *inode, struct file *file)
+{
+	struct logger_context *ctx = inode->i_private;
+	void *buf;
+	int ret;
+
+	mutex_lock(&ctx->con_mutex);
+
+	buf = kmalloc(CNSS_LOGGER_STATE_DUMP_BUFFER, GFP_KERNEL);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto error_unlock;
+	}
+
+	ret = logger_state_dump(ctx, buf, CNSS_LOGGER_STATE_DUMP_BUFFER);
+	if (ret)
+		goto error_free;
+
+	file->private_data = buf;
+	mutex_unlock(&ctx->con_mutex);
+	return 0;
+
+error_free:
+	kfree(buf);
+
+error_unlock:
+	mutex_unlock(&ctx->con_mutex);
+
+	return ret;
+}
+
+static int logger_state_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static ssize_t logger_state_read(struct file *file, char __user *user_buf,
+				 size_t count, loff_t *ppos)
+{
+	const char *buf = file->private_data;
+	unsigned int len = strlen(buf);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_logger_state = {
+	.open = logger_state_open,
+	.release = logger_state_release,
+	.read = logger_state_read,
+	.owner = THIS_MODULE,
+	.llseek = default_llseek,
+};
+
+void logger_debugfs_init(struct logger_context *ctx)
+{
+	if (!ctx->debugfs_entry)
+		ctx->debugfs_entry = debugfs_create_dir("cnss_logger", NULL);
+
+	debugfs_create_file("state", 0400, ctx->debugfs_entry, ctx,
+			    &fops_logger_state);
+}
+
+void logger_debugfs_remove(struct logger_context *ctx)
+{
+	debugfs_remove(ctx->debugfs_entry);
+}
+
diff --git a/drivers/net/wireless/cnss/logger/logger.h b/drivers/net/wireless/cnss/logger/logger.h
new file mode 100644
index 0000000..6531ac6
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/logger.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _LOGGER_H_
+#define _LOGGER_H_
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+
+#define CNSS_LOGGER_NL_MCAST_GRP_ID	0x01
+#define CNSS_LOGGER_NL_MAX_PAYLOAD	256
+#define CNSS_LOGGER_BROADCAST_ID	255
+
+/**
+ * struct aninlmsg - the wireless service message header
+ * @nlh:	the netlink message header
+ * @radio:	the radio index of this message
+ * @wmsg:	the pointer to the wireless message data
+ */
+struct aninlmsg {
+	struct  nlmsghdr *nlh;
+	int radio;
+	void *wmsg;
+};
+
+/**
+ * struct logger_event_handler - the logger event handler structure
+ * @list:	the event list associated to the same device
+ * @event:	the event number
+ * @radio_idx:	the callback handler
+ */
+struct logger_event_handler {
+	struct list_head list;
+
+	int event;
+	int (*cb)(struct sk_buff *skb);
+};
+
+/**
+ * struct logger_device - the logger device structure
+ * @list:	the device list registered to logger module
+ * @event_list:	the event list registered to this device
+ * @ctx:	the pointer to the logger context
+ * @wiphy:	the wiphy that associated to the device
+ * @name:	the name of the device driver module
+ * @radio_idx:	the radio index assigned to this device
+ */
+struct logger_device {
+	struct list_head list;
+	struct list_head event_list;
+
+	struct logger_context *ctx;
+	struct wiphy *wiphy;
+	char name[MODULE_NAME_LEN];
+	int radio_idx;
+};
+
+/**
+ * struct logger_context - the main context block for logger module
+ * @dev_list:	this is the list to maintain the devices that registered
+ *		to use the logger module feature
+ * @nl_sock:	the netlink socket to share accros the module
+ * @con_mutex:	the mutex to protect concurrent access
+ * @data_lock:	the lock to protect shared data
+ * @radio_mask: this mask would maintain the radio index assign and release
+ */
+struct logger_context {
+	struct list_head dev_list;
+
+	struct sock *nl_sock;
+	struct mutex con_mutex; /* concurrent access mutex */
+	spinlock_t data_lock;
+	unsigned long radio_mask; /* support up to 4 drivers registration? */
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *debugfs_entry;
+#endif
+};
+
+int logger_netlink_init(struct logger_context *ctx);
+int logger_netlink_deinit(struct logger_context *ctx);
+struct logger_context *logger_get_ctx(void);
+
+#ifdef CONFIG_DEBUG_FS
+void logger_debugfs_init(struct logger_context *ctx);
+void logger_debugfs_remove(struct logger_context *ctx);
+#else
+static inline void logger_debugfs_init(struct logger_context *ctx) {}
+static inline void logger_debugfs_remove(struct logger_context *ctx) {}
+#endif
+
+#endif /* _LOGGER_H_ */
diff --git a/drivers/net/wireless/cnss/logger/main.c b/drivers/net/wireless/cnss/logger/main.c
new file mode 100644
index 0000000..4013e69
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/main.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static struct logger_context *ctx;
+
+struct logger_context *logger_get_ctx(void)
+{
+	return ctx;
+}
+
+static int __init logger_module_init(void)
+{
+	int ret;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ret = logger_netlink_init(ctx);
+
+	mutex_init(&ctx->con_mutex);
+	spin_lock_init(&ctx->data_lock);
+	logger_debugfs_init(ctx);
+
+	return ret;
+}
+
+static void __exit logger_module_exit(void)
+{
+	logger_debugfs_remove(ctx);
+	logger_netlink_deinit(ctx);
+
+	kfree(ctx);
+}
+
+module_init(logger_module_init);
+module_exit(logger_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS Logging Service Driver");
diff --git a/drivers/net/wireless/cnss/logger/nl_service.c b/drivers/net/wireless/cnss/logger/nl_service.c
new file mode 100644
index 0000000..4ea76ae
--- /dev/null
+++ b/drivers/net/wireless/cnss/logger/nl_service.c
@@ -0,0 +1,476 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "cnss_logger: %s: "fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <net/cnss_logger.h>
+#include "logger.h"
+
+static DEFINE_MUTEX(logger_sem);
+
+/**
+ * logger_get_radio_idx() - to get the radio index
+ * @ctx: the logger context pointer
+ *
+ * Return: the first available radio index, otherwise failure code
+ */
+static int logger_get_radio_idx(struct logger_context *ctx)
+{
+	int i;
+
+	for (i = 0; i < sizeof(ctx->radio_mask); i++) {
+		if (!test_and_set_bit(i, &ctx->radio_mask))
+			return i;
+	}
+	return -EINVAL;
+}
+
+/**
+ * logger_put_radio_idx() - to release the radio index
+ * @radio: the radio index to release
+ *
+ * Return: None
+ */
+static void logger_put_radio_idx(struct logger_context *ctx, int radio)
+{
+	clear_bit(radio, &ctx->radio_mask);
+}
+
+/**
+ * logger_get_device() - to get the logger device per radio index
+ * @radio: the radio index
+ *
+ * Return: the logger_device pointer, otherwise return NULL.
+ */
+static struct logger_device *logger_get_device(int radio)
+{
+	struct logger_device *dev;
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return NULL;
+
+	list_for_each_entry(dev, &ctx->dev_list, list) {
+		if (dev->radio_idx == radio)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * logger_device_is_registered() - to check if device has been registered
+ * @dev: pointer to logger device
+ * @wiphy: the wiphy pointer of the device to register
+ *
+ * This helper function is to check if this device has been registered.
+ *
+ * Return: NULL if it has not, otherwise return the logger_device pointer.
+ */
+static struct logger_device *logger_device_is_registered(
+						 struct logger_context *ctx,
+						 struct wiphy *wiphy)
+{
+	struct logger_device *dev;
+
+	list_for_each_entry(dev, &ctx->dev_list, list) {
+		if (dev->wiphy == wiphy)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * logger_dispatch_skb() - to dispatch the skb to devices
+ * @skb: the socket buffer received and to dispatch
+ *
+ * The function will look up the header of the skb, and dispatch the skb
+ * to the associated event and device that registered.
+ *
+ * Return: 0 if successfully dispatch, otherwise failure code
+ */
+static int logger_dispatch_skb(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct logger_context *ctx;
+	struct logger_device *cur;
+	struct logger_event_handler *evt;
+	int handled = 0;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	pr_info("skb_len: %d, skb_data_len: %d\n",
+		skb->len, skb->data_len);
+
+	if (skb->len < sizeof(struct nlmsghdr))
+		return 0;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	list_for_each_entry(cur, &ctx->dev_list, list) {
+		list_for_each_entry(evt, &cur->event_list, list) {
+			if (nlh->nlmsg_type == evt->event) {
+				if (evt->cb) {
+					handled = 1;
+					evt->cb(skb);
+				}
+				/* Break inside loop, next dev */
+				break;
+			}
+		}
+	}
+
+	if (!handled)
+		pr_info("Not handled msg type: %d\n", nlh->nlmsg_type);
+
+	return 0;
+}
+
+/**
+ * logger_flush_event_handle() - to flush the event handle associate to device
+ * @dev: pointer to logger device
+ *
+ * The function will clean up all the event handle's resource, take it out
+ * from the list, and free the memory allocated.
+ *
+ * Return: None
+ */
+static void logger_flush_event_handle(struct logger_device *dev)
+{
+	struct list_head *pos, *temp;
+	struct logger_event_handler *cur;
+
+	list_for_each_safe(pos, temp, &dev->event_list) {
+		cur = container_of(pos, struct logger_event_handler, list);
+		pr_info("radio: %d, event: %d unregistered\n",
+			dev->radio_idx, cur->event);
+		list_del(&cur->list);
+		kfree(cur);
+	}
+}
+
+/**
+ * logger_flush_devices() - to flush the devices infomration
+ * @dev: pointer to logger device
+ *
+ * The helper function to flush the device information, all the device clean
+ * up prcoess should be starting from here.
+ *
+ * Return: None
+ */
+static void logger_flush_devices(struct logger_device *dev)
+{
+	pr_info("driver: [%s] and radio-%d is unregistered\n",
+		dev->name, dev->radio_idx);
+	logger_flush_event_handle(dev);
+	logger_put_radio_idx(dev->ctx, dev->radio_idx);
+	list_del(&dev->list);
+	kfree(dev);
+}
+
+/**
+ * logger_register_device_event() - register the evet to device
+ * @dev: pointer to logger device
+ * @event: the event to register
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if register successfully, otherwise the failure code
+ */
+static int logger_register_device_event(struct logger_device *dev, int event,
+					int (*cb)(struct sk_buff *skb))
+{
+	struct logger_event_handler *cur;
+
+	list_for_each_entry(cur, &dev->event_list, list) {
+		if (cur->event == event) {
+			pr_info("event %d, is already added\n", event);
+			return 0;
+		}
+	}
+
+	cur = kmalloc(sizeof(*cur), GFP_KERNEL);
+	if (!cur)
+		return -ENOMEM;
+
+	cur->event = event;
+	cur->cb = cb;
+
+	pr_info("radio: %d, event: %d\n", dev->radio_idx, cur->event);
+	list_add_tail(&cur->list, &dev->event_list);
+
+	return 0;
+}
+
+/**
+ * logger_unregister_device_event() - unregister the evet from device
+ * @dev: pointer to logger device
+ * @event: the event to unregister
+ * @cb: the callback associated to the device and event
+ *
+ * Return: 0 if unregister successfully, otherwise the failure code
+ */
+static int logger_unregister_device_event(struct logger_device *dev, int event,
+					  int (*cb)(struct sk_buff *skb))
+{
+	struct list_head *pos, *temp;
+	struct logger_event_handler *cur;
+
+	list_for_each_safe(pos, temp, &dev->event_list) {
+		cur = container_of(pos, struct logger_event_handler, list);
+		if (cur->event == event && cur->cb == cb) {
+			pr_info("radio: %d, event: %d\n",
+				dev->radio_idx, cur->event);
+			list_del(&cur->list);
+			kfree(cur);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ * logger_skb_input() - the callback to receive the skb
+ * @skb: the receive socket buffer
+ *
+ * Return: None
+ */
+static void logger_skb_input(struct sk_buff *skb)
+{
+	mutex_lock(&logger_sem);
+	logger_dispatch_skb(skb);
+	mutex_unlock(&logger_sem);
+}
+
+/**
+ * cnss_logger_event_register() - register the event
+ * @radio: the radio index to register
+ * @event: the event to register
+ * @cb: the callback
+ *
+ * This function is used to register event associated to the radio index.
+ *
+ * Return: 0 if register success, otherwise failure code
+ */
+int cnss_logger_event_register(int radio, int event,
+			       int (*cb)(struct sk_buff *skb))
+{
+	int ret = -ENOENT;
+	struct logger_device *dev;
+
+	dev = logger_get_device(radio);
+	if (dev)
+		ret = logger_register_device_event(dev, event, cb);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_register);
+
+/**
+ * cnss_logger_event_unregister() - unregister the event
+ * @radio: the radio index to unregister
+ * @event: the event to unregister
+ * @cb: the callback
+ *
+ * This function is used to unregister the event from cnss logger module.
+ *
+ * Return: 0 if unregister success, otherwise failure code
+ */
+int cnss_logger_event_unregister(int radio, int event,
+				 int (*cb)(struct sk_buff *skb))
+{
+	int ret = -ENOENT;
+	struct logger_device *dev;
+
+	dev = logger_get_device(radio);
+	if (dev)
+		ret = logger_unregister_device_event(dev, event, cb);
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_logger_event_unregister);
+
+/**
+ * cnss_logger_device_register() - register the driver
+ * @wiphy: the wiphy device to unregister
+ * @name: the module name of the driver
+ *
+ * This function is used to register the driver to cnss logger module,
+ * this will indicate the existence of the driver, and also assign the
+ * radio index for further operation.
+ *
+ * Return: the radio index if register successful, otherwise failure code
+ */
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name)
+{
+	int radio;
+	struct logger_context *ctx;
+	struct logger_device *new;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	/* sanity check, already registered? */
+	new = logger_device_is_registered(ctx, wiphy);
+	if (new)
+		return new->radio_idx;
+
+	radio = logger_get_radio_idx(ctx);
+	if (radio < 0) {
+		pr_err("driver registration is full\n");
+		return -ENOMEM;
+	}
+
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	if (!new) {
+		logger_put_radio_idx(ctx, radio);
+		return -ENOMEM;
+	}
+
+	new->radio_idx = radio;
+	new->wiphy = wiphy;
+	new->ctx = ctx;
+	strlcpy(new->name, name, sizeof(new->name));
+	INIT_LIST_HEAD(&new->event_list);
+
+	list_add(&new->list, &ctx->dev_list);
+
+	pr_info("driver: [%s] is registered as radio-%d\n",
+		new->name, new->radio_idx);
+
+	return new->radio_idx;
+}
+EXPORT_SYMBOL(cnss_logger_device_register);
+
+/**
+ * cnss_logger_device_unregister() - unregister the driver
+ * @radio: the radio to unregister
+ * @wiphy: the wiphy device to unregister
+ *
+ * This function is used to unregister the driver from cnss logger module.
+ * This will disable the driver to access the interface in cnss logger,
+ * and also all the related events that registered will be reset.
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+	struct logger_context *ctx;
+	struct logger_device *cur;
+	struct list_head *pos, *temp;
+
+	ctx = logger_get_ctx();
+	if (!ctx)
+		return -ENOENT;
+
+	list_for_each_safe(pos, temp, &ctx->dev_list) {
+		cur = list_entry(pos, struct logger_device, list);
+		if (cur->radio_idx == radio && cur->wiphy == wiphy) {
+			logger_flush_devices(cur);
+			break;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(cnss_logger_device_unregister);
+
+/**
+ * cnss_logger_nl_ucast() - nl interface to unicast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the flag to indicate if this is a nonblock call
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag)
+{
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx) {
+		dev_kfree_skb(skb);
+		return -ENOENT;
+	}
+
+	return netlink_unicast(ctx->nl_sock, skb, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_ucast);
+
+/**
+ * cnss_logger_nl_bcast() - nl interface to broadcast the buffer
+ * @skb: the socket buffer to transmit
+ * @portid: netlink portid of the destination socket
+ * @flag: the gfp_t flag
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag)
+{
+	struct logger_context *ctx;
+
+	ctx = logger_get_ctx();
+	if (!ctx) {
+		dev_kfree_skb(skb);
+		return -ENOENT;
+	}
+
+	return netlink_broadcast(ctx->nl_sock, skb, 0, portid, flag);
+}
+EXPORT_SYMBOL(cnss_logger_nl_bcast);
+
+/**
+ * logger_netlink_init() - initialize the netlink socket
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: the netlink handle if success, otherwise failure code
+ */
+int logger_netlink_init(struct logger_context *ctx)
+{
+	struct netlink_kernel_cfg cfg = {
+		.groups	= CNSS_LOGGER_NL_MCAST_GRP_ID,
+		.input	= logger_skb_input,
+	};
+
+	ctx->nl_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
+	if (!ctx->nl_sock) {
+		pr_err("cnss_logger: Cannot create netlink socket");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&ctx->dev_list);
+
+	return 0;
+}
+
+/**
+ * logger_netlink_deinit() - release the netlink socket and other resource
+ * @ctx: the cnss logger context pointer
+ *
+ * Return: 0 if success, otherwise failure code
+ */
+int logger_netlink_deinit(struct logger_context *ctx)
+{
+	struct list_head *pos, *temp;
+	struct logger_device *dev;
+
+	netlink_kernel_release(ctx->nl_sock);
+	list_for_each_safe(pos, temp, &ctx->dev_list) {
+		dev = container_of(pos, struct logger_device, list);
+		logger_flush_devices(dev);
+	}
+	return 0;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index d04babd..ff5ce1e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -1040,6 +1040,8 @@
 		return le32_to_cpu(txq_timer->p2p_go);
 	case NL80211_IFTYPE_P2P_DEVICE:
 		return le32_to_cpu(txq_timer->p2p_device);
+	case NL80211_IFTYPE_MONITOR:
+		return default_timeout;
 	default:
 		WARN_ON(1);
 		return mvm->cfg->base_params->wd_timeout;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 8d498a9..1a9dadf 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -86,6 +86,8 @@
 /* IRQ name is queue name with "-tx" or "-rx" appended */
 #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3)
 
+static DECLARE_WAIT_QUEUE_HEAD(module_unload_q);
+
 struct netfront_stats {
 	u64			packets;
 	u64			bytes;
@@ -2051,10 +2053,12 @@
 		break;
 
 	case XenbusStateClosed:
+		wake_up_all(&module_unload_q);
 		if (dev->state == XenbusStateClosed)
 			break;
 		/* Missed the backend's CLOSING state -- fallthrough */
 	case XenbusStateClosing:
+		wake_up_all(&module_unload_q);
 		xenbus_frontend_closed(dev);
 		break;
 	}
@@ -2160,6 +2164,20 @@
 
 	dev_dbg(&dev->dev, "%s\n", dev->nodename);
 
+	if (xenbus_read_driver_state(dev->otherend) != XenbusStateClosed) {
+		xenbus_switch_state(dev, XenbusStateClosing);
+		wait_event(module_unload_q,
+			   xenbus_read_driver_state(dev->otherend) ==
+			   XenbusStateClosing);
+
+		xenbus_switch_state(dev, XenbusStateClosed);
+		wait_event(module_unload_q,
+			   xenbus_read_driver_state(dev->otherend) ==
+			   XenbusStateClosed ||
+			   xenbus_read_driver_state(dev->otherend) ==
+			   XenbusStateUnknown);
+	}
+
 	xennet_disconnect_backend(info);
 
 	unregister_netdev(info->netdev);
diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c
index ea4bedf..0280d42 100644
--- a/drivers/nfc/nq-nci.c
+++ b/drivers/nfc/nq-nci.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -36,6 +36,8 @@
 	unsigned int firm_gpio;
 	unsigned int ese_gpio;
 	const char *clk_src_name;
+	/* NFC_CLK pin voting state */
+	bool clk_pin_voting;
 };
 
 static const struct of_device_id msm_match_table[] = {
@@ -469,39 +471,47 @@
 		dev_dbg(&nqx_dev->client->dev,
 			"gpio_set_value disable: %s: info: %p\n",
 			__func__, nqx_dev);
-		if (gpio_is_valid(nqx_dev->firm_gpio))
+		if (gpio_is_valid(nqx_dev->firm_gpio)) {
 			gpio_set_value(nqx_dev->firm_gpio, 0);
+			usleep_range(10000, 10100);
+		}
 
 		if (gpio_is_valid(nqx_dev->ese_gpio)) {
 			if (!gpio_get_value(nqx_dev->ese_gpio)) {
 				dev_dbg(&nqx_dev->client->dev, "disabling en_gpio\n");
 				gpio_set_value(nqx_dev->en_gpio, 0);
+				usleep_range(10000, 10100);
 			} else {
 				dev_dbg(&nqx_dev->client->dev, "keeping en_gpio high\n");
 			}
 		} else {
 			dev_dbg(&nqx_dev->client->dev, "ese_gpio invalid, set en_gpio to low\n");
 			gpio_set_value(nqx_dev->en_gpio, 0);
+			usleep_range(10000, 10100);
 		}
-		r = nqx_clock_deselect(nqx_dev);
-		if (r < 0)
-			dev_err(&nqx_dev->client->dev, "unable to disable clock\n");
+		if (nqx_dev->pdata->clk_pin_voting) {
+			r = nqx_clock_deselect(nqx_dev);
+			if (r < 0)
+				dev_err(&nqx_dev->client->dev, "unable to disable clock\n");
+		}
 		nqx_dev->nfc_ven_enabled = false;
-		/* hardware dependent delay */
-		msleep(100);
 	} else if (arg == 1) {
 		nqx_enable_irq(nqx_dev);
 		dev_dbg(&nqx_dev->client->dev,
 			"gpio_set_value enable: %s: info: %p\n",
 			__func__, nqx_dev);
-		if (gpio_is_valid(nqx_dev->firm_gpio))
+		if (gpio_is_valid(nqx_dev->firm_gpio)) {
 			gpio_set_value(nqx_dev->firm_gpio, 0);
+			usleep_range(10000, 10100);
+		}
 		gpio_set_value(nqx_dev->en_gpio, 1);
-		r = nqx_clock_select(nqx_dev);
-		if (r < 0)
-			dev_err(&nqx_dev->client->dev, "unable to enable clock\n");
+		usleep_range(10000, 10100);
+		if (nqx_dev->pdata->clk_pin_voting) {
+			r = nqx_clock_select(nqx_dev);
+			if (r < 0)
+				dev_err(&nqx_dev->client->dev, "unable to enable clock\n");
+		}
 		nqx_dev->nfc_ven_enabled = true;
-		msleep(20);
 	} else if (arg == 2) {
 		/*
 		 * We are switching to Dowload Mode, toggle the enable pin
@@ -515,14 +525,15 @@
 			}
 		}
 		gpio_set_value(nqx_dev->en_gpio, 1);
-		msleep(20);
-		if (gpio_is_valid(nqx_dev->firm_gpio))
+		usleep_range(10000, 10100);
+		if (gpio_is_valid(nqx_dev->firm_gpio)) {
 			gpio_set_value(nqx_dev->firm_gpio, 1);
-		msleep(20);
+			usleep_range(10000, 10100);
+		}
 		gpio_set_value(nqx_dev->en_gpio, 0);
-		msleep(100);
+		usleep_range(10000, 10100);
 		gpio_set_value(nqx_dev->en_gpio, 1);
-		msleep(20);
+		usleep_range(10000, 10100);
 	} else {
 		r = -ENOIOCTLCMD;
 	}
@@ -648,13 +659,14 @@
 	unsigned char nci_reset_rsp[6];
 	unsigned char init_rsp_len = 0;
 	unsigned int enable_gpio = nqx_dev->en_gpio;
+
 	/* making sure that the NFCC starts in a clean state. */
 	gpio_set_value(enable_gpio, 0);/* ULPM: Disable */
 	/* hardware dependent delay */
-	msleep(20);
+	usleep_range(10000, 10100);
 	gpio_set_value(enable_gpio, 1);/* HPD : Enable*/
 	/* hardware dependent delay */
-	msleep(20);
+	usleep_range(10000, 10100);
 
 	/* send NCI CORE RESET CMD with Keep Config parameters */
 	ret = i2c_master_send(client, raw_nci_reset_cmd,
@@ -670,21 +682,17 @@
 	/* Read Response of RESET command */
 	ret = i2c_master_recv(client, nci_reset_rsp,
 		sizeof(nci_reset_rsp));
-	dev_err(&client->dev,
-	"%s: - nq - reset cmd answer : NfcNciRx %x %x %x\n",
-	__func__, nci_reset_rsp[0],
-	nci_reset_rsp[1], nci_reset_rsp[2]);
 	if (ret < 0) {
 		dev_err(&client->dev,
 		"%s: - i2c_master_recv Error\n", __func__);
 		goto err_nfcc_hw_check;
 	}
-	ret = i2c_master_send(client, raw_nci_init_cmd,
-		sizeof(raw_nci_init_cmd));
+	ret = nqx_standby_write(nqx_dev, raw_nci_init_cmd,
+				sizeof(raw_nci_init_cmd));
 	if (ret < 0) {
 		dev_err(&client->dev,
 		"%s: - i2c_master_send Error\n", __func__);
-		goto err_nfcc_hw_check;
+		goto err_nfcc_core_init_fail;
 	}
 	/* hardware dependent delay */
 	msleep(30);
@@ -694,7 +702,7 @@
 	if (ret < 0) {
 		dev_err(&client->dev,
 		"%s: - i2c_master_recv Error\n", __func__);
-		goto err_nfcc_hw_check;
+		goto err_nfcc_core_init_fail;
 	}
 	init_rsp_len = 2 + nci_init_rsp[2]; /*payload + len*/
 	if (init_rsp_len > PAYLOAD_HEADER_LENGTH) {
@@ -707,6 +715,11 @@
 		nqx_dev->nqx_info.info.fw_minor =
 				nci_init_rsp[init_rsp_len];
 	}
+	dev_dbg(&client->dev,
+		"%s: - nq - reset cmd answer : NfcNciRx %x %x %x\n",
+		__func__, nci_reset_rsp[0],
+		nci_reset_rsp[1], nci_reset_rsp[2]);
+
 	dev_dbg(&nqx_dev->client->dev, "NQ NFCC chip_type = %x\n",
 		nqx_dev->nqx_info.info.chip_type);
 	dev_dbg(&nqx_dev->client->dev, "NQ fw version = %x.%x.%x\n",
@@ -746,6 +759,12 @@
 	ret = 0;
 	goto done;
 
+err_nfcc_core_init_fail:
+	dev_err(&client->dev,
+	"%s: - nq - reset cmd answer : NfcNciRx %x %x %x\n",
+	__func__, nci_reset_rsp[0],
+	nci_reset_rsp[1], nci_reset_rsp[2]);
+
 err_nfcc_hw_check:
 	ret = -ENXIO;
 	dev_err(&client->dev,
@@ -828,12 +847,13 @@
 		pdata->ese_gpio = -EINVAL;
 	}
 
-	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name);
+	if (of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name))
+		pdata->clk_pin_voting = false;
+	else
+		pdata->clk_pin_voting = true;
 
 	pdata->clkreq_gpio = of_get_named_gpio(np, "qcom,nq-clkreq", 0);
 
-	if (r)
-		return -EINVAL;
 	return r;
 }
 
@@ -1213,6 +1233,7 @@
 		.owner = THIS_MODULE,
 		.name = "nq-nci",
 		.of_match_table = msm_match_table,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.pm = &nfc_pm_ops,
 	},
 };
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 94733f7..7121453 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -183,13 +183,13 @@
 	return ret;
 }
 
-static int btt_log_read_pair(struct arena_info *arena, u32 lane,
-			struct log_entry *ent)
+static int btt_log_group_read(struct arena_info *arena, u32 lane,
+			struct log_group *log)
 {
-	WARN_ON(!ent);
+	WARN_ON(!log);
 	return arena_read_bytes(arena,
-			arena->logoff + (2 * lane * LOG_ENT_SIZE), ent,
-			2 * LOG_ENT_SIZE);
+			arena->logoff + (lane * LOG_GRP_SIZE), log,
+			LOG_GRP_SIZE);
 }
 
 static struct dentry *debugfs_root;
@@ -229,6 +229,8 @@
 	debugfs_create_x64("logoff", S_IRUGO, d, &a->logoff);
 	debugfs_create_x64("info2off", S_IRUGO, d, &a->info2off);
 	debugfs_create_x32("flags", S_IRUGO, d, &a->flags);
+	debugfs_create_u32("log_index_0", S_IRUGO, d, &a->log_index[0]);
+	debugfs_create_u32("log_index_1", S_IRUGO, d, &a->log_index[1]);
 }
 
 static void btt_debugfs_init(struct btt *btt)
@@ -247,6 +249,11 @@
 	}
 }
 
+static u32 log_seq(struct log_group *log, int log_idx)
+{
+	return le32_to_cpu(log->ent[log_idx].seq);
+}
+
 /*
  * This function accepts two log entries, and uses the
  * sequence number to find the 'older' entry.
@@ -256,8 +263,10 @@
  *
  * TODO The logic feels a bit kludge-y. make it better..
  */
-static int btt_log_get_old(struct log_entry *ent)
+static int btt_log_get_old(struct arena_info *a, struct log_group *log)
 {
+	int idx0 = a->log_index[0];
+	int idx1 = a->log_index[1];
 	int old;
 
 	/*
@@ -265,23 +274,23 @@
 	 * the next time, the following logic works out to put this
 	 * (next) entry into [1]
 	 */
-	if (ent[0].seq == 0) {
-		ent[0].seq = cpu_to_le32(1);
+	if (log_seq(log, idx0) == 0) {
+		log->ent[idx0].seq = cpu_to_le32(1);
 		return 0;
 	}
 
-	if (ent[0].seq == ent[1].seq)
+	if (log_seq(log, idx0) == log_seq(log, idx1))
 		return -EINVAL;
-	if (le32_to_cpu(ent[0].seq) + le32_to_cpu(ent[1].seq) > 5)
+	if (log_seq(log, idx0) + log_seq(log, idx1) > 5)
 		return -EINVAL;
 
-	if (le32_to_cpu(ent[0].seq) < le32_to_cpu(ent[1].seq)) {
-		if (le32_to_cpu(ent[1].seq) - le32_to_cpu(ent[0].seq) == 1)
+	if (log_seq(log, idx0) < log_seq(log, idx1)) {
+		if ((log_seq(log, idx1) - log_seq(log, idx0)) == 1)
 			old = 0;
 		else
 			old = 1;
 	} else {
-		if (le32_to_cpu(ent[0].seq) - le32_to_cpu(ent[1].seq) == 1)
+		if ((log_seq(log, idx0) - log_seq(log, idx1)) == 1)
 			old = 1;
 		else
 			old = 0;
@@ -306,17 +315,18 @@
 {
 	int ret;
 	int old_ent, ret_ent;
-	struct log_entry log[2];
+	struct log_group log;
 
-	ret = btt_log_read_pair(arena, lane, log);
+	ret = btt_log_group_read(arena, lane, &log);
 	if (ret)
 		return -EIO;
 
-	old_ent = btt_log_get_old(log);
+	old_ent = btt_log_get_old(arena, &log);
 	if (old_ent < 0 || old_ent > 1) {
 		dev_info(to_dev(arena),
 				"log corruption (%d): lane %d seq [%d, %d]\n",
-			old_ent, lane, log[0].seq, log[1].seq);
+				old_ent, lane, log.ent[arena->log_index[0]].seq,
+				log.ent[arena->log_index[1]].seq);
 		/* TODO set error state? */
 		return -EIO;
 	}
@@ -324,7 +334,7 @@
 	ret_ent = (old_flag ? old_ent : (1 - old_ent));
 
 	if (ent != NULL)
-		memcpy(ent, &log[ret_ent], LOG_ENT_SIZE);
+		memcpy(ent, &log.ent[arena->log_index[ret_ent]], LOG_ENT_SIZE);
 
 	return ret_ent;
 }
@@ -338,17 +348,13 @@
 			u32 sub, struct log_entry *ent)
 {
 	int ret;
-	/*
-	 * Ignore the padding in log_entry for calculating log_half.
-	 * The entry is 'committed' when we write the sequence number,
-	 * and we want to ensure that that is the last thing written.
-	 * We don't bother writing the padding as that would be extra
-	 * media wear and write amplification
-	 */
-	unsigned int log_half = (LOG_ENT_SIZE - 2 * sizeof(u64)) / 2;
-	u64 ns_off = arena->logoff + (((2 * lane) + sub) * LOG_ENT_SIZE);
+	u32 group_slot = arena->log_index[sub];
+	unsigned int log_half = LOG_ENT_SIZE / 2;
 	void *src = ent;
+	u64 ns_off;
 
+	ns_off = arena->logoff + (lane * LOG_GRP_SIZE) +
+		(group_slot * LOG_ENT_SIZE);
 	/* split the 16B write into atomic, durable halves */
 	ret = arena_write_bytes(arena, ns_off, src, log_half);
 	if (ret)
@@ -419,16 +425,16 @@
 {
 	int ret;
 	u32 i;
-	struct log_entry log, zerolog;
+	struct log_entry ent, zerolog;
 
 	memset(&zerolog, 0, sizeof(zerolog));
 
 	for (i = 0; i < arena->nfree; i++) {
-		log.lba = cpu_to_le32(i);
-		log.old_map = cpu_to_le32(arena->external_nlba + i);
-		log.new_map = cpu_to_le32(arena->external_nlba + i);
-		log.seq = cpu_to_le32(LOG_SEQ_INIT);
-		ret = __btt_log_write(arena, i, 0, &log);
+		ent.lba = cpu_to_le32(i);
+		ent.old_map = cpu_to_le32(arena->external_nlba + i);
+		ent.new_map = cpu_to_le32(arena->external_nlba + i);
+		ent.seq = cpu_to_le32(LOG_SEQ_INIT);
+		ret = __btt_log_write(arena, i, 0, &ent);
 		if (ret)
 			return ret;
 		ret = __btt_log_write(arena, i, 1, &zerolog);
@@ -490,6 +496,123 @@
 	return 0;
 }
 
+static bool ent_is_padding(struct log_entry *ent)
+{
+	return (ent->lba == 0) && (ent->old_map == 0) && (ent->new_map == 0)
+		&& (ent->seq == 0);
+}
+
+/*
+ * Detecting valid log indices: We read a log group (see the comments in btt.h
+ * for a description of a 'log_group' and its 'slots'), and iterate over its
+ * four slots. We expect that a padding slot will be all-zeroes, and use this
+ * to detect a padding slot vs. an actual entry.
+ *
+ * If a log_group is in the initial state, i.e. hasn't been used since the
+ * creation of this BTT layout, it will have three of the four slots with
+ * zeroes. We skip over these log_groups for the detection of log_index. If
+ * all log_groups are in the initial state (i.e. the BTT has never been
+ * written to), it is safe to assume the 'new format' of log entries in slots
+ * (0, 1).
+ */
+static int log_set_indices(struct arena_info *arena)
+{
+	bool idx_set = false, initial_state = true;
+	int ret, log_index[2] = {-1, -1};
+	u32 i, j, next_idx = 0;
+	struct log_group log;
+	u32 pad_count = 0;
+
+	for (i = 0; i < arena->nfree; i++) {
+		ret = btt_log_group_read(arena, i, &log);
+		if (ret < 0)
+			return ret;
+
+		for (j = 0; j < 4; j++) {
+			if (!idx_set) {
+				if (ent_is_padding(&log.ent[j])) {
+					pad_count++;
+					continue;
+				} else {
+					/* Skip if index has been recorded */
+					if ((next_idx == 1) &&
+						(j == log_index[0]))
+						continue;
+					/* valid entry, record index */
+					log_index[next_idx] = j;
+					next_idx++;
+				}
+				if (next_idx == 2) {
+					/* two valid entries found */
+					idx_set = true;
+				} else if (next_idx > 2) {
+					/* too many valid indices */
+					return -ENXIO;
+				}
+			} else {
+				/*
+				 * once the indices have been set, just verify
+				 * that all subsequent log groups are either in
+				 * their initial state or follow the same
+				 * indices.
+				 */
+				if (j == log_index[0]) {
+					/* entry must be 'valid' */
+					if (ent_is_padding(&log.ent[j]))
+						return -ENXIO;
+				} else if (j == log_index[1]) {
+					;
+					/*
+					 * log_index[1] can be padding if the
+					 * lane never got used and it is still
+					 * in the initial state (three 'padding'
+					 * entries)
+					 */
+				} else {
+					/* entry must be invalid (padding) */
+					if (!ent_is_padding(&log.ent[j]))
+						return -ENXIO;
+				}
+			}
+		}
+		/*
+		 * If any of the log_groups have more than one valid,
+		 * non-padding entry, then the we are no longer in the
+		 * initial_state
+		 */
+		if (pad_count < 3)
+			initial_state = false;
+		pad_count = 0;
+	}
+
+	if (!initial_state && !idx_set)
+		return -ENXIO;
+
+	/*
+	 * If all the entries in the log were in the initial state,
+	 * assume new padding scheme
+	 */
+	if (initial_state)
+		log_index[1] = 1;
+
+	/*
+	 * Only allow the known permutations of log/padding indices,
+	 * i.e. (0, 1), and (0, 2)
+	 */
+	if ((log_index[0] == 0) && ((log_index[1] == 1) || (log_index[1] == 2)))
+		; /* known index possibilities */
+	else {
+		dev_err(to_dev(arena), "Found an unknown padding scheme\n");
+		return -ENXIO;
+	}
+
+	arena->log_index[0] = log_index[0];
+	arena->log_index[1] = log_index[1];
+	dev_dbg(to_dev(arena), "log_index_0 = %d\n", log_index[0]);
+	dev_dbg(to_dev(arena), "log_index_1 = %d\n", log_index[1]);
+	return 0;
+}
+
 static int btt_rtt_init(struct arena_info *arena)
 {
 	arena->rtt = kcalloc(arena->nfree, sizeof(u32), GFP_KERNEL);
@@ -545,8 +668,7 @@
 	available -= 2 * BTT_PG_SIZE;
 
 	/* The log takes a fixed amount of space based on nfree */
-	logsize = roundup(2 * arena->nfree * sizeof(struct log_entry),
-				BTT_PG_SIZE);
+	logsize = roundup(arena->nfree * LOG_GRP_SIZE, BTT_PG_SIZE);
 	available -= logsize;
 
 	/* Calculate optimal split between map and data area */
@@ -563,6 +685,10 @@
 	arena->mapoff = arena->dataoff + datasize;
 	arena->logoff = arena->mapoff + mapsize;
 	arena->info2off = arena->logoff + logsize;
+
+	/* Default log indices are (0,1) */
+	arena->log_index[0] = 0;
+	arena->log_index[1] = 1;
 	return arena;
 }
 
@@ -653,6 +779,13 @@
 		arena->external_lba_start = cur_nlba;
 		parse_arena_meta(arena, super, cur_off);
 
+		ret = log_set_indices(arena);
+		if (ret) {
+			dev_err(to_dev(arena),
+				"Unable to deduce log/padding indices\n");
+			goto out;
+		}
+
 		ret = btt_freelist_init(arena);
 		if (ret)
 			goto out;
diff --git a/drivers/nvdimm/btt.h b/drivers/nvdimm/btt.h
index b2f8651..0f80b6b 100644
--- a/drivers/nvdimm/btt.h
+++ b/drivers/nvdimm/btt.h
@@ -26,6 +26,7 @@
 #define MAP_ERR_MASK (1 << MAP_ERR_SHIFT)
 #define MAP_LBA_MASK (~((1 << MAP_TRIM_SHIFT) | (1 << MAP_ERR_SHIFT)))
 #define MAP_ENT_NORMAL 0xC0000000
+#define LOG_GRP_SIZE sizeof(struct log_group)
 #define LOG_ENT_SIZE sizeof(struct log_entry)
 #define ARENA_MIN_SIZE (1UL << 24)	/* 16 MB */
 #define ARENA_MAX_SIZE (1ULL << 39)	/* 512 GB */
@@ -44,12 +45,52 @@
 	INIT_READY
 };
 
+/*
+ * A log group represents one log 'lane', and consists of four log entries.
+ * Two of the four entries are valid entries, and the remaining two are
+ * padding. Due to an old bug in the padding location, we need to perform a
+ * test to determine the padding scheme being used, and use that scheme
+ * thereafter.
+ *
+ * In kernels prior to 4.15, 'log group' would have actual log entries at
+ * indices (0, 2) and padding at indices (1, 3), where as the correct/updated
+ * format has log entries at indices (0, 1) and padding at indices (2, 3).
+ *
+ * Old (pre 4.15) format:
+ * +-----------------+-----------------+
+ * |      ent[0]     |      ent[1]     |
+ * |       16B       |       16B       |
+ * | lba/old/new/seq |       pad       |
+ * +-----------------------------------+
+ * |      ent[2]     |      ent[3]     |
+ * |       16B       |       16B       |
+ * | lba/old/new/seq |       pad       |
+ * +-----------------+-----------------+
+ *
+ * New format:
+ * +-----------------+-----------------+
+ * |      ent[0]     |      ent[1]     |
+ * |       16B       |       16B       |
+ * | lba/old/new/seq | lba/old/new/seq |
+ * +-----------------------------------+
+ * |      ent[2]     |      ent[3]     |
+ * |       16B       |       16B       |
+ * |       pad       |       pad       |
+ * +-----------------+-----------------+
+ *
+ * We detect during start-up which format is in use, and set
+ * arena->log_index[(0, 1)] with the detected format.
+ */
+
 struct log_entry {
 	__le32 lba;
 	__le32 old_map;
 	__le32 new_map;
 	__le32 seq;
-	__le64 padding[2];
+};
+
+struct log_group {
+	struct log_entry ent[4];
 };
 
 struct btt_sb {
@@ -117,6 +158,7 @@
  * @list:		List head for list of arenas
  * @debugfs_dir:	Debugfs dentry
  * @flags:		Arena flags - may signify error states.
+ * @log_index:		Indices of the valid log entries in a log_group
  *
  * arena_info is a per-arena handle. Once an arena is narrowed down for an
  * IO, this struct is passed around for the duration of the IO.
@@ -147,6 +189,7 @@
 	struct dentry *debugfs_dir;
 	/* Arena flags */
 	u32 flags;
+	int log_index[2];
 };
 
 /**
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index a268f4d..48a365e 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -395,6 +395,10 @@
 	if (ret)
 		return ERR_PTR(-ENODEV);
 
+	/* This phy type handled by the usb-phy subsystem for now */
+	if (of_device_is_compatible(args.np, "usb-nop-xceiv"))
+		return ERR_PTR(-ENODEV);
+
 	mutex_lock(&phy_provider_mutex);
 	phy_provider = of_phy_provider_lookup(args.np);
 	if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) {
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index d39a17f..6515ce4 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -89,6 +89,16 @@
 	  Technologies Inc MSM8953 platform.
 	  If unsure say N.
 
+config PINCTRL_MSM8937
+	tristate "Qualcomm Technologies Inc MSM8937 pin controller driver"
+	depends on GPIOLIB && OF
+	select PINCTRL_MSM
+	help
+	  This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+	  Qualcomm Technologies Inc TLMM block found on the Qualcomm
+	  Technologies Inc MSM8937 platform.
+	  If unsure say N.
+
 config PINCTRL_SDM845
 	tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
 	depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index d92db11..db71677 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -12,6 +12,7 @@
 obj-$(CONFIG_PINCTRL_QDF2XXX)	+= pinctrl-qdf2xxx.o
 obj-$(CONFIG_PINCTRL_MDM9615)	+= pinctrl-mdm9615.o
 obj-$(CONFIG_PINCTRL_MSM8953)   += pinctrl-msm8953.o
+obj-$(CONFIG_PINCTRL_MSM8937)   += pinctrl-msm8937.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
 obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
 obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index bf95849..1441678 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013, Sony Mobile Communications AB.
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -70,6 +70,7 @@
 
 	const struct msm_pinctrl_soc_data *soc;
 	void __iomem *regs;
+	void __iomem *pdc_regs;
 };
 
 static int msm_get_groups_count(struct pinctrl_dev *pctldev)
@@ -777,6 +778,102 @@
 	.irq_set_wake   = msm_gpio_irq_set_wake,
 };
 
+static struct irq_chip msm_dirconn_irq_chip;
+
+static void msm_gpio_dirconn_handler(struct irq_desc *desc)
+{
+	struct irq_data *irqd = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	chained_irq_enter(chip, desc);
+	generic_handle_irq(irqd->irq);
+	chained_irq_exit(chip, desc);
+}
+
+static void setup_pdc_gpio(struct irq_domain *domain,
+			unsigned int parent_irq, unsigned int gpio)
+{
+	int irq;
+
+	if (gpio != 0) {
+		irq = irq_find_mapping(domain, gpio);
+		irq_set_parent(irq, parent_irq);
+		irq_set_chip(irq, &msm_dirconn_irq_chip);
+		irq_set_handler_data(parent_irq, irq_get_irq_data(irq));
+	}
+
+	__irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL);
+}
+
+static void request_dc_interrupt(struct irq_domain *domain,
+			struct irq_domain *parent, irq_hw_number_t hwirq,
+			unsigned int gpio)
+{
+	struct irq_fwspec fwspec;
+	unsigned int parent_irq;
+
+	fwspec.fwnode = parent->fwnode;
+	fwspec.param[0] = 0; /* SPI */
+	fwspec.param[1] = hwirq;
+	fwspec.param[2] = IRQ_TYPE_NONE;
+	fwspec.param_count = 3;
+
+	parent_irq = irq_create_fwspec_mapping(&fwspec);
+
+	setup_pdc_gpio(domain, parent_irq, gpio);
+}
+
+/**
+ * gpio_muxed_to_pdc: Mux the GPIO to a PDC IRQ
+ *
+ * @pdc_domain: the PDC's domain
+ * @d: the GPIO's IRQ data
+ *
+ * Find a free PDC port for the GPIO and map the GPIO's mux information to the
+ * PDC registers; so the GPIO can be used a wakeup source.
+ */
+static void gpio_muxed_to_pdc(struct irq_domain *pdc_domain, struct irq_data *d)
+{
+	int i, j;
+	unsigned int mux;
+	struct irq_desc *desc = irq_data_to_desc(d);
+	struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	unsigned int gpio = d->hwirq;
+	struct msm_pinctrl *pctrl;
+	unsigned int irq;
+
+	if (!gc || !parent_data)
+		return;
+
+	pctrl = gpiochip_get_data(gc);
+
+	for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) {
+		if (gpio != pctrl->soc->gpio_mux_in[i].gpio)
+			continue;
+		mux = pctrl->soc->gpio_mux_in[i].mux;
+		for (j = 0; j < pctrl->soc->n_pdc_mux_out; j++) {
+			struct msm_pdc_mux_output *pdc_out =
+						&pctrl->soc->pdc_mux_out[j];
+
+			if (pdc_out->mux == mux)
+				break;
+			if (pdc_out->mux)
+				continue;
+			pdc_out->mux = gpio;
+			irq = irq_find_mapping(pdc_domain, pdc_out->hwirq + 32);
+			/* setup the IRQ parent for the GPIO */
+			setup_pdc_gpio(pctrl->chip.irqdomain, irq, gpio);
+			/* program pdc select grp register */
+			writel_relaxed((mux & 0x3F), pctrl->pdc_regs +
+				(0x14 * j));
+			break;
+		}
+		/* We have no more PDC port available */
+		WARN_ON(j == pctrl->soc->n_pdc_mux_out);
+	}
+}
+
 static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq)
 {
 	struct irq_desc *desc = irq_data_to_desc(d);
@@ -797,6 +894,17 @@
 			return true;
 		}
 	}
+
+	for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
+		struct msm_pdc_mux_output *dir_conn =
+					&pctrl->soc->pdc_mux_out[i];
+
+		if (dir_conn->mux == d->hwirq && (dir_conn->hwirq + 32)
+				!= parent_data->hwirq) {
+			*dir_conn_irq = dir_conn->hwirq + 32;
+			return true;
+		}
+	}
 	return false;
 }
 
@@ -814,13 +922,48 @@
 			irq_get_irq_data(irq_find_mapping(parent_data->domain,
 						dir_conn_irq));
 
-		if (dir_conn_data && dir_conn_data->chip->irq_mask)
+		if (!dir_conn_data)
+			return;
+		if (dir_conn_data->chip->irq_mask)
 			dir_conn_data->chip->irq_mask(dir_conn_data);
 	}
+
 	if (parent_data->chip->irq_mask)
 		parent_data->chip->irq_mask(parent_data);
 }
 
+static void msm_dirconn_irq_enable(struct irq_data *d)
+{
+	struct irq_desc *desc = irq_data_to_desc(d);
+	struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
+	irq_hw_number_t dir_conn_irq = 0;
+
+	if (!parent_data)
+		return;
+
+	if (is_gpio_dual_edge(d, &dir_conn_irq)) {
+		struct irq_data *dir_conn_data =
+			irq_get_irq_data(irq_find_mapping(parent_data->domain,
+						dir_conn_irq));
+
+		if (dir_conn_data &&
+				dir_conn_data->chip->irq_set_irqchip_state)
+			dir_conn_data->chip->irq_set_irqchip_state(
+					dir_conn_data,
+					IRQCHIP_STATE_PENDING, 0);
+
+		if (dir_conn_data && dir_conn_data->chip->irq_unmask)
+			dir_conn_data->chip->irq_unmask(dir_conn_data);
+	}
+
+	if (parent_data->chip->irq_set_irqchip_state)
+		parent_data->chip->irq_set_irqchip_state(parent_data,
+						IRQCHIP_STATE_PENDING, 0);
+
+	if (parent_data->chip->irq_unmask)
+		parent_data->chip->irq_unmask(parent_data);
+}
+
 static void msm_dirconn_irq_unmask(struct irq_data *d)
 {
 	struct irq_desc *desc = irq_data_to_desc(d);
@@ -835,7 +978,9 @@
 			irq_get_irq_data(irq_find_mapping(parent_data->domain,
 						dir_conn_irq));
 
-		if (dir_conn_data && dir_conn_data->chip->irq_unmask)
+		if (!dir_conn_data)
+			return;
+		if (dir_conn_data->chip->irq_unmask)
 			dir_conn_data->chip->irq_unmask(dir_conn_data);
 	}
 	if (parent_data->chip->irq_unmask)
@@ -1058,6 +1203,7 @@
 static struct irq_chip msm_dirconn_irq_chip = {
 	.name			= "msmgpio-dc",
 	.irq_mask		= msm_dirconn_irq_mask,
+	.irq_enable		= msm_dirconn_irq_enable,
 	.irq_unmask		= msm_dirconn_irq_unmask,
 	.irq_eoi		= msm_dirconn_irq_eoi,
 	.irq_ack		= msm_dirconn_irq_ack,
@@ -1103,57 +1249,53 @@
 	chained_irq_exit(chip, desc);
 }
 
-static void msm_gpio_dirconn_handler(struct irq_desc *desc)
-{
-	struct irq_data *irqd = irq_desc_get_handler_data(desc);
-	struct irq_chip *chip = irq_desc_get_chip(desc);
-
-	chained_irq_enter(chip, desc);
-	generic_handle_irq(irqd->irq);
-	chained_irq_exit(chip, desc);
-}
-
 static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl)
 {
 	struct device_node *parent_node;
-	struct irq_domain *parent_domain;
-	struct irq_fwspec fwspec;
+	struct irq_domain *pdc_domain;
 	unsigned int i;
 
 	parent_node = of_irq_find_parent(pctrl->dev->of_node);
-
 	if (!parent_node)
 		return;
 
-	parent_domain = irq_find_host(parent_node);
-	if (!parent_domain)
+	pdc_domain = irq_find_host(parent_node);
+	if (!pdc_domain)
 		return;
 
-	fwspec.fwnode = parent_domain->fwnode;
 	for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
 		const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i];
-		unsigned int parent_irq;
-		int irq;
 
-		fwspec.param[0] = 0; /* SPI */
-		fwspec.param[1] = dirconn->hwirq;
-		fwspec.param[2] = IRQ_TYPE_NONE;
-		fwspec.param_count = 3;
-		parent_irq = irq_create_fwspec_mapping(&fwspec);
+		request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain,
+					dirconn->hwirq, dirconn->gpio);
+	}
 
-		if (dirconn->gpio != 0) {
-			irq = irq_find_mapping(pctrl->chip.irqdomain,
-					dirconn->gpio);
+	for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
+		struct msm_pdc_mux_output *pdc_out =
+					&pctrl->soc->pdc_mux_out[i];
 
-			irq_set_parent(irq, parent_irq);
-			irq_set_chip(irq, &msm_dirconn_irq_chip);
-			__irq_set_handler(parent_irq, msm_gpio_dirconn_handler,
-				false, NULL);
-			irq_set_handler_data(parent_irq, irq_get_irq_data(irq));
-		} else {
-			__irq_set_handler(parent_irq, msm_gpio_dirconn_handler,
-				false, NULL);
-		}
+		request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain,
+					pdc_out->hwirq, 0);
+	}
+
+	/*
+	 * Statically choose the GPIOs for mapping to PDC. Dynamic mux mapping
+	 * is very difficult.
+	 */
+	for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
+		unsigned int irq;
+		struct irq_data *d;
+		struct msm_gpio_mux_input *gpio_in =
+					&pctrl->soc->gpio_mux_in[i];
+		if (!gpio_in->init)
+			continue;
+
+		irq = irq_find_mapping(pctrl->chip.irqdomain, gpio_in->gpio);
+		d = irq_get_irq_data(irq);
+		if (!d)
+			continue;
+
+		gpio_muxed_to_pdc(pdc_domain, d);
 	}
 }
 
@@ -1263,6 +1405,9 @@
 	if (IS_ERR(pctrl->regs))
 		return PTR_ERR(pctrl->regs);
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	pctrl->pdc_regs = devm_ioremap_resource(&pdev->dev, res);
+
 	msm_pinctrl_setup_pm_reset(pctrl);
 
 	pctrl->irq = platform_get_irq(pdev, 0);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 1c6df2f..9fc6660 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2013, Sony Mobile Communications AB.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -99,13 +100,35 @@
 	unsigned intr_detection_bit:5;
 	unsigned intr_detection_width:5;
 	unsigned dir_conn_en_bit:8;
-}
+};
+
+/**
+ * struct msm_gpio_mux_input - Map GPIO to Mux pin
+ * @mux::	The mux pin to which the GPIO is connected to
+ * @gpio:	GPIO pin number
+ * @init:	Setup PDC connection at probe
+ */
+struct msm_gpio_mux_input {
+	unsigned int mux;
+	unsigned int gpio;
+	bool init;
+};
+
+/**
+ * struct msm_pdc_mux_output - GPIO mux pin to PDC port
+ * @mux:	GPIO mux pin number
+ * @hwirq:	The PDC port (hwirq) that GPIO is connected to
+ */
+struct msm_pdc_mux_output {
+	unsigned int mux;
+	irq_hw_number_t hwirq;
+};
 
 /**
  * struct msm_dir_conn - Direct GPIO connect configuration
  * @gpio:	GPIO pin number
  * @hwirq:	The GIC interrupt that the pin is connected to
- */;
+ */
 struct msm_dir_conn {
 	unsigned int gpio;
 	irq_hw_number_t hwirq;
@@ -122,8 +145,12 @@
  * @ngpio:      The number of pingroups the driver should expose as GPIOs.
  * @dir_conn:   An array describing all the pins directly connected to GIC.
  * @ndirconns:  The number of pins directly connected to GIC
- * @dir_conn_offsets:   Direct connect register offsets for each tile.
  * @dir_conn_irq_base:  Direct connect interrupt base register for kpss.
+ * @gpio_mux_in:	Map of GPIO pin to the hwirq.
+ * @n_gpioc_mux_in:	The number of entries in @pdc_mux_in.
+ * @pdc_mux_out:	Map of GPIO mux to PDC port.
+ * @n_pdc_mux_out:	The number of entries in @pdc_mux_out.
+ * @n_pdc_offset:	The offset for the PDC mux pins
  */
 struct msm_pinctrl_soc_data {
 	const struct pinctrl_pin_desc *pins;
@@ -136,6 +163,11 @@
 	const struct msm_dir_conn *dir_conn;
 	unsigned int n_dir_conns;
 	unsigned int dir_conn_irq_base;
+	struct msm_pdc_mux_output *pdc_mux_out;
+	unsigned int n_pdc_mux_out;
+	struct msm_gpio_mux_input *gpio_mux_in;
+	unsigned int n_gpio_mux_in;
+	unsigned int n_pdc_mux_offset;
 };
 
 int msm_pinctrl_probe(struct platform_device *pdev,
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8937.c b/drivers/pinctrl/qcom/pinctrl-msm8937.c
new file mode 100644
index 0000000..2b72c54
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8937.c
@@ -0,0 +1,1479 @@
+/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname)			                \
+	[msm_mux_##fname] = {		                \
+		.name = #fname,				\
+		.groups = fname##_groups,               \
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)	\
+	{					        \
+		.name = "gpio" #id,			\
+		.pins = gpio##id##_pins,		\
+		.npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins),	\
+		.funcs = (int[]){			\
+			msm_mux_gpio, /* gpio mode */	\
+			msm_mux_##f1,			\
+			msm_mux_##f2,			\
+			msm_mux_##f3,			\
+			msm_mux_##f4,			\
+			msm_mux_##f5,			\
+			msm_mux_##f6,			\
+			msm_mux_##f7,			\
+			msm_mux_##f8,			\
+			msm_mux_##f9			\
+		},				        \
+		.nfuncs = 10,				\
+		.ctl_reg = REG_BASE + REG_SIZE * id,			\
+		.io_reg = REG_BASE + 0x4 + REG_SIZE * id,		\
+		.intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id,		\
+		.intr_status_reg = REG_BASE + 0xc + REG_SIZE * id,	\
+		.intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id,	\
+		.mux_bit = 2,			\
+		.pull_bit = 0,			\
+		.drv_bit = 6,			\
+		.oe_bit = 9,			\
+		.in_bit = 0,			\
+		.out_bit = 1,			\
+		.intr_enable_bit = 0,		\
+		.intr_status_bit = 0,		\
+		.intr_target_bit = 5,		\
+		.intr_target_kpss_val = 4,	\
+		.intr_raw_status_bit = 4,	\
+		.intr_polarity_bit = 1,		\
+		.intr_detection_bit = 2,	\
+		.intr_detection_width = 2,	\
+	}
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)	\
+	{					        \
+		.name = #pg_name,			\
+		.pins = pg_name##_pins,			\
+		.npins = (unsigned int)ARRAY_SIZE(pg_name##_pins),	\
+		.ctl_reg = ctl,				\
+		.io_reg = 0,				\
+		.intr_cfg_reg = 0,			\
+		.intr_status_reg = 0,			\
+		.intr_target_reg = 0,			\
+		.mux_bit = -1,				\
+		.pull_bit = pull,			\
+		.drv_bit = drv,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = -1,				\
+		.intr_enable_bit = -1,			\
+		.intr_status_bit = -1,			\
+		.intr_target_bit = -1,			\
+		.intr_raw_status_bit = -1,		\
+		.intr_polarity_bit = -1,		\
+		.intr_detection_bit = -1,		\
+		.intr_detection_width = -1,		\
+	}
+static const struct pinctrl_pin_desc msm8937_pins[] = {
+	PINCTRL_PIN(0, "GPIO_0"),
+	PINCTRL_PIN(1, "GPIO_1"),
+	PINCTRL_PIN(2, "GPIO_2"),
+	PINCTRL_PIN(3, "GPIO_3"),
+	PINCTRL_PIN(4, "GPIO_4"),
+	PINCTRL_PIN(5, "GPIO_5"),
+	PINCTRL_PIN(6, "GPIO_6"),
+	PINCTRL_PIN(7, "GPIO_7"),
+	PINCTRL_PIN(8, "GPIO_8"),
+	PINCTRL_PIN(9, "GPIO_9"),
+	PINCTRL_PIN(10, "GPIO_10"),
+	PINCTRL_PIN(11, "GPIO_11"),
+	PINCTRL_PIN(12, "GPIO_12"),
+	PINCTRL_PIN(13, "GPIO_13"),
+	PINCTRL_PIN(14, "GPIO_14"),
+	PINCTRL_PIN(15, "GPIO_15"),
+	PINCTRL_PIN(16, "GPIO_16"),
+	PINCTRL_PIN(17, "GPIO_17"),
+	PINCTRL_PIN(18, "GPIO_18"),
+	PINCTRL_PIN(19, "GPIO_19"),
+	PINCTRL_PIN(20, "GPIO_20"),
+	PINCTRL_PIN(21, "GPIO_21"),
+	PINCTRL_PIN(22, "GPIO_22"),
+	PINCTRL_PIN(23, "GPIO_23"),
+	PINCTRL_PIN(24, "GPIO_24"),
+	PINCTRL_PIN(25, "GPIO_25"),
+	PINCTRL_PIN(26, "GPIO_26"),
+	PINCTRL_PIN(27, "GPIO_27"),
+	PINCTRL_PIN(28, "GPIO_28"),
+	PINCTRL_PIN(29, "GPIO_29"),
+	PINCTRL_PIN(30, "GPIO_30"),
+	PINCTRL_PIN(31, "GPIO_31"),
+	PINCTRL_PIN(32, "GPIO_32"),
+	PINCTRL_PIN(33, "GPIO_33"),
+	PINCTRL_PIN(34, "GPIO_34"),
+	PINCTRL_PIN(35, "GPIO_35"),
+	PINCTRL_PIN(36, "GPIO_36"),
+	PINCTRL_PIN(37, "GPIO_37"),
+	PINCTRL_PIN(38, "GPIO_38"),
+	PINCTRL_PIN(39, "GPIO_39"),
+	PINCTRL_PIN(40, "GPIO_40"),
+	PINCTRL_PIN(41, "GPIO_41"),
+	PINCTRL_PIN(42, "GPIO_42"),
+	PINCTRL_PIN(43, "GPIO_43"),
+	PINCTRL_PIN(44, "GPIO_44"),
+	PINCTRL_PIN(45, "GPIO_45"),
+	PINCTRL_PIN(46, "GPIO_46"),
+	PINCTRL_PIN(47, "GPIO_47"),
+	PINCTRL_PIN(48, "GPIO_48"),
+	PINCTRL_PIN(49, "GPIO_49"),
+	PINCTRL_PIN(50, "GPIO_50"),
+	PINCTRL_PIN(51, "GPIO_51"),
+	PINCTRL_PIN(52, "GPIO_52"),
+	PINCTRL_PIN(53, "GPIO_53"),
+	PINCTRL_PIN(54, "GPIO_54"),
+	PINCTRL_PIN(55, "GPIO_55"),
+	PINCTRL_PIN(56, "GPIO_56"),
+	PINCTRL_PIN(57, "GPIO_57"),
+	PINCTRL_PIN(58, "GPIO_58"),
+	PINCTRL_PIN(59, "GPIO_59"),
+	PINCTRL_PIN(60, "GPIO_60"),
+	PINCTRL_PIN(61, "GPIO_61"),
+	PINCTRL_PIN(62, "GPIO_62"),
+	PINCTRL_PIN(63, "GPIO_63"),
+	PINCTRL_PIN(64, "GPIO_64"),
+	PINCTRL_PIN(65, "GPIO_65"),
+	PINCTRL_PIN(66, "GPIO_66"),
+	PINCTRL_PIN(67, "GPIO_67"),
+	PINCTRL_PIN(68, "GPIO_68"),
+	PINCTRL_PIN(69, "GPIO_69"),
+	PINCTRL_PIN(70, "GPIO_70"),
+	PINCTRL_PIN(71, "GPIO_71"),
+	PINCTRL_PIN(72, "GPIO_72"),
+	PINCTRL_PIN(73, "GPIO_73"),
+	PINCTRL_PIN(74, "GPIO_74"),
+	PINCTRL_PIN(75, "GPIO_75"),
+	PINCTRL_PIN(76, "GPIO_76"),
+	PINCTRL_PIN(77, "GPIO_77"),
+	PINCTRL_PIN(78, "GPIO_78"),
+	PINCTRL_PIN(79, "GPIO_79"),
+	PINCTRL_PIN(80, "GPIO_80"),
+	PINCTRL_PIN(81, "GPIO_81"),
+	PINCTRL_PIN(82, "GPIO_82"),
+	PINCTRL_PIN(83, "GPIO_83"),
+	PINCTRL_PIN(84, "GPIO_84"),
+	PINCTRL_PIN(85, "GPIO_85"),
+	PINCTRL_PIN(86, "GPIO_86"),
+	PINCTRL_PIN(87, "GPIO_87"),
+	PINCTRL_PIN(88, "GPIO_88"),
+	PINCTRL_PIN(89, "GPIO_89"),
+	PINCTRL_PIN(90, "GPIO_90"),
+	PINCTRL_PIN(91, "GPIO_91"),
+	PINCTRL_PIN(92, "GPIO_92"),
+	PINCTRL_PIN(93, "GPIO_93"),
+	PINCTRL_PIN(94, "GPIO_94"),
+	PINCTRL_PIN(95, "GPIO_95"),
+	PINCTRL_PIN(96, "GPIO_96"),
+	PINCTRL_PIN(97, "GPIO_97"),
+	PINCTRL_PIN(98, "GPIO_98"),
+	PINCTRL_PIN(99, "GPIO_99"),
+	PINCTRL_PIN(100, "GPIO_100"),
+	PINCTRL_PIN(101, "GPIO_101"),
+	PINCTRL_PIN(102, "GPIO_102"),
+	PINCTRL_PIN(103, "GPIO_103"),
+	PINCTRL_PIN(104, "GPIO_104"),
+	PINCTRL_PIN(105, "GPIO_105"),
+	PINCTRL_PIN(106, "GPIO_106"),
+	PINCTRL_PIN(107, "GPIO_107"),
+	PINCTRL_PIN(108, "GPIO_108"),
+	PINCTRL_PIN(109, "GPIO_109"),
+	PINCTRL_PIN(110, "GPIO_110"),
+	PINCTRL_PIN(111, "GPIO_111"),
+	PINCTRL_PIN(112, "GPIO_112"),
+	PINCTRL_PIN(113, "GPIO_113"),
+	PINCTRL_PIN(114, "GPIO_114"),
+	PINCTRL_PIN(115, "GPIO_115"),
+	PINCTRL_PIN(116, "GPIO_116"),
+	PINCTRL_PIN(117, "GPIO_117"),
+	PINCTRL_PIN(118, "GPIO_118"),
+	PINCTRL_PIN(119, "GPIO_119"),
+	PINCTRL_PIN(120, "GPIO_120"),
+	PINCTRL_PIN(121, "GPIO_121"),
+	PINCTRL_PIN(122, "GPIO_122"),
+	PINCTRL_PIN(123, "GPIO_123"),
+	PINCTRL_PIN(124, "GPIO_124"),
+	PINCTRL_PIN(125, "GPIO_125"),
+	PINCTRL_PIN(126, "GPIO_126"),
+	PINCTRL_PIN(127, "GPIO_127"),
+	PINCTRL_PIN(128, "GPIO_128"),
+	PINCTRL_PIN(129, "GPIO_129"),
+	PINCTRL_PIN(130, "GPIO_130"),
+	PINCTRL_PIN(131, "GPIO_131"),
+	PINCTRL_PIN(132, "GPIO_132"),
+	PINCTRL_PIN(133, "GPIO_133"),
+	PINCTRL_PIN(134, "SDC1_CLK"),
+	PINCTRL_PIN(135, "SDC1_CMD"),
+	PINCTRL_PIN(136, "SDC1_DATA"),
+	PINCTRL_PIN(137, "SDC1_RCLK"),
+	PINCTRL_PIN(138, "SDC2_CLK"),
+	PINCTRL_PIN(139, "SDC2_CMD"),
+	PINCTRL_PIN(140, "SDC2_DATA"),
+	PINCTRL_PIN(141, "QDSD_CLK"),
+	PINCTRL_PIN(142, "QDSD_CMD"),
+	PINCTRL_PIN(143, "QDSD_DATA0"),
+	PINCTRL_PIN(144, "QDSD_DATA1"),
+	PINCTRL_PIN(145, "QDSD_DATA2"),
+	PINCTRL_PIN(146, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+	static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+
+static const unsigned int sdc1_clk_pins[] = { 134 };
+static const unsigned int sdc1_cmd_pins[] = { 135 };
+static const unsigned int sdc1_data_pins[] = { 136 };
+static const unsigned int sdc1_rclk_pins[] = { 137 };
+static const unsigned int sdc2_clk_pins[] = { 138 };
+static const unsigned int sdc2_cmd_pins[] = { 139 };
+static const unsigned int sdc2_data_pins[] = { 140 };
+static const unsigned int qdsd_clk_pins[] = { 141 };
+static const unsigned int qdsd_cmd_pins[] = { 142 };
+static const unsigned int qdsd_data0_pins[] = { 143 };
+static const unsigned int qdsd_data1_pins[] = { 144 };
+static const unsigned int qdsd_data2_pins[] = { 145 };
+static const unsigned int qdsd_data3_pins[] = { 146 };
+
+enum msm8937_functions {
+	msm_mux_qdss_tracedata_b,
+	msm_mux_blsp_uart1,
+	msm_mux_gpio,
+	msm_mux_blsp_spi1,
+	msm_mux_adsp_ext,
+	msm_mux_blsp_i2c1,
+	msm_mux_prng_rosc,
+	msm_mux_qdss_cti_trig_out_b0,
+	msm_mux_blsp_spi2,
+	msm_mux_blsp_uart2,
+	msm_mux_blsp_uart3,
+	msm_mux_pbs0,
+	msm_mux_pbs1,
+	msm_mux_pwr_modem_enabled_b,
+	msm_mux_blsp_i2c3,
+	msm_mux_gcc_gp2_clk_b,
+	msm_mux_ldo_update,
+	msm_mux_atest_combodac_to_gpio_native,
+	msm_mux_ldo_en,
+	msm_mux_blsp_i2c2,
+	msm_mux_gcc_gp1_clk_b,
+	msm_mux_pbs2,
+	msm_mux_atest_gpsadc_dtest0_native,
+	msm_mux_blsp_spi3,
+	msm_mux_gcc_gp3_clk_b,
+	msm_mux_blsp_spi4,
+	msm_mux_blsp_uart4,
+	msm_mux_sec_mi2s,
+	msm_mux_pwr_nav_enabled_b,
+	msm_mux_codec_mad,
+	msm_mux_pwr_crypto_enabled_b,
+	msm_mux_blsp_i2c4,
+	msm_mux_blsp_spi5,
+	msm_mux_blsp_uart5,
+	msm_mux_qdss_traceclk_a,
+	msm_mux_atest_bbrx1,
+	msm_mux_m_voc,
+	msm_mux_qdss_cti_trig_in_a0,
+	msm_mux_qdss_cti_trig_in_b0,
+	msm_mux_blsp_i2c6,
+	msm_mux_qdss_traceclk_b,
+	msm_mux_atest_wlan0,
+	msm_mux_atest_wlan1,
+	msm_mux_atest_bbrx0,
+	msm_mux_blsp_i2c5,
+	msm_mux_qdss_tracectl_a,
+	msm_mux_atest_gpsadc_dtest1_native,
+	msm_mux_qdss_tracedata_a,
+	msm_mux_blsp_spi6,
+	msm_mux_blsp_uart6,
+	msm_mux_qdss_tracectl_b,
+	msm_mux_mdp_vsync,
+	msm_mux_pri_mi2s_mclk_a,
+	msm_mux_sec_mi2s_mclk_a,
+	msm_mux_cam_mclk,
+	msm_mux_cci_i2c,
+	msm_mux_pwr_modem_enabled_a,
+	msm_mux_cci_timer0,
+	msm_mux_cci_timer1,
+	msm_mux_cam1_standby,
+	msm_mux_pwr_nav_enabled_a,
+	msm_mux_cam1_rst,
+	msm_mux_pwr_crypto_enabled_a,
+	msm_mux_forced_usb,
+	msm_mux_qdss_cti_trig_out_b1,
+	msm_mux_cam2_rst,
+	msm_mux_webcam_standby,
+	msm_mux_cci_async,
+	msm_mux_webcam_rst,
+	msm_mux_ov_ldo,
+	msm_mux_sd_write,
+	msm_mux_accel_int,
+	msm_mux_gcc_gp1_clk_a,
+	msm_mux_alsp_int,
+	msm_mux_gcc_gp2_clk_a,
+	msm_mux_mag_int,
+	msm_mux_gcc_gp3_clk_a,
+	msm_mux_blsp6_spi,
+	msm_mux_fp_int,
+	msm_mux_qdss_cti_trig_in_b1,
+	msm_mux_uim_batt,
+	msm_mux_cam2_standby,
+	msm_mux_uim1_data,
+	msm_mux_uim1_clk,
+	msm_mux_uim1_reset,
+	msm_mux_uim1_present,
+	msm_mux_uim2_data,
+	msm_mux_uim2_clk,
+	msm_mux_uim2_reset,
+	msm_mux_uim2_present,
+	msm_mux_sensor_rst,
+	msm_mux_mipi_dsi0,
+	msm_mux_smb_int,
+	msm_mux_cam0_ldo,
+	msm_mux_us_euro,
+	msm_mux_atest_char3,
+	msm_mux_dbg_out,
+	msm_mux_bimc_dte0,
+	msm_mux_ts_resout,
+	msm_mux_ts_sample,
+	msm_mux_sec_mi2s_mclk_b,
+	msm_mux_pri_mi2s,
+	msm_mux_sdcard_det,
+	msm_mux_atest_char1,
+	msm_mux_ebi_cdc,
+	msm_mux_audio_reset,
+	msm_mux_atest_char0,
+	msm_mux_audio_ref,
+	msm_mux_cdc_pdm0,
+	msm_mux_pri_mi2s_mclk_b,
+	msm_mux_lpass_slimbus,
+	msm_mux_lpass_slimbus0,
+	msm_mux_lpass_slimbus1,
+	msm_mux_codec_int1,
+	msm_mux_codec_int2,
+	msm_mux_wcss_bt,
+	msm_mux_atest_char2,
+	msm_mux_ebi_ch0,
+	msm_mux_wcss_wlan2,
+	msm_mux_wcss_wlan1,
+	msm_mux_wcss_wlan0,
+	msm_mux_wcss_wlan,
+	msm_mux_wcss_fm,
+	msm_mux_ext_lpass,
+	msm_mux_cri_trng,
+	msm_mux_cri_trng1,
+	msm_mux_cri_trng0,
+	msm_mux_blsp_spi7,
+	msm_mux_blsp_uart7,
+	msm_mux_pri_mi2s_ws,
+	msm_mux_blsp_i2c7,
+	msm_mux_gcc_tlmm,
+	msm_mux_dmic0_clk,
+	msm_mux_dmic0_data,
+	msm_mux_key_volp,
+	msm_mux_qdss_cti_trig_in_a1,
+	msm_mux_us_emitter,
+	msm_mux_wsa_irq,
+	msm_mux_wsa_io,
+	msm_mux_wsa_reset,
+	msm_mux_blsp_spi8,
+	msm_mux_blsp_uart8,
+	msm_mux_blsp_i2c8,
+	msm_mux_gcc_plltest,
+	msm_mux_nav_pps_in_a,
+	msm_mux_pa_indicator,
+	msm_mux_modem_tsync,
+	msm_mux_nav_tsync,
+	msm_mux_nav_pps_in_b,
+	msm_mux_nav_pps,
+	msm_mux_gsm0_tx,
+	msm_mux_atest_char,
+	msm_mux_atest_tsens,
+	msm_mux_bimc_dte1,
+	msm_mux_ssbi_wtr1,
+	msm_mux_fp_gpio,
+	msm_mux_coex_uart,
+	msm_mux_key_snapshot,
+	msm_mux_key_focus,
+	msm_mux_nfc_pwr,
+	msm_mux_blsp8_spi,
+	msm_mux_qdss_cti_trig_out_a0,
+	msm_mux_qdss_cti_trig_out_a1,
+	msm_mux_NA,
+};
+
+static const char * const qdss_tracedata_b_groups[] = {
+	"gpio0", "gpio1", "gpio6", "gpio7", "gpio12", "gpio13", "gpio23",
+	"gpio42", "gpio43", "gpio44", "gpio47", "gpio66", "gpio86", "gpio87",
+	"gpio88", "gpio92",
+};
+static const char * const blsp_uart1_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const gpio_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+	"gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+	"gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+	"gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+	"gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+	"gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+	"gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+	"gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+	"gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+	"gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+	"gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+	"gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+	"gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+	"gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+	"gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+	"gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+	"gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+	"gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+	"gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+	"gpio129", "gpio130", "gpio131", "gpio132", "gpio133",
+};
+static const char * const blsp_spi1_groups[] = {
+	"gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const adsp_ext_groups[] = {
+	"gpio1",
+};
+static const char * const blsp_i2c1_groups[] = {
+	"gpio2", "gpio3",
+};
+static const char * const prng_rosc_groups[] = {
+	"gpio2",
+};
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+	"gpio2",
+};
+static const char * const blsp_spi2_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart2_groups[] = {
+	"gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart3_groups[] = {
+	"gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const pbs0_groups[] = {
+	"gpio8",
+};
+static const char * const pbs1_groups[] = {
+	"gpio9",
+};
+static const char * const pwr_modem_enabled_b_groups[] = {
+	"gpio9",
+};
+static const char * const blsp_i2c3_groups[] = {
+	"gpio10", "gpio11",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+	"gpio10",
+};
+static const char * const ldo_update_groups[] = {
+	"gpio4",
+};
+static const char * const atest_combodac_to_gpio_native_groups[] = {
+	"gpio4", "gpio12", "gpio13", "gpio20", "gpio21", "gpio28", "gpio29",
+	"gpio30", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", "gpio44",
+	"gpio45", "gpio46", "gpio47", "gpio48", "gpio67", "gpio115",
+};
+static const char * const ldo_en_groups[] = {
+	"gpio5",
+};
+static const char * const blsp_i2c2_groups[] = {
+	"gpio6", "gpio7",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+	"gpio6",
+};
+static const char * const pbs2_groups[] = {
+	"gpio7",
+};
+static const char * const atest_gpsadc_dtest0_native_groups[] = {
+	"gpio7",
+};
+static const char * const blsp_spi3_groups[] = {
+	"gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+	"gpio11",
+};
+static const char * const blsp_spi4_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const blsp_uart4_groups[] = {
+	"gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const sec_mi2s_groups[] = {
+	"gpio12", "gpio13", "gpio94", "gpio95",
+};
+static const char * const pwr_nav_enabled_b_groups[] = {
+	"gpio12",
+};
+static const char * const codec_mad_groups[] = {
+	"gpio13",
+};
+static const char * const pwr_crypto_enabled_b_groups[] = {
+	"gpio13",
+};
+static const char * const blsp_i2c4_groups[] = {
+	"gpio14", "gpio15",
+};
+static const char * const blsp_spi5_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_uart5_groups[] = {
+	"gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+	"gpio16",
+};
+static const char * const atest_bbrx1_groups[] = {
+	"gpio16",
+};
+static const char * const m_voc_groups[] = {
+	"gpio17", "gpio21",
+};
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+	"gpio17",
+};
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+	"gpio21",
+};
+static const char * const blsp_i2c6_groups[] = {
+	"gpio22", "gpio23",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+	"gpio22",
+};
+static const char * const atest_wlan0_groups[] = {
+	"gpio22",
+};
+static const char * const atest_wlan1_groups[] = {
+	"gpio23",
+};
+static const char * const atest_bbrx0_groups[] = {
+	"gpio17",
+};
+static const char * const blsp_i2c5_groups[] = {
+	"gpio18", "gpio19",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+	"gpio18",
+};
+static const char * const atest_gpsadc_dtest1_native_groups[] = {
+	"gpio18",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+	"gpio19", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+	"gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio38", "gpio39",
+	"gpio40", "gpio50",
+};
+static const char * const blsp_spi6_groups[] = {
+	"gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const blsp_uart6_groups[] = {
+	"gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+	"gpio20",
+};
+static const char * const mdp_vsync_groups[] = {
+	"gpio24", "gpio25",
+};
+static const char * const pri_mi2s_mclk_a_groups[] = {
+	"gpio25",
+};
+static const char * const sec_mi2s_mclk_a_groups[] = {
+	"gpio25",
+};
+static const char * const cam_mclk_groups[] = {
+	"gpio26", "gpio27", "gpio28",
+};
+static const char * const cci_i2c_groups[] = {
+	"gpio29", "gpio30", "gpio31", "gpio32",
+};
+static const char * const pwr_modem_enabled_a_groups[] = {
+	"gpio29",
+};
+static const char * const cci_timer0_groups[] = {
+	"gpio33",
+};
+static const char * const cci_timer1_groups[] = {
+	"gpio34",
+};
+static const char * const cam1_standby_groups[] = {
+	"gpio35",
+};
+static const char * const pwr_nav_enabled_a_groups[] = {
+	"gpio35",
+};
+static const char * const cam1_rst_groups[] = {
+	"gpio36",
+};
+static const char * const pwr_crypto_enabled_a_groups[] = {
+	"gpio36",
+};
+static const char * const forced_usb_groups[] = {
+	"gpio37",
+};
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+	"gpio37",
+};
+static const char * const cam2_rst_groups[] = {
+	"gpio38",
+};
+static const char * const webcam_standby_groups[] = {
+	"gpio39",
+};
+static const char * const cci_async_groups[] = {
+	"gpio39",
+};
+static const char * const webcam_rst_groups[] = {
+	"gpio40",
+};
+static const char * const ov_ldo_groups[] = {
+	"gpio41",
+};
+static const char * const sd_write_groups[] = {
+	"gpio41",
+};
+static const char * const accel_int_groups[] = {
+	"gpio42",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+	"gpio42",
+};
+static const char * const alsp_int_groups[] = {
+	"gpio43",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+	"gpio43",
+};
+static const char * const mag_int_groups[] = {
+	"gpio44",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+	"gpio44",
+};
+static const char * const blsp6_spi_groups[] = {
+	"gpio47",
+};
+static const char * const fp_int_groups[] = {
+	"gpio48",
+};
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+	"gpio48",
+};
+static const char * const uim_batt_groups[] = {
+	"gpio49",
+};
+static const char * const cam2_standby_groups[] = {
+	"gpio50",
+};
+static const char * const uim1_data_groups[] = {
+	"gpio51",
+};
+static const char * const uim1_clk_groups[] = {
+	"gpio52",
+};
+static const char * const uim1_reset_groups[] = {
+	"gpio53",
+};
+static const char * const uim1_present_groups[] = {
+	"gpio54",
+};
+static const char * const uim2_data_groups[] = {
+	"gpio55",
+};
+static const char * const uim2_clk_groups[] = {
+	"gpio56",
+};
+static const char * const uim2_reset_groups[] = {
+	"gpio57",
+};
+static const char * const uim2_present_groups[] = {
+	"gpio58",
+};
+static const char * const sensor_rst_groups[] = {
+	"gpio59",
+};
+static const char * const mipi_dsi0_groups[] = {
+	"gpio60",
+};
+static const char * const smb_int_groups[] = {
+	"gpio61",
+};
+static const char * const cam0_ldo_groups[] = {
+	"gpio62",
+};
+static const char * const us_euro_groups[] = {
+	"gpio63",
+};
+static const char * const atest_char3_groups[] = {
+	"gpio63",
+};
+static const char * const dbg_out_groups[] = {
+	"gpio63",
+};
+static const char * const bimc_dte0_groups[] = {
+	"gpio63", "gpio65",
+};
+static const char * const ts_resout_groups[] = {
+	"gpio64",
+};
+static const char * const ts_sample_groups[] = {
+	"gpio65",
+};
+static const char * const sec_mi2s_mclk_b_groups[] = {
+	"gpio66",
+};
+static const char * const pri_mi2s_groups[] = {
+	"gpio66", "gpio85", "gpio86", "gpio88", "gpio94", "gpio95",
+};
+static const char * const sdcard_det_groups[] = {
+	"gpio67",
+};
+static const char * const atest_char1_groups[] = {
+	"gpio67",
+};
+static const char * const ebi_cdc_groups[] = {
+	"gpio67", "gpio69", "gpio118", "gpio119", "gpio120", "gpio123",
+};
+static const char * const audio_reset_groups[] = {
+	"gpio68",
+};
+static const char * const atest_char0_groups[] = {
+	"gpio68",
+};
+static const char * const audio_ref_groups[] = {
+	"gpio69",
+};
+static const char * const cdc_pdm0_groups[] = {
+	"gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74",
+};
+static const char * const pri_mi2s_mclk_b_groups[] = {
+	"gpio69",
+};
+static const char * const lpass_slimbus_groups[] = {
+	"gpio70",
+};
+static const char * const lpass_slimbus0_groups[] = {
+	"gpio71",
+};
+static const char * const lpass_slimbus1_groups[] = {
+	"gpio72",
+};
+static const char * const codec_int1_groups[] = {
+	"gpio73",
+};
+static const char * const codec_int2_groups[] = {
+	"gpio74",
+};
+static const char * const wcss_bt_groups[] = {
+	"gpio75", "gpio83", "gpio84",
+};
+static const char * const atest_char2_groups[] = {
+	"gpio75",
+};
+static const char * const ebi_ch0_groups[] = {
+	"gpio75",
+};
+static const char * const wcss_wlan2_groups[] = {
+	"gpio76",
+};
+static const char * const wcss_wlan1_groups[] = {
+	"gpio77",
+};
+static const char * const wcss_wlan0_groups[] = {
+	"gpio78",
+};
+static const char * const wcss_wlan_groups[] = {
+	"gpio79", "gpio80",
+};
+static const char * const wcss_fm_groups[] = {
+	"gpio81", "gpio82",
+};
+static const char * const ext_lpass_groups[] = {
+	"gpio81",
+};
+static const char * const cri_trng_groups[] = {
+	"gpio82",
+};
+static const char * const cri_trng1_groups[] = {
+	"gpio83",
+};
+static const char * const cri_trng0_groups[] = {
+	"gpio84",
+};
+static const char * const blsp_spi7_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uart7_groups[] = {
+	"gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+	"gpio87",
+};
+static const char * const blsp_i2c7_groups[] = {
+	"gpio87", "gpio88",
+};
+static const char * const gcc_tlmm_groups[] = {
+	"gpio87",
+};
+static const char * const dmic0_clk_groups[] = {
+	"gpio89",
+};
+static const char * const dmic0_data_groups[] = {
+	"gpio90",
+};
+static const char * const key_volp_groups[] = {
+	"gpio91",
+};
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+	"gpio91",
+};
+static const char * const us_emitter_groups[] = {
+	"gpio92",
+};
+static const char * const wsa_irq_groups[] = {
+	"gpio93",
+};
+static const char * const wsa_io_groups[] = {
+	"gpio94", "gpio95",
+};
+static const char * const wsa_reset_groups[] = {
+	"gpio96",
+};
+static const char * const blsp_spi8_groups[] = {
+	"gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_uart8_groups[] = {
+	"gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const blsp_i2c8_groups[] = {
+	"gpio98", "gpio99",
+};
+static const char * const gcc_plltest_groups[] = {
+	"gpio98", "gpio99",
+};
+static const char * const nav_pps_in_a_groups[] = {
+	"gpio115",
+};
+static const char * const pa_indicator_groups[] = {
+	"gpio116",
+};
+static const char * const modem_tsync_groups[] = {
+	"gpio117",
+};
+static const char * const nav_tsync_groups[] = {
+	"gpio117",
+};
+static const char * const nav_pps_in_b_groups[] = {
+	"gpio117",
+};
+static const char * const nav_pps_groups[] = {
+	"gpio117",
+};
+static const char * const gsm0_tx_groups[] = {
+	"gpio119",
+};
+static const char * const atest_char_groups[] = {
+	"gpio120",
+};
+static const char * const atest_tsens_groups[] = {
+	"gpio120",
+};
+static const char * const bimc_dte1_groups[] = {
+	"gpio121", "gpio122",
+};
+static const char * const ssbi_wtr1_groups[] = {
+	"gpio122", "gpio123",
+};
+static const char * const fp_gpio_groups[] = {
+	"gpio124",
+};
+static const char * const coex_uart_groups[] = {
+	"gpio124", "gpio127",
+};
+static const char * const key_snapshot_groups[] = {
+	"gpio127",
+};
+static const char * const key_focus_groups[] = {
+	"gpio128",
+};
+static const char * const nfc_pwr_groups[] = {
+	"gpio129",
+};
+static const char * const blsp8_spi_groups[] = {
+	"gpio130",
+};
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+	"gpio132",
+};
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+	"gpio133",
+};
+
+static const struct msm_function msm8937_functions[] = {
+	FUNCTION(qdss_tracedata_b),
+	FUNCTION(blsp_uart1),
+	FUNCTION(gpio),
+	FUNCTION(blsp_spi1),
+	FUNCTION(adsp_ext),
+	FUNCTION(blsp_i2c1),
+	FUNCTION(prng_rosc),
+	FUNCTION(qdss_cti_trig_out_b0),
+	FUNCTION(blsp_spi2),
+	FUNCTION(blsp_uart2),
+	FUNCTION(blsp_uart3),
+	FUNCTION(pbs0),
+	FUNCTION(pbs1),
+	FUNCTION(pwr_modem_enabled_b),
+	FUNCTION(blsp_i2c3),
+	FUNCTION(gcc_gp2_clk_b),
+	FUNCTION(ldo_update),
+	FUNCTION(atest_combodac_to_gpio_native),
+	FUNCTION(ldo_en),
+	FUNCTION(blsp_i2c2),
+	FUNCTION(gcc_gp1_clk_b),
+	FUNCTION(pbs2),
+	FUNCTION(atest_gpsadc_dtest0_native),
+	FUNCTION(blsp_spi3),
+	FUNCTION(gcc_gp3_clk_b),
+	FUNCTION(blsp_spi4),
+	FUNCTION(blsp_uart4),
+	FUNCTION(sec_mi2s),
+	FUNCTION(pwr_nav_enabled_b),
+	FUNCTION(codec_mad),
+	FUNCTION(pwr_crypto_enabled_b),
+	FUNCTION(blsp_i2c4),
+	FUNCTION(blsp_spi5),
+	FUNCTION(blsp_uart5),
+	FUNCTION(qdss_traceclk_a),
+	FUNCTION(atest_bbrx1),
+	FUNCTION(m_voc),
+	FUNCTION(qdss_cti_trig_in_a0),
+	FUNCTION(qdss_cti_trig_in_b0),
+	FUNCTION(blsp_i2c6),
+	FUNCTION(qdss_traceclk_b),
+	FUNCTION(atest_wlan0),
+	FUNCTION(atest_wlan1),
+	FUNCTION(atest_bbrx0),
+	FUNCTION(blsp_i2c5),
+	FUNCTION(qdss_tracectl_a),
+	FUNCTION(atest_gpsadc_dtest1_native),
+	FUNCTION(qdss_tracedata_a),
+	FUNCTION(blsp_spi6),
+	FUNCTION(blsp_uart6),
+	FUNCTION(qdss_tracectl_b),
+	FUNCTION(mdp_vsync),
+	FUNCTION(pri_mi2s_mclk_a),
+	FUNCTION(sec_mi2s_mclk_a),
+	FUNCTION(cam_mclk),
+	FUNCTION(cci_i2c),
+	FUNCTION(pwr_modem_enabled_a),
+	FUNCTION(cci_timer0),
+	FUNCTION(cci_timer1),
+	FUNCTION(cam1_standby),
+	FUNCTION(pwr_nav_enabled_a),
+	FUNCTION(cam1_rst),
+	FUNCTION(pwr_crypto_enabled_a),
+	FUNCTION(forced_usb),
+	FUNCTION(qdss_cti_trig_out_b1),
+	FUNCTION(cam2_rst),
+	FUNCTION(webcam_standby),
+	FUNCTION(cci_async),
+	FUNCTION(webcam_rst),
+	FUNCTION(ov_ldo),
+	FUNCTION(sd_write),
+	FUNCTION(accel_int),
+	FUNCTION(gcc_gp1_clk_a),
+	FUNCTION(alsp_int),
+	FUNCTION(gcc_gp2_clk_a),
+	FUNCTION(mag_int),
+	FUNCTION(gcc_gp3_clk_a),
+	FUNCTION(blsp6_spi),
+	FUNCTION(fp_int),
+	FUNCTION(qdss_cti_trig_in_b1),
+	FUNCTION(uim_batt),
+	FUNCTION(cam2_standby),
+	FUNCTION(uim1_data),
+	FUNCTION(uim1_clk),
+	FUNCTION(uim1_reset),
+	FUNCTION(uim1_present),
+	FUNCTION(uim2_data),
+	FUNCTION(uim2_clk),
+	FUNCTION(uim2_reset),
+	FUNCTION(uim2_present),
+	FUNCTION(sensor_rst),
+	FUNCTION(mipi_dsi0),
+	FUNCTION(smb_int),
+	FUNCTION(cam0_ldo),
+	FUNCTION(us_euro),
+	FUNCTION(atest_char3),
+	FUNCTION(dbg_out),
+	FUNCTION(bimc_dte0),
+	FUNCTION(ts_resout),
+	FUNCTION(ts_sample),
+	FUNCTION(sec_mi2s_mclk_b),
+	FUNCTION(pri_mi2s),
+	FUNCTION(sdcard_det),
+	FUNCTION(atest_char1),
+	FUNCTION(ebi_cdc),
+	FUNCTION(audio_reset),
+	FUNCTION(atest_char0),
+	FUNCTION(audio_ref),
+	FUNCTION(cdc_pdm0),
+	FUNCTION(pri_mi2s_mclk_b),
+	FUNCTION(lpass_slimbus),
+	FUNCTION(lpass_slimbus0),
+	FUNCTION(lpass_slimbus1),
+	FUNCTION(codec_int1),
+	FUNCTION(codec_int2),
+	FUNCTION(wcss_bt),
+	FUNCTION(atest_char2),
+	FUNCTION(ebi_ch0),
+	FUNCTION(wcss_wlan2),
+	FUNCTION(wcss_wlan1),
+	FUNCTION(wcss_wlan0),
+	FUNCTION(wcss_wlan),
+	FUNCTION(wcss_fm),
+	FUNCTION(ext_lpass),
+	FUNCTION(cri_trng),
+	FUNCTION(cri_trng1),
+	FUNCTION(cri_trng0),
+	FUNCTION(blsp_spi7),
+	FUNCTION(blsp_uart7),
+	FUNCTION(pri_mi2s_ws),
+	FUNCTION(blsp_i2c7),
+	FUNCTION(gcc_tlmm),
+	FUNCTION(dmic0_clk),
+	FUNCTION(dmic0_data),
+	FUNCTION(key_volp),
+	FUNCTION(qdss_cti_trig_in_a1),
+	FUNCTION(us_emitter),
+	FUNCTION(wsa_irq),
+	FUNCTION(wsa_io),
+	FUNCTION(wsa_reset),
+	FUNCTION(blsp_spi8),
+	FUNCTION(blsp_uart8),
+	FUNCTION(blsp_i2c8),
+	FUNCTION(gcc_plltest),
+	FUNCTION(nav_pps_in_a),
+	FUNCTION(pa_indicator),
+	FUNCTION(modem_tsync),
+	FUNCTION(nav_tsync),
+	FUNCTION(nav_pps_in_b),
+	FUNCTION(nav_pps),
+	FUNCTION(gsm0_tx),
+	FUNCTION(atest_char),
+	FUNCTION(atest_tsens),
+	FUNCTION(bimc_dte1),
+	FUNCTION(ssbi_wtr1),
+	FUNCTION(fp_gpio),
+	FUNCTION(coex_uart),
+	FUNCTION(key_snapshot),
+	FUNCTION(key_focus),
+	FUNCTION(nfc_pwr),
+	FUNCTION(blsp8_spi),
+	FUNCTION(qdss_cti_trig_out_a0),
+	FUNCTION(qdss_cti_trig_out_a1),
+};
+
+static const struct msm_pingroup msm8937_groups[] = {
+	PINGROUP(0, blsp_spi1, blsp_uart1, qdss_tracedata_b, NA, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(1, blsp_spi1, blsp_uart1, adsp_ext, NA, NA, NA, NA, NA,
+		 qdss_tracedata_b),
+	PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, prng_rosc, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+	PINGROUP(4, blsp_spi2, blsp_uart2, ldo_update, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(5, blsp_spi2, blsp_uart2, ldo_en, NA, NA, NA, NA, NA, NA),
+	PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, gcc_gp1_clk_b,
+		 qdss_tracedata_b, NA, NA, NA, NA),
+	PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, pbs2, NA,
+		 qdss_tracedata_b, NA, atest_gpsadc_dtest0_native, NA),
+	PINGROUP(8, blsp_spi3, blsp_uart3, pbs0, NA, NA, NA, NA, NA, NA),
+	PINGROUP(9, blsp_spi3, blsp_uart3, pbs1, pwr_modem_enabled_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(10, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp2_clk_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(11, blsp_spi3, blsp_uart3, blsp_i2c3, gcc_gp3_clk_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(12, blsp_spi4, blsp_uart4, sec_mi2s, pwr_nav_enabled_b, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(13, blsp_spi4, blsp_uart4, sec_mi2s, pwr_crypto_enabled_b, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(14, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+	PINGROUP(15, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+	PINGROUP(16, blsp_spi5, blsp_uart5, NA, NA, NA, NA, qdss_traceclk_a,
+		 NA, atest_bbrx1),
+	PINGROUP(17, blsp_spi5, blsp_uart5, m_voc, qdss_cti_trig_in_a0, NA,
+		 atest_bbrx0, NA, NA, NA),
+	PINGROUP(18, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracectl_a, NA,
+		 atest_gpsadc_dtest1_native, NA, NA, NA),
+	PINGROUP(19, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracedata_a, NA,
+		 NA, NA, NA, NA),
+	PINGROUP(20, blsp_spi6, blsp_uart6, NA, NA, NA, NA, NA, NA,
+		 qdss_tracectl_b),
+	PINGROUP(21, blsp_spi6, blsp_uart6, m_voc, NA, NA, NA, NA, NA,
+		 qdss_cti_trig_in_b0),
+	PINGROUP(22, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_traceclk_b, NA,
+		 atest_wlan0, NA, NA, NA),
+	PINGROUP(23, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_tracedata_b, NA,
+		 atest_wlan1, NA, NA, NA),
+	PINGROUP(24, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(25, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a, NA, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(26, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA, NA),
+	PINGROUP(27, cam_mclk, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(28, cam_mclk, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(29, cci_i2c, pwr_modem_enabled_a, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a, NA),
+	PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(31, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(32, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(33, cci_timer0, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(34, cci_timer1, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_a),
+	PINGROUP(35, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a),
+	PINGROUP(36, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA,
+		 qdss_tracedata_a),
+	PINGROUP(37, NA, NA, NA, NA, NA, qdss_cti_trig_out_b1, NA, NA, NA),
+	PINGROUP(38, NA, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(39, cci_async, NA, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(40, NA, NA, NA, NA, qdss_tracedata_a, NA,
+		 atest_combodac_to_gpio_native, NA, NA),
+	PINGROUP(41, sd_write, NA, NA, NA, NA, NA, NA, NA,
+		 atest_combodac_to_gpio_native),
+	PINGROUP(42, gcc_gp1_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(43, gcc_gp2_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(44, gcc_gp3_clk_a, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(45, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(46, NA, NA, atest_combodac_to_gpio_native, NA, NA, NA, NA, NA,
+		 NA),
+	PINGROUP(47, blsp6_spi, NA, qdss_tracedata_b, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA),
+	PINGROUP(48, NA, qdss_cti_trig_in_b1, NA,
+		 atest_combodac_to_gpio_native, NA, NA, NA, NA, NA),
+	PINGROUP(49, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(50, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(51, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(52, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(53, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(54, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(55, uim2_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(56, uim2_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(57, uim2_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(58, uim2_present, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(63, atest_char3, dbg_out, bimc_dte0, NA, NA, NA, NA, NA, NA),
+	PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(65, bimc_dte0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(66, sec_mi2s_mclk_b, pri_mi2s, NA, qdss_tracedata_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(67, atest_char1, ebi_cdc, NA, atest_combodac_to_gpio_native,
+		 NA, NA, NA, NA, NA),
+	PINGROUP(68, atest_char0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(69, audio_ref, cdc_pdm0, pri_mi2s_mclk_b, ebi_cdc, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(70, lpass_slimbus, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(71, lpass_slimbus0, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(72, lpass_slimbus1, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(73, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(74, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(75, wcss_bt, atest_char2, NA, ebi_ch0, NA, NA, NA, NA, NA),
+	PINGROUP(76, wcss_wlan2, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(77, wcss_wlan1, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(78, wcss_wlan0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(79, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(80, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(81, wcss_fm, ext_lpass, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(82, wcss_fm, cri_trng, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(83, wcss_bt, cri_trng1, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(84, wcss_bt, cri_trng0, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(85, pri_mi2s, blsp_spi7, blsp_uart7, NA, NA, NA, NA, NA, NA),
+	PINGROUP(86, pri_mi2s, blsp_spi7, blsp_uart7, qdss_tracedata_b, NA, NA,
+		 NA, NA, NA),
+	PINGROUP(87, pri_mi2s_ws, blsp_spi7, blsp_uart7, blsp_i2c7,
+		 qdss_tracedata_b, gcc_tlmm, NA, NA, NA),
+	PINGROUP(88, pri_mi2s, blsp_spi7, blsp_uart7, blsp_i2c7, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(89, dmic0_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(90, dmic0_data, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(91, NA, NA, NA, NA, NA, qdss_cti_trig_in_a1, NA, NA, NA),
+	PINGROUP(92, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA, NA),
+	PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(94, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+	PINGROUP(95, wsa_io, sec_mi2s, pri_mi2s, NA, NA, NA, NA, NA, NA),
+	PINGROUP(96, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(97, blsp_spi8, blsp_uart8, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(98, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(99, blsp_spi8, blsp_uart8, blsp_i2c8, gcc_plltest, NA, NA, NA,
+		 NA, NA),
+	PINGROUP(100, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(102, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(103, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(105, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(106, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(107, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(108, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(109, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(110, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(111, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(112, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(113, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(114, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(115, NA, NA, nav_pps_in_a, NA, atest_combodac_to_gpio_native,
+		 NA, NA, NA, NA),
+	PINGROUP(116, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(117, NA, modem_tsync, nav_tsync, nav_pps_in_b, nav_pps, NA,
+		 NA, NA, NA),
+	PINGROUP(118, NA, ebi_cdc, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(119, gsm0_tx, NA, ebi_cdc, NA, NA, NA, NA, NA, NA),
+	PINGROUP(120, NA, atest_char, ebi_cdc, NA, atest_tsens, NA, NA, NA, NA),
+	PINGROUP(121, NA, NA, NA, bimc_dte1, NA, NA, NA, NA, NA),
+	PINGROUP(122, NA, ssbi_wtr1, NA, NA, bimc_dte1, NA, NA, NA, NA),
+	PINGROUP(123, NA, ssbi_wtr1, ebi_cdc, NA, NA, NA, NA, NA, NA),
+	PINGROUP(124, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(125, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(127, coex_uart, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(128, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(129, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(130, blsp8_spi, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(131, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(132, qdss_cti_trig_out_a0, NA, NA, NA, NA, NA, NA, NA, NA),
+	PINGROUP(133, qdss_cti_trig_out_a1, NA, NA, NA, NA, NA, NA, NA, NA),
+	SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+	SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+	SDC_QDSD_PINGROUP(sdc1_rclk, 0x10a000, 15, 0),
+	SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+	SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+	SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+	SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+	SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+	SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+	SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+	SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+	SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data msm8937_pinctrl = {
+	.pins = msm8937_pins,
+	.npins = ARRAY_SIZE(msm8937_pins),
+	.functions = msm8937_functions,
+	.nfunctions = ARRAY_SIZE(msm8937_functions),
+	.groups = msm8937_groups,
+	.ngroups = ARRAY_SIZE(msm8937_groups),
+	.ngpios = 134,
+};
+
+static int msm8937_pinctrl_probe(struct platform_device *pdev)
+{
+	return msm_pinctrl_probe(pdev, &msm8937_pinctrl);
+}
+
+static const struct of_device_id msm8937_pinctrl_of_match[] = {
+	{ .compatible = "qcom,msm8937-pinctrl", },
+	{ },
+};
+
+static struct platform_driver msm8937_pinctrl_driver = {
+	.driver = {
+		.name = "msm8937-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = msm8937_pinctrl_of_match,
+	},
+	.probe = msm8937_pinctrl_probe,
+	.remove = msm_pinctrl_remove,
+};
+
+static int __init msm8937_pinctrl_init(void)
+{
+	return platform_driver_register(&msm8937_pinctrl_driver);
+}
+arch_initcall(msm8937_pinctrl_init);
+
+static void __exit msm8937_pinctrl_exit(void)
+{
+	platform_driver_unregister(&msm8937_pinctrl_driver);
+}
+module_exit(msm8937_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI msm8937 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8937_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
index 6ceb39a..c5f1307 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1105,6 +1105,97 @@
 	[106] = SDC_QDSD_PINGROUP(sdc2_data, 0x0, 9, 0),
 };
 
+static struct msm_gpio_mux_input sdxpoorwills_mux_in[] = {
+	{0, 1},
+	{1, 2},
+	{2, 5},
+	{3, 6},
+	{4, 9},
+	{5, 10},
+	{6, 11},
+	{7, 12},
+	{8, 13},
+	{9, 14},
+	{10, 15},
+	{11, 16},
+	{12, 17},
+	{13, 18},
+	{14, 19},
+	{15, 21},
+	{16, 22},
+	{17, 24},
+	{18, 25},
+	{19, 35},
+	{20, 42, 1},
+	{21, 43},
+	{22, 45},
+	{23, 46},
+	{24, 48},
+	{25, 50},
+	{26, 52},
+	{27, 53},
+	{28, 54},
+	{29, 55},
+	{30, 56},
+	{31, 57},
+	{32, 60},
+	{33, 61},
+	{34, 64},
+	{35, 65},
+	{36, 68},
+	{37, 71},
+	{38, 75},
+	{39, 76},
+	{40, 78},
+	{41, 79},
+	{42, 80},
+	{43, 82},
+	{44, 83},
+	{45, 84},
+	{46, 86},
+	{47, 87},
+	{48, 88},
+	{49, 89},
+	{50, 90},
+	{51, 93},
+	{52, 94},
+	{53, 95},
+	{54, 97},
+	{55, 98},
+};
+
+static struct msm_pdc_mux_output sdxpoorwills_mux_out[] = {
+	{0, 167},
+	{0, 168},
+	{0, 169},
+	{0, 170},
+	{0, 171},
+	{0, 172},
+	{0, 173},
+	{0, 174},
+	{0, 175},
+	{0, 176},
+	{0, 177},
+	{0, 178},
+	{0, 179},
+	{0, 180},
+	{0, 181},
+	{0, 182},
+	{0, 183},
+	{0, 184},
+	{0, 185},
+	{0, 186},
+	{0, 187},
+	{0, 188},
+	{0, 189},
+	{0, 190},
+	{0, 191},
+	{0, 192},
+	{0, 193},
+	{0, 194},
+	{0, 195},
+};
+
 static const struct msm_pinctrl_soc_data sdxpoorwills_pinctrl = {
 	.pins = sdxpoorwills_pins,
 	.npins = ARRAY_SIZE(sdxpoorwills_pins),
@@ -1112,6 +1203,11 @@
 	.nfunctions = ARRAY_SIZE(sdxpoorwills_functions),
 	.groups = sdxpoorwills_groups,
 	.ngroups = ARRAY_SIZE(sdxpoorwills_groups),
+	.gpio_mux_in = sdxpoorwills_mux_in,
+	.n_gpio_mux_in = ARRAY_SIZE(sdxpoorwills_mux_in),
+	.pdc_mux_out = sdxpoorwills_mux_out,
+	.n_pdc_mux_out = ARRAY_SIZE(sdxpoorwills_mux_out),
+	.n_pdc_mux_offset = 20,
 	.ngpios = 100,
 };
 
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
index c02aabf..00ca8dc4 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -53,6 +53,8 @@
 #define PCIE20_PARF_DBI_BASE_ADDR_HI   0x354
 #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE        0x358
 #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI     0x35C
+#define PCIE20_PARF_ATU_BASE_ADDR      0x634
+#define PCIE20_PARF_ATU_BASE_ADDR_HI   0x638
 #define PCIE20_PARF_DEVICE_TYPE        0x1000
 
 #define PCIE20_ELBI_VERSION            0x00
@@ -98,6 +100,24 @@
 #define PCIE20_PLR_IATU_LTAR           0x918
 #define PCIE20_PLR_IATU_UTAR           0x91c
 
+#define PCIE20_IATU_BASE(n)            (n * 0x200)
+
+#define PCIE20_IATU_O_CTRL1(n)         (PCIE20_IATU_BASE(n) + 0x00)
+#define PCIE20_IATU_O_CTRL2(n)         (PCIE20_IATU_BASE(n) + 0x04)
+#define PCIE20_IATU_O_LBAR(n)          (PCIE20_IATU_BASE(n) + 0x08)
+#define PCIE20_IATU_O_UBAR(n)          (PCIE20_IATU_BASE(n) + 0x0c)
+#define PCIE20_IATU_O_LAR(n)           (PCIE20_IATU_BASE(n) + 0x10)
+#define PCIE20_IATU_O_LTAR(n)          (PCIE20_IATU_BASE(n) + 0x14)
+#define PCIE20_IATU_O_UTAR(n)          (PCIE20_IATU_BASE(n) + 0x18)
+
+#define PCIE20_IATU_I_CTRL1(n)         (PCIE20_IATU_BASE(n) + 0x100)
+#define PCIE20_IATU_I_CTRL2(n)         (PCIE20_IATU_BASE(n) + 0x104)
+#define PCIE20_IATU_I_LBAR(n)          (PCIE20_IATU_BASE(n) + 0x108)
+#define PCIE20_IATU_I_UBAR(n)          (PCIE20_IATU_BASE(n) + 0x10c)
+#define PCIE20_IATU_I_LAR(n)           (PCIE20_IATU_BASE(n) + 0x110)
+#define PCIE20_IATU_I_LTAR(n)          (PCIE20_IATU_BASE(n) + 0x114)
+#define PCIE20_IATU_I_UTAR(n)          (PCIE20_IATU_BASE(n) + 0x118)
+
 #define PCIE20_MHICFG                  0x110
 #define PCIE20_BHI_EXECENV             0x228
 
@@ -129,7 +149,7 @@
 
 #define EP_PCIE_LOG_PAGES 50
 #define EP_PCIE_MAX_VREG 2
-#define EP_PCIE_MAX_CLK 5
+#define EP_PCIE_MAX_CLK 7
 #define EP_PCIE_MAX_PIPE_CLK 1
 #define EP_PCIE_MAX_RESET 2
 
@@ -202,6 +222,7 @@
 	EP_PCIE_RES_MSI,
 	EP_PCIE_RES_DM_CORE,
 	EP_PCIE_RES_ELBI,
+	EP_PCIE_RES_IATU,
 	EP_PCIE_MAX_RES,
 };
 
@@ -292,6 +313,7 @@
 	void __iomem                 *msi;
 	void __iomem                 *dm_core;
 	void __iomem                 *elbi;
+	void __iomem                 *iatu;
 
 	struct msm_bus_scale_pdata   *bus_scale_table;
 	u32                          bus_client;
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
index e48409b..055f026 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -68,6 +68,8 @@
 	{NULL, "pcie_0_slv_axi_clk", 0, true},
 	{NULL, "pcie_0_aux_clk", 1000000, true},
 	{NULL, "pcie_0_ldo", 0, true},
+	{NULL, "pcie_0_sleep_clk", 0, false},
+	{NULL, "pcie_0_slv_q2a_axi_clk", 0, false},
 };
 
 static struct ep_pcie_clk_info_t
@@ -82,12 +84,13 @@
 };
 
 static const struct ep_pcie_res_info_t ep_pcie_res_info[EP_PCIE_MAX_RES] = {
-	{"parf",	0, 0},
-	{"phy",		0, 0},
-	{"mmio",	0, 0},
-	{"msi",		0, 0},
-	{"dm_core",	0, 0},
-	{"elbi",	0, 0}
+	{"parf",	NULL, NULL},
+	{"phy",		NULL, NULL},
+	{"mmio",	NULL, NULL},
+	{"msi",		NULL, NULL},
+	{"dm_core",	NULL, NULL},
+	{"elbi",	NULL, NULL},
+	{"iatu",	NULL, NULL},
 };
 
 static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = {
@@ -318,8 +321,8 @@
 				break;
 			}
 			EP_PCIE_DBG(dev,
-				"PCIe V%d: set rate for clk %s.\n",
-				dev->rev, info->name);
+				"PCIe V%d: set rate %d for clk %s.\n",
+				dev->rev, info->freq, info->name);
 		}
 
 		rc = clk_prepare_enable(info->hdl);
@@ -528,6 +531,47 @@
 				0xf, dev->link_speed);
 	}
 
+	if (dev->active_config) {
+		struct resource *dbi = dev->res[EP_PCIE_RES_DM_CORE].resource;
+		u32 dbi_lo = dbi->start;
+
+		EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
+		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
+
+		ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
+					0, BIT(0));
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
+					0x200);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
+					0x0);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
+					0x100);
+		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
+					dbi_lo);
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: DBI base:0x%x.\n", dev->rev,
+			readl_relaxed(dev->parf + PCIE20_PARF_DBI_BASE_ADDR));
+
+		if (dev->phy_rev >= 6) {
+			struct resource *atu =
+					dev->res[EP_PCIE_RES_IATU].resource;
+			u32 atu_lo = atu->start;
+
+			EP_PCIE_DBG(dev,
+				"PCIe V%d: configure MSB of ATU base for flipping and LSB as 0x%x.\n",
+				dev->rev, atu_lo);
+			ep_pcie_write_reg(dev->parf,
+					PCIE20_PARF_ATU_BASE_ADDR_HI, 0x100);
+			ep_pcie_write_reg(dev->parf, PCIE20_PARF_ATU_BASE_ADDR,
+					atu_lo);
+			EP_PCIE_DBG(dev,
+				"PCIe V%d: LSB of ATU base:0x%x.\n",
+				dev->rev, readl_relaxed(dev->parf
+						+ PCIE20_PARF_ATU_BASE_ADDR));
+		}
+	}
+
 	/* Read halts write */
 	ep_pcie_write_mask(dev->parf + PCIE20_PARF_AXI_MSTR_RD_HALT_NO_WRITES,
 			0, BIT(0));
@@ -646,13 +690,6 @@
 			dev->rev,
 			readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK));
 	}
-
-	if (dev->active_config) {
-		ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
-
-		EP_PCIE_DBG2(dev, "PCIe V%d: Enable L1.\n", dev->rev);
-		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
-	}
 }
 
 static void ep_pcie_config_inbound_iatu(struct ep_pcie_dev_t *dev)
@@ -671,6 +708,26 @@
 	ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_LOWER, lower);
 	ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_BASE_ADDR_UPPER, 0x0);
 
+	if (dev->phy_rev >= 6) {
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL1(0), 0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_LTAR(0), lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_UTAR(0), 0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_I_CTRL2(0),
+					0xc0000000);
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: Inbound iATU configuration.\n", dev->rev);
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL1(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL1(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_LTAR(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_LTAR(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_UTAR(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_UTAR(0)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_I_CTRL2(0):0x%x\n",
+			readl_relaxed(dev->iatu + PCIE20_IATU_I_CTRL2(0)));
+		return;
+	}
+
 	/* program inbound address translation using region 0 */
 	ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, 0x80000000);
 	/* set region to mem type */
@@ -701,6 +758,49 @@
 		"PCIe V%d: region:%d; lower:0x%x; limit:0x%x; target_lower:0x%x; target_upper:0x%x\n",
 		dev->rev, region, lower, limit, tgt_lower, tgt_upper);
 
+	if (dev->phy_rev >= 6) {
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_CTRL1(region),
+					0x0);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LBAR(region),
+					lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UBAR(region),
+					upper);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LAR(region),
+					limit);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_LTAR(region),
+					tgt_lower);
+		ep_pcie_write_reg(dev->iatu, PCIE20_IATU_O_UTAR(region),
+					tgt_upper);
+		ep_pcie_write_mask(dev->iatu + PCIE20_IATU_O_CTRL2(region),
+					0, BIT(31));
+
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: Outbound iATU configuration.\n", dev->rev);
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL1:0x%x\n",
+			readl_relaxed(dev->iatu
+					+ PCIE20_IATU_O_CTRL1(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LBAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LBAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_UBAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_UBAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_LTAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_LTAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_UTAR:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_UTAR(region)));
+		EP_PCIE_DBG(dev, "PCIE20_IATU_O_CTRL2:0x%x\n",
+			readl_relaxed(dev->iatu +
+					PCIE20_IATU_O_CTRL2(region)));
+
+		return;
+	}
+
 	/* program outbound address translation using an input region */
 	ep_pcie_write_reg(dev->dm_core, PCIE20_PLR_IATU_VIEWPORT, region);
 	/* set region to mem type */
@@ -813,12 +913,10 @@
 		ret = of_property_read_u32_array(
 			(&pdev->dev)->of_node,
 			"max-clock-frequency-hz", clkfreq, cnt);
-		if (ret) {
-			EP_PCIE_ERR(dev,
-				"PCIe V%d: invalid max-clock-frequency-hz property:%d\n",
+		if (ret)
+			EP_PCIE_DBG2(dev,
+				"PCIe V%d: cannot get max-clock-frequency-hz property from DT:%d\n",
 				dev->rev, ret);
-			goto out;
-		}
 	}
 
 	for (i = 0; i < EP_PCIE_MAX_VREG; i++) {
@@ -1037,6 +1135,7 @@
 	dev->msi = dev->res[EP_PCIE_RES_MSI].base;
 	dev->dm_core = dev->res[EP_PCIE_RES_DM_CORE].base;
 	dev->elbi = dev->res[EP_PCIE_RES_ELBI].base;
+	dev->iatu = dev->res[EP_PCIE_RES_IATU].base;
 
 out:
 	kfree(clkfreq);
@@ -1051,6 +1150,7 @@
 	dev->phy = NULL;
 	dev->mmio = NULL;
 	dev->msi = NULL;
+	dev->iatu = NULL;
 
 	if (dev->bus_client) {
 		msm_bus_scale_unregister_client(dev->bus_client);
@@ -1319,18 +1419,8 @@
 	}
 
 checkbme:
-	if (dev->active_config) {
-		ep_pcie_write_mask(dev->parf + PCIE20_PARF_SLV_ADDR_MSB_CTRL,
-					0, BIT(0));
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE_HI,
-					0x200);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE,
-					0x0);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR_HI,
-					0x100);
-		ep_pcie_write_reg(dev->parf, PCIE20_PARF_DBI_BASE_ADDR,
-					0x7FFFE000);
-	}
+	if (dev->active_config)
+		ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14);
 
 	if (!(opt & EP_PCIE_OPT_ENUM_ASYNC)) {
 		/* Wait for up to 1000ms for BME to be set */
diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
index 776ef08..f813bb9 100644
--- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
+++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,11 @@
 			"PCIe V%d: PHY V%d: Initializing 10nm QMP phy - 100MHz\n",
 			dev->rev, dev->phy_rev);
 		break;
+	case 6:
+		EP_PCIE_DBG(dev,
+			"PCIe V%d: PHY V%d: Initializing 7nm QMP phy - 100MHz\n",
+			dev->rev, dev->phy_rev);
+		break;
 	default:
 		EP_PCIE_ERR(dev,
 			"PCIe V%d: Unexpected phy version %d is caught!\n",
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index a8946bf..e23541c 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -747,6 +747,10 @@
 		&ipa3_usb_ctx->ttype_ctx[ttype];
 	int result;
 
+	/* there is one PM resource for teth and one for DPL */
+	if (!IPA3_USB_IS_TTYPE_DPL(ttype) && ipa3_usb_ctx->num_init_prot > 0)
+		return 0;
+
 	memset(&ttype_ctx->pm_ctx.reg_params, 0,
 		sizeof(ttype_ctx->pm_ctx.reg_params));
 	ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
@@ -1026,11 +1030,11 @@
 	return 0;
 
 teth_prot_init_fail:
-	if (ipa_pm_is_used()) {
-		ipa3_usb_deregister_pm(ttype);
-	} else {
-		if ((IPA3_USB_IS_TTYPE_DPL(ttype))
-			|| (ipa3_usb_ctx->num_init_prot == 0)) {
+	if ((IPA3_USB_IS_TTYPE_DPL(ttype))
+		|| (ipa3_usb_ctx->num_init_prot == 0)) {
+		if (ipa_pm_is_used()) {
+			ipa3_usb_deregister_pm(ttype);
+		} else {
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
 				false;
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
@@ -2539,14 +2543,15 @@
 		goto bad_params;
 	}
 
-	if (ipa_pm_is_used()) {
-		ipa3_usb_deregister_pm(ttype);
-	} else {
-		if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
-			(ipa3_usb_ctx->num_init_prot == 0)) {
-			if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
-				IPA_USB_ERR(
-					"failed to change state to invalid\n");
+	if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
+		(ipa3_usb_ctx->num_init_prot == 0)) {
+		if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
+			IPA_USB_ERR(
+				"failed to change state to invalid\n");
+		if (ipa_pm_is_used()) {
+			ipa3_usb_deregister_pm(ttype);
+			ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
+		} else {
 			ipa_rm_delete_resource(
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
index 4f60896..ad23d82 100644
--- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -574,13 +574,15 @@
 		goto fail_set_device_ethernet;
 	}
 	RNDIS_IPA_DEBUG("Device Ethernet address set %pM\n", net->dev_addr);
-
+#ifdef CONFIG_IPA3
 	if (ipa_is_vlan_mode(IPA_VLAN_IF_RNDIS,
 		&rndis_ipa_ctx->is_vlan_mode)) {
 		RNDIS_IPA_ERROR("couldn't acquire vlan mode, is ipa ready?\n");
-		goto fail_get_vlan_mode;
+		goto fail_hdrs_cfg;
 	}
-
+#else
+	rndis_ipa_ctx->is_vlan_mode = 0;
+#endif
 	RNDIS_IPA_DEBUG("is_vlan_mode %d\n", rndis_ipa_ctx->is_vlan_mode);
 
 	result = rndis_ipa_hdrs_cfg
@@ -631,7 +633,6 @@
 fail_register_tx:
 	rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
 fail_hdrs_cfg:
-fail_get_vlan_mode:
 fail_set_device_ethernet:
 	rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
 fail_netdev_priv:
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index f19e9d6..52ffa52 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3591,8 +3591,8 @@
 		IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 	} else {
 		IPADBG_LOW("clocks are gated, not setting rate\n");
+		ipa_active_clients_unlock();
 	}
-	ipa_active_clients_unlock();
 	IPADBG_LOW("Done\n");
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index 37614cc..f062ed2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1455,7 +1455,11 @@
 	pr_err("Table Size:%d\n",
 				ipa_ctx->nat_mem.size_base_tables);
 
-	pr_err("Expansion Table Size:%d\n",
+	if (!ipa_ctx->nat_mem.size_expansion_tables)
+		pr_err("Expansion Table Size:%d\n",
+				ipa_ctx->nat_mem.size_expansion_tables);
+	else
+		pr_err("Expansion Table Size:%d\n",
 				ipa_ctx->nat_mem.size_expansion_tables-1);
 
 	if (!ipa_ctx->nat_mem.is_sys_mem)
@@ -1470,6 +1474,8 @@
 
 			pr_err("\nBase Table:\n");
 		} else {
+			if (!ipa_ctx->nat_mem.size_expansion_tables)
+				continue;
 			tbl_size = ipa_ctx->nat_mem.size_expansion_tables-1;
 			base_tbl =
 			 (u32 *)ipa_ctx->nat_mem.ipv4_expansion_rules_addr;
@@ -1569,6 +1575,8 @@
 
 			pr_err("\nIndex Table:\n");
 		} else {
+			if (!ipa_ctx->nat_mem.size_expansion_tables)
+				continue;
 			tbl_size = ipa_ctx->nat_mem.size_expansion_tables-1;
 			indx_tbl =
 			 (u32 *)ipa_ctx->nat_mem.index_table_expansion_addr;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 227a12a..a3db092 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -103,7 +103,7 @@
 		entry->hw_len = buf - start;
 	} else if (entry->hw_len != (buf - start)) {
 		IPAERR(
-		"hw_len differs b/w passes passed=0x%x calc=0x%lxtd\n",
+		"hw_len differs b/w passes passed=0x%x calc=0x%zxtd\n",
 		entry->hw_len,
 		(buf - start));
 		return -EPERM;
@@ -197,7 +197,7 @@
 	if (entry->hw_len == 0) {
 		entry->hw_len = buf - start;
 	} else if (entry->hw_len != (buf - start)) {
-		IPAERR("hw_len differs b/w passes passed=0x%x calc=0x%lxtd\n",
+		IPAERR("hw_len differs b/w passes passed=0x%x calc=0x%zxtd\n",
 			entry->hw_len, (buf - start));
 		return -EPERM;
 	}
@@ -1145,6 +1145,15 @@
 		return -EINVAL;
 	}
 
+	if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
+		IPADBG("Deleting rule from default rt table idx=%u\n",
+			entry->tbl->idx);
+		if (entry->tbl->rule_cnt == 1) {
+			IPAERR_RL("Default tbl last rule cannot be deleted\n");
+			return -EINVAL;
+		}
+	}
+
 	if (entry->hdr)
 		__ipa_release_hdr(entry->hdr->id);
 	else if (entry->proc_ctx)
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
index a454382..cf8f0b8 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -583,7 +583,8 @@
 {
 	IPADBG("--res_idx=%d pa=0x%pa iova=0x%lx sz=0x%zx\n", res_idx,
 			&pa, iova, len);
-	wdi_res[res_idx].res = kzalloc(sizeof(struct ipa_wdi_res), GFP_KERNEL);
+	wdi_res[res_idx].res = kzalloc(sizeof(*wdi_res[res_idx].res),
+					GFP_KERNEL);
 	if (!wdi_res[res_idx].res)
 		BUG();
 	wdi_res[res_idx].nents = 1;
@@ -609,8 +610,8 @@
 		return;
 	}
 
-	wdi_res[res_idx].res = kcalloc(sgt->nents, sizeof(struct ipa_wdi_res),
-			GFP_KERNEL);
+	wdi_res[res_idx].res = kcalloc(sgt->nents,
+		sizeof(*wdi_res[res_idx].res), GFP_KERNEL);
 	if (!wdi_res[res_idx].res)
 		BUG();
 	wdi_res[res_idx].nents = sgt->nents;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 8a3fbd4..e06f6cf 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -161,6 +161,7 @@
 	[IPA_2_0][IPA_CLIENT_TEST4_CONS]         = {true, 15},
 
 
+	[IPA_2_6L][IPA_CLIENT_USB_PROD]          =  {true,  1},
 	[IPA_2_6L][IPA_CLIENT_APPS_LAN_WAN_PROD]  = {true,  4},
 	[IPA_2_6L][IPA_CLIENT_APPS_CMD_PROD]      = {true,  3},
 	[IPA_2_6L][IPA_CLIENT_Q6_LAN_PROD]        = {true,  6},
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 5b2d13a..068c6c5 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -1661,6 +1661,7 @@
 				IPAWANERR("Failed to allocate memory.\n");
 				return -ENOMEM;
 			}
+			extend_ioctl_data.u.if_name[IFNAMSIZ-1] = '\0';
 			len = sizeof(wan_msg->upstream_ifname) >
 			sizeof(extend_ioctl_data.u.if_name) ?
 				sizeof(extend_ioctl_data.u.if_name) :
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index ae24675..da3b399 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -4394,6 +4394,8 @@
 	/* Prevent consequent calls from trying to load the FW again. */
 	if (ipa3_ctx->ipa_initialization_complete)
 		return 0;
+	/* move proxy vote for modem on ipa3_post_init */
+	IPA_ACTIVE_CLIENTS_INC_SPECIAL("PROXY_CLK_VOTE");
 
 	/*
 	 * indication whether working in MHI config or non MHI config is given
@@ -4858,7 +4860,6 @@
 	int result = 0;
 	int i;
 	struct ipa3_rt_tbl_set *rset;
-	struct ipa_active_client_logging_info log_info;
 
 	IPADBG("IPA Driver initialization started\n");
 
@@ -5049,8 +5050,7 @@
 	}
 
 	mutex_init(&ipa3_ctx->ipa3_active_clients.mutex);
-	IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "PROXY_CLK_VOTE");
-	ipa3_active_clients_log_inc(&log_info, false);
+	/* move proxy vote for modem to ipa3_post_init() */
 	atomic_set(&ipa3_ctx->ipa3_active_clients.cnt, 1);
 
 	/* Create workqueues for power management */
@@ -5296,6 +5296,8 @@
 	IPADBG("ipa cdev added successful. major:%d minor:%d\n",
 			MAJOR(ipa3_ctx->dev_num),
 			MINOR(ipa3_ctx->dev_num));
+	/* proxy vote for modem is added in ipa3_post_init() phase */
+	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 	return 0;
 
 fail_cdev_add:
@@ -5971,6 +5973,7 @@
 	int bypass = 1;
 	u32 iova_ap_mapping[2];
 	u32 add_map_size;
+	u32 q6_smem_size;
 	const u32 *add_map;
 	void *smem_addr;
 	int i;
@@ -6087,9 +6090,18 @@
 		}
 	}
 
-	/* map SMEM memory for IPA table accesses */
-	smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
-		SMEM_MODEM, 0);
+	result = of_property_read_u32_array(dev->of_node,
+			"qcom,ipa-q6-smem-size", &q6_smem_size, 1);
+	if (result) {
+		IPADBG("ipa q6 smem size = %d\n", IPA_SMEM_SIZE);
+		/* map SMEM memory for IPA table accesses */
+		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, IPA_SMEM_SIZE,
+				SMEM_MODEM, 0);
+	} else {
+		IPADBG("ipa q6 smem size = %d\n", q6_smem_size);
+		smem_addr = smem_alloc(SMEM_IPA_FILTER_TABLE, q6_smem_size,
+				SMEM_MODEM, 0);
+	}
 	if (smem_addr) {
 		phys_addr_t iova = smem_virt_to_phys(smem_addr);
 		phys_addr_t pa = iova;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
index 80a39b5..140afa8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
@@ -156,6 +156,7 @@
  * @activate_work: work for activate (blocking case)
  * @deactivate work: delayed work for deferred_deactivate function
  * @complete: generic wait-for-completion handler
+ * @wlock: wake source to prevent AP suspend
  */
 struct ipa_pm_client {
 	char name[IPA_PM_MAX_EX_CL];
@@ -170,6 +171,7 @@
 	struct work_struct activate_work;
 	struct delayed_work deactivate_work;
 	struct completion complete;
+	struct wakeup_source wlock;
 };
 
 /*
@@ -395,8 +397,11 @@
 	unsigned long flags;
 
 	client = container_of(work, struct ipa_pm_client, activate_work);
-	if (!client->skip_clk_vote)
+	if (!client->skip_clk_vote) {
 		IPA_ACTIVE_CLIENTS_INC_SPECIAL(client->name);
+		if (client->group == IPA_PM_GROUP_APPS)
+			__pm_stay_awake(&client->wlock);
+	}
 
 	spin_lock_irqsave(&client->state_lock, flags);
 	IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
@@ -414,8 +419,11 @@
 	complete_all(&client->complete);
 
 	if (dec_clk) {
-		if (!client->skip_clk_vote)
+		if (!client->skip_clk_vote) {
 			IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+			if (client->group == IPA_PM_GROUP_APPS)
+				__pm_relax(&client->wlock);
+		}
 
 		IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
 		return;
@@ -464,8 +472,11 @@
 		client->state = IPA_PM_DEACTIVATED;
 		IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
 		spin_unlock_irqrestore(&client->state_lock, flags);
-		if (!client->skip_clk_vote)
+		if (!client->skip_clk_vote) {
 			IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+			if (client->group == IPA_PM_GROUP_APPS)
+				__pm_relax(&client->wlock);
+		}
 
 		deactivate_client(client->hdl);
 		do_clk_scaling();
@@ -669,7 +680,7 @@
 }
 
 /**
- * ipa_rm_delete_register() - register an IPA PM client with the PM
+ * ipa_pm_register() - register an IPA PM client with the PM
  * @register_params: params for a client like throughput, callback, etc.
  * @hdl: int pointer that will be used as an index to access the client
  *
@@ -681,6 +692,7 @@
 int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl)
 {
 	struct ipa_pm_client *client;
+	struct wakeup_source *wlock;
 
 	if (ipa_pm_ctx == NULL) {
 		IPA_PM_ERR("PM_ctx is null\n");
@@ -729,6 +741,8 @@
 	client->group = params->group;
 	client->hdl = *hdl;
 	client->skip_clk_vote = params->skip_clk_vote;
+	wlock = &client->wlock;
+	wakeup_source_init(wlock, client->name);
 
 	/* add client to exception list */
 	if (add_client_to_exception_list(*hdl)) {
@@ -792,6 +806,7 @@
 		if (ipa_pm_ctx->clients_by_pipe[i] == ipa_pm_ctx->clients[hdl])
 			ipa_pm_ctx->clients_by_pipe[i] = NULL;
 	}
+	wakeup_source_trash(&client->wlock);
 	kfree(client);
 	ipa_pm_ctx->clients[hdl] = NULL;
 
@@ -909,6 +924,8 @@
 	/* we got the clocks */
 	if (result == 0) {
 		client->state = IPA_PM_ACTIVATED;
+		if (client->group == IPA_PM_GROUP_APPS)
+			__pm_stay_awake(&client->wlock);
 		spin_unlock_irqrestore(&client->state_lock, flags);
 		activate_client(client->hdl);
 		if (sync)
@@ -1072,8 +1089,11 @@
 			IPA_PM_DBG_STATE(client->hdl, client->name,
 				client->state);
 			spin_unlock_irqrestore(&client->state_lock, flags);
-			if (!client->skip_clk_vote)
+			if (!client->skip_clk_vote) {
 				IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+				if (client->group == IPA_PM_GROUP_APPS)
+					__pm_relax(&client->wlock);
+			}
 			deactivate_client(client->hdl);
 		} else /* if activated or deactivated, we do nothing */
 			spin_unlock_irqrestore(&client->state_lock, flags);
@@ -1124,8 +1144,11 @@
 	spin_unlock_irqrestore(&client->state_lock, flags);
 
 	/* else case (Deactivates all Activated cases)*/
-	if (!client->skip_clk_vote)
+	if (!client->skip_clk_vote) {
 		IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
+		if (client->group == IPA_PM_GROUP_APPS)
+			__pm_relax(&client->wlock);
+	}
 
 	spin_lock_irqsave(&client->state_lock, flags);
 	client->state = IPA_PM_DEACTIVATED;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index fc76604..1bdc0fb 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1282,6 +1282,15 @@
 		return -EINVAL;
 	}
 
+	if (!strcmp(entry->tbl->name, IPA_DFLT_RT_TBL_NAME)) {
+		IPADBG("Deleting rule from default rt table idx=%u\n",
+			entry->tbl->idx);
+		if (entry->tbl->rule_cnt == 1) {
+			IPAERR_RL("Default tbl last rule cannot be deleted\n");
+			return -EINVAL;
+		}
+	}
+
 	if (entry->hdr)
 		__ipa3_release_hdr(entry->hdr->id);
 	else if (entry->proc_ctx)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 941e489..648db5e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1209,8 +1209,6 @@
 		IPADBG("Skipping endpoint configuration.\n");
 	}
 
-	ipa3_enable_data_path(ipa_ep_idx);
-
 	out->clnt_hdl = ipa_ep_idx;
 
 	if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
@@ -1316,6 +1314,7 @@
 	struct ipa3_ep_context *ep;
 	union IpaHwWdiCommonChCmdData_t enable;
 	struct ipa_ep_cfg_holb holb_cfg;
+	struct ipahal_reg_endp_init_rsrc_grp rsrc_grp;
 
 	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
 	    ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1348,6 +1347,20 @@
 		goto uc_timeout;
 	}
 
+	/* Assign the resource group for pipe */
+	memset(&rsrc_grp, 0, sizeof(rsrc_grp));
+	rsrc_grp.rsrc_grp = ipa_get_ep_group(ep->client);
+	if (rsrc_grp.rsrc_grp == -1) {
+		IPAERR("invalid group for client %d\n", ep->client);
+		WARN_ON(1);
+		return -EFAULT;
+	}
+
+	IPADBG("Setting group %d for pipe %d\n",
+		rsrc_grp.rsrc_grp, clnt_hdl);
+	ipahal_write_reg_n_fields(IPA_ENDP_INIT_RSRC_GRP_n, clnt_hdl,
+		&rsrc_grp);
+
 	if (IPA_CLIENT_IS_CONS(ep->client)) {
 		memset(&holb_cfg, 0, sizeof(holb_cfg));
 		holb_cfg.en = IPA_HOLB_TMR_DIS;
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index bf3a8c9..2d86200 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1740,6 +1740,7 @@
 				IPAWANERR("Failed to allocate memory.\n");
 				return -ENOMEM;
 			}
+			extend_ioctl_data.u.if_name[IFNAMSIZ-1] = '\0';
 			len = sizeof(wan_msg->upstream_ifname) >
 			sizeof(extend_ioctl_data.u.if_name) ?
 				sizeof(extend_ioctl_data.u.if_name) :
@@ -4025,9 +4026,10 @@
 	ipa3_qmi_init();
 
 	/* Register for Modem SSR */
-	/* SSR is not supported yet on IPA 4.0 */
-	if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_0)
-		return platform_driver_register(&rmnet_ipa_driver);
+	if (ipa3_ctx != NULL)
+		/* SSR is not supported yet on IPA 4.0 */
+		if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_0)
+			return platform_driver_register(&rmnet_ipa_driver);
 
 	rmnet_ipa3_ctx->subsys_notify_handle = subsys_notif_register_notifier(
 			SUBSYS_MODEM,
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 5d094d2..348b287 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -31,6 +31,14 @@
 #define GENI_SE_IOMMU_VA_START	(0x40000000)
 #define GENI_SE_IOMMU_VA_SIZE	(0xC0000000)
 
+#ifdef CONFIG_ARM64
+#define GENI_SE_DMA_PTR_L(ptr) ((u32)ptr)
+#define GENI_SE_DMA_PTR_H(ptr) ((u32)(ptr >> 32))
+#else
+#define GENI_SE_DMA_PTR_L(ptr) ((u32)ptr)
+#define GENI_SE_DMA_PTR_H(ptr) 0
+#endif
+
 #define NUM_LOG_PAGES 2
 #define MAX_CLK_PERF_LEVEL 32
 static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, 100000000};
@@ -999,8 +1007,8 @@
 		return ret;
 
 	geni_write_reg(7, base, SE_DMA_TX_IRQ_EN_SET);
-	geni_write_reg((u32)(*tx_dma), base, SE_DMA_TX_PTR_L);
-	geni_write_reg((u32)((*tx_dma) >> 32), base, SE_DMA_TX_PTR_H);
+	geni_write_reg(GENI_SE_DMA_PTR_L(*tx_dma), base, SE_DMA_TX_PTR_L);
+	geni_write_reg(GENI_SE_DMA_PTR_H(*tx_dma), base, SE_DMA_TX_PTR_H);
 	geni_write_reg(1, base, SE_DMA_TX_ATTR);
 	geni_write_reg(tx_len, base, SE_DMA_TX_LEN);
 	return 0;
@@ -1033,8 +1041,8 @@
 		return ret;
 
 	geni_write_reg(7, base, SE_DMA_RX_IRQ_EN_SET);
-	geni_write_reg((u32)(*rx_dma), base, SE_DMA_RX_PTR_L);
-	geni_write_reg((u32)((*rx_dma) >> 32), base, SE_DMA_RX_PTR_H);
+	geni_write_reg(GENI_SE_DMA_PTR_L(*rx_dma), base, SE_DMA_RX_PTR_L);
+	geni_write_reg(GENI_SE_DMA_PTR_H(*rx_dma), base, SE_DMA_RX_PTR_H);
 	/* RX does not have EOT bit */
 	geni_write_reg(0, base, SE_DMA_RX_ATTR);
 	geni_write_reg(rx_len, base, SE_DMA_RX_LEN);
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 684aec8..05e8172 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -61,6 +61,9 @@
 	[PM660_SUBTYPE] = "PM660",
 	[PMI632_SUBTYPE] = "PMI632",
 	[PMI8937_SUBTYPE] = "PMI8937",
+	[PM855_SUBTYPE] = "PM855",
+	[PM855B_SUBTYPE] = "PM855B",
+	[PM855L_SUBTYPE] = "PM855L",
 };
 
 struct revid_chip {
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 95e3782..dec698f 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -3139,7 +3139,8 @@
 	}
 
 	dev = &ctx->usb_bam_pdev->dev;
-	if (dev && dev->parent && !device_property_present(dev->parent,
+	if (dev && dev->parent && device_property_present(dev->parent, "iommus")
+		&& !device_property_present(dev->parent,
 						"qcom,smmu-s1-bypass")) {
 		pr_info("%s: setting SPS_BAM_SMMU_EN flag with (%s)\n",
 						__func__, dev_name(dev));
diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c
index b0b1eb3..76153ac 100644
--- a/drivers/power/reset/zx-reboot.c
+++ b/drivers/power/reset/zx-reboot.c
@@ -81,3 +81,7 @@
 	},
 };
 module_platform_driver(zx_reboot_driver);
+
+MODULE_DESCRIPTION("ZTE SoCs reset driver");
+MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 819fbf0..6adb44c 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -321,8 +321,11 @@
 	POWER_SUPPLY_ATTR(sdp_current_max),
 	POWER_SUPPLY_ATTR(connector_type),
 	POWER_SUPPLY_ATTR(parallel_batfet_mode),
+	POWER_SUPPLY_ATTR(parallel_fcc_max),
 	POWER_SUPPLY_ATTR(min_icl),
 	POWER_SUPPLY_ATTR(moisture_detected),
+	POWER_SUPPLY_ATTR(batt_full_current),
+	POWER_SUPPLY_ATTR(recharge_soc),
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_ATTR(charge_counter_ext),
 	/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig
index 35aa6cc..c8e731a 100644
--- a/drivers/power/supply/qcom/Kconfig
+++ b/drivers/power/supply/qcom/Kconfig
@@ -62,6 +62,19 @@
 	  VBUS and VCONN regulators are registered for supporting OTG,
 	  and powered Type-C cables respectively.
 
+config QPNP_SMB5
+	tristate "SMB5 Battery Charger"
+	depends on MFD_SPMI_PMIC
+	help
+	  Say Y to enables support for the SMB5 charging peripheral.
+	  The QPNP SMB5 charger driver supports the charger peripheral
+	  present in the chip.
+	  The power supply framework is used to communicate battery and
+	  usb properties to userspace and other driver consumers such
+	  as fuel gauge, USB, and USB-PD.
+	  VBUS and VCONN regulators are registered for supporting OTG,
+	  and powered Type-C cables respectively.
+
 config SMB138X_CHARGER
 	tristate "SMB138X Battery Charger"
 	depends on MFD_I2C_PMIC
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index 7350c30..870a67e 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -8,3 +8,4 @@
 obj-$(CONFIG_SMB138X_CHARGER)	+= step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o
 obj-$(CONFIG_QPNP_QNOVO)	+= qpnp-qnovo.o battery.o
 obj-$(CONFIG_QPNP_TYPEC)	+= qpnp-typec.o
+obj-$(CONFIG_QPNP_SMB5)		+= step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 3f8c727..223af14 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -73,6 +73,7 @@
 	int			charge_type;
 	int			total_settled_ua;
 	int			pl_settled_ua;
+	int			pl_fcc_max;
 	struct class		qcom_batt_class;
 	struct wakeup_source	*pl_ws;
 	struct notifier_block	nb;
@@ -418,6 +419,7 @@
 	effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
 	slave_limited_ua = min(effective_total_ua, bcl_ua);
 	*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
+	*slave_ua = min(*slave_ua, chip->pl_fcc_max);
 
 	/*
 	 * In stacked BATFET configuration charger's current goes
@@ -935,6 +937,12 @@
 					&pval);
 	chip->pl_min_icl_ua = pval.intval;
 
+	chip->pl_fcc_max = INT_MAX;
+	rc = power_supply_get_property(chip->pl_psy,
+			POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, &pval);
+	if (!rc)
+		chip->pl_fcc_max = pval.intval;
+
 	vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
 
 	return true;
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 99120f4..a2a35c6 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -170,6 +170,7 @@
 	FG_SRAM_SYS_TERM_CURR,
 	FG_SRAM_CHG_TERM_CURR,
 	FG_SRAM_CHG_TERM_BASE_CURR,
+	FG_SRAM_CUTOFF_CURR,
 	FG_SRAM_DELTA_MSOC_THR,
 	FG_SRAM_DELTA_BSOC_THR,
 	FG_SRAM_RECHARGE_SOC_THR,
@@ -262,6 +263,7 @@
 	int	chg_term_curr_ma;
 	int	chg_term_base_curr_ma;
 	int	sys_term_curr_ma;
+	int	cutoff_curr_ma;
 	int	delta_soc_thr;
 	int	recharge_soc_thr;
 	int	recharge_volt_thr_mv;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 2c62218..0894f37 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -35,6 +35,8 @@
 #define ESR_PULSE_THRESH_OFFSET		3
 #define SLOPE_LIMIT_WORD		3
 #define SLOPE_LIMIT_OFFSET		0
+#define CUTOFF_CURR_WORD		4
+#define CUTOFF_CURR_OFFSET		0
 #define CUTOFF_VOLT_WORD		5
 #define CUTOFF_VOLT_OFFSET		0
 #define SYS_TERM_CURR_WORD		6
@@ -208,6 +210,8 @@
 		1000000, 122070, 0, fg_encode_current, NULL),
 	PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1,
 		100000, 390625, 0, fg_encode_current, NULL),
+	PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3,
+		1000000, 122070, 0, fg_encode_current, NULL),
 	PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_WORD, DELTA_MSOC_THR_OFFSET, 1,
 		2048, 100, 0, fg_encode_default, NULL),
 	PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_WORD, DELTA_BSOC_THR_OFFSET, 1,
@@ -284,6 +288,8 @@
 	PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD,
 		CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0,
 		fg_encode_current, NULL),
+	PARAM(CUTOFF_CURR, CUTOFF_CURR_WORD, CUTOFF_CURR_OFFSET, 3,
+		1000000, 122070, 0, fg_encode_current, NULL),
 	PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET,
 		1, 2048, 100, 0, fg_encode_default, NULL),
 	PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET,
@@ -3974,6 +3980,16 @@
 		return rc;
 	}
 
+	fg_encode(chip->sp, FG_SRAM_CUTOFF_CURR, chip->dt.cutoff_curr_ma,
+		buf);
+	rc = fg_sram_write(chip, chip->sp[FG_SRAM_CUTOFF_CURR].addr_word,
+			chip->sp[FG_SRAM_CUTOFF_CURR].addr_byte, buf,
+			chip->sp[FG_SRAM_CUTOFF_CURR].len, FG_IMA_DEFAULT);
+	if (rc < 0) {
+		pr_err("Error in writing cutoff_curr, rc=%d\n", rc);
+		return rc;
+	}
+
 	if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
 		fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
 			chip->dt.chg_term_base_curr_ma, buf);
@@ -4697,6 +4713,7 @@
 #define DEFAULT_CHG_TERM_CURR_MA	100
 #define DEFAULT_CHG_TERM_BASE_CURR_MA	75
 #define DEFAULT_SYS_TERM_CURR_MA	-125
+#define DEFAULT_CUTOFF_CURR_MA		500
 #define DEFAULT_DELTA_SOC_THR		1
 #define DEFAULT_RECHARGE_SOC_THR	95
 #define DEFAULT_BATT_TEMP_COLD		0
@@ -4860,6 +4877,12 @@
 	else
 		chip->dt.chg_term_base_curr_ma = temp;
 
+	rc = of_property_read_u32(node, "qcom,fg-cutoff-current", &temp);
+	if (rc < 0)
+		chip->dt.cutoff_curr_ma = DEFAULT_CUTOFF_CURR_MA;
+	else
+		chip->dt.cutoff_curr_ma = temp;
+
 	rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
 	if (rc < 0)
 		chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
new file mode 100644
index 0000000..b07efdf
--- /dev/null
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -0,0 +1,2260 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/log2.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/pmic-voter.h>
+#include "smb5-reg.h"
+#include "smb5-lib.h"
+
+static struct smb_params smb5_pmi632_params = {
+	.fcc			= {
+		.name   = "fast charge current",
+		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.fv			= {
+		.name   = "float voltage",
+		.reg    = CHGR_FLOAT_VOLTAGE_CFG_REG,
+		.min_u  = 3600000,
+		.max_u  = 4800000,
+		.step_u = 10000,
+	},
+	.usb_icl		= {
+		.name   = "usb input current limit",
+		.reg    = USBIN_CURRENT_LIMIT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.icl_stat		= {
+		.name   = "input current limit status",
+		.reg    = AICL_ICL_STATUS_REG,
+		.min_u  = 0,
+		.max_u  = 3000000,
+		.step_u = 50000,
+	},
+	.otg_cl			= {
+		.name	= "usb otg current limit",
+		.reg	= DCDC_OTG_CURRENT_LIMIT_CFG_REG,
+		.min_u	= 500000,
+		.max_u	= 1000000,
+		.step_u	= 250000,
+	},
+	.jeita_cc_comp_hot	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_HOT_REG,
+		.min_u	= 0,
+		.max_u	= 1575000,
+		.step_u	= 25000,
+	},
+	.jeita_cc_comp_cold	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_COLD_REG,
+		.min_u	= 0,
+		.max_u	= 1575000,
+		.step_u	= 25000,
+	},
+	.freq_switcher		= {
+		.name	= "switching frequency",
+		.reg	= DCDC_FSW_SEL_REG,
+		.min_u	= 600,
+		.max_u	= 1200,
+		.step_u	= 400,
+		.set_proc = smblib_set_chg_freq,
+	},
+};
+
+static struct smb_params smb5_pmi855_params = {
+	.fcc			= {
+		.name   = "fast charge current",
+		.reg    = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 8000000,
+		.step_u = 25000,
+	},
+	.fv			= {
+		.name   = "float voltage",
+		.reg    = CHGR_FLOAT_VOLTAGE_CFG_REG,
+		.min_u  = 3600000,
+		.max_u  = 4790000,
+		.step_u = 10000,
+	},
+	.usb_icl		= {
+		.name   = "usb input current limit",
+		.reg    = USBIN_CURRENT_LIMIT_CFG_REG,
+		.min_u  = 0,
+		.max_u  = 5000000,
+		.step_u = 50000,
+	},
+	.icl_stat		= {
+		.name   = "input current limit status",
+		.reg    = AICL_ICL_STATUS_REG,
+		.min_u  = 0,
+		.max_u  = 5000000,
+		.step_u = 50000,
+	},
+	.otg_cl			= {
+		.name	= "usb otg current limit",
+		.reg	= DCDC_OTG_CURRENT_LIMIT_CFG_REG,
+		.min_u	= 500000,
+		.max_u	= 3000000,
+		.step_u	= 500000,
+	},
+	.jeita_cc_comp_hot	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_HOT_REG,
+		.min_u	= 0,
+		.max_u	= 8000000,
+		.step_u	= 25000,
+		.set_proc = NULL,
+	},
+	.jeita_cc_comp_cold	= {
+		.name	= "jeita fcc reduction",
+		.reg	= JEITA_CCCOMP_CFG_COLD_REG,
+		.min_u	= 0,
+		.max_u	= 8000000,
+		.step_u	= 25000,
+		.set_proc = NULL,
+	},
+	.freq_switcher		= {
+		.name	= "switching frequency",
+		.reg	= DCDC_FSW_SEL_REG,
+		.min_u	= 1200,
+		.max_u	= 2400,
+		.step_u	= 400,
+		.set_proc = NULL,
+	},
+};
+
+struct smb_dt_props {
+	int			usb_icl_ua;
+	struct device_node	*revid_dev_node;
+	enum float_options	float_option;
+	int			chg_inhibit_thr_mv;
+	bool			no_battery;
+	bool			hvdcp_disable;
+	bool			auto_recharge_soc;
+	int			wd_bark_time;
+	int			batt_profile_fcc_ua;
+	int			batt_profile_fv_uv;
+};
+
+struct smb5 {
+	struct smb_charger	chg;
+	struct dentry		*dfs_root;
+	struct smb_dt_props	dt;
+};
+
+static int __debug_mask;
+module_param_named(
+	debug_mask, __debug_mask, int, 0600
+);
+
+static int __weak_chg_icl_ua = 500000;
+module_param_named(
+	weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
+);
+
+#define PMI632_MAX_ICL_UA	3000000
+static int smb5_chg_config_init(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct pmic_revid_data *pmic_rev_id;
+	struct device_node *revid_dev_node;
+	int rc = 0;
+
+	revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
+					  "qcom,pmic-revid", 0);
+	if (!revid_dev_node) {
+		pr_err("Missing qcom,pmic-revid property\n");
+		return -EINVAL;
+	}
+
+	pmic_rev_id = get_revid_data(revid_dev_node);
+	if (IS_ERR_OR_NULL(pmic_rev_id)) {
+		/*
+		 * the revid peripheral must be registered, any failure
+		 * here only indicates that the rev-id module has not
+		 * probed yet.
+		 */
+		rc =  -EPROBE_DEFER;
+		goto out;
+	}
+
+	switch (pmic_rev_id->pmic_subtype) {
+	case PM855B_SUBTYPE:
+		chip->chg.smb_version = PM855B_SUBTYPE;
+		chg->param = smb5_pmi855_params;
+		chg->name = "pm855b_charger";
+		break;
+	case PMI632_SUBTYPE:
+		chip->chg.smb_version = PMI632_SUBTYPE;
+		chg->param = smb5_pmi632_params;
+		chg->use_extcon = true;
+		chg->name = "pmi632_charger";
+		chg->hw_max_icl_ua =
+			(chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
+						: PMI632_MAX_ICL_UA;
+		chg->chg_freq.freq_5V			= 600;
+		chg->chg_freq.freq_6V_8V		= 800;
+		chg->chg_freq.freq_9V			= 1050;
+		chg->chg_freq.freq_removal		= 1050;
+		chg->chg_freq.freq_below_otg_threshold	= 800;
+		chg->chg_freq.freq_above_otg_threshold	= 800;
+		break;
+	default:
+		pr_err("PMIC subtype %d not supported\n",
+				pmic_rev_id->pmic_subtype);
+		rc = -EINVAL;
+	}
+
+out:
+	of_node_put(revid_dev_node);
+	return rc;
+}
+
+#define MICRO_1P5A		1500000
+#define MICRO_P1A		100000
+#define OTG_DEFAULT_DEGLITCH_TIME_MS	50
+#define MIN_WD_BARK_TIME		16
+#define DEFAULT_WD_BARK_TIME		64
+#define BITE_WDOG_TIMEOUT_8S		0x3
+#define BARK_WDOG_TIMEOUT_MASK		GENMASK(3, 2)
+#define BARK_WDOG_TIMEOUT_SHIFT		2
+static int smb5_parse_dt(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct device_node *node = chg->dev->of_node;
+	int rc, byte_len;
+
+	if (!node) {
+		pr_err("device tree node missing\n");
+		return -EINVAL;
+	}
+
+	chg->step_chg_enabled = of_property_read_bool(node,
+				"qcom,step-charging-enable");
+
+	chg->sw_jeita_enabled = of_property_read_bool(node,
+				"qcom,sw-jeita-enable");
+
+	rc = of_property_read_u32(node, "qcom,wd-bark-time-secs",
+					&chip->dt.wd_bark_time);
+	if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME)
+		chip->dt.wd_bark_time = DEFAULT_WD_BARK_TIME;
+
+	chip->dt.no_battery = of_property_read_bool(node,
+						"qcom,batteryless-platform");
+
+	rc = of_property_read_u32(node,
+			"qcom,fcc-max-ua", &chip->dt.batt_profile_fcc_ua);
+	if (rc < 0)
+		chip->dt.batt_profile_fcc_ua = -EINVAL;
+
+	rc = of_property_read_u32(node,
+				"qcom,fv-max-uv", &chip->dt.batt_profile_fv_uv);
+	if (rc < 0)
+		chip->dt.batt_profile_fv_uv = -EINVAL;
+
+	rc = of_property_read_u32(node,
+				"qcom,usb-icl-ua", &chip->dt.usb_icl_ua);
+	if (rc < 0)
+		chip->dt.usb_icl_ua = -EINVAL;
+
+	rc = of_property_read_u32(node,
+				"qcom,otg-cl-ua", &chg->otg_cl_ua);
+	if (rc < 0)
+		chg->otg_cl_ua = MICRO_1P5A;
+
+	if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) {
+		chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len,
+			GFP_KERNEL);
+
+		if (chg->thermal_mitigation == NULL)
+			return -ENOMEM;
+
+		chg->thermal_levels = byte_len / sizeof(u32);
+		rc = of_property_read_u32_array(node,
+				"qcom,thermal-mitigation",
+				chg->thermal_mitigation,
+				chg->thermal_levels);
+		if (rc < 0) {
+			dev_err(chg->dev,
+				"Couldn't read threm limits rc = %d\n", rc);
+			return rc;
+		}
+	}
+
+	rc = of_property_read_u32(node, "qcom,float-option",
+						&chip->dt.float_option);
+	if (!rc && (chip->dt.float_option < 0 || chip->dt.float_option > 4)) {
+		pr_err("qcom,float-option is out of range [0, 4]\n");
+		return -EINVAL;
+	}
+
+	chip->dt.hvdcp_disable = of_property_read_bool(node,
+						"qcom,hvdcp-disable");
+
+
+	rc = of_property_read_u32(node, "qcom,chg-inhibit-threshold-mv",
+				&chip->dt.chg_inhibit_thr_mv);
+	if (!rc && (chip->dt.chg_inhibit_thr_mv < 0 ||
+				chip->dt.chg_inhibit_thr_mv > 300)) {
+		pr_err("qcom,chg-inhibit-threshold-mv is incorrect\n");
+		return -EINVAL;
+	}
+
+	chip->dt.auto_recharge_soc = of_property_read_bool(node,
+						"qcom,auto-recharge-soc");
+
+	chg->dcp_icl_ua = chip->dt.usb_icl_ua;
+
+	chg->suspend_input_on_debug_batt = of_property_read_bool(node,
+					"qcom,suspend-input-on-debug-batt");
+
+	rc = of_property_read_u32(node, "qcom,otg-deglitch-time-ms",
+					&chg->otg_delay_ms);
+	if (rc < 0)
+		chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS;
+
+	return 0;
+}
+
+/************************
+ * USB PSY REGISTRATION *
+ ************************/
+static enum power_supply_property smb5_usb_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_PD_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_TYPEC_MODE,
+	POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
+	POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
+	POWER_SUPPLY_PROP_PD_ALLOWED,
+	POWER_SUPPLY_PROP_PD_ACTIVE,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
+	POWER_SUPPLY_PROP_BOOST_CURRENT,
+	POWER_SUPPLY_PROP_PE_START,
+	POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
+	POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+	POWER_SUPPLY_PROP_REAL_TYPE,
+	POWER_SUPPLY_PROP_PR_SWAP,
+	POWER_SUPPLY_PROP_PD_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_PD_VOLTAGE_MIN,
+	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+};
+
+static int smb5_usb_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		rc = smblib_get_prop_usb_present(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		rc = smblib_get_prop_usb_online(chg, val);
+		if (!val->intval)
+			break;
+
+		if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+		   (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+			&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
+			val->intval = 0;
+		else
+			val->intval = 1;
+
+		if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN)
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		rc = smblib_get_prop_usb_voltage_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
+		val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_USB_PD;
+		break;
+	case POWER_SUPPLY_PROP_REAL_TYPE:
+		val->intval = chg->real_charger_type;
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_MODE:
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			val->intval = POWER_SUPPLY_TYPEC_NONE;
+		else
+			val->intval = chg->typec_mode;
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
+		else
+			rc = smblib_get_prop_typec_power_role(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION:
+		if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			val->intval = 0;
+		else
+			rc = smblib_get_prop_typec_cc_orientation(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_ALLOWED:
+		rc = smblib_get_prop_pd_allowed(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_ACTIVE:
+		val->intval = chg->pd_active;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_BOOST_CURRENT:
+		val->intval = chg->boost_current_ua;
+		break;
+	case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
+		rc = smblib_get_prop_pd_in_hard_reset(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
+		val->intval = chg->system_suspend_supported;
+		break;
+	case POWER_SUPPLY_PROP_PE_START:
+		rc = smblib_get_pe_start(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+		val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
+		rc = smblib_get_charge_current(chg, &val->intval);
+		break;
+	case POWER_SUPPLY_PROP_PR_SWAP:
+		rc = smblib_get_prop_pr_swap_in_progress(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
+		val->intval = chg->voltage_max_uv;
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
+		val->intval = chg->voltage_min_uv;
+		break;
+	case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
+		val->intval = get_client_vote(chg->usb_icl_votable,
+					      USB_PSY_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_CONNECTOR_TYPE:
+		val->intval = chg->connector_type;
+		break;
+	default:
+		pr_err("get prop %d is not supported in usb\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_usb_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	mutex_lock(&chg->lock);
+	if (!chg->typec_present) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
+		rc = smblib_set_prop_pd_current_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
+		rc = smblib_set_prop_typec_power_role(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_ACTIVE:
+		rc = smblib_set_prop_pd_active(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_IN_HARD_RESET:
+		rc = smblib_set_prop_pd_in_hard_reset(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED:
+		chg->system_suspend_supported = val->intval;
+		break;
+	case POWER_SUPPLY_PROP_BOOST_CURRENT:
+		rc = smblib_set_prop_boost_current(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+		rc = vote(chg->usb_icl_votable, CTM_VOTER,
+						val->intval >= 0, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_PR_SWAP:
+		rc = smblib_set_prop_pr_swap_in_progress(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MAX:
+		rc = smblib_set_prop_pd_voltage_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PD_VOLTAGE_MIN:
+		rc = smblib_set_prop_pd_voltage_min(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_SDP_CURRENT_MAX:
+		rc = smblib_set_prop_sdp_current_max(chg, val);
+		break;
+	default:
+		pr_err("set prop %d is not supported\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+
+unlock:
+	mutex_unlock(&chg->lock);
+	return rc;
+}
+
+static int smb5_usb_prop_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct power_supply_desc usb_psy_desc = {
+	.name = "usb",
+	.type = POWER_SUPPLY_TYPE_USB_PD,
+	.properties = smb5_usb_props,
+	.num_properties = ARRAY_SIZE(smb5_usb_props),
+	.get_property = smb5_usb_get_prop,
+	.set_property = smb5_usb_set_prop,
+	.property_is_writeable = smb5_usb_prop_is_writeable,
+};
+
+static int smb5_init_usb_psy(struct smb5 *chip)
+{
+	struct power_supply_config usb_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	usb_cfg.drv_data = chip;
+	usb_cfg.of_node = chg->dev->of_node;
+	chg->usb_psy = devm_power_supply_register(chg->dev,
+						  &usb_psy_desc,
+						  &usb_cfg);
+	if (IS_ERR(chg->usb_psy)) {
+		pr_err("Couldn't register USB power supply\n");
+		return PTR_ERR(chg->usb_psy);
+	}
+
+	return 0;
+}
+
+/********************************
+ * USB PC_PORT PSY REGISTRATION *
+ ********************************/
+static enum power_supply_property smb5_usb_port_props[] = {
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static int smb5_usb_port_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_USB;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		rc = smblib_get_prop_usb_online(chg, val);
+		if (!val->intval)
+			break;
+
+		if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) ||
+		   (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+			&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
+			val->intval = 1;
+		else
+			val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		val->intval = 5000000;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	default:
+		pr_err_ratelimited("Get prop %d is not supported in pc_port\n",
+				psp);
+		return -EINVAL;
+	}
+
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_usb_port_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	switch (psp) {
+	default:
+		pr_err_ratelimited("Set prop %d is not supported in pc_port\n",
+				psp);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static const struct power_supply_desc usb_port_psy_desc = {
+	.name		= "pc_port",
+	.type		= POWER_SUPPLY_TYPE_USB,
+	.properties	= smb5_usb_port_props,
+	.num_properties	= ARRAY_SIZE(smb5_usb_port_props),
+	.get_property	= smb5_usb_port_get_prop,
+	.set_property	= smb5_usb_port_set_prop,
+};
+
+static int smb5_init_usb_port_psy(struct smb5 *chip)
+{
+	struct power_supply_config usb_port_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	usb_port_cfg.drv_data = chip;
+	usb_port_cfg.of_node = chg->dev->of_node;
+	chg->usb_port_psy = devm_power_supply_register(chg->dev,
+						  &usb_port_psy_desc,
+						  &usb_port_cfg);
+	if (IS_ERR(chg->usb_port_psy)) {
+		pr_err("Couldn't register USB pc_port power supply\n");
+		return PTR_ERR(chg->usb_port_psy);
+	}
+
+	return 0;
+}
+
+/*****************************
+ * USB MAIN PSY REGISTRATION *
+ *****************************/
+
+static enum power_supply_property smb5_usb_main_props[] = {
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
+	POWER_SUPPLY_PROP_FCC_DELTA,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static int smb5_usb_main_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		rc = smblib_get_charge_param(chg, &chg->param.fcc,
+							&val->intval);
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_MAIN;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+		rc = smblib_get_prop_input_current_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED:
+		rc = smblib_get_prop_input_voltage_settled(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_FCC_DELTA:
+		rc = smblib_get_prop_fcc_delta(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_get_icl_current(chg, &val->intval);
+		break;
+	default:
+		pr_debug("get prop %d is not supported in usb-main\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_usb_main_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		rc = smblib_set_icl_current(chg, val->intval);
+		break;
+	default:
+		pr_err("set prop %d is not supported\n", psp);
+		rc = -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static const struct power_supply_desc usb_main_psy_desc = {
+	.name		= "main",
+	.type		= POWER_SUPPLY_TYPE_MAIN,
+	.properties	= smb5_usb_main_props,
+	.num_properties	= ARRAY_SIZE(smb5_usb_main_props),
+	.get_property	= smb5_usb_main_get_prop,
+	.set_property	= smb5_usb_main_set_prop,
+};
+
+static int smb5_init_usb_main_psy(struct smb5 *chip)
+{
+	struct power_supply_config usb_main_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	usb_main_cfg.drv_data = chip;
+	usb_main_cfg.of_node = chg->dev->of_node;
+	chg->usb_main_psy = devm_power_supply_register(chg->dev,
+						  &usb_main_psy_desc,
+						  &usb_main_cfg);
+	if (IS_ERR(chg->usb_main_psy)) {
+		pr_err("Couldn't register USB main power supply\n");
+		return PTR_ERR(chg->usb_main_psy);
+	}
+
+	return 0;
+}
+
+/*************************
+ * DC PSY REGISTRATION   *
+ *************************/
+
+static enum power_supply_property smb5_dc_props[] = {
+	POWER_SUPPLY_PROP_INPUT_SUSPEND,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_REAL_TYPE,
+};
+
+static int smb5_dc_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		val->intval = get_effective_result(chg->dc_suspend_votable);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		rc = smblib_get_prop_dc_present(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		rc = smblib_get_prop_dc_online(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_REAL_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_WIPOWER;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+	return 0;
+}
+
+static int smb5_dc_set_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct smb5 *chip = power_supply_get_drvdata(psy);
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		rc = vote(chg->dc_suspend_votable, WBC_VOTER,
+				(bool)val->intval, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int smb5_dc_prop_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	int rc;
+
+	switch (psp) {
+	default:
+		rc = 0;
+		break;
+	}
+
+	return rc;
+}
+
+static const struct power_supply_desc dc_psy_desc = {
+	.name = "dc",
+	.type = POWER_SUPPLY_TYPE_WIRELESS,
+	.properties = smb5_dc_props,
+	.num_properties = ARRAY_SIZE(smb5_dc_props),
+	.get_property = smb5_dc_get_prop,
+	.set_property = smb5_dc_set_prop,
+	.property_is_writeable = smb5_dc_prop_is_writeable,
+};
+
+static int smb5_init_dc_psy(struct smb5 *chip)
+{
+	struct power_supply_config dc_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	dc_cfg.drv_data = chip;
+	dc_cfg.of_node = chg->dev->of_node;
+	chg->dc_psy = devm_power_supply_register(chg->dev,
+						  &dc_psy_desc,
+						  &dc_cfg);
+	if (IS_ERR(chg->dc_psy)) {
+		pr_err("Couldn't register USB power supply\n");
+		return PTR_ERR(chg->dc_psy);
+	}
+
+	return 0;
+}
+
+/*************************
+ * BATT PSY REGISTRATION *
+ *************************/
+static enum power_supply_property smb5_batt_props[] = {
+	POWER_SUPPLY_PROP_INPUT_SUSPEND,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
+	POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
+	POWER_SUPPLY_PROP_CHARGE_DONE,
+	POWER_SUPPLY_PROP_PARALLEL_DISABLE,
+	POWER_SUPPLY_PROP_SET_SHIP_MODE,
+	POWER_SUPPLY_PROP_DIE_HEALTH,
+	POWER_SUPPLY_PROP_RERUN_AICL,
+	POWER_SUPPLY_PROP_DP_DM,
+	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
+	POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
+	POWER_SUPPLY_PROP_CHARGE_COUNTER,
+};
+
+static int smb5_batt_get_prop(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct smb_charger *chg = power_supply_get_drvdata(psy);
+	int rc = 0;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		rc = smblib_get_prop_batt_status(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		rc = smblib_get_prop_batt_health(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		rc = smblib_get_prop_batt_present(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		rc = smblib_get_prop_input_suspend(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		rc = smblib_get_prop_batt_charge_type(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		rc = smblib_get_prop_batt_capacity(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+		rc = smblib_get_prop_system_temp_level(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
+		rc = smblib_get_prop_system_temp_level_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+		rc = smblib_get_prop_input_current_limited(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+		val->intval = chg->step_chg_enabled;
+		break;
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+		val->intval = chg->sw_jeita_enabled;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		rc = smblib_get_prop_batt_voltage_now(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		val->intval = get_client_vote(chg->fv_votable,
+				BATT_PROFILE_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		rc = smblib_get_prop_batt_current_now(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		val->intval = get_client_vote(chg->fcc_votable,
+					      BATT_PROFILE_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		rc = smblib_get_prop_batt_temp(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_DONE:
+		rc = smblib_get_prop_batt_charge_done(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+		val->intval = get_client_vote(chg->pl_disable_votable,
+					      USER_VOTER);
+		break;
+	case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+		/* Not in ship mode as long as device is active */
+		val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_DIE_HEALTH:
+		if (chg->die_health == -EINVAL)
+			rc = smblib_get_prop_die_health(chg, val);
+		else
+			val->intval = chg->die_health;
+		break;
+	case POWER_SUPPLY_PROP_DP_DM:
+		val->intval = chg->pulse_cnt;
+		break;
+	case POWER_SUPPLY_PROP_RERUN_AICL:
+		val->intval = 0;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+		rc = smblib_get_prop_batt_charge_counter(chg, val);
+		break;
+	default:
+		pr_err("batt power supply prop %d not supported\n", psp);
+		return -EINVAL;
+	}
+
+	if (rc < 0) {
+		pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+static int smb5_batt_set_prop(struct power_supply *psy,
+		enum power_supply_property prop,
+		const union power_supply_propval *val)
+{
+	int rc = 0;
+	struct smb_charger *chg = power_supply_get_drvdata(psy);
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_STATUS:
+		rc = smblib_set_prop_batt_status(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		rc = smblib_set_prop_input_suspend(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+		rc = smblib_set_prop_system_temp_level(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		rc = smblib_set_prop_batt_capacity(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+		vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		chg->batt_profile_fv_uv = val->intval;
+		vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+		chg->step_chg_enabled = !!val->intval;
+		break;
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+		if (chg->sw_jeita_enabled != (!!val->intval)) {
+			rc = smblib_disable_hw_jeita(chg, !!val->intval);
+			if (rc == 0)
+				chg->sw_jeita_enabled = !!val->intval;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		chg->batt_profile_fcc_ua = val->intval;
+		vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+		/* Not in ship mode as long as the device is active */
+		if (!val->intval)
+			break;
+		if (chg->pl.psy)
+			power_supply_set_property(chg->pl.psy,
+				POWER_SUPPLY_PROP_SET_SHIP_MODE, val);
+		rc = smblib_set_prop_ship_mode(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_RERUN_AICL:
+		rc = smblib_rerun_aicl(chg);
+		break;
+	case POWER_SUPPLY_PROP_DP_DM:
+		rc = smblib_dp_dm(chg, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+		rc = smblib_set_prop_input_current_limited(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_DIE_HEALTH:
+		chg->die_health = val->intval;
+		power_supply_changed(chg->batt_psy);
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int smb5_batt_prop_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
+	case POWER_SUPPLY_PROP_CAPACITY:
+	case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
+	case POWER_SUPPLY_PROP_DP_DM:
+	case POWER_SUPPLY_PROP_RERUN_AICL:
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+	case POWER_SUPPLY_PROP_DIE_HEALTH:
+		return 1;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct power_supply_desc batt_psy_desc = {
+	.name = "battery",
+	.type = POWER_SUPPLY_TYPE_BATTERY,
+	.properties = smb5_batt_props,
+	.num_properties = ARRAY_SIZE(smb5_batt_props),
+	.get_property = smb5_batt_get_prop,
+	.set_property = smb5_batt_set_prop,
+	.property_is_writeable = smb5_batt_prop_is_writeable,
+};
+
+static int smb5_init_batt_psy(struct smb5 *chip)
+{
+	struct power_supply_config batt_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	batt_cfg.drv_data = chg;
+	batt_cfg.of_node = chg->dev->of_node;
+	chg->batt_psy = devm_power_supply_register(chg->dev,
+					   &batt_psy_desc,
+					   &batt_cfg);
+	if (IS_ERR(chg->batt_psy)) {
+		pr_err("Couldn't register battery power supply\n");
+		return PTR_ERR(chg->batt_psy);
+	}
+
+	return rc;
+}
+
+/******************************
+ * VBUS REGULATOR REGISTRATION *
+ ******************************/
+
+static struct regulator_ops smb5_vbus_reg_ops = {
+	.enable = smblib_vbus_regulator_enable,
+	.disable = smblib_vbus_regulator_disable,
+	.is_enabled = smblib_vbus_regulator_is_enabled,
+};
+
+static int smb5_init_vbus_regulator(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct regulator_config cfg = {};
+	int rc = 0;
+
+	chg->vbus_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vbus_vreg),
+				      GFP_KERNEL);
+	if (!chg->vbus_vreg)
+		return -ENOMEM;
+
+	cfg.dev = chg->dev;
+	cfg.driver_data = chip;
+
+	chg->vbus_vreg->rdesc.owner = THIS_MODULE;
+	chg->vbus_vreg->rdesc.type = REGULATOR_VOLTAGE;
+	chg->vbus_vreg->rdesc.ops = &smb5_vbus_reg_ops;
+	chg->vbus_vreg->rdesc.of_match = "qcom,smb5-vbus";
+	chg->vbus_vreg->rdesc.name = "qcom,smb5-vbus";
+
+	chg->vbus_vreg->rdev = devm_regulator_register(chg->dev,
+						&chg->vbus_vreg->rdesc, &cfg);
+	if (IS_ERR(chg->vbus_vreg->rdev)) {
+		rc = PTR_ERR(chg->vbus_vreg->rdev);
+		chg->vbus_vreg->rdev = NULL;
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't register VBUS regulator rc=%d\n", rc);
+	}
+
+	return rc;
+}
+
+/******************************
+ * VCONN REGULATOR REGISTRATION *
+ ******************************/
+
+static struct regulator_ops smb5_vconn_reg_ops = {
+	.enable = smblib_vconn_regulator_enable,
+	.disable = smblib_vconn_regulator_disable,
+	.is_enabled = smblib_vconn_regulator_is_enabled,
+};
+
+static int smb5_init_vconn_regulator(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct regulator_config cfg = {};
+	int rc = 0;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		return 0;
+
+	chg->vconn_vreg = devm_kzalloc(chg->dev, sizeof(*chg->vconn_vreg),
+				      GFP_KERNEL);
+	if (!chg->vconn_vreg)
+		return -ENOMEM;
+
+	cfg.dev = chg->dev;
+	cfg.driver_data = chip;
+
+	chg->vconn_vreg->rdesc.owner = THIS_MODULE;
+	chg->vconn_vreg->rdesc.type = REGULATOR_VOLTAGE;
+	chg->vconn_vreg->rdesc.ops = &smb5_vconn_reg_ops;
+	chg->vconn_vreg->rdesc.of_match = "qcom,smb5-vconn";
+	chg->vconn_vreg->rdesc.name = "qcom,smb5-vconn";
+
+	chg->vconn_vreg->rdev = devm_regulator_register(chg->dev,
+						&chg->vconn_vreg->rdesc, &cfg);
+	if (IS_ERR(chg->vconn_vreg->rdev)) {
+		rc = PTR_ERR(chg->vconn_vreg->rdev);
+		chg->vconn_vreg->rdev = NULL;
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't register VCONN regulator rc=%d\n", rc);
+	}
+
+	return rc;
+}
+
+/***************************
+ * HARDWARE INITIALIZATION *
+ ***************************/
+static int smb5_configure_typec(struct smb_charger *chg)
+{
+	int rc;
+
+	rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
+				TYPEC_CCOUT_DETACH_INT_EN_BIT |
+				TYPEC_CCOUT_ATTACH_INT_EN_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure Type-C interrupts rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
+				TYPEC_WATER_DETECTION_INT_EN_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure Type-C interrupts rc=%d\n", rc);
+		return rc;
+	}
+
+	/* configure VCONN for software control */
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT,
+				 VCONN_EN_SRC_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure VCONN for SW control rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int smb5_configure_micro_usb(struct smb_charger *chg)
+{
+	int rc;
+
+	/* configure micro USB mode */
+	rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
+			EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
+					MICRO_USB_STATE_CHANGE_INT_EN_BIT,
+					MICRO_USB_STATE_CHANGE_INT_EN_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure Type-C interrupts rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int smb5_init_hw(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	int rc, type = 0;
+	u8 val = 0;
+
+	if (chip->dt.no_battery)
+		chg->fake_capacity = 50;
+
+	if (chip->dt.batt_profile_fcc_ua < 0)
+		smblib_get_charge_param(chg, &chg->param.fcc,
+				&chg->batt_profile_fcc_ua);
+
+	if (chip->dt.batt_profile_fv_uv < 0)
+		smblib_get_charge_param(chg, &chg->param.fv,
+				&chg->batt_profile_fv_uv);
+
+	smblib_get_charge_param(chg, &chg->param.usb_icl,
+				&chg->default_icl_ua);
+
+	/* Use SW based VBUS control, disable HW autonomous mode */
+	/* TODO: auth can be enabled through vote based on APSD flow */
+	rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+		HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
+		HVDCP_AUTH_ALG_EN_CFG_BIT);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc);
+		return rc;
+	}
+
+	/*
+	 * PMI632 can have the connector type defined by a dedicated register
+	 * TYPEC_MICRO_USB_MODE_REG or by a common TYPEC_U_USB_CFG_REG.
+	 */
+	if (chg->smb_version == PMI632_SUBTYPE) {
+		rc = smblib_read(chg, TYPEC_MICRO_USB_MODE_REG, &val);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't read USB mode rc=%d\n", rc);
+			return rc;
+		}
+		type = !!(val & MICRO_USB_MODE_ONLY_BIT);
+	}
+
+	/*
+	 * If TYPEC_MICRO_USB_MODE_REG is not set and for all non-PMI632
+	 * check the connector type using TYPEC_U_USB_CFG_REG.
+	 */
+	if (!type) {
+		rc = smblib_read(chg, TYPEC_U_USB_CFG_REG, &val);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't read U_USB config rc=%d\n",
+					rc);
+			return rc;
+		}
+
+		type = !!(val & EN_MICRO_USB_MODE_BIT);
+	}
+
+	chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
+					: POWER_SUPPLY_CONNECTOR_TYPEC;
+	pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
+
+	smblib_rerun_apsd_if_required(chg);
+
+	/* vote 0mA on usb_icl for non battery platforms */
+	vote(chg->usb_icl_votable,
+		DEFAULT_VOTER, chip->dt.no_battery, 0);
+	vote(chg->dc_suspend_votable,
+		DEFAULT_VOTER, chip->dt.no_battery, 0);
+	vote(chg->fcc_votable, HW_LIMIT_VOTER,
+		chip->dt.batt_profile_fcc_ua > 0, chip->dt.batt_profile_fcc_ua);
+	vote(chg->fv_votable, HW_LIMIT_VOTER,
+		chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv);
+	vote(chg->fcc_votable,
+		BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0,
+		chg->batt_profile_fcc_ua);
+	vote(chg->fv_votable,
+		BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
+		chg->batt_profile_fv_uv);
+	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
+			true, 0);
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+			true, 0);
+	vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
+		chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);
+
+	/* Some h/w limit maximum supported ICL */
+	vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
+			chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua);
+
+	/*
+	 * AICL configuration:
+	 * start from min and AICL ADC disable
+	 */
+	rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
+				USBIN_AICL_ADC_EN_BIT, 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc);
+		return rc;
+	}
+
+	/* enable the charging path */
+	rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
+		return rc;
+	}
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		rc = smb5_configure_micro_usb(chg);
+	else
+		rc = smb5_configure_typec(chg);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
+		return rc;
+	}
+
+	/* configure VBUS for software control */
+	rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure VBUS for SW control rc=%d\n", rc);
+		return rc;
+	}
+
+	val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT)
+			& BARK_WDOG_TIMEOUT_MASK;
+	val |= BITE_WDOG_TIMEOUT_8S;
+	rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
+			BITE_WDOG_DISABLE_CHARGING_CFG_BIT |
+			BARK_WDOG_TIMEOUT_MASK | BITE_WDOG_TIMEOUT_MASK,
+			val);
+	if (rc < 0) {
+		pr_err("Couldn't configue WD config rc=%d\n", rc);
+		return rc;
+	}
+
+	/* enable WD BARK and enable it on plugin */
+	rc = smblib_masked_write(chg, WD_CFG_REG,
+			WATCHDOG_TRIGGER_AFP_EN_BIT |
+			WDOG_TIMER_EN_ON_PLUGIN_BIT |
+			BARK_WDOG_INT_EN_BIT,
+			WDOG_TIMER_EN_ON_PLUGIN_BIT |
+			BARK_WDOG_INT_EN_BIT);
+	if (rc < 0) {
+		pr_err("Couldn't configue WD config rc=%d\n", rc);
+		return rc;
+	}
+
+	/* configure float charger options */
+	switch (chip->dt.float_option) {
+	case FLOAT_DCP:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, 0);
+		break;
+	case FLOAT_SDP:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, FORCE_FLOAT_SDP_CFG_BIT);
+		break;
+	case DISABLE_CHARGING:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, FLOAT_DIS_CHGING_CFG_BIT);
+		break;
+	case SUSPEND_INPUT:
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				FLOAT_OPTIONS_MASK, SUSPEND_FLOAT_CFG_BIT);
+		break;
+	default:
+		rc = 0;
+		break;
+	}
+
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure float charger options rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	rc = smblib_read(chg, USBIN_OPTIONS_2_CFG_REG, &chg->float_cfg);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't read float charger options rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	switch (chip->dt.chg_inhibit_thr_mv) {
+	case 50:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_50MV);
+		break;
+	case 100:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_100MV);
+		break;
+	case 200:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_200MV);
+		break;
+	case 300:
+		rc = smblib_masked_write(chg, CHARGE_INHIBIT_THRESHOLD_CFG_REG,
+				CHARGE_INHIBIT_THRESHOLD_MASK,
+				INHIBIT_ANALOG_VFLT_MINUS_300MV);
+		break;
+	case 0:
+		rc = smblib_masked_write(chg, CHGR_CFG2_REG,
+				CHARGER_INHIBIT_BIT, 0);
+	default:
+		break;
+	}
+
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure charge inhibit threshold rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	rc = smblib_masked_write(chg, CHGR_CFG2_REG,
+			SOC_BASED_RECHG_BIT,
+			chip->dt.auto_recharge_soc ? SOC_BASED_RECHG_BIT : 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	if (chg->sw_jeita_enabled) {
+		rc = smblib_disable_hw_jeita(chg, true);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int smb5_post_init(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	union power_supply_propval pval;
+	int rc;
+
+	/*
+	 * In case the usb path is suspended, we would have missed disabling
+	 * the icl change interrupt because the interrupt could have been
+	 * not requested
+	 */
+	rerun_election(chg->usb_icl_votable);
+
+	/* configure power role for dual-role */
+	pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+	rc = smblib_set_prop_typec_power_role(chg, &pval);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure DRP role rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	rerun_election(chg->usb_irq_enable_votable);
+
+	return 0;
+}
+
+/****************************
+ * DETERMINE INITIAL STATUS *
+ ****************************/
+
+static int smb5_determine_initial_status(struct smb5 *chip)
+{
+	struct smb_irq_data irq_data = {chip, "determine-initial-status"};
+	struct smb_charger *chg = &chip->chg;
+
+	if (chg->bms_psy)
+		smblib_suspend_on_debug_battery(chg);
+
+	usb_plugin_irq_handler(0, &irq_data);
+	typec_state_change_irq_handler(0, &irq_data);
+	usb_source_change_irq_handler(0, &irq_data);
+	chg_state_change_irq_handler(0, &irq_data);
+	icl_change_irq_handler(0, &irq_data);
+	batt_temp_changed_irq_handler(0, &irq_data);
+	wdog_bark_irq_handler(0, &irq_data);
+	typec_or_rid_detection_change_irq_handler(0, &irq_data);
+
+	return 0;
+}
+
+/**************************
+ * INTERRUPT REGISTRATION *
+ **************************/
+
+static struct smb_irq_info smb5_irqs[] = {
+	/* CHARGER IRQs */
+	[CHGR_ERROR_IRQ] = {
+		.name		= "chgr-error",
+		.handler	= default_irq_handler,
+	},
+	[CHG_STATE_CHANGE_IRQ] = {
+		.name		= "chg-state-change",
+		.handler	= chg_state_change_irq_handler,
+	},
+	[STEP_CHG_STATE_CHANGE_IRQ] = {
+		.name		= "step-chg-state-change",
+		.handler	= default_irq_handler,
+	},
+	[STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
+		.name		= "step-chg-soc-update-fail",
+		.handler	= default_irq_handler,
+	},
+	[STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
+		.name		= "step-chg-soc-update-req",
+		.handler	= default_irq_handler,
+	},
+	[FG_FVCAL_QUALIFIED_IRQ] = {
+		.name		= "fg-fvcal-qualified",
+		.handler	= default_irq_handler,
+	},
+	[VPH_ALARM_IRQ] = {
+		.name		= "vph-alarm",
+		.handler	= default_irq_handler,
+	},
+	[VPH_DROP_PRECHG_IRQ] = {
+		.name		= "vph-drop-prechg",
+		.handler	= default_irq_handler,
+	},
+	/* DCDC IRQs */
+	[OTG_FAIL_IRQ] = {
+		.name		= "otg-fail",
+		.handler	= default_irq_handler,
+	},
+	[OTG_OC_DISABLE_SW_IRQ] = {
+		.name		= "otg-oc-disable-sw",
+		.handler	= default_irq_handler,
+	},
+	[OTG_OC_HICCUP_IRQ] = {
+		.name		= "otg-oc-hiccup",
+		.handler	= default_irq_handler,
+	},
+	[BSM_ACTIVE_IRQ] = {
+		.name		= "bsm-active",
+		.handler	= default_irq_handler,
+	},
+	[HIGH_DUTY_CYCLE_IRQ] = {
+		.name		= "high-duty-cycle",
+		.handler	= high_duty_cycle_irq_handler,
+	},
+	[INPUT_CURRENT_LIMITING_IRQ] = {
+		.name		= "input-current-limiting",
+		.handler	= default_irq_handler,
+	},
+	[CONCURRENT_MODE_DISABLE_IRQ] = {
+		.name		= "concurrent-mode-disable",
+		.handler	= default_irq_handler,
+	},
+	[SWITCHER_POWER_OK_IRQ] = {
+		.name		= "switcher-power-ok",
+		.handler	= switcher_power_ok_irq_handler,
+	},
+	/* BATTERY IRQs */
+	[BAT_TEMP_IRQ] = {
+		.name		= "bat-temp",
+		.handler	= batt_temp_changed_irq_handler,
+	},
+	[ALL_CHNL_CONV_DONE_IRQ] = {
+		.name		= "all-chnl-conv-done",
+		.handler	= default_irq_handler,
+	},
+	[BAT_OV_IRQ] = {
+		.name		= "bat-ov",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BAT_LOW_IRQ] = {
+		.name		= "bat-low",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BAT_THERM_OR_ID_MISSING_IRQ] = {
+		.name		= "bat-therm-or-id-missing",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BAT_TERMINAL_MISSING_IRQ] = {
+		.name		= "bat-terminal-missing",
+		.handler	= batt_psy_changed_irq_handler,
+	},
+	[BUCK_OC_IRQ] = {
+		.name		= "buck-oc",
+		.handler	= default_irq_handler,
+	},
+	[VPH_OV_IRQ] = {
+		.name		= "vph-ov",
+		.handler	= default_irq_handler,
+	},
+	/* USB INPUT IRQs */
+	[USBIN_COLLAPSE_IRQ] = {
+		.name		= "usbin-collapse",
+		.handler	= default_irq_handler,
+	},
+	[USBIN_VASHDN_IRQ] = {
+		.name		= "usbin-vashdn",
+		.handler	= default_irq_handler,
+	},
+	[USBIN_UV_IRQ] = {
+		.name		= "usbin-uv",
+		.handler	= usbin_uv_irq_handler,
+	},
+	[USBIN_OV_IRQ] = {
+		.name		= "usbin-ov",
+		.handler	= default_irq_handler,
+	},
+	[USBIN_PLUGIN_IRQ] = {
+		.name		= "usbin-plugin",
+		.handler	= usb_plugin_irq_handler,
+	},
+	[USBIN_REVI_CHANGE_IRQ] = {
+		.name		= "usbin-revi-change",
+		.handler	= default_irq_handler,
+	},
+	[USBIN_SRC_CHANGE_IRQ] = {
+		.name		= "usbin-src-change",
+		.handler	= usb_source_change_irq_handler,
+	},
+	[USBIN_ICL_CHANGE_IRQ] = {
+		.name		= "usbin-icl-change",
+		.handler	= icl_change_irq_handler,
+	},
+	/* DC INPUT IRQs */
+	[DCIN_VASHDN_IRQ] = {
+		.name		= "dcin-vashdn",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_UV_IRQ] = {
+		.name		= "dcin-uv",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_OV_IRQ] = {
+		.name		= "dcin-ov",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_PLUGIN_IRQ] = {
+		.name		= "dcin-plugin",
+		.handler	= dc_plugin_irq_handler,
+		.wake           = true,
+	},
+	[DCIN_REVI_IRQ] = {
+		.name		= "dcin-revi",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_PON_IRQ] = {
+		.name		= "dcin-pon",
+		.handler	= default_irq_handler,
+	},
+	[DCIN_EN_IRQ] = {
+		.name		= "dcin-en",
+		.handler	= default_irq_handler,
+	},
+	/* TYPEC IRQs */
+	[TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = {
+		.name		= "typec-or-rid-detect-change",
+		.handler	= typec_or_rid_detection_change_irq_handler,
+	},
+	[TYPEC_VPD_DETECT_IRQ] = {
+		.name		= "typec-vpd-detect",
+		.handler	= default_irq_handler,
+	},
+	[TYPEC_CC_STATE_CHANGE_IRQ] = {
+		.name		= "typec-cc-state-change",
+		.handler	= typec_state_change_irq_handler,
+	},
+	[TYPEC_VCONN_OC_IRQ] = {
+		.name		= "typec-vconn-oc",
+		.handler	= default_irq_handler,
+	},
+	[TYPEC_VBUS_CHANGE_IRQ] = {
+		.name		= "typec-vbus-change",
+		.handler	= default_irq_handler,
+	},
+	[TYPEC_ATTACH_DETACH_IRQ] = {
+		.name		= "typec-attach-detach",
+		.handler	= default_irq_handler,
+	},
+	[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
+		.name		= "typec-legacy-cable-detect",
+		.handler	= default_irq_handler,
+	},
+	[TYPEC_TRY_SNK_SRC_DETECT_IRQ] = {
+		.name		= "typec-try-snk-src-detect",
+		.handler	= default_irq_handler,
+	},
+	/* MISCELLANEOUS IRQs */
+	[WDOG_SNARL_IRQ] = {
+		.name		= "wdog-snarl",
+		.handler	= NULL,
+	},
+	[WDOG_BARK_IRQ] = {
+		.name		= "wdog-bark",
+		.handler	= wdog_bark_irq_handler,
+	},
+	[AICL_FAIL_IRQ] = {
+		.name		= "aicl-fail",
+		.handler	= default_irq_handler,
+	},
+	[AICL_DONE_IRQ] = {
+		.name		= "aicl-done",
+		.handler	= default_irq_handler,
+	},
+	[SMB_EN_IRQ] = {
+		.name		= "smb-en",
+		.handler	= default_irq_handler,
+	},
+	[IMP_TRIGGER_IRQ] = {
+		.name		= "imp-trigger",
+		.handler	= default_irq_handler,
+	},
+	[TEMP_CHANGE_IRQ] = {
+		.name		= "temp-change",
+		.handler	= default_irq_handler,
+	},
+	[TEMP_CHANGE_SMB_IRQ] = {
+		.name		= "temp-change-smb",
+		.handler	= default_irq_handler,
+	},
+};
+
+static int smb5_get_irq_index_byname(const char *irq_name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
+		if (strcmp(smb5_irqs[i].name, irq_name) == 0)
+			return i;
+	}
+
+	return -ENOENT;
+}
+
+static int smb5_request_interrupt(struct smb5 *chip,
+				struct device_node *node, const char *irq_name)
+{
+	struct smb_charger *chg = &chip->chg;
+	int rc, irq, irq_index;
+	struct smb_irq_data *irq_data;
+
+	irq = of_irq_get_byname(node, irq_name);
+	if (irq < 0) {
+		pr_err("Couldn't get irq %s byname\n", irq_name);
+		return irq;
+	}
+
+	irq_index = smb5_get_irq_index_byname(irq_name);
+	if (irq_index < 0) {
+		pr_err("%s is not a defined irq\n", irq_name);
+		return irq_index;
+	}
+
+	if (!smb5_irqs[irq_index].handler)
+		return 0;
+
+	irq_data = devm_kzalloc(chg->dev, sizeof(*irq_data), GFP_KERNEL);
+	if (!irq_data)
+		return -ENOMEM;
+
+	irq_data->parent_data = chip;
+	irq_data->name = irq_name;
+	irq_data->storm_data = smb5_irqs[irq_index].storm_data;
+	mutex_init(&irq_data->storm_data.storm_lock);
+
+	rc = devm_request_threaded_irq(chg->dev, irq, NULL,
+					smb5_irqs[irq_index].handler,
+					IRQF_ONESHOT, irq_name, irq_data);
+	if (rc < 0) {
+		pr_err("Couldn't request irq %d\n", irq);
+		return rc;
+	}
+
+	smb5_irqs[irq_index].irq = irq;
+	smb5_irqs[irq_index].irq_data = irq_data;
+	if (smb5_irqs[irq_index].wake)
+		enable_irq_wake(irq);
+
+	return rc;
+}
+
+static int smb5_request_interrupts(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	struct device_node *node = chg->dev->of_node;
+	struct device_node *child;
+	int rc = 0;
+	const char *name;
+	struct property *prop;
+
+	for_each_available_child_of_node(node, child) {
+		of_property_for_each_string(child, "interrupt-names",
+					    prop, name) {
+			rc = smb5_request_interrupt(chip, child, name);
+			if (rc < 0)
+				return rc;
+		}
+	}
+	if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq)
+		chg->usb_icl_change_irq_enabled = true;
+
+	return rc;
+}
+
+static void smb5_free_interrupts(struct smb_charger *chg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
+		if (smb5_irqs[i].irq > 0) {
+			if (smb5_irqs[i].wake)
+				disable_irq_wake(smb5_irqs[i].irq);
+
+			devm_free_irq(chg->dev, smb5_irqs[i].irq,
+						smb5_irqs[i].irq_data);
+		}
+	}
+}
+
+static void smb5_disable_interrupts(struct smb_charger *chg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(smb5_irqs); i++) {
+		if (smb5_irqs[i].irq > 0)
+			disable_irq(smb5_irqs[i].irq);
+	}
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int force_batt_psy_update_write(void *data, u64 val)
+{
+	struct smb_charger *chg = data;
+
+	power_supply_changed(chg->batt_psy);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_batt_psy_update_ops, NULL,
+			force_batt_psy_update_write, "0x%02llx\n");
+
+static int force_usb_psy_update_write(void *data, u64 val)
+{
+	struct smb_charger *chg = data;
+
+	power_supply_changed(chg->usb_psy);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_usb_psy_update_ops, NULL,
+			force_usb_psy_update_write, "0x%02llx\n");
+
+static int force_dc_psy_update_write(void *data, u64 val)
+{
+	struct smb_charger *chg = data;
+
+	power_supply_changed(chg->dc_psy);
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(force_dc_psy_update_ops, NULL,
+			force_dc_psy_update_write, "0x%02llx\n");
+
+static void smb5_create_debugfs(struct smb5 *chip)
+{
+	struct dentry *file;
+
+	chip->dfs_root = debugfs_create_dir("charger", NULL);
+	if (IS_ERR_OR_NULL(chip->dfs_root)) {
+		pr_err("Couldn't create charger debugfs rc=%ld\n",
+			(long)chip->dfs_root);
+		return;
+	}
+
+	file = debugfs_create_file("force_batt_psy_update", 0600,
+			    chip->dfs_root, chip, &force_batt_psy_update_ops);
+	if (IS_ERR_OR_NULL(file))
+		pr_err("Couldn't create force_batt_psy_update file rc=%ld\n",
+			(long)file);
+
+	file = debugfs_create_file("force_usb_psy_update", 0600,
+			    chip->dfs_root, chip, &force_usb_psy_update_ops);
+	if (IS_ERR_OR_NULL(file))
+		pr_err("Couldn't create force_usb_psy_update file rc=%ld\n",
+			(long)file);
+
+	file = debugfs_create_file("force_dc_psy_update", 0600,
+			    chip->dfs_root, chip, &force_dc_psy_update_ops);
+	if (IS_ERR_OR_NULL(file))
+		pr_err("Couldn't create force_dc_psy_update file rc=%ld\n",
+			(long)file);
+}
+
+#else
+
+static void smb5_create_debugfs(struct smb5 *chip)
+{}
+
+#endif
+
+static int smb5_show_charger_status(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	union power_supply_propval val;
+	int usb_present, batt_present, batt_health, batt_charge_type;
+	int rc;
+
+	rc = smblib_get_prop_usb_present(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get usb present rc=%d\n", rc);
+		return rc;
+	}
+	usb_present = val.intval;
+
+	rc = smblib_get_prop_batt_present(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get batt present rc=%d\n", rc);
+		return rc;
+	}
+	batt_present = val.intval;
+
+	rc = smblib_get_prop_batt_health(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get batt health rc=%d\n", rc);
+		val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+	}
+	batt_health = val.intval;
+
+	rc = smblib_get_prop_batt_charge_type(chg, &val);
+	if (rc < 0) {
+		pr_err("Couldn't get batt charge type rc=%d\n", rc);
+		return rc;
+	}
+	batt_charge_type = val.intval;
+
+	pr_info("SMB5 status - usb:present=%d type=%d batt:present = %d health = %d charge = %d\n",
+		usb_present, chg->real_charger_type,
+		batt_present, batt_health, batt_charge_type);
+	return rc;
+}
+
+static int smb5_probe(struct platform_device *pdev)
+{
+	struct smb5 *chip;
+	struct smb_charger *chg;
+	int rc = 0;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chg = &chip->chg;
+	chg->dev = &pdev->dev;
+	chg->debug_mask = &__debug_mask;
+	chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
+	chg->mode = PARALLEL_MASTER;
+	chg->irq_info = smb5_irqs;
+	chg->die_health = -EINVAL;
+	chg->otg_present = false;
+
+	chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
+	if (!chg->regmap) {
+		pr_err("parent regmap is missing\n");
+		return -EINVAL;
+	}
+
+	rc = smb5_parse_dt(chip);
+	if (rc < 0) {
+		pr_err("Couldn't parse device tree rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smb5_chg_config_init(chip);
+	if (rc < 0) {
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't setup chg_config rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = smblib_init(chg);
+	if (rc < 0) {
+		pr_err("Smblib_init failed rc=%d\n", rc);
+		return rc;
+	}
+
+	/* set driver data before resources request it */
+	platform_set_drvdata(pdev, chip);
+
+	rc = smb5_init_vbus_regulator(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize vbus regulator rc=%d\n",
+			rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_vconn_regulator(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize vconn regulator rc=%d\n",
+				rc);
+		goto cleanup;
+	}
+
+	/* extcon registration */
+	chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable);
+	if (IS_ERR(chg->extcon)) {
+		rc = PTR_ERR(chg->extcon);
+		dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
+				rc);
+		goto cleanup;
+	}
+
+	rc = devm_extcon_dev_register(chg->dev, chg->extcon);
+	if (rc < 0) {
+		dev_err(chg->dev, "failed to register extcon device rc=%d\n",
+				rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_hw(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize hardware rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	if (chg->smb_version == PM855B_SUBTYPE) {
+		rc = smb5_init_dc_psy(chip);
+		if (rc < 0) {
+			pr_err("Couldn't initialize dc psy rc=%d\n", rc);
+			goto cleanup;
+		}
+	}
+
+	rc = smb5_init_usb_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize usb psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_usb_main_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize usb main psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_usb_port_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize usb pc_port psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_init_batt_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize batt psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_determine_initial_status(chip);
+	if (rc < 0) {
+		pr_err("Couldn't determine initial status rc=%d\n",
+			rc);
+		goto cleanup;
+	}
+
+	rc = smb5_request_interrupts(chip);
+	if (rc < 0) {
+		pr_err("Couldn't request interrupts rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb5_post_init(chip);
+	if (rc < 0) {
+		pr_err("Failed in post init rc=%d\n", rc);
+		goto free_irq;
+	}
+
+	smb5_create_debugfs(chip);
+
+	rc = smb5_show_charger_status(chip);
+	if (rc < 0) {
+		pr_err("Failed in getting charger status rc=%d\n", rc);
+		goto free_irq;
+	}
+
+	device_init_wakeup(chg->dev, true);
+
+	pr_info("QPNP SMB5 probed successfully\n");
+
+	return rc;
+
+free_irq:
+	smb5_free_interrupts(chg);
+cleanup:
+	smblib_deinit(chg);
+	platform_set_drvdata(pdev, NULL);
+
+	return rc;
+}
+
+static int smb5_remove(struct platform_device *pdev)
+{
+	struct smb5 *chip = platform_get_drvdata(pdev);
+	struct smb_charger *chg = &chip->chg;
+
+	smb5_free_interrupts(chg);
+	smblib_deinit(chg);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static void smb5_shutdown(struct platform_device *pdev)
+{
+	struct smb5 *chip = platform_get_drvdata(pdev);
+	struct smb_charger *chg = &chip->chg;
+
+	/* disable all interrupts */
+	smb5_disable_interrupts(chg);
+
+	/* configure power role for UFP */
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC)
+		smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				TYPEC_POWER_ROLE_CMD_MASK, EN_SNK_ONLY_BIT);
+
+	/* force HVDCP to 5V */
+	smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+				HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
+	smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
+
+	/* force enable APSD */
+	smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+				BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
+}
+
+static const struct of_device_id match_table[] = {
+	{ .compatible = "qcom,qpnp-smb5", },
+	{ },
+};
+
+static struct platform_driver smb5_driver = {
+	.driver		= {
+		.name		= "qcom,qpnp-smb5",
+		.owner		= THIS_MODULE,
+		.of_match_table	= match_table,
+	},
+	.probe		= smb5_probe,
+	.remove		= smb5_remove,
+	.shutdown	= smb5_shutdown,
+};
+module_platform_driver(smb5_driver);
+
+MODULE_DESCRIPTION("QPNP SMB5 Charger Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index ebaaf5c..ffbced6 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -31,6 +31,7 @@
 
 /* SMB1355 registers, different than mentioned in smb-reg.h */
 
+#define REVID_BASE	0x0100
 #define CHGR_BASE	0x1000
 #define ANA2_BASE	0x1100
 #define BATIF_BASE	0x1200
@@ -38,6 +39,8 @@
 #define ANA1_BASE	0x1400
 #define MISC_BASE	0x1600
 
+#define REVID_MFG_ID_SPARE_REG			(REVID_BASE + 0xFF)
+
 #define BATTERY_STATUS_2_REG			(CHGR_BASE + 0x0B)
 #define DISABLE_CHARGING_BIT			BIT(3)
 
@@ -222,6 +225,8 @@
 	char			*name;
 	struct regmap		*regmap;
 
+	int			max_fcc;
+
 	struct smb_dt_props	dt;
 	struct smb_params	param;
 	struct smb_iio		iio;
@@ -483,6 +488,7 @@
 	POWER_SUPPLY_PROP_PARALLEL_MODE,
 	POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
 	POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+	POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -624,6 +630,9 @@
 	case POWER_SUPPLY_PROP_MIN_ICL:
 		val->intval = MIN_PARALLEL_ICL_UA;
 		break;
+	case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX:
+		val->intval = chip->max_fcc;
+		break;
 	default:
 		pr_err_ratelimited("parallel psy get prop %d not supported\n",
 			prop);
@@ -798,6 +807,37 @@
  * HARDWARE INITIALIZATION *
  ***************************/
 
+#define MFG_ID_SMB1354			0x01
+#define MFG_ID_SMB1355			0xFF
+#define SMB1354_MAX_PARALLEL_FCC_UA	2500000
+static int smb1355_detect_version(struct smb1355 *chip)
+{
+	int rc;
+	u8 val;
+
+	rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val);
+	if (rc < 0) {
+		pr_err("Unable to read REVID rc=%d\n", rc);
+		return rc;
+	}
+
+	switch (val) {
+	case MFG_ID_SMB1354:
+		chip->name = "smb1354";
+		chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA;
+		break;
+	case MFG_ID_SMB1355:
+		chip->name = "smb1355";
+		chip->max_fcc = INT_MAX;
+		break;
+	default:
+		pr_err("Invalid value of REVID val=%d", val);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
 static int smb1355_tskin_sensor_config(struct smb1355 *chip)
 {
 	int rc;
@@ -1196,7 +1236,6 @@
 	chip->dev = &pdev->dev;
 	chip->param = v1_params;
 	chip->c_health = -EINVAL;
-	chip->name = "smb1355";
 	mutex_init(&chip->write_lock);
 	INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work);
 	chip->disabled = true;
@@ -1214,6 +1253,12 @@
 		return -ENODEV;
 	}
 
+	rc = smb1355_detect_version(chip);
+	if (rc < 0) {
+		pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc);
+		goto cleanup;
+	}
+
 	platform_set_drvdata(pdev, chip);
 
 	rc = smb1355_parse_dt(chip);
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
new file mode 100644
index 0000000..dbadd95
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -0,0 +1,3681 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/driver.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/irq.h>
+#include <linux/pmic-voter.h>
+#include "smb5-lib.h"
+#include "smb5-reg.h"
+#include "battery.h"
+#include "step-chg-jeita.h"
+#include "storm-watch.h"
+
+#define smblib_err(chg, fmt, ...)		\
+	pr_err("%s: %s: " fmt, chg->name,	\
+		__func__, ##__VA_ARGS__)	\
+
+#define smblib_dbg(chg, reason, fmt, ...)			\
+	do {							\
+		if (*chg->debug_mask & (reason))		\
+			pr_info("%s: %s: " fmt, chg->name,	\
+				__func__, ##__VA_ARGS__);	\
+		else						\
+			pr_debug("%s: %s: " fmt, chg->name,	\
+				__func__, ##__VA_ARGS__);	\
+	} while (0)
+
+
+int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
+{
+	unsigned int value;
+	int rc = 0;
+
+	rc = regmap_read(chg->regmap, addr, &value);
+	if (rc >= 0)
+		*val = (u8)value;
+
+	return rc;
+}
+
+int smblib_batch_read(struct smb_charger *chg, u16 addr, u8 *val,
+			int count)
+{
+	return regmap_bulk_read(chg->regmap, addr, val, count);
+}
+
+int smblib_write(struct smb_charger *chg, u16 addr, u8 val)
+{
+	return regmap_write(chg->regmap, addr, val);
+}
+
+int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
+{
+
+	return regmap_update_bits(chg->regmap, addr, mask, val);
+
+}
+
+int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
+{
+	int rc, cc_minus_ua;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	if (stat & BAT_TEMP_STATUS_HOT_SOFT_BIT) {
+		rc = smblib_get_charge_param(chg, &chg->param.jeita_cc_comp_hot,
+					&cc_minus_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n",
+					rc);
+			return rc;
+		}
+	} else if (stat & BAT_TEMP_STATUS_COLD_SOFT_BIT) {
+		rc = smblib_get_charge_param(chg,
+					&chg->param.jeita_cc_comp_cold,
+					&cc_minus_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get jeita cc minus rc=%d\n",
+					rc);
+			return rc;
+		}
+	} else {
+		cc_minus_ua = 0;
+	}
+
+	*cc_delta_ua = -cc_minus_ua;
+
+	return 0;
+}
+
+int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
+{
+	int rc = 0;
+
+	/* override  = 1, SW STAT override; override = 0, HW auto mode */
+	rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
+				SMB_EN_OVERRIDE_BIT,
+				override ? SMB_EN_OVERRIDE_BIT : 0);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
+{
+	union extcon_property_value val;
+	union power_supply_propval prop_val;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) {
+		smblib_get_prop_typec_cc_orientation(chg, &prop_val);
+		val.intval = ((prop_val.intval == 2) ? 1 : 0);
+		extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_TYPEC_POLARITY, val);
+	}
+
+	val.intval = true;
+	extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_SS, val);
+}
+
+static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
+}
+
+static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
+}
+
+/********************
+ * REGISTER GETTERS *
+ ********************/
+
+int smblib_get_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int *val_u)
+{
+	int rc = 0;
+	u8 val_raw;
+
+	rc = smblib_read(chg, param->reg, &val_raw);
+	if (rc < 0) {
+		smblib_err(chg, "%s: Couldn't read from 0x%04x rc=%d\n",
+			param->name, param->reg, rc);
+		return rc;
+	}
+
+	if (param->get_proc)
+		*val_u = param->get_proc(param, val_raw);
+	else
+		*val_u = val_raw * param->step_u + param->min_u;
+	smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
+		   param->name, *val_u, val_raw);
+
+	return rc;
+}
+
+int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
+{
+	int rc = 0;
+	u8 temp;
+
+	rc = smblib_read(chg, USBIN_CMD_IL_REG, &temp);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc);
+		return rc;
+	}
+	*suspend = temp & USBIN_SUSPEND_BIT;
+
+	return rc;
+}
+
+struct apsd_result {
+	const char * const name;
+	const u8 bit;
+	const enum power_supply_type pst;
+};
+
+enum {
+	UNKNOWN,
+	SDP,
+	CDP,
+	DCP,
+	OCP,
+	FLOAT,
+	HVDCP2,
+	HVDCP3,
+	MAX_TYPES
+};
+
+static const struct apsd_result smblib_apsd_results[] = {
+	[UNKNOWN] = {
+		.name	= "UNKNOWN",
+		.bit	= 0,
+		.pst	= POWER_SUPPLY_TYPE_UNKNOWN
+	},
+	[SDP] = {
+		.name	= "SDP",
+		.bit	= SDP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB
+	},
+	[CDP] = {
+		.name	= "CDP",
+		.bit	= CDP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_CDP
+	},
+	[DCP] = {
+		.name	= "DCP",
+		.bit	= DCP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_DCP
+	},
+	[OCP] = {
+		.name	= "OCP",
+		.bit	= OCP_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_DCP
+	},
+	[FLOAT] = {
+		.name	= "FLOAT",
+		.bit	= FLOAT_CHARGER_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_FLOAT
+	},
+	[HVDCP2] = {
+		.name	= "HVDCP2",
+		.bit	= DCP_CHARGER_BIT | QC_2P0_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_HVDCP
+	},
+	[HVDCP3] = {
+		.name	= "HVDCP3",
+		.bit	= DCP_CHARGER_BIT | QC_3P0_BIT,
+		.pst	= POWER_SUPPLY_TYPE_USB_HVDCP_3,
+	},
+};
+
+static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
+{
+	int rc, i;
+	u8 apsd_stat, stat;
+	const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
+
+	rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+		return result;
+	}
+	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
+
+	if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
+		return result;
+
+	rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
+			rc);
+		return result;
+	}
+	stat &= APSD_RESULT_STATUS_MASK;
+
+	for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
+		if (smblib_apsd_results[i].bit == stat)
+			result = &smblib_apsd_results[i];
+	}
+
+	if (apsd_stat & QC_CHARGER_BIT) {
+		/* since its a qc_charger, either return HVDCP3 or HVDCP2 */
+		if (result != &smblib_apsd_results[HVDCP3])
+			result = &smblib_apsd_results[HVDCP2];
+	}
+
+	return result;
+}
+
+/********************
+ * REGISTER SETTERS *
+ ********************/
+static const struct buck_boost_freq chg_freq_list[] = {
+	[0] = {
+		.freq_khz	= 2400,
+		.val		= 7,
+	},
+	[1] = {
+		.freq_khz	= 2100,
+		.val		= 8,
+	},
+	[2] = {
+		.freq_khz	= 1600,
+		.val		= 11,
+	},
+	[3] = {
+		.freq_khz	= 1200,
+		.val		= 15,
+	},
+};
+
+int smblib_set_chg_freq(struct smb_chg_param *param,
+				int val_u, u8 *val_raw)
+{
+	u8 i;
+
+	if (val_u > param->max_u || val_u < param->min_u)
+		return -EINVAL;
+
+	/* Charger FSW is the configured freqency / 2 */
+	val_u *= 2;
+	for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
+		if (chg_freq_list[i].freq_khz == val_u)
+			break;
+	}
+	if (i == ARRAY_SIZE(chg_freq_list)) {
+		pr_err("Invalid frequency %d Hz\n", val_u / 2);
+		return -EINVAL;
+	}
+
+	*val_raw = chg_freq_list[i].val;
+
+	return 0;
+}
+
+int smblib_set_opt_switcher_freq(struct smb_charger *chg, int fsw_khz)
+{
+	union power_supply_propval pval = {0, };
+	int rc = 0;
+
+	rc = smblib_set_charge_param(chg, &chg->param.freq_switcher, fsw_khz);
+	if (rc < 0)
+		dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
+
+	if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
+		pval.intval = fsw_khz;
+		/*
+		 * Some parallel charging implementations may not have
+		 * PROP_BUCK_FREQ property - they could be running
+		 * with a fixed frequency
+		 */
+		power_supply_set_property(chg->pl.psy,
+				POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
+	}
+
+	return rc;
+}
+
+int smblib_set_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int val_u)
+{
+	int rc = 0;
+	u8 val_raw;
+
+	if (param->set_proc) {
+		rc = param->set_proc(param, val_u, &val_raw);
+		if (rc < 0)
+			return -EINVAL;
+	} else {
+		if (val_u > param->max_u || val_u < param->min_u)
+			smblib_dbg(chg, PR_MISC,
+				"%s: %d is out of range [%d, %d]\n",
+				param->name, val_u, param->min_u, param->max_u);
+
+		if (val_u > param->max_u)
+			val_u = param->max_u;
+		if (val_u < param->min_u)
+			val_u = param->min_u;
+
+		val_raw = (val_u - param->min_u) / param->step_u;
+	}
+
+	rc = smblib_write(chg, param->reg, val_raw);
+	if (rc < 0) {
+		smblib_err(chg, "%s: Couldn't write 0x%02x to 0x%04x rc=%d\n",
+			param->name, val_raw, param->reg, rc);
+		return rc;
+	}
+
+	smblib_dbg(chg, PR_REGISTER, "%s = %d (0x%02x)\n",
+		   param->name, val_u, val_raw);
+
+	return rc;
+}
+
+int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend)
+{
+	int rc = 0;
+	int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq;
+
+	if (suspend && irq) {
+		if (chg->usb_icl_change_irq_enabled) {
+			disable_irq_nosync(irq);
+			chg->usb_icl_change_irq_enabled = false;
+		}
+	}
+
+	rc = smblib_masked_write(chg, USBIN_CMD_IL_REG, USBIN_SUSPEND_BIT,
+				 suspend ? USBIN_SUSPEND_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write %s to USBIN_SUSPEND_BIT rc=%d\n",
+			suspend ? "suspend" : "resume", rc);
+
+	if (!suspend && irq) {
+		if (!chg->usb_icl_change_irq_enabled) {
+			enable_irq(irq);
+			chg->usb_icl_change_irq_enabled = true;
+		}
+	}
+
+	return rc;
+}
+
+int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend)
+{
+	int rc = 0;
+
+	rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT,
+				 suspend ? DCIN_SUSPEND_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write %s to DCIN_SUSPEND_BIT rc=%d\n",
+			suspend ? "suspend" : "resume", rc);
+
+	return rc;
+}
+
+static int smblib_set_adapter_allowance(struct smb_charger *chg,
+					u8 allowed_voltage)
+{
+	int rc = 0;
+
+	rc = smblib_write(chg, USBIN_ADAPTER_ALLOW_CFG_REG, allowed_voltage);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't write 0x%02x to USBIN_ADAPTER_ALLOW_CFG rc=%d\n",
+			allowed_voltage, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+#define MICRO_5V	5000000
+#define MICRO_9V	9000000
+#define MICRO_12V	12000000
+static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
+					int min_allowed_uv, int max_allowed_uv)
+{
+	int rc;
+	u8 allowed_voltage;
+
+	if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
+		smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_5V);
+	} else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
+		smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_9V);
+	} else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
+		smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_12V);
+	} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
+	} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_12V;
+	} else if (min_allowed_uv < MICRO_12V && max_allowed_uv <= MICRO_12V) {
+		allowed_voltage = USBIN_ADAPTER_ALLOW_9V_TO_12V;
+	} else {
+		smblib_err(chg, "invalid allowed voltage [%d, %d]\n",
+			min_allowed_uv, max_allowed_uv);
+		return -EINVAL;
+	}
+
+	rc = smblib_set_adapter_allowance(chg, allowed_voltage);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't configure adapter allowance rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/********************
+ * HELPER FUNCTIONS *
+ ********************/
+static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
+{
+	int rc = 0;
+
+	/* fetch the DPDM regulator */
+	if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
+				"dpdm-supply", NULL)) {
+		chg->dpdm_reg = devm_regulator_get(chg->dev, "dpdm");
+		if (IS_ERR(chg->dpdm_reg)) {
+			rc = PTR_ERR(chg->dpdm_reg);
+			smblib_err(chg, "Couldn't get dpdm regulator rc=%d\n",
+					rc);
+			chg->dpdm_reg = NULL;
+			return rc;
+		}
+	}
+
+	if (enable) {
+		if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
+			smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
+			rc = regulator_enable(chg->dpdm_reg);
+			if (rc < 0)
+				smblib_err(chg,
+					"Couldn't enable dpdm regulator rc=%d\n",
+					rc);
+		}
+	} else {
+		if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
+			smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
+			rc = regulator_disable(chg->dpdm_reg);
+			if (rc < 0)
+				smblib_err(chg,
+					"Couldn't disable dpdm regulator rc=%d\n",
+					rc);
+		}
+	}
+
+	return rc;
+}
+
+static void smblib_rerun_apsd(struct smb_charger *chg)
+{
+	int rc;
+
+	smblib_dbg(chg, PR_MISC, "re-running APSD\n");
+
+	rc = smblib_masked_write(chg, CMD_APSD_REG,
+				APSD_RERUN_BIT, APSD_RERUN_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
+}
+
+static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
+{
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+
+	/* if PD is active, APSD is disabled so won't have a valid result */
+	if (chg->pd_active) {
+		chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD;
+	} else {
+		/*
+		 * Update real charger type only if its not FLOAT
+		 * detected as as SDP
+		 */
+		if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
+			chg->real_charger_type == POWER_SUPPLY_TYPE_USB))
+			chg->real_charger_type = apsd_result->pst;
+	}
+
+	smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n",
+					apsd_result->name, chg->pd_active);
+	return apsd_result;
+}
+
+static int smblib_notifier_call(struct notifier_block *nb,
+		unsigned long ev, void *v)
+{
+	struct power_supply *psy = v;
+	struct smb_charger *chg = container_of(nb, struct smb_charger, nb);
+
+	if (!strcmp(psy->desc->name, "bms")) {
+		if (!chg->bms_psy)
+			chg->bms_psy = psy;
+		if (ev == PSY_EVENT_PROP_CHANGED)
+			schedule_work(&chg->bms_update_work);
+	}
+
+	if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
+		chg->pl.psy = psy;
+		schedule_work(&chg->pl_update_work);
+	}
+
+	return NOTIFY_OK;
+}
+
+static int smblib_register_notifier(struct smb_charger *chg)
+{
+	int rc;
+
+	chg->nb.notifier_call = smblib_notifier_call;
+	rc = power_supply_reg_notifier(&chg->nb);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't register psy notifier rc = %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw)
+{
+	if (val_u > param->max_u || val_u < param->min_u)
+		return -EINVAL;
+
+	*val_raw = val_u << 1;
+
+	return 0;
+}
+
+int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
+					   u8 val_raw)
+{
+	int val_u  = val_raw * param->step_u + param->min_u;
+
+	if (val_u > param->max_u)
+		val_u -= param->max_u * 2;
+
+	return val_u;
+}
+
+int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw)
+{
+	if (val_u > param->max_u || val_u < param->min_u - param->max_u)
+		return -EINVAL;
+
+	val_u += param->max_u * 2 - param->min_u;
+	val_u %= param->max_u * 2;
+	*val_raw = val_u / param->step_u;
+
+	return 0;
+}
+
+static void smblib_uusb_removal(struct smb_charger *chg)
+{
+	int rc;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	cancel_delayed_work_sync(&chg->pl_enable_work);
+
+	rc = smblib_request_dpdm(chg, false);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
+
+	if (chg->wa_flags & BOOST_BACK_WA) {
+		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+		if (data) {
+			wdata = &data->storm_data;
+			update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
+			vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
+			vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+					false, 0);
+		}
+	}
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+
+	/* reset both usbin current and voltage votes */
+	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
+
+	/* reconfigure allowed voltage for HVDCP */
+	rc = smblib_set_adapter_allowance(chg,
+			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+			rc);
+
+	chg->voltage_min_uv = MICRO_5V;
+	chg->voltage_max_uv = MICRO_5V;
+	chg->usb_icl_delta_ua = 0;
+	chg->pulse_cnt = 0;
+	chg->uusb_apsd_rerun_done = false;
+
+	/* clear USB ICL vote for USB_PSY_VOTER */
+	rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
+
+	/* clear USB ICL vote for DCP_VOTER */
+	rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+	if (rc < 0)
+		smblib_err(chg,
+			"Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
+}
+
+void smblib_suspend_on_debug_battery(struct smb_charger *chg)
+{
+	int rc;
+	union power_supply_propval val;
+
+	if (!chg->suspend_input_on_debug_batt)
+		return;
+
+	rc = power_supply_get_property(chg->bms_psy,
+			POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
+		return;
+	}
+
+	vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+	vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+	if (val.intval)
+		pr_info("Input suspended: Fake battery\n");
+}
+
+int smblib_rerun_apsd_if_required(struct smb_charger *chg)
+{
+	union power_supply_propval val;
+	int rc;
+
+	rc = smblib_get_prop_usb_present(chg, &val);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get usb present rc = %d\n", rc);
+		return rc;
+	}
+
+	if (!val.intval)
+		return 0;
+
+	rc = smblib_request_dpdm(chg, true);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+
+	chg->uusb_apsd_rerun_done = true;
+	smblib_rerun_apsd(chg);
+
+	return 0;
+}
+
+static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count)
+{
+	*count = chg->pulse_cnt;
+	return 0;
+}
+
+#define USBIN_25MA	25000
+#define USBIN_100MA	100000
+#define USBIN_150MA	150000
+#define USBIN_500MA	500000
+#define USBIN_900MA	900000
+static int set_sdp_current(struct smb_charger *chg, int icl_ua)
+{
+	int rc;
+	u8 icl_options;
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+
+	/* power source is SDP */
+	switch (icl_ua) {
+	case USBIN_100MA:
+		/* USB 2.0 100mA */
+		icl_options = 0;
+		break;
+	case USBIN_150MA:
+		/* USB 3.0 150mA */
+		icl_options = CFG_USB3P0_SEL_BIT;
+		break;
+	case USBIN_500MA:
+		/* USB 2.0 500mA */
+		icl_options = USB51_MODE_BIT;
+		break;
+	case USBIN_900MA:
+		/* USB 3.0 900mA */
+		icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT;
+		break;
+	default:
+		smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
+		return -EINVAL;
+	}
+
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB &&
+		apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
+		/*
+		 * change the float charger configuration to SDP, if this
+		 * is the case of SDP being detected as FLOAT
+		 */
+		rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+			FORCE_FLOAT_SDP_CFG_BIT, FORCE_FLOAT_SDP_CFG_BIT);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't set float ICL options rc=%d\n",
+						rc);
+			return rc;
+		}
+	}
+
+	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
+		CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int get_sdp_current(struct smb_charger *chg, int *icl_ua)
+{
+	int rc;
+	u8 icl_options;
+	bool usb3 = false;
+
+	rc = smblib_read(chg, USBIN_ICL_OPTIONS_REG, &icl_options);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get ICL options rc=%d\n", rc);
+		return rc;
+	}
+
+	usb3 = (icl_options & CFG_USB3P0_SEL_BIT);
+
+	if (icl_options & USB51_MODE_BIT)
+		*icl_ua = usb3 ? USBIN_900MA : USBIN_500MA;
+	else
+		*icl_ua = usb3 ? USBIN_150MA : USBIN_100MA;
+
+	return rc;
+}
+
+int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
+{
+	int rc = 0;
+	bool hc_mode = false;
+
+	/* suspend and return if 25mA or less is requested */
+	if (icl_ua <= USBIN_25MA)
+		return smblib_set_usb_suspend(chg, true);
+
+	if (icl_ua == INT_MAX)
+		goto set_mode;
+
+	/* configure current */
+	if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT)
+		|| (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB))
+		&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
+		rc = set_sdp_current(chg, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
+			goto out;
+		}
+	} else {
+		set_sdp_current(chg, 100000);
+		rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
+			goto out;
+		}
+		hc_mode = true;
+	}
+
+set_mode:
+	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
+		USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0);
+
+	/* unsuspend after configuring current and override */
+	rc = smblib_set_usb_suspend(chg, false);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
+		goto out;
+	}
+
+out:
+	return rc;
+}
+
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
+{
+	int rc = 0;
+	u8 load_cfg;
+	bool override;
+
+	if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+		|| chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		&& (chg->usb_psy->desc->type == POWER_SUPPLY_TYPE_USB)) {
+		rc = get_sdp_current(chg, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get SDP ICL rc=%d\n", rc);
+			return rc;
+		}
+	} else {
+		rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &load_cfg);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get load cfg rc=%d\n", rc);
+			return rc;
+		}
+		override = load_cfg & ICL_OVERRIDE_AFTER_APSD_BIT;
+		if (!override)
+			return INT_MAX;
+
+		/* override is set */
+		rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/*********************
+ * VOTABLE CALLBACKS *
+ *********************/
+
+static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
+			int suspend, const char *client)
+{
+	struct smb_charger *chg = data;
+
+	if (chg->smb_version == PMI632_SUBTYPE)
+		return 0;
+
+	/* resume input if suspend is invalid */
+	if (suspend < 0)
+		suspend = 0;
+
+	return smblib_set_dc_suspend(chg, (bool)suspend);
+}
+
+static int smblib_pd_disallowed_votable_indirect_callback(
+	struct votable *votable, void *data, int disallowed, const char *client)
+{
+	struct smb_charger *chg = data;
+	int rc;
+
+	rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
+		!disallowed, 0);
+
+	return rc;
+}
+
+static int smblib_awake_vote_callback(struct votable *votable, void *data,
+			int awake, const char *client)
+{
+	struct smb_charger *chg = data;
+
+	if (awake)
+		pm_stay_awake(chg->dev);
+	else
+		pm_relax(chg->dev);
+
+	return 0;
+}
+
+static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
+			int chg_disable, const char *client)
+{
+	struct smb_charger *chg = data;
+	int rc;
+
+	rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
+				 CHARGING_ENABLE_CMD_BIT,
+				 chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't %s charging rc=%d\n",
+			chg_disable ? "disable" : "enable", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
+				void *data, int enable, const char *client)
+{
+	struct smb_charger *chg = data;
+
+	if (!chg->irq_info[INPUT_CURRENT_LIMITING_IRQ].irq ||
+				!chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+		return 0;
+
+	if (enable) {
+		enable_irq(chg->irq_info[INPUT_CURRENT_LIMITING_IRQ].irq);
+		enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+	} else {
+		disable_irq_nosync(
+			chg->irq_info[INPUT_CURRENT_LIMITING_IRQ].irq);
+		disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+	}
+
+	return 0;
+}
+
+/*******************
+ * VCONN REGULATOR *
+ * *****************/
+
+int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
+
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_VALUE_BIT, VCONN_EN_VALUE_BIT);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_VALUE_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't disable vconn regulator rc=%d\n", rc);
+
+	return 0;
+}
+
+int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc;
+	u8 cmd;
+
+	rc = smblib_read(chg, TYPE_C_VCONN_CONTROL_REG, &cmd);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	return (cmd & VCONN_EN_VALUE_BIT) ? 1 : 0;
+}
+
+/*****************
+ * OTG REGULATOR *
+ *****************/
+
+int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc;
+
+	smblib_dbg(chg, PR_OTG, "enabling OTG\n");
+
+	rc = smblib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, OTG_EN_BIT);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc;
+
+	smblib_dbg(chg, PR_OTG, "disabling OTG\n");
+
+	rc = smblib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, 0);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct smb_charger *chg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u8 cmd;
+
+	rc = smblib_read(chg, DCDC_CMD_OTG_REG, &cmd);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read CMD_OTG rc=%d", rc);
+		return rc;
+	}
+
+	return (cmd & OTG_EN_BIT) ? 1 : 0;
+}
+
+/********************
+ * BATT PSY GETTERS *
+ ********************/
+
+int smblib_get_prop_input_suspend(struct smb_charger *chg,
+				  union power_supply_propval *val)
+{
+	val->intval
+		= (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
+		 && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
+	return 0;
+}
+
+int smblib_get_prop_batt_present(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATIF_INT_RT_STS rc=%d\n", rc);
+		return rc;
+	}
+
+	val->intval = !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT
+					| BAT_TERMINAL_MISSING_RT_STS_BIT));
+
+	return rc;
+}
+
+int smblib_get_prop_batt_capacity(struct smb_charger *chg,
+				  union power_supply_propval *val)
+{
+	int rc = -EINVAL;
+
+	if (chg->fake_capacity >= 0) {
+		val->intval = chg->fake_capacity;
+		return 0;
+	}
+
+	if (chg->bms_psy)
+		rc = power_supply_get_property(chg->bms_psy,
+				POWER_SUPPLY_PROP_CAPACITY, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_status(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	union power_supply_propval pval = {0, };
+	bool usb_online, dc_online;
+	u8 stat;
+	int rc;
+
+	rc = smblib_get_prop_usb_online(chg, &pval);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get usb online property rc=%d\n",
+			rc);
+		return rc;
+	}
+	usb_online = (bool)pval.intval;
+
+	rc = smblib_get_prop_dc_online(chg, &pval);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get dc online property rc=%d\n",
+			rc);
+		return rc;
+	}
+	dc_online = (bool)pval.intval;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+			rc);
+		return rc;
+	}
+	stat = stat & BATTERY_CHARGER_STATUS_MASK;
+
+	if (!usb_online && !dc_online) {
+		switch (stat) {
+		case TERMINATE_CHARGE:
+		case INHIBIT_CHARGE:
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+			break;
+		}
+		return rc;
+	}
+
+	switch (stat) {
+	case TRICKLE_CHARGE:
+	case PRE_CHARGE:
+	case FULLON_CHARGE:
+	case TAPER_CHARGE:
+		val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case TERMINATE_CHARGE:
+	case INHIBIT_CHARGE:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		break;
+	case DISABLE_CHARGE:
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	}
+
+	if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
+		return 0;
+
+	if (!usb_online && dc_online
+		&& chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		return 0;
+	}
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_5_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+				rc);
+			return rc;
+	}
+
+	stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
+						ENABLE_FULLON_MODE_BIT;
+
+	if (!stat)
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
+	return 0;
+}
+
+int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	switch (stat & BATTERY_CHARGER_STATUS_MASK) {
+	case TRICKLE_CHARGE:
+	case PRE_CHARGE:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+		break;
+	case FULLON_CHARGE:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		break;
+	case TAPER_CHARGE:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_TAPER;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+	}
+
+	return rc;
+}
+
+int smblib_get_prop_batt_health(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	union power_supply_propval pval;
+	int rc;
+	int effective_fv_uv;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n",
+		   stat);
+
+	if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) {
+		rc = smblib_get_prop_batt_voltage_now(chg, &pval);
+		if (!rc) {
+			/*
+			 * If Vbatt is within 40mV above Vfloat, then don't
+			 * treat it as overvoltage.
+			 */
+			effective_fv_uv = get_effective_result(chg->fv_votable);
+			if (pval.intval >= effective_fv_uv + 40000) {
+				val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+				smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n",
+						pval.intval, effective_fv_uv);
+				goto done;
+			}
+		}
+	}
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+			rc);
+		return rc;
+	}
+	if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_COLD;
+	else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+	else if (stat & BAT_TEMP_STATUS_COLD_SOFT_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_COOL;
+	else if (stat & BAT_TEMP_STATUS_HOT_SOFT_BIT)
+		val->intval = POWER_SUPPLY_HEALTH_WARM;
+	else
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+
+done:
+	return rc;
+}
+
+int smblib_get_prop_system_temp_level(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	val->intval = chg->system_temp_level;
+	return 0;
+}
+
+int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	val->intval = chg->thermal_levels;
+	return 0;
+}
+
+int smblib_get_prop_input_current_limited(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	u8 stat;
+	int rc;
+
+	if (chg->fake_input_current_limited >= 0) {
+		val->intval = chg->fake_input_current_limited;
+		return 0;
+	}
+
+	rc = smblib_read(chg, AICL_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n", rc);
+		return rc;
+	}
+	val->intval = (stat & SOFT_ILIMIT_BIT) || chg->is_hdc;
+	return 0;
+}
+
+int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_VOLTAGE_NOW, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_current_now(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_CURRENT_NOW, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_temp(struct smb_charger *chg,
+			      union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_TEMP, val);
+	return rc;
+}
+
+int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
+					union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	stat = stat & BATTERY_CHARGER_STATUS_MASK;
+	val->intval = (stat == TERMINATE_CHARGE);
+	return 0;
+}
+
+int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc;
+
+	if (!chg->bms_psy)
+		return -EINVAL;
+
+	rc = power_supply_get_property(chg->bms_psy,
+				       POWER_SUPPLY_PROP_CHARGE_COUNTER, val);
+	return rc;
+}
+
+/***********************
+ * BATTERY PSY SETTERS *
+ ***********************/
+
+int smblib_set_prop_input_suspend(struct smb_charger *chg,
+				  const union power_supply_propval *val)
+{
+	int rc;
+
+	/* vote 0mA when suspended */
+	rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
+			(bool)val->intval ? "suspend" : "resume", rc);
+		return rc;
+	}
+
+	rc = vote(chg->dc_suspend_votable, USER_VOTER, (bool)val->intval, 0);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't vote to %s DC rc=%d\n",
+			(bool)val->intval ? "suspend" : "resume", rc);
+		return rc;
+	}
+
+	power_supply_changed(chg->batt_psy);
+	return rc;
+}
+
+int smblib_set_prop_batt_capacity(struct smb_charger *chg,
+				  const union power_supply_propval *val)
+{
+	chg->fake_capacity = val->intval;
+
+	power_supply_changed(chg->batt_psy);
+
+	return 0;
+}
+
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+				  const union power_supply_propval *val)
+{
+	/* Faking battery full */
+	if (val->intval == POWER_SUPPLY_STATUS_FULL)
+		chg->fake_batt_status = val->intval;
+	else
+		chg->fake_batt_status = -EINVAL;
+
+	power_supply_changed(chg->batt_psy);
+
+	return 0;
+}
+
+int smblib_set_prop_system_temp_level(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	if (val->intval < 0)
+		return -EINVAL;
+
+	if (chg->thermal_levels <= 0)
+		return -EINVAL;
+
+	if (val->intval > chg->thermal_levels)
+		return -EINVAL;
+
+	chg->system_temp_level = val->intval;
+	/* disable parallel charge in case of system temp level */
+	vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
+			chg->system_temp_level ? true : false, 0);
+
+	if (chg->system_temp_level == chg->thermal_levels)
+		return vote(chg->chg_disable_votable,
+			THERMAL_DAEMON_VOTER, true, 0);
+
+	vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
+	if (chg->system_temp_level == 0)
+		return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
+
+	vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
+			chg->thermal_mitigation[chg->system_temp_level]);
+	return 0;
+}
+
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	chg->fake_input_current_limited = val->intval;
+	return 0;
+}
+
+int smblib_rerun_aicl(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+								rc);
+		return rc;
+	}
+
+	/* USB is suspended so skip re-running AICL */
+	if (stat & USBIN_SUSPEND_STS_BIT)
+		return rc;
+
+	smblib_dbg(chg, PR_MISC, "re-running AICL\n");
+
+	rc = smblib_masked_write(chg, AICL_CMD_REG, RERUN_AICL_BIT,
+				RERUN_AICL_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to AICL_CMD_REG rc=%d\n",
+				rc);
+	return 0;
+}
+
+static int smblib_dp_pulse(struct smb_charger *chg)
+{
+	int rc;
+
+	/* QC 3.0 increment */
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_INCREMENT_BIT,
+			SINGLE_INCREMENT_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+static int smblib_dm_pulse(struct smb_charger *chg)
+{
+	int rc;
+
+	/* QC 3.0 decrement */
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, SINGLE_DECREMENT_BIT,
+			SINGLE_DECREMENT_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val)
+{
+	int rc;
+
+	rc = smblib_masked_write(chg, CMD_HVDCP_2_REG, val, val);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write to CMD_HVDCP_2_REG rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+int smblib_dp_dm(struct smb_charger *chg, int val)
+{
+	int target_icl_ua, rc = 0;
+	union power_supply_propval pval;
+
+	switch (val) {
+	case POWER_SUPPLY_DP_DM_DP_PULSE:
+		rc = smblib_dp_pulse(chg);
+		if (!rc)
+			chg->pulse_cnt++;
+		smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n",
+				rc, chg->pulse_cnt);
+		break;
+	case POWER_SUPPLY_DP_DM_DM_PULSE:
+		rc = smblib_dm_pulse(chg);
+		if (!rc && chg->pulse_cnt)
+			chg->pulse_cnt--;
+		smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n",
+				rc, chg->pulse_cnt);
+		break;
+	case POWER_SUPPLY_DP_DM_ICL_DOWN:
+		target_icl_ua = get_effective_result(chg->usb_icl_votable);
+		if (target_icl_ua < 0) {
+			/* no client vote, get the ICL from charger */
+			rc = power_supply_get_property(chg->usb_psy,
+					POWER_SUPPLY_PROP_HW_CURRENT_MAX,
+					&pval);
+			if (rc < 0) {
+				smblib_err(chg, "Couldn't get max curr rc=%d\n",
+					rc);
+				return rc;
+			}
+			target_icl_ua = pval.intval;
+		}
+
+		/*
+		 * Check if any other voter voted on USB_ICL in case of
+		 * voter other than SW_QC3_VOTER reset and restart reduction
+		 * again.
+		 */
+		if (target_icl_ua != get_client_vote(chg->usb_icl_votable,
+							SW_QC3_VOTER))
+			chg->usb_icl_delta_ua = 0;
+
+		chg->usb_icl_delta_ua += 100000;
+		vote(chg->usb_icl_votable, SW_QC3_VOTER, true,
+						target_icl_ua - 100000);
+		smblib_dbg(chg, PR_PARALLEL, "ICL DOWN ICL=%d reduction=%d\n",
+				target_icl_ua, chg->usb_icl_delta_ua);
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_5V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 5V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_9V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 9V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_FORCE_12V:
+		rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT);
+		if (rc < 0)
+			pr_err("Failed to force 12V\n");
+		break;
+	case POWER_SUPPLY_DP_DM_ICL_UP:
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
+{
+	int rc;
+	u8 mask;
+
+	/*
+	 * Disable h/w base JEITA compensation if s/w JEITA is enabled
+	 */
+	mask = JEITA_EN_COLD_SL_FCV_BIT
+		| JEITA_EN_HOT_SL_FCV_BIT
+		| JEITA_EN_HOT_SL_CCC_BIT
+		| JEITA_EN_COLD_SL_CCC_BIT,
+	rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
+			disable ? 0 : mask);
+	if (rc < 0) {
+		dev_err(chg->dev, "Couldn't configure s/w jeita rc=%d\n",
+				rc);
+		return rc;
+	}
+	return 0;
+}
+
+/*******************
+ * DC PSY GETTERS *
+ *******************/
+
+int smblib_get_prop_dc_present(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, DCIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read DCIN_RT_STS rc=%d\n", rc);
+		return rc;
+	}
+
+	val->intval = (bool)(stat & DCIN_PLUGIN_RT_STS_BIT);
+	return 0;
+}
+
+int smblib_get_prop_dc_online(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 stat;
+
+	if (get_client_vote(chg->dc_suspend_votable, USER_VOTER)) {
+		val->intval = false;
+		return rc;
+	}
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
+		   stat);
+
+	val->intval = (stat & USE_DCIN_BIT) &&
+		      (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
+
+	return rc;
+}
+
+/*******************
+ * USB PSY GETTERS *
+ *******************/
+
+int smblib_get_prop_usb_present(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc);
+		return rc;
+	}
+
+	val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+	return 0;
+}
+
+int smblib_get_prop_usb_online(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 stat;
+
+	if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) {
+		val->intval = false;
+		return rc;
+	}
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "POWER_PATH_STATUS = 0x%02x\n",
+		   stat);
+
+	val->intval = (stat & USE_USBIN_BIT) &&
+		      (stat & VALID_INPUT_POWER_SOURCE_STS_BIT);
+	return rc;
+}
+
+int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
+				    union power_supply_propval *val)
+{
+	switch (chg->real_charger_type) {
+	case POWER_SUPPLY_TYPE_USB_HVDCP:
+	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
+	case POWER_SUPPLY_TYPE_USB_PD:
+		if (chg->smb_version == PMI632_SUBTYPE)
+			val->intval = MICRO_9V;
+		else
+			val->intval = MICRO_12V;
+		break;
+	default:
+		val->intval = MICRO_5V;
+		break;
+	}
+
+	return 0;
+}
+
+int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
+					 union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
+
+	if (stat & CC_ATTACHED_BIT)
+		val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
+	else
+		val->intval = 0;
+
+	return rc;
+}
+
+static const char * const smblib_typec_mode_name[] = {
+	[POWER_SUPPLY_TYPEC_NONE]		  = "NONE",
+	[POWER_SUPPLY_TYPEC_SOURCE_DEFAULT]	  = "SOURCE_DEFAULT",
+	[POWER_SUPPLY_TYPEC_SOURCE_MEDIUM]	  = "SOURCE_MEDIUM",
+	[POWER_SUPPLY_TYPEC_SOURCE_HIGH]	  = "SOURCE_HIGH",
+	[POWER_SUPPLY_TYPEC_NON_COMPLIANT]	  = "NON_COMPLIANT",
+	[POWER_SUPPLY_TYPEC_SINK]		  = "SINK",
+	[POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE]   = "SINK_POWERED_CABLE",
+	[POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY] = "SINK_DEBUG_ACCESSORY",
+	[POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER]   = "SINK_AUDIO_ADAPTER",
+	[POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY]   = "POWERED_CABLE_ONLY",
+};
+
+static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_SNK_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
+		return POWER_SUPPLY_TYPEC_NONE;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
+
+	switch (stat & DETECTED_SRC_TYPE_MASK) {
+	case SNK_RP_STD_BIT:
+		return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
+	case SNK_RP_1P5_BIT:
+		return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM;
+	case SNK_RP_3P0_BIT:
+		return POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_TYPEC_NONE;
+}
+
+static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_SRC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_SRC_STATUS_REG rc=%d\n",
+				rc);
+		return POWER_SUPPLY_TYPEC_NONE;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_SRC_STATUS_REG = 0x%02x\n", stat);
+
+	switch (stat & DETECTED_SNK_TYPE_MASK) {
+	case AUDIO_ACCESS_RA_RA_BIT:
+		return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
+	case SRC_DEBUG_ACCESS_BIT:
+		return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY;
+	case SRC_RD_RA_VCONN_BIT:
+		return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
+	case SRC_RD_OPEN_BIT:
+		return POWER_SUPPLY_TYPEC_SINK;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_TYPEC_NONE;
+}
+
+static int smblib_get_prop_typec_mode(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n",
+				rc);
+		return 0;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_MISC_STATUS_REG = 0x%02x\n", stat);
+
+	if (stat & SNK_SRC_MODE_BIT)
+		return smblib_get_prop_dfp_mode(chg);
+	else
+		return smblib_get_prop_ufp_mode(chg);
+}
+
+int smblib_get_prop_typec_power_role(struct smb_charger *chg,
+				     union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 ctrl;
+
+	rc = smblib_read(chg, TYPE_C_MODE_CFG_REG, &ctrl);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_MODE_CFG_REG rc=%d\n",
+			rc);
+		return rc;
+	}
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_MODE_CFG_REG = 0x%02x\n",
+		   ctrl);
+
+	if (ctrl & TYPEC_DISABLE_CMD_BIT) {
+		val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
+		return rc;
+	}
+
+	switch (ctrl & (EN_SRC_ONLY_BIT | EN_SNK_ONLY_BIT)) {
+	case 0:
+		val->intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+		break;
+	case EN_SRC_ONLY_BIT:
+		val->intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
+		break;
+	case EN_SNK_ONLY_BIT:
+		val->intval = POWER_SUPPLY_TYPEC_PR_SINK;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_TYPEC_PR_NONE;
+		smblib_err(chg, "unsupported power role 0x%02lx\n",
+			ctrl & (EN_SRC_ONLY_BIT | EN_SNK_ONLY_BIT));
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int smblib_get_prop_pd_allowed(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	val->intval = get_effective_result(chg->pd_allowed_votable);
+	return 0;
+}
+
+int smblib_get_prop_input_current_settled(struct smb_charger *chg,
+					  union power_supply_propval *val)
+{
+	return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
+}
+
+#define HVDCP3_STEP_UV	200000
+int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
+						union power_supply_propval *val)
+{
+	int rc, pulses;
+
+	switch (chg->real_charger_type) {
+	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
+		rc = smblib_get_pulse_cnt(chg, &pulses);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
+			return 0;
+		}
+		val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
+		break;
+	case POWER_SUPPLY_TYPE_USB_PD:
+		val->intval = chg->voltage_min_uv;
+		break;
+	default:
+		val->intval = MICRO_5V;
+		break;
+	}
+
+	return 0;
+}
+
+int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	val->intval = chg->pd_hard_reset;
+	return 0;
+}
+
+int smblib_get_pe_start(struct smb_charger *chg,
+			       union power_supply_propval *val)
+{
+	/*
+	 * hvdcp timeout voter is the last one to allow pd. Use its vote
+	 * to indicate start of pe engine
+	 */
+	val->intval
+		= !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
+			APSD_VOTER);
+	return 0;
+}
+
+int smblib_get_prop_die_health(struct smb_charger *chg,
+						union power_supply_propval *val)
+{
+	int rc;
+	u8 stat;
+
+	rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
+									rc);
+		return rc;
+	}
+
+	/* TEMP_RANGE bits are mutually exclusive */
+	switch (stat & TEMP_RANGE_MASK) {
+	case TEMP_BELOW_RANGE_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_COOL;
+		break;
+	case TEMP_WITHIN_RANGE_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_WARM;
+		break;
+	case TEMP_ABOVE_RANGE_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_HOT;
+		break;
+	case ALERT_LEVEL_BIT:
+		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+	}
+
+	return 0;
+}
+
+#define SDP_CURRENT_UA			500000
+#define CDP_CURRENT_UA			1500000
+#define DCP_CURRENT_UA			1500000
+#define HVDCP_CURRENT_UA		3000000
+#define TYPEC_DEFAULT_CURRENT_UA	900000
+#define TYPEC_MEDIUM_CURRENT_UA		1500000
+#define TYPEC_HIGH_CURRENT_UA		3000000
+static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode)
+{
+	int rp_ua;
+
+	switch (typec_mode) {
+	case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
+		rp_ua = TYPEC_HIGH_CURRENT_UA;
+		break;
+	case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
+	case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
+	/* fall through */
+	default:
+		rp_ua = DCP_CURRENT_UA;
+	}
+
+	return rp_ua;
+}
+
+/*******************
+ * USB PSY SETTERS *
+ * *****************/
+
+int smblib_set_prop_pd_current_max(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc;
+
+	if (chg->pd_active)
+		rc = vote(chg->usb_icl_votable, PD_VOTER, true, val->intval);
+	else
+		rc = -EPERM;
+
+	return rc;
+}
+
+static int smblib_handle_usb_current(struct smb_charger *chg,
+					int usb_current)
+{
+	int rc = 0, rp_ua, typec_mode;
+
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
+		if (usb_current == -ETIMEDOUT) {
+			/*
+			 * Valid FLOAT charger, report the current based
+			 * of Rp
+			 */
+			typec_mode = smblib_get_prop_typec_mode(chg);
+			rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+			rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
+								true, rp_ua);
+			if (rc < 0)
+				return rc;
+		} else {
+			/*
+			 * FLOAT charger detected as SDP by USB driver,
+			 * charge with the requested current and update the
+			 * real_charger_type
+			 */
+			chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
+			rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+						true, usb_current);
+			if (rc < 0)
+				return rc;
+			rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER,
+							false, 0);
+			if (rc < 0)
+				return rc;
+		}
+	} else {
+		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
+					true, usb_current);
+	}
+
+	return rc;
+}
+
+int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	if (!chg->pd_active) {
+		rc = smblib_handle_usb_current(chg, val->intval);
+	} else if (chg->system_suspend_supported) {
+		if (val->intval <= USBIN_25MA)
+			rc = vote(chg->usb_icl_votable,
+				PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
+		else
+			rc = vote(chg->usb_icl_votable,
+				PD_SUSPEND_SUPPORTED_VOTER, false, 0);
+	}
+	return rc;
+}
+
+int smblib_set_prop_boost_current(struct smb_charger *chg,
+					const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	rc = smblib_set_charge_param(chg, &chg->param.freq_switcher,
+				val->intval <= chg->boost_threshold_ua ?
+				chg->chg_freq.freq_below_otg_threshold :
+				chg->chg_freq.freq_above_otg_threshold);
+	if (rc < 0) {
+		dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->boost_current_ua = val->intval;
+	return rc;
+}
+
+int smblib_set_prop_typec_power_role(struct smb_charger *chg,
+				     const union power_supply_propval *val)
+{
+	int rc = 0;
+	u8 power_role;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		return 0;
+
+	switch (val->intval) {
+	case POWER_SUPPLY_TYPEC_PR_NONE:
+		power_role = TYPEC_DISABLE_CMD_BIT;
+		break;
+	case POWER_SUPPLY_TYPEC_PR_DUAL:
+		power_role = 0;
+		break;
+	case POWER_SUPPLY_TYPEC_PR_SINK:
+		power_role = EN_SNK_ONLY_BIT;
+		break;
+	case POWER_SUPPLY_TYPEC_PR_SOURCE:
+		power_role = EN_SRC_ONLY_BIT;
+		break;
+	default:
+		smblib_err(chg, "power role %d not supported\n", val->intval);
+		return -EINVAL;
+	}
+
+	rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				 TYPEC_POWER_ROLE_CMD_MASK, power_role);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
+			power_role, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc, min_uv;
+
+	min_uv = min(val->intval, chg->voltage_max_uv);
+	rc = smblib_set_usb_pd_allowed_voltage(chg, min_uv,
+					       chg->voltage_max_uv);
+	if (rc < 0) {
+		smblib_err(chg, "invalid max voltage %duV rc=%d\n",
+			val->intval, rc);
+		return rc;
+	}
+
+	chg->voltage_min_uv = min_uv;
+	power_supply_changed(chg->usb_main_psy);
+
+	return rc;
+}
+
+int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
+				    const union power_supply_propval *val)
+{
+	int rc, max_uv;
+
+	max_uv = max(val->intval, chg->voltage_min_uv);
+	rc = smblib_set_usb_pd_allowed_voltage(chg, chg->voltage_min_uv,
+					       max_uv);
+	if (rc < 0) {
+		smblib_err(chg, "invalid min voltage %duV rc=%d\n",
+			val->intval, rc);
+		return rc;
+	}
+
+	chg->voltage_max_uv = max_uv;
+	power_supply_changed(chg->usb_main_psy);
+
+	return rc;
+}
+
+static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
+{
+	int rc = 0;
+
+	chg->pd_active = pd_active;
+
+	if (chg->pd_active) {
+		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+		vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+
+		/*
+		 * Enforce 500mA for PD until the real vote comes in later.
+		 * It is guaranteed that pd_active is set prior to
+		 * pd_current_max
+		 */
+		rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
+									rc);
+
+		/* since PD was found the cable must be non-legacy */
+		vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
+
+		/* clear USB ICL vote for DCP_VOTER */
+		rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
+									rc);
+
+		/* remove USB_PSY_VOTER */
+		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
+	} else {
+		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+		vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+	}
+
+	smblib_update_usb_type(chg);
+	power_supply_changed(chg->usb_psy);
+	return rc;
+}
+
+int smblib_set_prop_pd_active(struct smb_charger *chg,
+			      const union power_supply_propval *val)
+{
+	if (!get_effective_result(chg->pd_allowed_votable))
+		return -EINVAL;
+
+	return __smblib_set_prop_pd_active(chg, val->intval);
+}
+
+int smblib_set_prop_ship_mode(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	int rc;
+
+	smblib_dbg(chg, PR_MISC, "Set ship mode: %d!!\n", !!val->intval);
+
+	rc = smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT,
+			!!val->intval ? SHIP_MODE_EN_BIT : 0);
+	if (rc < 0)
+		dev_err(chg->dev, "Couldn't %s ship mode, rc=%d\n",
+				!!val->intval ? "enable" : "disable", rc);
+
+	return rc;
+}
+
+int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	int rc = 0;
+
+	if (chg->pd_hard_reset == val->intval)
+		return rc;
+
+	chg->pd_hard_reset = val->intval;
+	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
+			EXIT_SNK_BASED_ON_CC_BIT,
+			(chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
+				rc);
+
+	return rc;
+}
+
+static int smblib_recover_from_soft_jeita(struct smb_charger *chg)
+{
+	u8 stat1, stat7;
+	int rc;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat1);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat7);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	if ((chg->jeita_status && !(stat7 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK) &&
+		((stat1 & BATTERY_CHARGER_STATUS_MASK) == TERMINATE_CHARGE))) {
+		/*
+		 * We are moving from JEITA soft -> Normal and charging
+		 * is terminated
+		 */
+		rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG, 0);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't disable charging rc=%d\n",
+						rc);
+			return rc;
+		}
+		rc = smblib_write(chg, CHARGING_ENABLE_CMD_REG,
+						CHARGING_ENABLE_CMD_BIT);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't enable charging rc=%d\n",
+						rc);
+			return rc;
+		}
+	}
+
+	chg->jeita_status = stat7 & BAT_TEMP_STATUS_SOFT_LIMIT_MASK;
+
+	return 0;
+}
+
+/************************
+ * USB MAIN PSY GETTERS *
+ ************************/
+int smblib_get_prop_fcc_delta(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	int rc, jeita_cc_delta_ua = 0;
+
+	if (chg->sw_jeita_enabled) {
+		val->intval = 0;
+		return 0;
+	}
+
+	rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
+		jeita_cc_delta_ua = 0;
+	}
+
+	val->intval = jeita_cc_delta_ua;
+	return 0;
+}
+
+/************************
+ * USB MAIN PSY SETTERS *
+ ************************/
+int smblib_get_charge_current(struct smb_charger *chg,
+				int *total_current_ua)
+{
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+	union power_supply_propval val = {0, };
+	int rc = 0, typec_source_rd, current_ua;
+	bool non_compliant;
+	u8 stat;
+
+	if (chg->pd_active) {
+		*total_current_ua =
+			get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
+		return rc;
+	}
+
+	rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
+		return rc;
+	}
+	non_compliant = stat & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
+
+	/* get settled ICL */
+	rc = smblib_get_prop_input_current_settled(chg, &val);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
+		return rc;
+	}
+
+	typec_source_rd = smblib_get_prop_ufp_mode(chg);
+
+	/* QC 2.0/3.0 adapter */
+	if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
+		*total_current_ua = HVDCP_CURRENT_UA;
+		return 0;
+	}
+
+	if (non_compliant) {
+		switch (apsd_result->bit) {
+		case CDP_CHARGER_BIT:
+			current_ua = CDP_CURRENT_UA;
+			break;
+		case DCP_CHARGER_BIT:
+		case OCP_CHARGER_BIT:
+		case FLOAT_CHARGER_BIT:
+			current_ua = DCP_CURRENT_UA;
+			break;
+		default:
+			current_ua = 0;
+			break;
+		}
+
+		*total_current_ua = max(current_ua, val.intval);
+		return 0;
+	}
+
+	switch (typec_source_rd) {
+	case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
+		switch (apsd_result->bit) {
+		case CDP_CHARGER_BIT:
+			current_ua = CDP_CURRENT_UA;
+			break;
+		case DCP_CHARGER_BIT:
+		case OCP_CHARGER_BIT:
+		case FLOAT_CHARGER_BIT:
+			current_ua = chg->default_icl_ua;
+			break;
+		default:
+			current_ua = 0;
+			break;
+		}
+		break;
+	case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
+		current_ua = TYPEC_MEDIUM_CURRENT_UA;
+		break;
+	case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
+		current_ua = TYPEC_HIGH_CURRENT_UA;
+		break;
+	case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
+	case POWER_SUPPLY_TYPEC_NONE:
+	default:
+		current_ua = 0;
+		break;
+	}
+
+	*total_current_ua = max(current_ua, val.intval);
+	return 0;
+}
+
+/**********************
+ * INTERRUPT HANDLERS *
+ **********************/
+
+irqreturn_t default_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t chg_state_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	u8 stat;
+	int rc;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n",
+				rc);
+		return IRQ_HANDLED;
+	}
+
+	stat = stat & BATTERY_CHARGER_STATUS_MASK;
+	power_supply_changed(chg->batt_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t batt_temp_changed_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc;
+
+	rc = smblib_recover_from_soft_jeita(chg);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't recover chg from soft jeita rc=%d\n",
+				rc);
+		return IRQ_HANDLED;
+	}
+
+	rerun_election(chg->fcc_votable);
+	power_supply_changed(chg->batt_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t batt_psy_changed_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+	power_supply_changed(chg->batt_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t usbin_uv_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	struct storm_watch *wdata;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+	if (!chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data)
+		return IRQ_HANDLED;
+
+	wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data;
+	reset_storm_count(wdata);
+	return IRQ_HANDLED;
+}
+
+#define USB_WEAK_INPUT_UA	1400000
+#define ICL_CHANGE_DELAY_MS	1000
+irqreturn_t icl_change_irq_handler(int irq, void *data)
+{
+	u8 stat;
+	int rc, settled_ua, delay = ICL_CHANGE_DELAY_MS;
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	if (chg->mode == PARALLEL_MASTER) {
+		rc = smblib_read(chg, AICL_STATUS_REG, &stat);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't read AICL_STATUS rc=%d\n",
+					rc);
+			return IRQ_HANDLED;
+		}
+
+		rc = smblib_get_charge_param(chg, &chg->param.icl_stat,
+					&settled_ua);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
+			return IRQ_HANDLED;
+		}
+
+		/* If AICL settled then schedule work now */
+		if (settled_ua == get_effective_result(chg->usb_icl_votable))
+			delay = 0;
+
+		cancel_delayed_work_sync(&chg->icl_change_work);
+		schedule_delayed_work(&chg->icl_change_work,
+						msecs_to_jiffies(delay));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+	if (vbus_rising) {
+		/* use the typec flag even though its not typec */
+		chg->typec_present = 1;
+	} else {
+		chg->typec_present = 0;
+		smblib_update_usb_type(chg);
+		smblib_notify_device_mode(chg, false);
+		smblib_uusb_removal(chg);
+	}
+}
+
+void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+	bool vbus_rising;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+		return;
+	}
+
+	vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+
+	if (!vbus_rising) {
+		if (chg->wa_flags & BOOST_BACK_WA) {
+			data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+			if (data) {
+				wdata = &data->storm_data;
+				update_storm_count(wdata,
+						WEAK_CHG_STORM_COUNT);
+				vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
+						false, 0);
+				vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+						false, 0);
+			}
+		}
+	}
+
+	power_supply_changed(chg->usb_psy);
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+					vbus_rising ? "attached" : "detached");
+}
+
+#define PL_DELAY_MS	30000
+void smblib_usb_plugin_locked(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+	bool vbus_rising;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+		return;
+	}
+
+	vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
+	smblib_set_opt_switcher_freq(chg, vbus_rising ? chg->chg_freq.freq_5V :
+						chg->chg_freq.freq_removal);
+
+	if (vbus_rising) {
+		rc = smblib_request_dpdm(chg, true);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+
+		/* Schedule work to enable parallel charger */
+		vote(chg->awake_votable, PL_DELAY_VOTER, true, 0);
+		schedule_delayed_work(&chg->pl_enable_work,
+					msecs_to_jiffies(PL_DELAY_MS));
+	} else {
+		if (chg->wa_flags & BOOST_BACK_WA) {
+			data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+			if (data) {
+				wdata = &data->storm_data;
+				update_storm_count(wdata,
+						WEAK_CHG_STORM_COUNT);
+				vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
+						false, 0);
+				vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+						false, 0);
+			}
+		}
+
+		rc = smblib_request_dpdm(chg, false);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+	}
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		smblib_micro_usb_plugin(chg, vbus_rising);
+
+	power_supply_changed(chg->usb_psy);
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+					vbus_rising ? "attached" : "detached");
+}
+
+irqreturn_t usb_plugin_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	mutex_lock(&chg->lock);
+	if (chg->pd_hard_reset)
+		smblib_usb_plugin_hard_reset_locked(chg);
+	else
+		smblib_usb_plugin_locked(chg);
+	mutex_unlock(&chg->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg,
+					      bool rising)
+{
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: slow-plugin-timeout %s\n",
+		   rising ? "rising" : "falling");
+}
+
+static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg,
+					       bool rising)
+{
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n",
+		   rising ? "rising" : "falling");
+}
+
+#define QC3_PULSES_FOR_6V	5
+#define QC3_PULSES_FOR_9V	20
+#define QC3_PULSES_FOR_12V	35
+static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+	int pulses;
+
+	power_supply_changed(chg->usb_main_psy);
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) {
+		rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't read QC_CHANGE_STATUS rc=%d\n", rc);
+			return;
+		}
+
+		switch (stat & QC_2P0_STATUS_MASK) {
+		case QC_5V_BIT:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_5V);
+			break;
+		case QC_9V_BIT:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_9V);
+			break;
+		case QC_12V_BIT:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_12V);
+			break;
+		default:
+			smblib_set_opt_switcher_freq(chg,
+					chg->chg_freq.freq_removal);
+			break;
+		}
+	}
+
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) {
+		rc = smblib_get_pulse_cnt(chg, &pulses);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
+			return;
+		}
+
+		if (pulses < QC3_PULSES_FOR_6V)
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_5V);
+		else if (pulses < QC3_PULSES_FOR_9V)
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_6V_8V);
+		else if (pulses < QC3_PULSES_FOR_12V)
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_9V);
+		else
+			smblib_set_opt_switcher_freq(chg,
+				chg->chg_freq.freq_12V);
+	}
+}
+
+/* triggers when HVDCP 3.0 authentication has finished */
+static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
+					      bool rising)
+{
+	const struct apsd_result *apsd_result;
+
+	if (!rising)
+		return;
+
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
+
+	if (chg->mode == PARALLEL_MASTER)
+		vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
+
+	/* the APSD done handler will set the USB supply type */
+	apsd_result = smblib_get_apsd_result(chg);
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
+		   apsd_result->name);
+}
+
+static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
+					      bool rising, bool qc_charger)
+{
+	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+
+	/* Hold off PD only until hvdcp 2.0 detection timeout */
+	if (rising) {
+
+		/* enable HDC and ICL irq for QC2/3 charger */
+		if (qc_charger)
+			vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
+		else
+			vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+							false, 0);
+
+		/*
+		 * HVDCP detection timeout done
+		 * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
+		 */
+		if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
+			/* enforce DCP ICL if specified */
+			vote(chg->usb_icl_votable, DCP_VOTER,
+				chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
+
+		/*
+		 * if pd is not allowed, then set pd_active = false right here,
+		 * so that it starts the hvdcp engine
+		 */
+		if (!get_effective_result(chg->pd_allowed_votable))
+			__smblib_set_prop_pd_active(chg, 0);
+	}
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
+		   rising ? "rising" : "falling");
+}
+
+/* triggers when HVDCP is detected */
+static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
+					    bool rising)
+{
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n",
+		   rising ? "rising" : "falling");
+}
+
+static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
+{
+	const struct apsd_result *apsd_result;
+
+	if (!rising)
+		return;
+
+	apsd_result = smblib_update_usb_type(chg);
+
+	switch (apsd_result->bit) {
+	case SDP_CHARGER_BIT:
+	case CDP_CHARGER_BIT:
+		/* if not DCP then no hvdcp timeout happens. Enable pd here */
+		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+				false, 0);
+		if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+				|| chg->use_extcon)
+			smblib_notify_device_mode(chg, true);
+		break;
+	case OCP_CHARGER_BIT:
+	case FLOAT_CHARGER_BIT:
+		/* if not DCP then no hvdcp timeout happens, Enable pd here. */
+		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+				false, 0);
+		break;
+	case DCP_CHARGER_BIT:
+		break;
+	default:
+		break;
+	}
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n",
+		   apsd_result->name);
+}
+
+irqreturn_t usb_source_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc = 0;
+	u8 stat;
+
+	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+		return IRQ_HANDLED;
+	}
+	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+
+	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+		&& (stat & APSD_DTC_STATUS_DONE_BIT)
+		&& !chg->uusb_apsd_rerun_done) {
+		/*
+		 * Force re-run APSD to handle slow insertion related
+		 * charger-mis-detection.
+		 */
+		chg->uusb_apsd_rerun_done = true;
+		smblib_rerun_apsd(chg);
+		return IRQ_HANDLED;
+	}
+
+	smblib_handle_apsd_done(chg,
+		(bool)(stat & APSD_DTC_STATUS_DONE_BIT));
+
+	smblib_handle_hvdcp_detect_done(chg,
+		(bool)(stat & QC_CHARGER_BIT));
+
+	smblib_handle_hvdcp_check_timeout(chg,
+		(bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
+		(bool)(stat & QC_CHARGER_BIT));
+
+	smblib_handle_hvdcp_3p0_auth_done(chg,
+		(bool)(stat & QC_AUTH_DONE_STATUS_BIT));
+
+	smblib_handle_sdp_enumeration_done(chg,
+		(bool)(stat & ENUMERATION_DONE_BIT));
+
+	smblib_handle_slow_plugin_timeout(chg,
+		(bool)(stat & SLOW_PLUGIN_TIMEOUT_BIT));
+
+	smblib_hvdcp_adaptive_voltage_change(chg);
+
+	power_supply_changed(chg->usb_psy);
+
+	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+		return IRQ_HANDLED;
+	}
+	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+
+	return IRQ_HANDLED;
+}
+
+static void typec_sink_insertion(struct smb_charger *chg)
+{
+	/* when a sink is inserted we should not wait on hvdcp timeout to
+	 * enable pd
+	 */
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
+	if (chg->use_extcon) {
+		smblib_notify_usb_host(chg, true);
+		chg->otg_present = true;
+	}
+}
+
+static void typec_sink_removal(struct smb_charger *chg)
+{
+	smblib_set_charge_param(chg, &chg->param.freq_switcher,
+			chg->chg_freq.freq_above_otg_threshold);
+	chg->boost_current_ua = 0;
+}
+
+static void smblib_handle_typec_removal(struct smb_charger *chg)
+{
+	int rc;
+	struct smb_irq_data *data;
+	struct storm_watch *wdata;
+
+	rc = smblib_request_dpdm(chg, false);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+
+	if (chg->wa_flags & BOOST_BACK_WA) {
+		data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
+		if (data) {
+			wdata = &data->storm_data;
+			update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
+			vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
+			vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+					false, 0);
+		}
+	}
+
+	cancel_delayed_work_sync(&chg->pl_enable_work);
+
+	/* reset input current limit voters */
+	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+	vote(chg->usb_icl_votable, PD_VOTER, false, 0);
+	vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+	vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+	vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
+	vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
+	vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
+
+	/* reset power delivery voters */
+	vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
+	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
+	vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0);
+
+	/* reset usb irq voters */
+	vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+	vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
+
+	/* reset parallel voters */
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+	vote(chg->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+
+	chg->vconn_attempts = 0;
+	chg->otg_attempts = 0;
+	chg->pulse_cnt = 0;
+	chg->usb_icl_delta_ua = 0;
+	chg->voltage_min_uv = MICRO_5V;
+	chg->voltage_max_uv = MICRO_5V;
+	chg->pd_active = 0;
+	chg->pd_hard_reset = 0;
+
+	/* write back the default FLOAT charger configuration */
+	rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
+				(u8)FLOAT_OPTIONS_MASK, chg->float_cfg);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't write float charger options rc=%d\n",
+			rc);
+
+	/* reset back to 103mS tCC debounce */
+	rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
+					REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
+
+	/* reconfigure allowed voltage for HVDCP */
+	rc = smblib_set_adapter_allowance(chg,
+			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+			rc);
+
+	/* enable DRP */
+	rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+				 TYPEC_POWER_ROLE_CMD_MASK, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+
+	/* HW controlled CC_OUT */
+	rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
+				TYPEC_CCOUT_SRC_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
+
+
+	rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG,
+				 VCONN_EN_SRC_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set TYPE_C_VCONN_CONTROL_REG rc=%d\n",
+				rc);
+
+	/* clear exit sink based on cc */
+	rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
+						EXIT_SNK_BASED_ON_CC_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
+				rc);
+
+	typec_sink_removal(chg);
+	smblib_update_usb_type(chg);
+
+	if (chg->use_extcon) {
+		if (chg->otg_present)
+			smblib_notify_usb_host(chg, false);
+		else
+			smblib_notify_device_mode(chg, false);
+	}
+	chg->otg_present = false;
+}
+
+static void smblib_handle_typec_insertion(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return;
+	}
+
+	if (stat & SNK_SRC_MODE_BIT) {
+		typec_sink_insertion(chg);
+	} else {
+		rc = smblib_request_dpdm(chg, true);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
+		typec_sink_removal(chg);
+	}
+}
+
+static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
+{
+	int rp_ua;
+	const struct apsd_result *apsd = smblib_get_apsd_result(chg);
+
+	if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
+		&& (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
+		return;
+
+	/*
+	 * if APSD indicates FLOAT and the USB stack had detected SDP,
+	 * do not respond to Rp changes as we do not confirm that its
+	 * a legacy cable
+	 */
+	if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+		return;
+	/*
+	 * We want the ICL vote @ 100mA for a FLOAT charger
+	 * until the detection by the USB stack is complete.
+	 * Ignore the Rp changes unless there is a
+	 * pre-existing valid vote.
+	 */
+	if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
+		get_client_vote(chg->usb_icl_votable,
+			LEGACY_UNKNOWN_VOTER) <= 100000)
+		return;
+
+	/*
+	 * handle Rp change for DCP/FLOAT/OCP.
+	 * Update the current only if the Rp is different from
+	 * the last Rp value.
+	 */
+	smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
+						chg->typec_mode, typec_mode);
+
+	rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua);
+}
+
+static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
+{
+	u8 stat;
+	int typec_mode, rc;
+
+	if (chg->pr_swap_in_progress)
+		return;
+
+	typec_mode = smblib_get_prop_typec_mode(chg);
+	if (chg->typec_present && (typec_mode != chg->typec_mode))
+		smblib_handle_rp_change(chg, typec_mode);
+
+	chg->typec_mode = typec_mode;
+
+	if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
+		chg->typec_present = true;
+		smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
+			smblib_typec_mode_name[chg->typec_mode]);
+		smblib_handle_typec_insertion(chg);
+	} else if (chg->typec_present &&
+				chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+		chg->typec_present = false;
+		smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+		smblib_handle_typec_removal(chg);
+	}
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return;
+	}
+	/* suspend usb if sink */
+	if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present)
+		vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
+	else
+		vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+				smblib_typec_mode_name[chg->typec_mode]);
+}
+
+static void smblib_usb_typec_change(struct smb_charger *chg)
+{
+	int rc;
+	u8 stat;
+
+	smblib_handle_typec_cc_state_change(chg);
+
+	rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		return;
+	}
+
+	if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
+		smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
+
+	power_supply_changed(chg->usb_psy);
+}
+
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
+		cancel_delayed_work_sync(&chg->uusb_otg_work);
+		vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
+		smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
+		schedule_delayed_work(&chg->uusb_otg_work,
+				msecs_to_jiffies(chg->otg_delay_ms));
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t typec_state_change_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
+			|| chg->pr_swap_in_progress) {
+		smblib_dbg(chg, PR_INTERRUPT,
+				"Ignoring since pr_swap_in_progress\n");
+		return IRQ_HANDLED;
+	}
+
+	mutex_lock(&chg->lock);
+	smblib_usb_typec_change(chg);
+	mutex_unlock(&chg->lock);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t dc_plugin_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	power_supply_changed(chg->dc_psy);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t high_duty_cycle_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	chg->is_hdc = true;
+	/*
+	 * Disable usb IRQs after the flag set and re-enable IRQs after
+	 * the flag cleared in the delayed work queue, to avoid any IRQ
+	 * storming during the delays
+	 */
+	if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+		disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+
+	schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
+
+	return IRQ_HANDLED;
+}
+
+static void smblib_bb_removal_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						bb_removal_work.work);
+
+	vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
+	vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0);
+}
+
+#define BOOST_BACK_UNVOTE_DELAY_MS		750
+#define BOOST_BACK_STORM_COUNT			3
+#define WEAK_CHG_STORM_COUNT			8
+irqreturn_t switcher_power_ok_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	struct storm_watch *wdata = &irq_data->storm_data;
+	int rc, usb_icl;
+	u8 stat;
+
+	if (!(chg->wa_flags & BOOST_BACK_WA))
+		return IRQ_HANDLED;
+
+	rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
+		return IRQ_HANDLED;
+	}
+
+	/* skip suspending input if its already suspended by some other voter */
+	usb_icl = get_effective_result(chg->usb_icl_votable);
+	if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
+		return IRQ_HANDLED;
+
+	if (stat & USE_DCIN_BIT)
+		return IRQ_HANDLED;
+
+	if (is_storming(&irq_data->storm_data)) {
+		/* This could be a weak charger reduce ICL */
+		if (!is_client_vote_enabled(chg->usb_icl_votable,
+						WEAK_CHARGER_VOTER)) {
+			smblib_err(chg,
+				"Weak charger detected: voting %dmA ICL\n",
+				*chg->weak_chg_icl_ua / 1000);
+			vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
+					true, *chg->weak_chg_icl_ua);
+			/*
+			 * reset storm data and set the storm threshold
+			 * to 3 for reverse boost detection.
+			 */
+			update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
+		} else {
+			smblib_err(chg,
+				"Reverse boost detected: voting 0mA to suspend input\n");
+			vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
+			vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
+			/*
+			 * Remove the boost-back vote after a delay, to avoid
+			 * permanently suspending the input if the boost-back
+			 * condition is unintentionally hit.
+			 */
+			schedule_delayed_work(&chg->bb_removal_work,
+				msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t wdog_bark_irq_handler(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+	int rc;
+
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
+	rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
+
+	if (chg->step_chg_enabled || chg->sw_jeita_enabled)
+		power_supply_changed(chg->batt_psy);
+
+	return IRQ_HANDLED;
+}
+
+/**************
+ * Additional USB PSY getters/setters
+ * that call interrupt functions
+ ***************/
+
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+				union power_supply_propval *val)
+{
+	val->intval = chg->pr_swap_in_progress;
+	return 0;
+}
+
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+				const union power_supply_propval *val)
+{
+	int rc;
+
+	chg->pr_swap_in_progress = val->intval;
+
+	/*
+	 * call the cc changed irq to handle real removals while
+	 * PR_SWAP was in progress
+	 */
+	smblib_usb_typec_change(chg);
+	rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
+			REDUCE_TCCDEBOUNCE_TO_2MS_BIT,
+			val->intval ? REDUCE_TCCDEBOUNCE_TO_2MS_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
+	return 0;
+}
+
+/***************
+ * Work Queues *
+ ***************/
+static void smblib_uusb_otg_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						uusb_otg_work.work);
+	int rc;
+	u8 stat;
+	bool otg;
+
+	rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc);
+		goto out;
+	}
+	otg = !!(stat & U_USB_GROUND_NOVBUS_BIT);
+	if (chg->otg_present != otg)
+		smblib_notify_usb_host(chg, otg);
+	chg->otg_present = otg;
+	if (!otg)
+		chg->boost_current_ua = 0;
+
+	rc = smblib_set_charge_param(chg, &chg->param.freq_switcher,
+				otg ? chg->chg_freq.freq_below_otg_threshold
+					: chg->chg_freq.freq_removal);
+	if (rc < 0)
+		dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
+
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_U_USB_STATUS = 0x%02x OTG=%d\n",
+			stat, otg);
+	power_supply_changed(chg->usb_psy);
+
+out:
+	vote(chg->awake_votable, OTG_DELAY_VOTER, false, 0);
+}
+
+static void bms_update_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						bms_update_work);
+
+	smblib_suspend_on_debug_battery(chg);
+
+	if (chg->batt_psy)
+		power_supply_changed(chg->batt_psy);
+}
+
+static void pl_update_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						pl_update_work);
+
+	smblib_stat_sw_override_cfg(chg, false);
+}
+
+static void clear_hdc_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+						clear_hdc_work.work);
+
+	chg->is_hdc = 0;
+	if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+		enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+}
+
+static void smblib_icl_change_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+							icl_change_work.work);
+	int rc, settled_ua;
+
+	rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
+		return;
+	}
+
+	power_supply_changed(chg->usb_main_psy);
+
+	smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
+}
+
+static void smblib_pl_enable_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+							pl_enable_work.work);
+
+	smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n");
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0);
+	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+}
+
+static int smblib_create_votables(struct smb_charger *chg)
+{
+	int rc = 0;
+
+	chg->fcc_votable = find_votable("FCC");
+	if (chg->fcc_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->fv_votable = find_votable("FV");
+	if (chg->fv_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->usb_icl_votable = find_votable("USB_ICL");
+	if (chg->usb_icl_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->pl_disable_votable = find_votable("PL_DISABLE");
+	if (chg->pl_disable_votable == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
+		return rc;
+	}
+
+	chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
+	if (chg->pl_enable_votable_indirect == NULL) {
+		rc = -EINVAL;
+		smblib_err(chg,
+			"Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+
+	chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
+					smblib_dc_suspend_vote_callback,
+					chg);
+	if (IS_ERR(chg->dc_suspend_votable)) {
+		rc = PTR_ERR(chg->dc_suspend_votable);
+		chg->dc_suspend_votable = NULL;
+		return rc;
+	}
+
+	chg->pd_disallowed_votable_indirect
+		= create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
+			smblib_pd_disallowed_votable_indirect_callback, chg);
+	if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
+		rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
+		chg->pd_disallowed_votable_indirect = NULL;
+		return rc;
+	}
+
+	chg->pd_allowed_votable = create_votable("PD_ALLOWED",
+					VOTE_SET_ANY, NULL, NULL);
+	if (IS_ERR(chg->pd_allowed_votable)) {
+		rc = PTR_ERR(chg->pd_allowed_votable);
+		chg->pd_allowed_votable = NULL;
+		return rc;
+	}
+
+	chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
+					smblib_awake_vote_callback,
+					chg);
+	if (IS_ERR(chg->awake_votable)) {
+		rc = PTR_ERR(chg->awake_votable);
+		chg->awake_votable = NULL;
+		return rc;
+	}
+
+	chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
+					smblib_chg_disable_vote_callback,
+					chg);
+	if (IS_ERR(chg->chg_disable_votable)) {
+		rc = PTR_ERR(chg->chg_disable_votable);
+		chg->chg_disable_votable = NULL;
+		return rc;
+	}
+
+	chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
+					VOTE_SET_ANY,
+					smblib_usb_irq_enable_vote_callback,
+					chg);
+	if (IS_ERR(chg->usb_irq_enable_votable)) {
+		rc = PTR_ERR(chg->usb_irq_enable_votable);
+		chg->usb_irq_enable_votable = NULL;
+		return rc;
+	}
+
+	return rc;
+}
+
+static void smblib_destroy_votables(struct smb_charger *chg)
+{
+	if (chg->dc_suspend_votable)
+		destroy_votable(chg->dc_suspend_votable);
+	if (chg->usb_icl_votable)
+		destroy_votable(chg->usb_icl_votable);
+	if (chg->pd_disallowed_votable_indirect)
+		destroy_votable(chg->pd_disallowed_votable_indirect);
+	if (chg->pd_allowed_votable)
+		destroy_votable(chg->pd_allowed_votable);
+	if (chg->awake_votable)
+		destroy_votable(chg->awake_votable);
+	if (chg->chg_disable_votable)
+		destroy_votable(chg->chg_disable_votable);
+}
+
+int smblib_init(struct smb_charger *chg)
+{
+	int rc = 0;
+
+	mutex_init(&chg->lock);
+	mutex_init(&chg->otg_oc_lock);
+	INIT_WORK(&chg->bms_update_work, bms_update_work);
+	INIT_WORK(&chg->pl_update_work, pl_update_work);
+	INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
+	INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
+	INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
+	INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
+	INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
+	chg->fake_capacity = -EINVAL;
+	chg->fake_input_current_limited = -EINVAL;
+	chg->fake_batt_status = -EINVAL;
+
+	switch (chg->mode) {
+	case PARALLEL_MASTER:
+		rc = qcom_batt_init();
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		rc = qcom_step_chg_init(chg->dev, chg->step_chg_enabled,
+						chg->sw_jeita_enabled);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		rc = smblib_create_votables(chg);
+		if (rc < 0) {
+			smblib_err(chg, "Couldn't create votables rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		chg->bms_psy = power_supply_get_by_name("bms");
+		chg->pl.psy = power_supply_get_by_name("parallel");
+		if (chg->pl.psy) {
+			rc = smblib_stat_sw_override_cfg(chg, false);
+			if (rc < 0) {
+				smblib_err(chg,
+					"Couldn't config stat sw rc=%d\n", rc);
+				return rc;
+			}
+		}
+		rc = smblib_register_notifier(chg);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't register notifier rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case PARALLEL_SLAVE:
+		break;
+	default:
+		smblib_err(chg, "Unsupported mode %d\n", chg->mode);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+int smblib_deinit(struct smb_charger *chg)
+{
+	switch (chg->mode) {
+	case PARALLEL_MASTER:
+		cancel_work_sync(&chg->bms_update_work);
+		cancel_work_sync(&chg->pl_update_work);
+		cancel_delayed_work_sync(&chg->clear_hdc_work);
+		cancel_delayed_work_sync(&chg->icl_change_work);
+		cancel_delayed_work_sync(&chg->pl_enable_work);
+		cancel_delayed_work_sync(&chg->uusb_otg_work);
+		cancel_delayed_work_sync(&chg->bb_removal_work);
+		power_supply_unreg_notifier(&chg->nb);
+		smblib_destroy_votables(chg);
+		qcom_step_chg_deinit();
+		qcom_batt_deinit();
+		break;
+	case PARALLEL_SLAVE:
+		break;
+	default:
+		smblib_err(chg, "Unsupported mode %d\n", chg->mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
new file mode 100644
index 0000000..fa7381c
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -0,0 +1,508 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SMB5_CHARGER_H
+#define __SMB5_CHARGER_H
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irqreturn.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/consumer.h>
+#include <linux/extcon.h>
+#include "storm-watch.h"
+
+enum print_reason {
+	PR_INTERRUPT	= BIT(0),
+	PR_REGISTER	= BIT(1),
+	PR_MISC		= BIT(2),
+	PR_PARALLEL	= BIT(3),
+	PR_OTG		= BIT(4),
+};
+
+#define DEFAULT_VOTER			"DEFAULT_VOTER"
+#define USER_VOTER			"USER_VOTER"
+#define PD_VOTER			"PD_VOTER"
+#define DCP_VOTER			"DCP_VOTER"
+#define QC_VOTER			"QC_VOTER"
+#define PL_USBIN_USBIN_VOTER		"PL_USBIN_USBIN_VOTER"
+#define USB_PSY_VOTER			"USB_PSY_VOTER"
+#define PL_TAPER_WORK_RUNNING_VOTER	"PL_TAPER_WORK_RUNNING_VOTER"
+#define PL_QNOVO_VOTER			"PL_QNOVO_VOTER"
+#define USBIN_V_VOTER			"USBIN_V_VOTER"
+#define CHG_STATE_VOTER			"CHG_STATE_VOTER"
+#define TYPEC_SRC_VOTER			"TYPEC_SRC_VOTER"
+#define TAPER_END_VOTER			"TAPER_END_VOTER"
+#define THERMAL_DAEMON_VOTER		"THERMAL_DAEMON_VOTER"
+#define CC_DETACHED_VOTER		"CC_DETACHED_VOTER"
+#define APSD_VOTER			"APSD_VOTER"
+#define PD_DISALLOWED_INDIRECT_VOTER	"PD_DISALLOWED_INDIRECT_VOTER"
+#define VBUS_CC_SHORT_VOTER		"VBUS_CC_SHORT_VOTER"
+#define PD_INACTIVE_VOTER		"PD_INACTIVE_VOTER"
+#define BOOST_BACK_VOTER		"BOOST_BACK_VOTER"
+#define USBIN_USBIN_BOOST_VOTER		"USBIN_USBIN_BOOST_VOTER"
+#define MICRO_USB_VOTER			"MICRO_USB_VOTER"
+#define DEBUG_BOARD_VOTER		"DEBUG_BOARD_VOTER"
+#define PD_SUSPEND_SUPPORTED_VOTER	"PD_SUSPEND_SUPPORTED_VOTER"
+#define PL_DELAY_VOTER			"PL_DELAY_VOTER"
+#define CTM_VOTER			"CTM_VOTER"
+#define SW_QC3_VOTER			"SW_QC3_VOTER"
+#define AICL_RERUN_VOTER		"AICL_RERUN_VOTER"
+#define LEGACY_UNKNOWN_VOTER		"LEGACY_UNKNOWN_VOTER"
+#define QNOVO_VOTER			"QNOVO_VOTER"
+#define BATT_PROFILE_VOTER		"BATT_PROFILE_VOTER"
+#define OTG_DELAY_VOTER			"OTG_DELAY_VOTER"
+#define USBIN_I_VOTER			"USBIN_I_VOTER"
+#define WEAK_CHARGER_VOTER		"WEAK_CHARGER_VOTER"
+#define OTG_VOTER			"OTG_VOTER"
+#define PL_FCC_LOW_VOTER		"PL_FCC_LOW_VOTER"
+#define WBC_VOTER			"WBC_VOTER"
+#define HW_LIMIT_VOTER			"HW_LIMIT_VOTER"
+
+#define BOOST_BACK_STORM_COUNT	3
+#define WEAK_CHG_STORM_COUNT	8
+
+enum smb_mode {
+	PARALLEL_MASTER = 0,
+	PARALLEL_SLAVE,
+	NUM_MODES,
+};
+
+enum {
+	BOOST_BACK_WA			= BIT(0),
+};
+
+enum smb_irq_index {
+	/* CHGR */
+	CHGR_ERROR_IRQ = 0,
+	CHG_STATE_CHANGE_IRQ,
+	STEP_CHG_STATE_CHANGE_IRQ,
+	STEP_CHG_SOC_UPDATE_FAIL_IRQ,
+	STEP_CHG_SOC_UPDATE_REQ_IRQ,
+	FG_FVCAL_QUALIFIED_IRQ,
+	VPH_ALARM_IRQ,
+	VPH_DROP_PRECHG_IRQ,
+	/* DCDC */
+	OTG_FAIL_IRQ,
+	OTG_OC_DISABLE_SW_IRQ,
+	OTG_OC_HICCUP_IRQ,
+	BSM_ACTIVE_IRQ,
+	HIGH_DUTY_CYCLE_IRQ,
+	INPUT_CURRENT_LIMITING_IRQ,
+	CONCURRENT_MODE_DISABLE_IRQ,
+	SWITCHER_POWER_OK_IRQ,
+	/* BATIF */
+	BAT_TEMP_IRQ,
+	ALL_CHNL_CONV_DONE_IRQ,
+	BAT_OV_IRQ,
+	BAT_LOW_IRQ,
+	BAT_THERM_OR_ID_MISSING_IRQ,
+	BAT_TERMINAL_MISSING_IRQ,
+	BUCK_OC_IRQ,
+	VPH_OV_IRQ,
+	/* USB */
+	USBIN_COLLAPSE_IRQ,
+	USBIN_VASHDN_IRQ,
+	USBIN_UV_IRQ,
+	USBIN_OV_IRQ,
+	USBIN_PLUGIN_IRQ,
+	USBIN_REVI_CHANGE_IRQ,
+	USBIN_SRC_CHANGE_IRQ,
+	USBIN_ICL_CHANGE_IRQ,
+	/* DC */
+	DCIN_VASHDN_IRQ,
+	DCIN_UV_IRQ,
+	DCIN_OV_IRQ,
+	DCIN_PLUGIN_IRQ,
+	DCIN_REVI_IRQ,
+	DCIN_PON_IRQ,
+	DCIN_EN_IRQ,
+	/* TYPEC */
+	TYPEC_OR_RID_DETECTION_CHANGE_IRQ,
+	TYPEC_VPD_DETECT_IRQ,
+	TYPEC_CC_STATE_CHANGE_IRQ,
+	TYPEC_VCONN_OC_IRQ,
+	TYPEC_VBUS_CHANGE_IRQ,
+	TYPEC_ATTACH_DETACH_IRQ,
+	TYPEC_LEGACY_CABLE_DETECT_IRQ,
+	TYPEC_TRY_SNK_SRC_DETECT_IRQ,
+	/* MISC */
+	WDOG_SNARL_IRQ,
+	WDOG_BARK_IRQ,
+	AICL_FAIL_IRQ,
+	AICL_DONE_IRQ,
+	SMB_EN_IRQ,
+	IMP_TRIGGER_IRQ,
+	TEMP_CHANGE_IRQ,
+	TEMP_CHANGE_SMB_IRQ,
+	/* END */
+	SMB_IRQ_MAX,
+};
+
+enum float_options {
+	FLOAT_DCP		= 1,
+	FLOAT_SDP		= 2,
+	DISABLE_CHARGING	= 3,
+	SUSPEND_INPUT		= 4,
+};
+
+struct smb_irq_info {
+	const char			*name;
+	const irq_handler_t		handler;
+	const bool			wake;
+	const struct storm_watch	storm_data;
+	struct smb_irq_data		*irq_data;
+	int				irq;
+};
+
+static const unsigned int smblib_extcon_cable[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_NONE,
+};
+
+/* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */
+static const u32 smblib_extcon_exclusive[] = {0x3, 0};
+
+struct smb_regulator {
+	struct regulator_dev	*rdev;
+	struct regulator_desc	rdesc;
+};
+
+struct smb_irq_data {
+	void			*parent_data;
+	const char		*name;
+	struct storm_watch	storm_data;
+};
+
+struct smb_chg_param {
+	const char	*name;
+	u16		reg;
+	int		min_u;
+	int		max_u;
+	int		step_u;
+	int		(*get_proc)(struct smb_chg_param *param,
+				    u8 val_raw);
+	int		(*set_proc)(struct smb_chg_param *param,
+				    int val_u,
+				    u8 *val_raw);
+};
+
+struct buck_boost_freq {
+	int freq_khz;
+	u8 val;
+};
+
+struct smb_chg_freq {
+	unsigned int		freq_5V;
+	unsigned int		freq_6V_8V;
+	unsigned int		freq_9V;
+	unsigned int		freq_12V;
+	unsigned int		freq_removal;
+	unsigned int		freq_below_otg_threshold;
+	unsigned int		freq_above_otg_threshold;
+};
+
+struct smb_params {
+	struct smb_chg_param	fcc;
+	struct smb_chg_param	fv;
+	struct smb_chg_param	usb_icl;
+	struct smb_chg_param	icl_stat;
+	struct smb_chg_param	otg_cl;
+	struct smb_chg_param	jeita_cc_comp_hot;
+	struct smb_chg_param	jeita_cc_comp_cold;
+	struct smb_chg_param	freq_switcher;
+};
+
+struct parallel_params {
+	struct power_supply	*psy;
+};
+
+struct smb_iio {
+	struct iio_channel	*temp_chan;
+	struct iio_channel	*temp_max_chan;
+	struct iio_channel	*usbin_i_chan;
+	struct iio_channel	*usbin_v_chan;
+	struct iio_channel	*batt_i_chan;
+	struct iio_channel	*connector_temp_chan;
+	struct iio_channel	*connector_temp_thr1_chan;
+	struct iio_channel	*connector_temp_thr2_chan;
+	struct iio_channel	*connector_temp_thr3_chan;
+};
+
+struct smb_charger {
+	struct device		*dev;
+	char			*name;
+	struct regmap		*regmap;
+	struct smb_irq_info	*irq_info;
+	struct smb_params	param;
+	struct smb_iio		iio;
+	int			*debug_mask;
+	enum smb_mode		mode;
+	struct smb_chg_freq	chg_freq;
+	int			smb_version;
+	int			otg_delay_ms;
+	int			*weak_chg_icl_ua;
+
+	/* locks */
+	struct mutex		lock;
+	struct mutex		ps_change_lock;
+	struct mutex		otg_oc_lock;
+
+	/* power supplies */
+	struct power_supply		*batt_psy;
+	struct power_supply		*usb_psy;
+	struct power_supply		*dc_psy;
+	struct power_supply		*bms_psy;
+	struct power_supply		*usb_main_psy;
+	struct power_supply		*usb_port_psy;
+	enum power_supply_type		real_charger_type;
+
+	/* notifiers */
+	struct notifier_block	nb;
+
+	/* parallel charging */
+	struct parallel_params	pl;
+
+	/* regulators */
+	struct smb_regulator	*vbus_vreg;
+	struct smb_regulator	*vconn_vreg;
+	struct regulator	*dpdm_reg;
+
+	/* votables */
+	struct votable		*dc_suspend_votable;
+	struct votable		*fcc_votable;
+	struct votable		*fv_votable;
+	struct votable		*usb_icl_votable;
+	struct votable		*pd_disallowed_votable_indirect;
+	struct votable		*pd_allowed_votable;
+	struct votable		*awake_votable;
+	struct votable		*pl_disable_votable;
+	struct votable		*chg_disable_votable;
+	struct votable		*pl_enable_votable_indirect;
+	struct votable		*usb_irq_enable_votable;
+
+	/* work */
+	struct work_struct	bms_update_work;
+	struct work_struct	pl_update_work;
+	struct delayed_work	ps_change_timeout_work;
+	struct delayed_work	clear_hdc_work;
+	struct delayed_work	icl_change_work;
+	struct delayed_work	pl_enable_work;
+	struct delayed_work	uusb_otg_work;
+	struct delayed_work	bb_removal_work;
+
+	/* cached status */
+	int			voltage_min_uv;
+	int			voltage_max_uv;
+	int			pd_active;
+	bool			system_suspend_supported;
+	int			boost_threshold_ua;
+	int			system_temp_level;
+	int			thermal_levels;
+	int			*thermal_mitigation;
+	int			dcp_icl_ua;
+	int			fake_capacity;
+	int			fake_batt_status;
+	bool			step_chg_enabled;
+	bool			sw_jeita_enabled;
+	bool			is_hdc;
+	bool			chg_done;
+	int			connector_type;
+	bool			otg_en;
+	bool			suspend_input_on_debug_batt;
+	int			otg_attempts;
+	int			vconn_attempts;
+	int			default_icl_ua;
+	int			otg_cl_ua;
+	bool			uusb_apsd_rerun_done;
+	bool			pd_hard_reset;
+	bool			typec_present;
+	int			fake_input_current_limited;
+	bool			pr_swap_in_progress;
+	int			typec_mode;
+	int			usb_icl_change_irq_enabled;
+	u32			jeita_status;
+	u8			float_cfg;
+	bool			use_extcon;
+	bool			otg_present;
+	int			hw_max_icl_ua;
+
+	/* workaround flag */
+	u32			wa_flags;
+	int			boost_current_ua;
+
+	/* extcon for VBUS / ID notification to USB for uUSB */
+	struct extcon_dev	*extcon;
+
+	/* battery profile */
+	int			batt_profile_fcc_ua;
+	int			batt_profile_fv_uv;
+
+	int			usb_icl_delta_ua;
+	int			pulse_cnt;
+
+	int			die_health;
+};
+
+int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
+int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val);
+int smblib_write(struct smb_charger *chg, u16 addr, u8 val);
+
+int smblib_get_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int *val_u);
+int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend);
+
+int smblib_enable_charging(struct smb_charger *chg, bool enable);
+int smblib_set_charge_param(struct smb_charger *chg,
+			    struct smb_chg_param *param, int val_u);
+int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend);
+int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend);
+
+int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw);
+int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
+					   u8 val_raw);
+int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
+					     int val_u, u8 *val_raw);
+int smblib_set_chg_freq(struct smb_chg_param *param,
+				int val_u, u8 *val_raw);
+int smblib_set_prop_boost_current(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_vbus_regulator_enable(struct regulator_dev *rdev);
+int smblib_vbus_regulator_disable(struct regulator_dev *rdev);
+int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev);
+
+int smblib_vconn_regulator_enable(struct regulator_dev *rdev);
+int smblib_vconn_regulator_disable(struct regulator_dev *rdev);
+int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev);
+
+irqreturn_t default_irq_handler(int irq, void *data);
+irqreturn_t chg_state_change_irq_handler(int irq, void *data);
+irqreturn_t batt_temp_changed_irq_handler(int irq, void *data);
+irqreturn_t batt_psy_changed_irq_handler(int irq, void *data);
+irqreturn_t usbin_uv_irq_handler(int irq, void *data);
+irqreturn_t usb_plugin_irq_handler(int irq, void *data);
+irqreturn_t usb_source_change_irq_handler(int irq, void *data);
+irqreturn_t icl_change_irq_handler(int irq, void *data);
+irqreturn_t typec_state_change_irq_handler(int irq, void *data);
+irqreturn_t dc_plugin_irq_handler(int irq, void *data);
+irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
+irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);
+irqreturn_t wdog_bark_irq_handler(int irq, void *data);
+irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data);
+
+int smblib_get_prop_input_suspend(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_present(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_capacity(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_status(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_health(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_system_temp_level(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_input_current_limited(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_voltage_now(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_current_now(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_temp(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_batt_charge_counter(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_set_prop_input_suspend(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_batt_capacity(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_system_temp_level(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_input_current_limited(struct smb_charger *chg,
+				const union power_supply_propval *val);
+
+int smblib_get_prop_dc_present(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_dc_online(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_dc_current_max(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_set_prop_dc_current_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_get_prop_usb_present(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_usb_online(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_usb_suspend(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_typec_power_role(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_pd_allowed(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_input_current_settled(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
+			       union power_supply_propval *val);
+int smblib_get_pe_start(struct smb_charger *chg,
+			       union power_supply_propval *val);
+int smblib_get_prop_die_health(struct smb_charger *chg,
+			       union power_supply_propval *val);
+int smblib_set_prop_pd_current_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_typec_power_role(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_active(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_set_prop_ship_mode(struct smb_charger *chg,
+				const union power_supply_propval *val);
+void smblib_suspend_on_debug_battery(struct smb_charger *chg);
+int smblib_rerun_apsd_if_required(struct smb_charger *chg);
+int smblib_get_prop_fcc_delta(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_dp_dm(struct smb_charger *chg, int val);
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable);
+int smblib_rerun_aicl(struct smb_charger *chg);
+int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
+int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
+int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+				union power_supply_propval *val);
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+				const union power_supply_propval *val);
+int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override);
+
+int smblib_init(struct smb_charger *chg);
+int smblib_deinit(struct smb_charger *chg);
+#endif /* __SMB5_CHARGER_H */
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
new file mode 100644
index 0000000..9a418c8
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -0,0 +1,350 @@
+/* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SMB5_CHARGER_REG_H
+#define __SMB5_CHARGER_REG_H
+
+#include <linux/bitops.h>
+
+#define CHGR_BASE	0x1000
+#define DCDC_BASE	0x1100
+#define BATIF_BASE	0x1200
+#define USBIN_BASE	0x1300
+#define DCIN_BASE	0x1400
+#define TYPEC_BASE	0X1500
+#define MISC_BASE	0x1600
+
+#define PERPH_TYPE_OFFSET	0x04
+#define TYPE_MASK		GENMASK(7, 0)
+#define PERPH_SUBTYPE_OFFSET	0x05
+#define SUBTYPE_MASK		GENMASK(7, 0)
+#define INT_RT_STS_OFFSET	0x10
+
+/********************************
+ *  CHGR Peripheral Registers  *
+ ********************************/
+#define BATTERY_CHARGER_STATUS_1_REG		(CHGR_BASE + 0x06)
+#define BATTERY_CHARGER_STATUS_MASK		GENMASK(2, 0)
+enum {
+	INHIBIT_CHARGE = 0,
+	TRICKLE_CHARGE,
+	PRE_CHARGE,
+	FULLON_CHARGE,
+	TAPER_CHARGE,
+	TERMINATE_CHARGE,
+	PAUSE_CHARGE,
+	DISABLE_CHARGE,
+};
+
+#define BATTERY_CHARGER_STATUS_2_REG		(CHGR_BASE + 0x07)
+#define CHARGER_ERROR_STATUS_BAT_OV_BIT		BIT(1)
+
+#define BATTERY_CHARGER_STATUS_5_REG		(CHGR_BASE + 0x0B)
+#define ENABLE_TRICKLE_BIT			BIT(2)
+#define ENABLE_PRE_CHARGING_BIT			BIT(1)
+#define ENABLE_FULLON_MODE_BIT			BIT(0)
+
+#define BATTERY_CHARGER_STATUS_7_REG		(CHGR_BASE + 0x0D)
+#define BAT_TEMP_STATUS_SOFT_LIMIT_MASK		GENMASK(5, 4)
+#define BAT_TEMP_STATUS_HOT_SOFT_BIT		BIT(5)
+#define BAT_TEMP_STATUS_COLD_SOFT_BIT		BIT(4)
+#define BAT_TEMP_STATUS_TOO_HOT_BIT		BIT(3)
+#define BAT_TEMP_STATUS_TOO_COLD_BIT		BIT(2)
+#define BAT_TEMP_STATUS_TOO_HOT_AFP_BIT		BIT(1)
+#define BAT_TEMP_STATUS_TOO_COLD_AFP_BIT	BIT(0)
+
+#define CHARGING_ENABLE_CMD_REG			(CHGR_BASE + 0x42)
+#define CHARGING_ENABLE_CMD_BIT			BIT(0)
+
+#define CHGR_CFG2_REG				(CHGR_BASE + 0x51)
+#define SOC_BASED_RECHG_BIT			BIT(1)
+#define CHARGER_INHIBIT_BIT			BIT(0)
+
+#define CHGR_FAST_CHARGE_CURRENT_CFG_REG	(CHGR_BASE + 0x61)
+
+#define CHGR_FLOAT_VOLTAGE_CFG_REG		(CHGR_BASE + 0x70)
+
+#define CHARGE_INHIBIT_THRESHOLD_CFG_REG	(CHGR_BASE + 0x72)
+#define CHARGE_INHIBIT_THRESHOLD_MASK		GENMASK(1, 0)
+#define INHIBIT_ANALOG_VFLT_MINUS_50MV		0
+#define INHIBIT_ANALOG_VFLT_MINUS_100MV		1
+#define INHIBIT_ANALOG_VFLT_MINUS_200MV		2
+#define INHIBIT_ANALOG_VFLT_MINUS_300MV		3
+
+#define JEITA_EN_CFG_REG			(CHGR_BASE + 0x90)
+#define JEITA_EN_HOT_SL_FCV_BIT			BIT(3)
+#define JEITA_EN_COLD_SL_FCV_BIT		BIT(2)
+#define JEITA_EN_HOT_SL_CCC_BIT			BIT(1)
+#define JEITA_EN_COLD_SL_CCC_BIT		BIT(0)
+
+#define JEITA_CCCOMP_CFG_HOT_REG		(CHGR_BASE + 0x92)
+#define JEITA_CCCOMP_CFG_COLD_REG		(CHGR_BASE + 0x93)
+
+/********************************
+ *  DCDC Peripheral Registers  *
+ ********************************/
+#define AICL_ICL_STATUS_REG			(DCDC_BASE + 0x08)
+
+#define AICL_STATUS_REG				(DCDC_BASE + 0x0A)
+#define SOFT_ILIMIT_BIT				BIT(6)
+#define AICL_DONE_BIT				BIT(0)
+
+#define POWER_PATH_STATUS_REG			(DCDC_BASE + 0x0B)
+#define USBIN_SUSPEND_STS_BIT			BIT(6)
+#define USE_USBIN_BIT				BIT(4)
+#define USE_DCIN_BIT				BIT(3)
+#define VALID_INPUT_POWER_SOURCE_STS_BIT	BIT(0)
+
+#define DCDC_CMD_OTG_REG			(DCDC_BASE + 0x40)
+#define OTG_EN_BIT				BIT(0)
+
+#define DCDC_FSW_SEL_REG			(DCDC_BASE + 0x50)
+
+#define DCDC_OTG_CURRENT_LIMIT_CFG_REG		(DCDC_BASE + 0x52)
+
+#define DCDC_OTG_CFG_REG			(DCDC_BASE + 0x53)
+#define OTG_EN_SRC_CFG_BIT			BIT(1)
+
+/********************************
+ *  BATIF Peripheral Registers  *
+ ********************************/
+
+/* BATIF Interrupt Bits	 */
+#define VPH_OV_RT_STS_BIT			BIT(7)
+#define BUCK_OC_RT_STS_BIT			BIT(6)
+#define BAT_TERMINAL_MISSING_RT_STS_BIT		BIT(5)
+#define BAT_THERM_OR_ID_MISSING_RT_STS_BIT      BIT(4)
+#define BAT_LOW_RT_STS_BIT			BIT(3)
+#define BAT_OV_RT_STS_BIT			BIT(2)
+#define ALL_CHNL_CONV_DONE_RT_STS		BIT(1)
+#define BAT_TEMP_RT_STS_BIT			BIT(0)
+
+#define SHIP_MODE_REG				(BATIF_BASE + 0x40)
+#define SHIP_MODE_EN_BIT			BIT(0)
+
+/********************************
+ *  USBIN Peripheral Registers  *
+ ********************************/
+#define APSD_STATUS_REG				(USBIN_BASE + 0x07)
+#define APSD_STATUS_7_BIT			BIT(7)
+#define HVDCP_CHECK_TIMEOUT_BIT			BIT(6)
+#define SLOW_PLUGIN_TIMEOUT_BIT			BIT(5)
+#define ENUMERATION_DONE_BIT			BIT(4)
+#define VADP_CHANGE_DONE_AFTER_AUTH_BIT		BIT(3)
+#define QC_AUTH_DONE_STATUS_BIT			BIT(2)
+#define QC_CHARGER_BIT				BIT(1)
+#define APSD_DTC_STATUS_DONE_BIT		BIT(0)
+
+#define APSD_RESULT_STATUS_REG			(USBIN_BASE + 0x08)
+#define APSD_RESULT_STATUS_7_BIT		BIT(7)
+#define APSD_RESULT_STATUS_MASK			GENMASK(6, 0)
+#define QC_3P0_BIT				BIT(6)
+#define QC_2P0_BIT				BIT(5)
+#define FLOAT_CHARGER_BIT			BIT(4)
+#define DCP_CHARGER_BIT				BIT(3)
+#define CDP_CHARGER_BIT				BIT(2)
+#define OCP_CHARGER_BIT				BIT(1)
+#define SDP_CHARGER_BIT				BIT(0)
+
+#define QC_CHANGE_STATUS_REG			(USBIN_BASE + 0x09)
+#define QC_12V_BIT				BIT(2)
+#define QC_9V_BIT				BIT(1)
+#define QC_5V_BIT				BIT(0)
+#define QC_2P0_STATUS_MASK			GENMASK(2, 0)
+
+/* USBIN Interrupt Bits */
+#define USBIN_ICL_CHANGE_RT_STS_BIT		BIT(7)
+#define USBIN_SOURCE_CHANGE_RT_STS_BIT		BIT(6)
+#define USBIN_REVI_RT_STS_BIT			BIT(5)
+#define USBIN_PLUGIN_RT_STS_BIT			BIT(4)
+#define USBIN_OV_RT_STS_BIT			BIT(3)
+#define USBIN_UV_RT_STS_BIT			BIT(2)
+#define USBIN_VASHDN_RT_STS_BIT			BIT(1)
+#define USBIN_COLLAPSE_RT_STS_BIT		BIT(0)
+
+#define USBIN_CMD_IL_REG			(USBIN_BASE + 0x40)
+#define USBIN_SUSPEND_BIT			BIT(0)
+
+#define CMD_APSD_REG				(USBIN_BASE + 0x41)
+#define APSD_RERUN_BIT				BIT(0)
+
+#define CMD_HVDCP_2_REG				(USBIN_BASE + 0x43)
+#define FORCE_12V_BIT				BIT(5)
+#define FORCE_9V_BIT				BIT(4)
+#define FORCE_5V_BIT				BIT(3)
+#define SINGLE_DECREMENT_BIT			BIT(1)
+#define SINGLE_INCREMENT_BIT			BIT(0)
+
+#define USBIN_ADAPTER_ALLOW_CFG_REG		(USBIN_BASE + 0x60)
+enum {
+	USBIN_ADAPTER_ALLOW_5V		= 0,
+	USBIN_ADAPTER_ALLOW_9V		= 2,
+	USBIN_ADAPTER_ALLOW_5V_OR_9V	= 3,
+	USBIN_ADAPTER_ALLOW_12V		= 4,
+	USBIN_ADAPTER_ALLOW_5V_OR_12V	= 5,
+	USBIN_ADAPTER_ALLOW_9V_TO_12V	= 6,
+	USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V = 7,
+	USBIN_ADAPTER_ALLOW_5V_TO_9V	= 8,
+	USBIN_ADAPTER_ALLOW_5V_TO_12V	= 12,
+};
+
+#define USBIN_OPTIONS_1_CFG_REG			(USBIN_BASE + 0x62)
+#define HVDCP_AUTH_ALG_EN_CFG_BIT		BIT(6)
+#define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT	BIT(5)
+#define BC1P2_SRC_DETECT_BIT			BIT(3)
+
+#define USBIN_OPTIONS_2_CFG_REG			(USBIN_BASE + 0x63)
+#define FLOAT_OPTIONS_MASK			GENMASK(2, 0)
+#define FLOAT_DIS_CHGING_CFG_BIT		BIT(2)
+#define SUSPEND_FLOAT_CFG_BIT			BIT(1)
+#define FORCE_FLOAT_SDP_CFG_BIT			BIT(0)
+
+#define USBIN_LOAD_CFG_REG			(USBIN_BASE + 0x65)
+#define ICL_OVERRIDE_AFTER_APSD_BIT		BIT(4)
+
+#define USBIN_ICL_OPTIONS_REG			(USBIN_BASE + 0x66)
+#define CFG_USB3P0_SEL_BIT			BIT(2)
+#define	USB51_MODE_BIT				BIT(1)
+#define USBIN_MODE_CHG_BIT			BIT(0)
+
+#define USBIN_CURRENT_LIMIT_CFG_REG		(USBIN_BASE + 0x70)
+
+#define USBIN_AICL_OPTIONS_CFG_REG		(USBIN_BASE + 0x80)
+#define USBIN_AICL_ADC_EN_BIT			BIT(3)
+
+/********************************
+ *  DCIN Peripheral Registers   *
+ ********************************/
+
+/* DCIN Interrupt Bits */
+#define DCIN_PLUGIN_RT_STS_BIT			BIT(4)
+
+#define DCIN_CMD_IL_REG				(DCIN_BASE + 0x40)
+#define DCIN_SUSPEND_BIT			BIT(0)
+
+/********************************
+ *  TYPEC Peripheral Registers  *
+ ********************************/
+#define TYPE_C_SNK_STATUS_REG			(TYPEC_BASE + 0x06)
+#define DETECTED_SRC_TYPE_MASK			GENMASK(3, 1)
+#define SNK_RP_STD_BIT				BIT(3)
+#define SNK_RP_1P5_BIT				BIT(2)
+#define SNK_RP_3P0_BIT				BIT(1)
+
+#define TYPE_C_SRC_STATUS_REG			(TYPEC_BASE + 0x08)
+#define DETECTED_SNK_TYPE_MASK			GENMASK(4, 0)
+#define SRC_DEBUG_ACCESS_BIT			BIT(4)
+#define SRC_RD_OPEN_BIT				BIT(3)
+#define SRC_RD_RA_VCONN_BIT			BIT(2)
+#define SRC_RA_OPEN_BIT				BIT(1)
+#define AUDIO_ACCESS_RA_RA_BIT			BIT(0)
+
+#define TYPE_C_MISC_STATUS_REG			(TYPEC_BASE + 0x0B)
+#define SNK_SRC_MODE_BIT			BIT(6)
+#define TYPEC_VBUS_ERROR_STATUS_BIT		BIT(4)
+#define CC_ORIENTATION_BIT			BIT(1)
+#define CC_ATTACHED_BIT				BIT(0)
+
+#define LEGACY_CABLE_STATUS_REG			(TYPEC_BASE + 0x0D)
+#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT	BIT(0)
+
+#define TYPEC_U_USB_STATUS_REG			(TYPEC_BASE + 0x0F)
+#define U_USB_GROUND_NOVBUS_BIT			BIT(6)
+#define U_USB_GROUND_BIT			BIT(4)
+
+#define TYPE_C_MODE_CFG_REG			(TYPEC_BASE + 0x44)
+#define TYPEC_POWER_ROLE_CMD_MASK		GENMASK(2, 0)
+#define EN_SRC_ONLY_BIT				BIT(2)
+#define EN_SNK_ONLY_BIT				BIT(1)
+#define TYPEC_DISABLE_CMD_BIT			BIT(0)
+
+#define TYPE_C_VCONN_CONTROL_REG		(TYPEC_BASE + 0x46)
+#define VCONN_EN_VALUE_BIT			BIT(1)
+#define VCONN_EN_SRC_BIT			BIT(0)
+
+#define TYPE_C_CCOUT_CONTROL_REG		(TYPEC_BASE + 0x48)
+#define TYPEC_CCOUT_SRC_BIT			BIT(0)
+
+#define TYPE_C_EXIT_STATE_CFG_REG		(TYPEC_BASE + 0x50)
+#define EXIT_SNK_BASED_ON_CC_BIT		BIT(0)
+
+#define TYPE_C_INTERRUPT_EN_CFG_1_REG			(TYPEC_BASE + 0x5E)
+#define TYPEC_LEGACY_CABLE_INT_EN_BIT			BIT(7)
+#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT	BIT(6)
+#define TYPEC_TRYSOURCE_DETECT_INT_EN_BIT		BIT(5)
+#define TYPEC_TRYSINK_DETECT_INT_EN_BIT			BIT(4)
+#define TYPEC_CCOUT_DETACH_INT_EN_BIT			BIT(3)
+#define TYPEC_CCOUT_ATTACH_INT_EN_BIT			BIT(2)
+#define TYPEC_VBUS_DEASSERT_INT_EN_BIT			BIT(1)
+#define TYPEC_VBUS_ASSERT_INT_EN_BIT			BIT(0)
+
+#define TYPE_C_INTERRUPT_EN_CFG_2_REG		(TYPEC_BASE + 0x60)
+#define TYPEC_SRC_BATT_HPWR_INT_EN_BIT		BIT(6)
+#define MICRO_USB_STATE_CHANGE_INT_EN_BIT	BIT(5)
+#define TYPEC_STATE_MACHINE_CHANGE_INT_EN_BIT	BIT(4)
+#define TYPEC_DEBUG_ACCESS_DETECT_INT_EN_BIT	BIT(3)
+#define TYPEC_WATER_DETECTION_INT_EN_BIT	BIT(2)
+#define TYPEC_VBUS_ERROR_INT_EN_BIT		BIT(1)
+#define TYPEC_DEBOUNCE_DONE_INT_EN_BIT		BIT(0)
+
+#define TYPE_C_DEBOUNCE_OPTION_REG		(TYPEC_BASE + 0x62)
+#define REDUCE_TCCDEBOUNCE_TO_2MS_BIT		BIT(2)
+
+#define TYPEC_U_USB_CFG_REG			(TYPEC_BASE + 0x70)
+#define EN_MICRO_USB_MODE_BIT			BIT(0)
+
+#define TYPEC_MICRO_USB_MODE_REG		(TYPEC_BASE + 0x70)
+#define MICRO_USB_MODE_ONLY_BIT			BIT(0)
+/********************************
+ *  MISC Peripheral Registers  *
+ ********************************/
+#define TEMP_RANGE_STATUS_REG			(MISC_BASE + 0x06)
+#define THERM_REG_ACTIVE_BIT			BIT(6)
+#define TLIM_BIT				BIT(5)
+#define TEMP_RANGE_MASK				GENMASK(4, 1)
+#define ALERT_LEVEL_BIT				BIT(4)
+#define TEMP_ABOVE_RANGE_BIT			BIT(3)
+#define TEMP_WITHIN_RANGE_BIT			BIT(2)
+#define TEMP_BELOW_RANGE_BIT			BIT(1)
+#define THERMREG_DISABLED_BIT			BIT(0)
+
+#define BARK_BITE_WDOG_PET_REG			(MISC_BASE + 0x43)
+#define BARK_BITE_WDOG_PET_BIT			BIT(0)
+
+#define AICL_CMD_REG				(MISC_BASE + 0x44)
+#define RERUN_AICL_BIT				BIT(0)
+
+#define SNARL_BARK_BITE_WD_CFG_REG		(MISC_BASE + 0x43)
+#define BITE_WDOG_DISABLE_CHARGING_CFG_BIT	BIT(7)
+#define BARK_WDOG_TIMEOUT_MASK			GENMASK(3, 2)
+#define BITE_WDOG_TIMEOUT_MASK			GENMASK(1, 0)
+
+#define MISC_SMB_EN_CMD_REG			(MISC_BASE + 0x48)
+#define SMB_EN_OVERRIDE_VALUE_BIT		BIT(4)
+#define SMB_EN_OVERRIDE_BIT			BIT(3)
+#define EN_STAT_CMD_BIT				BIT(2)
+#define EN_CP_FPF_CMD_BIT			BIT(1)
+#define EN_CP_CMD_BIT				BIT(0)
+
+#define WD_CFG_REG				(MISC_BASE + 0x51)
+#define WATCHDOG_TRIGGER_AFP_EN_BIT		BIT(7)
+#define BARK_WDOG_INT_EN_BIT			BIT(6)
+#define WDOG_TIMER_EN_ON_PLUGIN_BIT		BIT(1)
+
+#define MISC_SMB_CFG_REG			(MISC_BASE + 0x90)
+#define SMB_EN_SEL_BIT				BIT(4)
+#define CP_EN_POLARITY_CFG_BIT			BIT(3)
+#define STAT_POLARITY_CFG_BIT			BIT(2)
+#define STAT_FUNCTION_CFG_BIT			BIT(1)
+#define STAT_IRQ_PULSING_EN_BIT			BIT(0)
+
+#endif /* __SMB5_CHARGER_REG_H */
diff --git a/drivers/regulator/cpr-regulator.c b/drivers/regulator/cpr-regulator.c
index 9c47e82..cabcf7f 100644
--- a/drivers/regulator/cpr-regulator.c
+++ b/drivers/regulator/cpr-regulator.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,8 +38,6 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/cpr-regulator.h>
-#include <linux/msm_thermal.h>
-#include <linux/msm_tsens.h>
 #include <soc/qcom/scm.h>
 
 /* Register Offsets for RB-CPR and Bit Definitions */
@@ -287,7 +285,6 @@
 	int				corner;
 	int				ceiling_max;
 	struct dentry			*debugfs;
-	struct device			*dev;
 
 	/* eFuse parameters */
 	phys_addr_t	efuse_addr;
@@ -319,14 +316,6 @@
 	/* mem-acc regulator */
 	struct regulator	*mem_acc_vreg;
 
-	/* thermal monitor */
-	int			tsens_id;
-	int			cpr_disable_temp_threshold;
-	int			cpr_enable_temp_threshold;
-	bool			cpr_disable_on_temperature;
-	bool			cpr_thermal_disable;
-	struct threshold_info	tsens_threshold_config;
-
 	/* CPR parameters */
 	u32		num_fuse_corners;
 	u64		cpr_fuse_bits;
@@ -565,8 +554,7 @@
 
 static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
 {
-	if (cpr_vreg->cpr_fuse_disable || !cpr_vreg->enable ||
-				cpr_vreg->cpr_thermal_disable)
+	if (cpr_vreg->cpr_fuse_disable || !cpr_vreg->enable)
 		return false;
 	else
 		return true;
@@ -5102,145 +5090,6 @@
 	return rc;
 }
 
-static int cpr_disable_on_temp(struct cpr_regulator *cpr_vreg, bool disable)
-{
-	int rc = 0;
-
-	mutex_lock(&cpr_vreg->cpr_mutex);
-
-	if (cpr_vreg->cpr_fuse_disable ||
-		(cpr_vreg->cpr_thermal_disable == disable))
-		goto out;
-
-	cpr_vreg->cpr_thermal_disable = disable;
-
-	if (cpr_vreg->enable && cpr_vreg->corner) {
-		if (disable) {
-			cpr_debug(cpr_vreg, "Disabling CPR - below temperature threshold [%d]\n",
-					cpr_vreg->cpr_disable_temp_threshold);
-			/* disable CPR and force open-loop */
-			cpr_ctl_disable(cpr_vreg);
-			rc = cpr_regulator_set_voltage(cpr_vreg->rdev,
-						cpr_vreg->corner, false);
-			if (rc < 0)
-				cpr_err(cpr_vreg, "Failed to set voltage, rc=%d\n",
-						rc);
-		} else {
-			/* enable CPR */
-			cpr_debug(cpr_vreg, "Enabling CPR - above temperature thresold [%d]\n",
-					cpr_vreg->cpr_enable_temp_threshold);
-			rc = cpr_regulator_set_voltage(cpr_vreg->rdev,
-						cpr_vreg->corner, true);
-			if (rc < 0)
-				cpr_err(cpr_vreg, "Failed to set voltage, rc=%d\n",
-						rc);
-		}
-	}
-out:
-	mutex_unlock(&cpr_vreg->cpr_mutex);
-	return rc;
-}
-
-static void tsens_threshold_notify(struct therm_threshold *tsens_cb_data)
-{
-	struct threshold_info *info = tsens_cb_data->parent;
-	struct cpr_regulator *cpr_vreg = container_of(info,
-			struct cpr_regulator, tsens_threshold_config);
-	int rc = 0;
-
-	cpr_debug(cpr_vreg, "Triggered tsens-notification trip_type=%d for thermal_zone_id=%d\n",
-		tsens_cb_data->trip_triggered, tsens_cb_data->sensor_id);
-
-	switch (tsens_cb_data->trip_triggered) {
-	case THERMAL_TRIP_CONFIGURABLE_HI:
-		rc = cpr_disable_on_temp(cpr_vreg, false);
-		if (rc < 0)
-			cpr_err(cpr_vreg, "Failed to enable CPR, rc=%d\n", rc);
-		break;
-	case THERMAL_TRIP_CONFIGURABLE_LOW:
-		rc = cpr_disable_on_temp(cpr_vreg, true);
-		if (rc < 0)
-			cpr_err(cpr_vreg, "Failed to disable CPR, rc=%d\n", rc);
-		break;
-	default:
-		cpr_debug(cpr_vreg, "trip-type %d not supported\n",
-				tsens_cb_data->trip_triggered);
-		break;
-	}
-
-	if (tsens_cb_data->cur_state != tsens_cb_data->trip_triggered) {
-		rc = sensor_mgr_set_threshold(tsens_cb_data->sensor_id,
-						tsens_cb_data->threshold);
-		if (rc < 0)
-			cpr_err(cpr_vreg,
-			"Failed to set temp. threshold, rc=%d\n", rc);
-		else
-			tsens_cb_data->cur_state =
-				tsens_cb_data->trip_triggered;
-	}
-}
-
-static int cpr_check_tsens(struct cpr_regulator *cpr_vreg)
-{
-	int rc = 0;
-	struct tsens_device tsens_dev;
-	unsigned long temp = 0;
-	bool disable;
-
-	if (tsens_is_ready() > 0) {
-		tsens_dev.sensor_num = cpr_vreg->tsens_id;
-		rc = tsens_get_temp(&tsens_dev, &temp);
-		if (rc < 0) {
-			cpr_err(cpr_vreg, "Faled to read tsens, rc=%d\n", rc);
-			return rc;
-		}
-
-		disable = (int) temp <= cpr_vreg->cpr_disable_temp_threshold;
-		rc = cpr_disable_on_temp(cpr_vreg, disable);
-		if (rc)
-			cpr_err(cpr_vreg, "Failed to %s CPR, rc=%d\n",
-					disable ? "disable" : "enable", rc);
-	}
-
-	return rc;
-}
-
-static int cpr_thermal_init(struct cpr_regulator *cpr_vreg)
-{
-	int rc;
-	struct device_node *of_node = cpr_vreg->dev->of_node;
-
-	if (!of_find_property(of_node, "qcom,cpr-thermal-sensor-id", NULL))
-		return 0;
-
-	CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-thermal-sensor-id",
-			  &cpr_vreg->tsens_id, rc);
-	if (rc < 0)
-		return rc;
-
-	CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-disable-temp-threshold",
-			  &cpr_vreg->cpr_disable_temp_threshold, rc);
-	if (rc < 0)
-		return rc;
-
-	CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-enable-temp-threshold",
-			  &cpr_vreg->cpr_enable_temp_threshold, rc);
-	if (rc < 0)
-		return rc;
-
-	if (cpr_vreg->cpr_disable_temp_threshold >=
-				cpr_vreg->cpr_enable_temp_threshold) {
-		cpr_err(cpr_vreg, "Invalid temperature threshold cpr_disable_temp[%d] >= cpr_enable_temp[%d]\n",
-				cpr_vreg->cpr_disable_temp_threshold,
-				cpr_vreg->cpr_enable_temp_threshold);
-		return -EINVAL;
-	}
-
-	cpr_vreg->cpr_disable_on_temperature = true;
-
-	return 0;
-}
-
 static int cpr_init_cpr(struct platform_device *pdev,
 			       struct cpr_regulator *cpr_vreg)
 {
@@ -6067,7 +5916,13 @@
 		return -EINVAL;
 	}
 
-	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+	cpr_vreg = devm_kzalloc(&pdev->dev, sizeof(struct cpr_regulator),
+				GFP_KERNEL);
+	if (!cpr_vreg)
+		return -ENOMEM;
+
+	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
+						&cpr_vreg->rdesc);
 	if (!init_data) {
 		dev_err(dev, "regulator init data is missing\n");
 		return -EINVAL;
@@ -6078,14 +5933,6 @@
 			|= REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS;
 	}
 
-	cpr_vreg = devm_kzalloc(&pdev->dev, sizeof(struct cpr_regulator),
-				GFP_KERNEL);
-	if (!cpr_vreg) {
-		dev_err(dev, "Can't allocate cpr_regulator memory\n");
-		return -ENOMEM;
-	}
-
-	cpr_vreg->dev = &pdev->dev;
 	cpr_vreg->rdesc.name = init_data->constraints.name;
 	if (cpr_vreg->rdesc.name == NULL) {
 		dev_err(dev, "regulator-name missing\n");
@@ -6182,12 +6029,6 @@
 		return rc;
 	}
 
-	rc = cpr_thermal_init(cpr_vreg);
-	if (rc) {
-		cpr_err(cpr_vreg, "Thermal intialization failed rc=%d\n", rc);
-		return rc;
-	}
-
 	if (of_property_read_bool(pdev->dev.of_node,
 				"qcom,disable-closed-loop-in-pc")) {
 		rc = cpr_init_pm_notification(cpr_vreg);
@@ -6247,17 +6088,6 @@
 	platform_set_drvdata(pdev, cpr_vreg);
 	cpr_debugfs_init(cpr_vreg);
 
-	if (cpr_vreg->cpr_disable_on_temperature) {
-		rc = cpr_check_tsens(cpr_vreg);
-		if (rc < 0) {
-			cpr_err(cpr_vreg, "Unable to config CPR on tsens, rc=%d\n",
-									rc);
-			cpr_apc_exit(cpr_vreg);
-			cpr_debugfs_remove(cpr_vreg);
-			return rc;
-		}
-	}
-
 	/* Register panic notification call back */
 	cpr_vreg->panic_notifier.notifier_call = cpr_panic_callback;
 	atomic_notifier_chain_register(&panic_notifier_list,
@@ -6293,10 +6123,6 @@
 		if (cpr_vreg->cpu_notifier.notifier_call)
 			unregister_hotcpu_notifier(&cpr_vreg->cpu_notifier);
 
-		if (cpr_vreg->cpr_disable_on_temperature)
-			sensor_mgr_remove_threshold(
-				&cpr_vreg->tsens_threshold_config);
-
 		atomic_notifier_chain_unregister(&panic_notifier_list,
 			&cpr_vreg->panic_notifier);
 
@@ -6325,56 +6151,6 @@
 	.resume		= cpr_regulator_resume,
 };
 
-static int initialize_tsens_monitor(struct cpr_regulator *cpr_vreg)
-{
-	int rc;
-
-	rc = cpr_check_tsens(cpr_vreg);
-	if (rc < 0) {
-		cpr_err(cpr_vreg, "Unable to check tsens, rc=%d\n", rc);
-		return rc;
-	}
-
-	rc = sensor_mgr_init_threshold(&cpr_vreg->tsens_threshold_config,
-				cpr_vreg->tsens_id,
-				cpr_vreg->cpr_enable_temp_threshold, /* high */
-				cpr_vreg->cpr_disable_temp_threshold, /* low */
-				tsens_threshold_notify);
-	if (rc < 0) {
-		cpr_err(cpr_vreg, "Failed to init tsens monitor, rc=%d\n", rc);
-		return rc;
-	}
-
-	rc = sensor_mgr_convert_id_and_set_threshold(
-			&cpr_vreg->tsens_threshold_config);
-	if (rc < 0)
-		cpr_err(cpr_vreg, "Failed to set tsens threshold, rc=%d\n",
-					rc);
-
-	return rc;
-}
-
-int __init cpr_regulator_late_init(void)
-{
-	int rc;
-	struct cpr_regulator *cpr_vreg;
-
-	mutex_lock(&cpr_regulator_list_mutex);
-
-	list_for_each_entry(cpr_vreg, &cpr_regulator_list, list) {
-		if (cpr_vreg->cpr_disable_on_temperature) {
-			rc = initialize_tsens_monitor(cpr_vreg);
-			if (rc)
-				cpr_err(cpr_vreg, "Failed to initialize temperature monitor, rc=%d\n",
-					rc);
-		}
-	}
-
-	mutex_unlock(&cpr_regulator_list_mutex);
-	return 0;
-}
-late_initcall(cpr_regulator_late_init);
-
 /**
  * cpr_regulator_init() - register cpr-regulator driver
  *
diff --git a/drivers/regulator/msm_gfx_ldo.c b/drivers/regulator/msm_gfx_ldo.c
index 2800607..115a9b7 100644
--- a/drivers/regulator/msm_gfx_ldo.c
+++ b/drivers/regulator/msm_gfx_ldo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -773,12 +773,34 @@
 	return ldo_vreg->vreg_enabled;
 }
 
+/**
+ * msm_gfx_ldo_list_corner_voltage() - return the ldo voltage mapped to
+ *			the specified voltage corner
+ * @rdev:		Regulator device pointer for the msm_gfx_ldo
+ * @corner:		Voltage corner
+ *
+ * Return: voltage value in microvolts or -EINVAL if the corner is out of range
+ */
+static int msm_gfx_ldo_list_corner_voltage(struct regulator_dev *rdev,
+		int corner)
+{
+	struct msm_gfx_ldo *ldo_vreg  = rdev_get_drvdata(rdev);
+
+	corner -= MIN_CORNER_OFFSET;
+
+	if (corner >= 0 && corner < ldo_vreg->num_corners)
+		return ldo_vreg->open_loop_volt[corner];
+	else
+		return -EINVAL;
+}
+
 static struct regulator_ops msm_gfx_ldo_corner_ops = {
-	.enable		= msm_gfx_ldo_corner_enable,
-	.disable	= msm_gfx_ldo_disable,
-	.is_enabled	= msm_gfx_ldo_is_enabled,
-	.set_voltage	= msm_gfx_ldo_set_corner,
-	.get_voltage	= msm_gfx_ldo_get_corner,
+	.enable			= msm_gfx_ldo_corner_enable,
+	.disable		= msm_gfx_ldo_disable,
+	.is_enabled		= msm_gfx_ldo_is_enabled,
+	.set_voltage		= msm_gfx_ldo_set_corner,
+	.get_voltage		= msm_gfx_ldo_get_corner,
+	.list_corner_voltage	= msm_gfx_ldo_list_corner_voltage,
 };
 
 static int msm_gfx_ldo_get_bypass(struct regulator_dev *rdev,
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c
index f457eea..88c5697 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -2840,8 +2840,11 @@
 		return true;
 
 	if (labibb->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE &&
-		labibb->mode == QPNP_LABIBB_LCD_MODE)
+		labibb->mode == QPNP_LABIBB_LCD_MODE) {
+		if (labibb->ttw_en)
+			return false;
 		return true;
+	}
 
 	return false;
 }
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 0aeecec..e2962f1 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1416,13 +1416,13 @@
 	 * will ensure that i/o is queisced and the card is flushed in that
 	 * case.
 	 */
+	aac_free_irq(aac);
 	aac_fib_map_free(aac);
 	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
 	aac->comm_addr = NULL;
 	aac->comm_phys = 0;
 	kfree(aac->queues);
 	aac->queues = NULL;
-	aac_free_irq(aac);
 	kfree(aac->fsa_dev);
 	aac->fsa_dev = NULL;
 	quirks = aac_get_driver_ident(index)->quirks;
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 9962370..0b8db8a 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3857,6 +3857,7 @@
 		if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
 			hpsa_get_ioaccel_status(h, scsi3addr, this_device);
 		volume_offline = hpsa_volume_offline(h, scsi3addr);
+		this_device->volume_offline = volume_offline;
 		if (volume_offline == HPSA_LV_FAILED) {
 			rc = HPSA_LV_FAILED;
 			dev_err(&h->pdev->dev,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index a530f08..4abd3fc 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1727,7 +1727,7 @@
 
 	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
 		reason = FAILURE_SESSION_IN_RECOVERY;
-		sc->result = DID_REQUEUE;
+		sc->result = DID_REQUEUE << 16;
 		goto fault;
 	}
 
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9965135..3a7a86d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -149,7 +149,6 @@
 	struct list_head rq_list; /* head of request list */
 	struct fasync_struct *async_qp;	/* used by asynchronous notification */
 	Sg_request req_arr[SG_MAX_QUEUE];	/* used as singly-linked list */
-	char low_dma;		/* as in parent but possibly overridden to 1 */
 	char force_packid;	/* 1 -> pack_id input to read(), 0 -> ignored */
 	char cmd_q;		/* 1 -> allow command queuing, 0 -> don't */
 	unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
@@ -928,26 +927,14 @@
 				/* strange ..., for backward compatibility */
 		return sfp->timeout_user;
 	case SG_SET_FORCE_LOW_DMA:
-		result = get_user(val, ip);
-		if (result)
-			return result;
-		if (val) {
-			sfp->low_dma = 1;
-			if ((0 == sfp->low_dma) && !sfp->res_in_use) {
-				val = (int) sfp->reserve.bufflen;
-				mutex_lock(&sfp->parentdp->open_rel_lock);
-				sg_remove_scat(sfp, &sfp->reserve);
-				sg_build_reserve(sfp, val);
-				mutex_unlock(&sfp->parentdp->open_rel_lock);
-			}
-		} else {
-			if (atomic_read(&sdp->detaching))
-				return -ENODEV;
-			sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-		}
+		/*
+		 * N.B. This ioctl never worked properly, but failed to
+		 * return an error value. So returning '0' to keep compability
+		 * with legacy applications.
+		 */
 		return 0;
 	case SG_GET_LOW_DMA:
-		return put_user((int) sfp->low_dma, ip);
+		return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
 	case SG_GET_SCSI_ID:
 		if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
 			return -EFAULT;
@@ -1866,6 +1853,7 @@
 	int sg_tablesize = sfp->parentdp->sg_tablesize;
 	int blk_size = buff_size, order;
 	gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
+	struct sg_device *sdp = sfp->parentdp;
 
 	if (blk_size < 0)
 		return -EFAULT;
@@ -1891,7 +1879,7 @@
 			scatter_elem_sz_prev = num;
 	}
 
-	if (sfp->low_dma)
+	if (sdp->device->host->unchecked_isa_dma)
 		gfp_mask |= GFP_DMA;
 
 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2154,8 +2142,6 @@
 	sfp->timeout = SG_DEFAULT_TIMEOUT;
 	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
 	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-	    sdp->device->host->unchecked_isa_dma : 1;
 	sfp->cmd_q = SG_DEF_COMMAND_Q;
 	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
 	sfp->parentdp = sdp;
@@ -2614,7 +2600,7 @@
 			   jiffies_to_msecs(fp->timeout),
 			   fp->reserve.bufflen,
 			   (int) fp->reserve.k_use_sg,
-			   (int) fp->low_dma);
+			   (int) sdp->device->host->unchecked_isa_dma);
 		seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
 			   (int) fp->cmd_q, (int) fp->force_packid,
 			   (int) fp->keep_orphan);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 1a93164..02dfbcc 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -8517,12 +8517,15 @@
 		struct ufs_vreg *vreg, bool on)
 {
 	int ret = 0;
-	struct regulator *reg = vreg->reg;
-	const char *name = vreg->name;
+	struct regulator *reg;
+	const char *name;
 	int min_uV, uA_load;
 
 	BUG_ON(!vreg);
 
+	reg = vreg->reg;
+	name = vreg->name;
+
 	if (regulator_count_voltages(reg) > 0) {
 		min_uV = on ? vreg->min_uV : 0;
 		ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0255761..c882403 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -65,9 +65,9 @@
 obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
 
 obj-$(CONFIG_MEM_SHARE_QMI_SERVICE)		+= memshare/
+obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
 obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
-obj-$(CONFIG_MSM_PIL)   +=      peripheral-loader.o
 
 obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o
 
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index d8cc2c4..59897ea 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -376,7 +376,7 @@
 
 static struct channel_ctx *ch_name_to_ch_ctx_create(
 					struct glink_core_xprt_ctx *xprt_ctx,
-					const char *name);
+					const char *name, bool local);
 
 static void ch_push_remote_rx_intent(struct channel_ctx *ctx, size_t size,
 					uint32_t riid, void *cookie);
@@ -1836,13 +1836,14 @@
  *                              it is not found and get reference of context.
  * @xprt_ctx:	Transport to search for a matching channel.
  * @name:	Name of the desired channel.
+ * @local:	If called from local open or not
  *
  * Return: The channel corresponding to @name, NULL if a matching channel was
  *         not found AND a new channel could not be created.
  */
 static struct channel_ctx *ch_name_to_ch_ctx_create(
 					struct glink_core_xprt_ctx *xprt_ctx,
-					const char *name)
+					const char *name, bool local)
 {
 	struct channel_ctx *entry;
 	struct channel_ctx *ctx;
@@ -1886,10 +1887,23 @@
 	list_for_each_entry_safe(entry, temp, &xprt_ctx->channels,
 		    port_list_node)
 		if (!strcmp(entry->name, name) && !entry->pending_delete) {
+			rwref_get(&entry->ch_state_lhb2);
+			/* port already exists */
+			if (entry->local_open_state != GLINK_CHANNEL_CLOSED
+								&& local) {
+				/* not ready to be re-opened */
+				GLINK_INFO_CH_XPRT(entry, xprt_ctx,
+					"%s: Ch not ready. State: %u\n",
+					__func__, entry->local_open_state);
+				rwref_put(&entry->ch_state_lhb2);
+				entry = NULL;
+			} else if (local) {
+				entry->local_open_state =
+						GLINK_CHANNEL_OPENING;
+			}
 			spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1,
 					flags);
 			kfree(ctx);
-			rwref_get(&entry->ch_state_lhb2);
 			rwref_write_put(&xprt_ctx->xprt_state_lhb0);
 			return entry;
 		}
@@ -1919,6 +1933,8 @@
 
 		ctx->transport_ptr = xprt_ctx;
 		rwref_get(&ctx->ch_state_lhb2);
+		if (local)
+			ctx->local_open_state = GLINK_CHANNEL_OPENING;
 		list_add_tail(&ctx->port_list_node, &xprt_ctx->channels);
 
 		GLINK_INFO_PERF_CH_XPRT(ctx, xprt_ctx,
@@ -2604,23 +2620,13 @@
 	 * look for an existing port structure which can occur in
 	 * reopen and remote-open-first cases
 	 */
-	ctx = ch_name_to_ch_ctx_create(transport_ptr, cfg->name);
+	ctx = ch_name_to_ch_ctx_create(transport_ptr, cfg->name, true);
 	if (ctx == NULL) {
 		GLINK_ERR("%s:%s %s: Error - unable to allocate new channel\n",
 				cfg->transport, cfg->edge, __func__);
 		return ERR_PTR(-ENOMEM);
 	}
 
-	/* port already exists */
-	if (ctx->local_open_state != GLINK_CHANNEL_CLOSED) {
-		/* not ready to be re-opened */
-		GLINK_INFO_CH_XPRT(ctx, transport_ptr,
-		"%s: Channel not ready to be re-opened. State: %u\n",
-		__func__, ctx->local_open_state);
-		rwref_put(&ctx->ch_state_lhb2);
-		return ERR_PTR(-EBUSY);
-	}
-
 	/* initialize port structure */
 	ctx->user_priv = cfg->priv;
 	ctx->rx_intent_req_timeout_jiffies =
@@ -2651,7 +2657,6 @@
 	ctx->local_xprt_req = best_id;
 	ctx->no_migrate = cfg->transport &&
 				!(cfg->options & GLINK_OPT_INITIAL_XPORT);
-	ctx->local_open_state = GLINK_CHANNEL_OPENING;
 	GLINK_INFO_PERF_CH(ctx,
 		"%s: local:GLINK_CHANNEL_CLOSED->GLINK_CHANNEL_OPENING\n",
 		__func__);
@@ -4912,7 +4917,7 @@
 	bool do_migrate;
 
 	glink_core_migration_edge_lock(if_ptr->glink_core_priv);
-	ctx = ch_name_to_ch_ctx_create(if_ptr->glink_core_priv, name);
+	ctx = ch_name_to_ch_ctx_create(if_ptr->glink_core_priv, name, false);
 	if (ctx == NULL) {
 		GLINK_ERR_XPRT(if_ptr->glink_core_priv,
 		       "%s: invalid rcid %u received, name '%s'\n",
@@ -5015,6 +5020,7 @@
 	struct channel_ctx *ctx;
 	bool is_ch_fully_closed;
 	struct glink_core_xprt_ctx *xprt_ptr = if_ptr->glink_core_priv;
+	unsigned long flags;
 
 	ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid);
 	if (!ctx) {
@@ -5032,11 +5038,13 @@
 		rwref_put(&ctx->ch_state_lhb2);
 		return;
 	}
+	spin_lock_irqsave(&ctx->transport_ptr->xprt_ctx_lock_lhb1, flags);
+	ctx->pending_delete = true;
+	spin_unlock_irqrestore(&ctx->transport_ptr->xprt_ctx_lock_lhb1, flags);
 	GLINK_INFO_CH(ctx, "%s: remote: OPENED->CLOSED\n", __func__);
 
 	is_ch_fully_closed = glink_core_remote_close_common(ctx, false);
 
-	ctx->pending_delete = true;
 	if_ptr->tx_cmd_ch_remote_close_ack(if_ptr, rcid);
 
 	if (is_ch_fully_closed) {
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 9becb10..da122fc 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -216,7 +216,6 @@
 	bool tx_blocked_signal_sent;
 	struct kthread_work kwork;
 	struct kthread_worker kworker;
-	struct work_struct wakeup_work;
 	struct task_struct *task;
 	struct tasklet_struct tasklet;
 	struct srcu_struct use_ref;
@@ -854,6 +853,39 @@
 }
 
 /**
+ * tx_wakeup_worker() - worker function to wakeup tx blocked thread
+ * @work:	kwork associated with the edge to process commands on.
+ */
+static void tx_wakeup_worker(struct edge_info *einfo)
+{
+	struct glink_transport_if xprt_if = einfo->xprt_if;
+	bool trigger_wakeup = false;
+	bool trigger_resume = false;
+	unsigned long flags;
+
+	if (einfo->in_ssr)
+		return;
+
+	spin_lock_irqsave(&einfo->write_lock, flags);
+	if (fifo_write_avail(einfo)) {
+		if (einfo->tx_blocked_signal_sent)
+			einfo->tx_blocked_signal_sent = false;
+		if (einfo->tx_resume_needed) {
+			einfo->tx_resume_needed = false;
+			trigger_resume = true;
+		}
+	}
+	if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
+		trigger_wakeup = true;
+	}
+	spin_unlock_irqrestore(&einfo->write_lock, flags);
+	if (trigger_wakeup)
+		wake_up_all(&einfo->tx_blocked_queue);
+	if (trigger_resume)
+		xprt_if.glink_core_if_ptr->tx_resume(&xprt_if);
+}
+
+/**
  * __rx_worker() - process received commands on a specific edge
  * @einfo:	Edge to process commands on.
  * @atomic_ctx:	Indicates if the caller is in atomic context and requires any
@@ -903,7 +935,7 @@
 
 	if ((atomic_ctx) && ((einfo->tx_resume_needed) ||
 		(waitqueue_active(&einfo->tx_blocked_queue)))) /* tx waiting ?*/
-		schedule_work(&einfo->wakeup_work);
+		tx_wakeup_worker(einfo);
 
 	/*
 	 * Access to the fifo needs to be synchronized, however only the calls
@@ -1211,39 +1243,6 @@
 }
 
 /**
- * tx_wakeup_worker() - worker function to wakeup tx blocked thread
- * @work:	kwork associated with the edge to process commands on.
- */
-static void tx_wakeup_worker(struct work_struct *work)
-{
-	struct edge_info *einfo;
-	bool trigger_wakeup = false;
-	unsigned long flags;
-	int rcu_id;
-
-	einfo = container_of(work, struct edge_info, wakeup_work);
-	rcu_id = srcu_read_lock(&einfo->use_ref);
-	if (einfo->in_ssr) {
-		srcu_read_unlock(&einfo->use_ref, rcu_id);
-		return;
-	}
-	if (einfo->tx_resume_needed && fifo_write_avail(einfo)) {
-		einfo->tx_resume_needed = false;
-		einfo->xprt_if.glink_core_if_ptr->tx_resume(
-						&einfo->xprt_if);
-	}
-	spin_lock_irqsave(&einfo->write_lock, flags);
-	if (waitqueue_active(&einfo->tx_blocked_queue)) { /* tx waiting ?*/
-		einfo->tx_blocked_signal_sent = false;
-		trigger_wakeup = true;
-	}
-	spin_unlock_irqrestore(&einfo->write_lock, flags);
-	if (trigger_wakeup)
-		wake_up_all(&einfo->tx_blocked_queue);
-	srcu_read_unlock(&einfo->use_ref, rcu_id);
-}
-
-/**
  * rx_worker() - worker function to process received commands
  * @work:	kwork associated with the edge to process commands on.
  */
@@ -2425,7 +2424,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->read_from_fifo = read_from_fifo;
 	einfo->write_to_fifo = write_to_fifo;
@@ -2541,7 +2539,6 @@
 reg_xprt_fail:
 smem_alloc_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
@@ -2629,7 +2626,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->intentless = true;
 	einfo->read_from_fifo = memcpy32_fromio;
@@ -2790,7 +2786,6 @@
 reg_xprt_fail:
 toc_init_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
@@ -2922,7 +2917,6 @@
 	init_waitqueue_head(&einfo->tx_blocked_queue);
 	kthread_init_work(&einfo->kwork, rx_worker);
 	kthread_init_worker(&einfo->kworker);
-	INIT_WORK(&einfo->wakeup_work, tx_wakeup_worker);
 	tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo);
 	einfo->read_from_fifo = read_from_fifo;
 	einfo->write_to_fifo = write_to_fifo;
@@ -3043,7 +3037,6 @@
 reg_xprt_fail:
 smem_alloc_fail:
 	kthread_flush_worker(&einfo->kworker);
-	flush_work(&einfo->wakeup_work);
 	kthread_stop(einfo->task);
 	einfo->task = NULL;
 	tasklet_kill(&einfo->tasklet);
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 2fb95fe..d92b495 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -195,6 +195,7 @@
 	ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
 	ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
 	ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
+	ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND,
 	ICNSS_DRIVER_EVENT_MAX,
 };
 
@@ -464,6 +465,7 @@
 	bool bypass_s1_smmu;
 	bool force_err_fatal;
 	bool allow_recursive_recovery;
+	bool early_crash_ind;
 	u8 cause_for_rejuvenation;
 	u8 requesting_sub_system;
 	u16 line_number;
@@ -608,6 +610,8 @@
 		return "UNREGISTER_DRIVER";
 	case ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN:
 		return "PD_SERVICE_DOWN";
+	case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND:
+		return "FW_EARLY_CRASH_IND";
 	case ICNSS_DRIVER_EVENT_MAX:
 		return "EVENT_MAX";
 	}
@@ -1194,7 +1198,24 @@
 	return IRQ_HANDLED;
 }
 
-static void icnss_register_force_error_fatal(struct icnss_priv *priv)
+static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
+{
+	struct icnss_priv *priv = ctx;
+
+	icnss_pr_err("Received early crash indication from FW\n");
+
+	if (priv) {
+		set_bit(ICNSS_FW_DOWN, &priv->state);
+		icnss_ignore_qmi_timeout(true);
+	}
+
+	icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND,
+				0, NULL);
+
+	return IRQ_HANDLED;
+}
+
+static void register_fw_error_notifications(struct icnss_priv *priv)
 {
 	int gpio, irq, ret;
 
@@ -1217,11 +1238,38 @@
 	ret = request_irq(irq, fw_error_fatal_handler,
 			IRQF_TRIGGER_RISING, "wlanfw-err", priv);
 	if (ret < 0) {
-		icnss_pr_err("Unable to regiser for error fatal IRQ handler %d",
+		icnss_pr_err("Unable to register for error fatal IRQ handler %d",
 				irq);
 		return;
 	}
 	icnss_pr_dbg("FW force error fatal handler registered\n");
+
+	if (!of_find_property(priv->pdev->dev.of_node,
+				"qcom,gpio-early-crash-ind", NULL)) {
+		icnss_pr_dbg("FW early crash indication handler not registered\n");
+		return;
+	}
+	gpio = of_get_named_gpio(priv->pdev->dev.of_node,
+				"qcom,gpio-early-crash-ind", 0);
+	if (!gpio_is_valid(gpio)) {
+		icnss_pr_err("Invalid GPIO for early crash indication %d\n",
+				gpio);
+		return;
+	}
+	irq = gpio_to_irq(gpio);
+	if (irq < 0) {
+		icnss_pr_err("Invalid IRQ for early crash indication %u\n",
+				irq);
+		return;
+	}
+	ret = request_irq(irq, fw_crash_indication_handler,
+			IRQF_TRIGGER_RISING, "wlanfw-early-crash-ind", priv);
+	if (ret < 0) {
+		icnss_pr_err("Unable to register for early crash indication IRQ handler %d",
+				irq);
+		return;
+	}
+	icnss_pr_dbg("FW crash indication handler registered\n");
 }
 
 static int wlfw_msa_mem_info_send_sync_msg(void)
@@ -2113,7 +2161,7 @@
 
 	icnss_init_vph_monitor(penv);
 
-	icnss_register_force_error_fatal(penv);
+	register_fw_error_notifications(penv);
 
 	return ret;
 
@@ -2213,6 +2261,7 @@
 	icnss_call_driver_shutdown(priv);
 
 	clear_bit(ICNSS_PD_RESTART, &priv->state);
+	priv->early_crash_ind = false;
 
 	if (!priv->ops || !priv->ops->reinit)
 		goto out;
@@ -2354,29 +2403,6 @@
 	return 0;
 }
 
-static int icnss_call_driver_remove(struct icnss_priv *priv)
-{
-	icnss_pr_dbg("Calling driver remove state: 0x%lx\n", priv->state);
-
-	clear_bit(ICNSS_FW_READY, &priv->state);
-
-	if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
-		return 0;
-
-	if (!priv->ops || !priv->ops->remove)
-		return 0;
-
-	set_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
-	penv->ops->remove(&priv->pdev->dev);
-
-	clear_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
-	clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
-
-	icnss_hw_power_off(penv);
-
-	return 0;
-}
-
 static int icnss_fw_crashed(struct icnss_priv *priv,
 			    struct icnss_event_pd_service_down_data *event_data)
 {
@@ -2390,7 +2416,7 @@
 	if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
 		icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
 
-	if (event_data->fw_rejuvenate)
+	if (event_data && event_data->fw_rejuvenate)
 		wlfw_rejuvenate_ack_send_sync_msg(priv);
 
 	return 0;
@@ -2405,6 +2431,12 @@
 	if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
 		goto out;
 
+	if (priv->early_crash_ind) {
+		icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n",
+			     event_data->crashed, priv->state);
+		goto out;
+	}
+
 	if (test_bit(ICNSS_PD_RESTART, &priv->state) && event_data->crashed) {
 		icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n",
 			     event_data->crashed, priv->state);
@@ -2416,10 +2448,7 @@
 	if (priv->force_err_fatal)
 		ICNSS_ASSERT(0);
 
-	if (event_data->crashed)
-		icnss_fw_crashed(priv, event_data);
-	else
-		icnss_call_driver_remove(priv);
+	icnss_fw_crashed(priv, event_data);
 
 out:
 	kfree(data);
@@ -2429,6 +2458,25 @@
 	return ret;
 }
 
+static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv,
+					      void *data)
+{
+	int ret = 0;
+
+	if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
+		goto out;
+
+	priv->early_crash_ind = true;
+	icnss_fw_crashed(priv, NULL);
+
+out:
+	kfree(data);
+	icnss_ignore_qmi_timeout(false);
+
+	return ret;
+}
+
+
 static void icnss_driver_event_work(struct work_struct *work)
 {
 	struct icnss_driver_event *event;
@@ -2470,6 +2518,10 @@
 			ret = icnss_driver_event_pd_service_down(penv,
 								 event->data);
 			break;
+		case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND:
+			ret = icnss_driver_event_early_crash_ind(penv,
+								 event->data);
+			break;
 		default:
 			icnss_pr_err("Invalid Event type: %d", event->type);
 			kfree(event);
@@ -3102,6 +3154,12 @@
 	if (!dev)
 		return -ENODEV;
 
+	if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+		icnss_pr_err("FW down, ignoring fw_log_mode state: 0x%lx\n",
+			     penv->state);
+		return -EINVAL;
+	}
+
 	icnss_pr_dbg("FW log mode: %u\n", fw_log_mode);
 
 	ret = wlfw_ini_send_sync_msg(fw_log_mode);
@@ -3195,6 +3253,12 @@
 	if (!dev)
 		return -ENODEV;
 
+	if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+		icnss_pr_err("FW down, ignoring wlan_enable state: 0x%lx\n",
+			     penv->state);
+		return -EINVAL;
+	}
+
 	icnss_pr_dbg("Mode: %d, config: %p, host_version: %s\n",
 		     mode, config, host_version);
 
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index cef3c77..c93e0e1 100644
--- a/drivers/soc/qcom/ipc_router_glink_xprt.c
+++ b/drivers/soc/qcom/ipc_router_glink_xprt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -31,6 +31,7 @@
 module_param_named(debug_mask, ipc_router_glink_xprt_debug_mask,
 		   int, 0664);
 
+#define IPCRTR_INTENT_REQ_TIMEOUT_MS 5000
 #if defined(DEBUG)
 #define D(x...) do { \
 if (ipc_router_glink_xprt_debug_mask) \
@@ -43,6 +44,7 @@
 #define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
 #define IPC_RTR_XPRT_NAME_LEN (2 * GLINK_NAME_SIZE)
 #define PIL_SUBSYSTEM_NAME_LEN 32
+#define IPC_RTR_WS_NAME_LEN ((2 * GLINK_NAME_SIZE) + 4)
 
 #define MAX_NUM_LO_INTENTS 5
 #define MAX_NUM_MD_INTENTS 3
@@ -59,6 +61,7 @@
  * @transport: Physical Transport Name as identified by Glink.
  * @pil_edge: Edge name understood by PIL.
  * @ipc_rtr_xprt_name: XPRT Name to be registered with IPC Router.
+ * @notify_rx_ws_name: Name of wakesource used in notify rx path.
  * @xprt: IPC Router XPRT structure to contain XPRT specific info.
  * @ch_hndl: Opaque Channel handle returned by GLink.
  * @xprt_wq: Workqueue to queue read & other XPRT related works.
@@ -79,9 +82,11 @@
 	char transport[GLINK_NAME_SIZE];
 	char pil_edge[PIL_SUBSYSTEM_NAME_LEN];
 	char ipc_rtr_xprt_name[IPC_RTR_XPRT_NAME_LEN];
+	char notify_rx_ws_name[IPC_RTR_WS_NAME_LEN];
 	struct msm_ipc_router_xprt xprt;
 	void *ch_hndl;
 	struct workqueue_struct *xprt_wq;
+	struct wakeup_source notify_rxv_ws;
 	struct rw_semaphore ss_reset_rwlock;
 	int ss_reset;
 	void *pil;
@@ -379,6 +384,7 @@
 	glink_rx_done(glink_xprtp->ch_hndl, rx_work->iovec, reuse_intent);
 	kfree(rx_work);
 	up_read(&glink_xprtp->ss_reset_rwlock);
+	__pm_relax(&glink_xprtp->notify_rxv_ws);
 }
 
 static void glink_xprt_open_event(struct work_struct *work)
@@ -493,6 +499,8 @@
 	rx_work->iovec_size = size;
 	rx_work->vbuf_provider = vbuf_provider;
 	rx_work->pbuf_provider = pbuf_provider;
+	if (!glink_xprtp->dynamic_wakeup_source)
+		__pm_stay_awake(&glink_xprtp->notify_rxv_ws);
 	INIT_WORK(&rx_work->work, glink_xprt_read_data);
 	queue_work(glink_xprtp->xprt_wq, &rx_work->work);
 }
@@ -602,6 +610,7 @@
 	open_cfg.notify_state = glink_xprt_notify_state;
 	open_cfg.notify_rx_intent_req = glink_xprt_notify_rx_intent_req;
 	open_cfg.priv = glink_xprtp;
+	open_cfg.rx_intent_req_timeout_ms = IPCRTR_INTENT_REQ_TIMEOUT_MS;
 
 	glink_xprtp->pil = msm_ipc_load_subsystem(glink_xprtp);
 	glink_xprtp->ch_hndl =  glink_open(&open_cfg);
@@ -760,7 +769,10 @@
 		kfree(glink_xprtp);
 		return -EFAULT;
 	}
-
+	scnprintf(glink_xprtp->notify_rx_ws_name, IPC_RTR_WS_NAME_LEN,
+			"%s_%s_rx", glink_xprtp->ch_name, glink_xprtp->edge);
+	wakeup_source_init(&glink_xprtp->notify_rxv_ws,
+				glink_xprtp->notify_rx_ws_name);
 	mutex_lock(&glink_xprt_list_lock_lha1);
 	list_add(&glink_xprtp->list, &glink_xprt_list);
 	mutex_unlock(&glink_xprt_list_lock_lha1);
diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c
index 4a41eee..a4d59f4 100644
--- a/drivers/soc/qcom/lpm-stats.c
+++ b/drivers/soc/qcom/lpm-stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -697,8 +697,10 @@
 
 	centry = &stats->child;
 	list_for_each_entry_reverse(pos, centry, sibling) {
-		if (!list_empty(&pos->child))
+		if (!list_empty(&pos->child)) {
 			cleanup_stats(pos);
+			continue;
+		}
 
 		list_del_init(&pos->child);
 
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c
index 95c127d..974f74e 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_bimc_adhoc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -243,7 +243,7 @@
 	(M_BKE_GC_GC_BMSK >> \
 	(M_BKE_GC_GC_SHFT + 1))
 
-static int bimc_div(int64_t *a, uint32_t b)
+static int bimc_div(uint64_t *a, uint32_t b)
 {
 	if ((*a > 0) && (*a < b)) {
 		*a = 0;
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 1bc9239..3b6c0bd 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -161,7 +161,7 @@
 	region_info = (struct md_ss_region __iomem *)subsys_segtable_base;
 	if (!region_info)
 		return -EINVAL;
-	pr_debug("Segments in minidump 0x%x\n", ss_mdump_seg_cnt);
+	pr_info("Minidump : Segments in minidump 0x%x\n", ss_mdump_seg_cnt);
 	ramdump_segs = kcalloc(ss_mdump_seg_cnt,
 			       sizeof(*ramdump_segs), GFP_KERNEL);
 	if (!ramdump_segs)
@@ -184,7 +184,7 @@
 			offset = offset +
 				sizeof(region_info->region_base_address);
 			s->size = __raw_readl(offset);
-			pr_debug("Minidump : Dumping segment %s with address 0x%lx and size 0x%x\n",
+			pr_info("Minidump : Dumping segment %s with address 0x%lx and size 0x%x\n",
 				s->name, s->address, (unsigned int)s->size);
 		} else
 			ss_valid_seg_cnt--;
@@ -220,15 +220,15 @@
 	int count = 0, ret;
 
 	if (desc->minidump) {
-		pr_debug("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n",
 			(unsigned int)desc->minidump->md_ss_toc_init);
-		pr_debug("Minidump : md_ss_toc->md_ss_enable_status is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->md_ss_enable_status is 0x%x\n",
 			(unsigned int)desc->minidump->md_ss_enable_status);
-		pr_debug("Minidump : md_ss_toc->encryption_status is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->encryption_status is 0x%x\n",
 			(unsigned int)desc->minidump->encryption_status);
-		pr_debug("Minidump : md_ss_toc->ss_region_count is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->ss_region_count is 0x%x\n",
 			(unsigned int)desc->minidump->ss_region_count);
-		pr_debug("Minidump : md_ss_toc->md_ss_smem_regions_baseptr is 0x%x\n",
+		pr_info("Minidump : md_ss_toc->md_ss_smem_regions_baseptr is 0x%x\n",
 			(unsigned int)
 			desc->minidump->md_ss_smem_regions_baseptr);
 		/**
@@ -241,11 +241,11 @@
 				MD_SS_ENABLED)) {
 			if (desc->minidump->encryption_status ==
 				MD_SS_ENCR_DONE) {
-				pr_debug("Dumping Minidump for %s\n",
+				pr_info("Minidump : Dumping for %s\n",
 					desc->name);
 				return pil_do_minidump(desc, minidump_dev);
 			}
-			pr_debug("Minidump aborted for %s\n", desc->name);
+			pr_info("Minidump : aborted for %s\n", desc->name);
 			return -EINVAL;
 		}
 	}
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 68ff0f3..bc47a95 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -557,7 +557,7 @@
 {
 	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
 	phys_addr_t start_addr = pil_get_entry_addr(pil);
-	u32 debug_val;
+	u32 debug_val = 0;
 	int ret;
 
 	trace_pil_func(__func__);
@@ -576,8 +576,10 @@
 	if (ret)
 		goto err_clks;
 
-	/* Save state of modem debug register before full reset */
-	debug_val = readl_relaxed(drv->reg_base + QDSP6SS_DBG_CFG);
+	if (!pil->minidump || !pil->modem_ssr) {
+		/* Save state of modem debug register before full reset */
+		debug_val = readl_relaxed(drv->reg_base + QDSP6SS_DBG_CFG);
+	}
 
 	/* Assert reset to subsystem */
 	pil_mss_assert_resets(drv);
@@ -587,9 +589,12 @@
 	if (ret)
 		goto err_restart;
 
-	writel_relaxed(debug_val, drv->reg_base + QDSP6SS_DBG_CFG);
-	if (modem_dbg_cfg)
-		writel_relaxed(modem_dbg_cfg, drv->reg_base + QDSP6SS_DBG_CFG);
+	if (!pil->minidump || !pil->modem_ssr) {
+		writel_relaxed(debug_val, drv->reg_base + QDSP6SS_DBG_CFG);
+		if (modem_dbg_cfg)
+			writel_relaxed(modem_dbg_cfg,
+				drv->reg_base + QDSP6SS_DBG_CFG);
+	}
 
 	/* Program Image Address */
 	if (drv->self_auth) {
@@ -819,8 +824,8 @@
 	 * Need to Wait for timeout for debug reset sequence to
 	 * complete before returning
 	 */
-	pr_debug("Minidump: waiting encryption to complete\n");
-	msleep(30000);
+	pr_info("Minidump: waiting encryption to complete\n");
+	msleep(10000);
 	if (pil->minidump) {
 		writel_relaxed(0x2, drv->reg_base + QDSP6SS_NMI_CFG);
 		/* Let write complete before proceeding */
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 721124c..ac322f8 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -167,6 +167,11 @@
 	if (ret)
 		return ret;
 
+	pil_mss_remove_proxy_votes(&drv->q6->desc);
+	ret = pil_mss_make_proxy_votes(&drv->q6->desc);
+	if (ret)
+		return ret;
+
 	ret = pil_mss_reset_load_mba(&drv->q6->desc);
 	if (ret)
 		return ret;
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index cab7178..fec6f17 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -185,9 +185,8 @@
 	case SCM_ENOMEM:
 		return -ENOMEM;
 	case SCM_EBUSY:
-		return SCM_EBUSY;
 	case SCM_V2_EBUSY:
-		return SCM_V2_EBUSY;
+		return -EBUSY;
 	}
 	return -EINVAL;
 }
@@ -338,13 +337,13 @@
 	do {
 		ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len,
 					resp_buf, resp_len, cmd, len);
-		if (ret == SCM_EBUSY)
+		if (ret == -EBUSY)
 			msleep(SCM_EBUSY_WAIT_MS);
 		if (retry_count == 33)
 			pr_warn("scm: secure world has been busy for 1 second!\n");
-	} while (ret == SCM_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
+	} while (ret == -EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
 
-	if (ret == SCM_EBUSY)
+	if (ret == -EBUSY)
 		pr_err("scm: secure world busy (rc = SCM_EBUSY)\n");
 
 	return ret;
@@ -799,7 +798,7 @@
 
 	ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
 				resp_len, cmd, len);
-	if (unlikely(ret == SCM_EBUSY))
+	if (unlikely(ret == -EBUSY))
 		ret = _scm_call_retry(svc_id, cmd_id, cmd_buf, cmd_len,
 				      resp_buf, resp_len, cmd, PAGE_ALIGN(len));
 	kfree(cmd);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 556882c..0e83971 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -591,6 +591,15 @@
 	[349] = {MSM_CPU_SDM632, "SDM632"},
 	[350] = {MSM_CPU_SDA632, "SDA632"},
 
+	/*MSM8937 ID  */
+	[294] = {MSM_CPU_8937, "MSM8937"},
+	[295] = {MSM_CPU_8937, "APQ8937"},
+
+	/* SDM429 and SDM439 ID*/
+	[353] = {MSM_CPU_SDM439, "SDM439"},
+	[354] = {MSM_CPU_SDM429, "SDM429"},
+
+
 	/* Uninitialized IDs are not known to run Linux.
 	 * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	 * considered as unknown CPU.
@@ -1518,6 +1527,10 @@
 		dummy_socinfo.id = 293;
 		strlcpy(dummy_socinfo.build_id, "msm8953 - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8937()) {
+		dummy_socinfo.id = 294;
+		strlcpy(dummy_socinfo.build_id, "msm8937 - ",
+			sizeof(dummy_socinfo.build_id));
 	} else if (early_machine_is_sdm450()) {
 		dummy_socinfo.id = 338;
 		strlcpy(dummy_socinfo.build_id, "sdm450 - ",
@@ -1526,6 +1539,14 @@
 		dummy_socinfo.id = 349;
 		strlcpy(dummy_socinfo.build_id, "sdm632 - ",
 			sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_sdm439()) {
+		dummy_socinfo.id = 353;
+		strlcpy(dummy_socinfo.build_id, "sdm439 - ",
+				sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_sdm429()) {
+		dummy_socinfo.id = 354;
+		strlcpy(dummy_socinfo.build_id, "sdm429 - ",
+				sizeof(dummy_socinfo.build_id));
 	}
 
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index f5e76e0..6d58d6b 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -691,7 +691,7 @@
 	wdog_dd->user_pet_complete = true;
 	wdog_dd->user_pet_enabled = false;
 	wake_up_process(wdog_dd->watchdog_task);
-	init_timer(&wdog_dd->pet_timer);
+	init_timer_deferrable(&wdog_dd->pet_timer);
 	wdog_dd->pet_timer.data = (unsigned long)wdog_dd;
 	wdog_dd->pet_timer.function = pet_task_wakeup;
 	wdog_dd->pet_timer.expires = jiffies + delay_time;
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index deb782f..a6e34f0 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -1307,12 +1307,23 @@
 {
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
+	int ret;
 
 	spi_bitbang_stop(&spi_imx->bitbang);
 
+	ret = clk_enable(spi_imx->clk_per);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(spi_imx->clk_ipg);
+	if (ret) {
+		clk_disable(spi_imx->clk_per);
+		return ret;
+	}
+
 	writel(0, spi_imx->base + MXC_CSPICTRL);
-	clk_unprepare(spi_imx->clk_ipg);
-	clk_unprepare(spi_imx->clk_per);
+	clk_disable_unprepare(spi_imx->clk_ipg);
+	clk_disable_unprepare(spi_imx->clk_per);
 	spi_imx_sdma_exit(spi_imx);
 	spi_master_put(master);
 
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 41f1a19..a1602e4 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -510,17 +510,36 @@
 		if (test_task_flag(tsk, TIF_MM_RELEASED))
 			continue;
 
-		if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
-			if (test_task_lmk_waiting(tsk)) {
-				rcu_read_unlock();
-				mutex_unlock(&scan_mutex);
-				return 0;
-			}
-		}
+		if (oom_reaper) {
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
 
-		p = find_lock_task_mm(tsk);
-		if (!p)
-			continue;
+			if (test_bit(MMF_OOM_VICTIM, &p->mm->flags)) {
+				if (test_bit(MMF_OOM_SKIP, &p->mm->flags)) {
+					task_unlock(p);
+					continue;
+				} else if (time_before_eq(jiffies,
+						lowmem_deathpending_timeout)) {
+					task_unlock(p);
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+			}
+		} else {
+			if (time_before_eq(jiffies,
+					   lowmem_deathpending_timeout))
+				if (test_task_lmk_waiting(tsk)) {
+					rcu_read_unlock();
+					mutex_unlock(&scan_mutex);
+					return 0;
+				}
+
+			p = find_lock_task_mm(tsk);
+			if (!p)
+				continue;
+		}
 
 		oom_score_adj = p->signal->oom_score_adj;
 		if (oom_score_adj < min_score_adj) {
@@ -561,13 +580,15 @@
 
 		task_lock(selected);
 		send_sig(SIGKILL, selected, 0);
-		if (selected->mm)
+		if (selected->mm) {
 			task_set_lmk_waiting(selected);
-		if (oom_reaper)
-			mark_lmk_victim(selected);
+			if (!test_bit(MMF_OOM_SKIP, &selected->mm->flags) &&
+			    oom_reaper) {
+				mark_lmk_victim(selected);
+				wake_oom_reaper(selected);
+			}
+		}
 		task_unlock(selected);
-		if (oom_reaper)
-			wake_oom_reaper(selected);
 		trace_lowmemory_kill(selected, cache_size, cache_limit, free);
 		lowmem_print(1, "Killing '%s' (%d) (tgid %d), adj %hd,\n"
 			"to free %ldkB on behalf of '%s' (%d) because\n"
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 9e88021..e8d9db4 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -824,14 +824,15 @@
 	return conn;
 
  failed_2:
-	kiblnd_destroy_conn(conn, true);
+	kiblnd_destroy_conn(conn);
+	LIBCFS_FREE(conn, sizeof(*conn));
  failed_1:
 	LIBCFS_FREE(init_qp_attr, sizeof(*init_qp_attr));
  failed_0:
 	return NULL;
 }
 
-void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn)
+void kiblnd_destroy_conn(struct kib_conn *conn)
 {
 	struct rdma_cm_id *cmid = conn->ibc_cmid;
 	struct kib_peer *peer = conn->ibc_peer;
@@ -894,8 +895,6 @@
 		rdma_destroy_id(cmid);
 		atomic_dec(&net->ibn_nconns);
 	}
-
-	LIBCFS_FREE(conn, sizeof(*conn));
 }
 
 int kiblnd_close_peer_conns_locked(struct kib_peer *peer, int why)
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
index 1457697..30cb2f5 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
@@ -1018,7 +1018,7 @@
 struct kib_conn *kiblnd_create_conn(struct kib_peer *peer,
 				    struct rdma_cm_id *cmid,
 				    int state, int version);
-void kiblnd_destroy_conn(struct kib_conn *conn, bool free_conn);
+void kiblnd_destroy_conn(struct kib_conn *conn);
 void kiblnd_close_conn(struct kib_conn *conn, int error);
 void kiblnd_close_conn_locked(struct kib_conn *conn, int error);
 
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index 995f2da..ea9a0c2 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -3323,11 +3323,13 @@
 			spin_unlock_irqrestore(lock, flags);
 			dropped_lock = 1;
 
-			kiblnd_destroy_conn(conn, !peer);
+			kiblnd_destroy_conn(conn);
 
 			spin_lock_irqsave(lock, flags);
-			if (!peer)
+			if (!peer) {
+				kfree(conn);
 				continue;
+			}
 
 			conn->ibc_peer = peer;
 			if (peer->ibp_reconnected < KIB_RECONN_HIGH_RACE)
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
index 4de9dbc..c7bf8ab 100644
--- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -1397,19 +1397,13 @@
 	if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
 	    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) {
 		len = pcur_bss->Ssid.SsidLength;
-
-		wrqu->essid.length = len;
-
 		memcpy(extra, pcur_bss->Ssid.Ssid, len);
-
-		wrqu->essid.flags = 1;
 	} else {
-		ret = -1;
-		goto exit;
+		len = 0;
+		*extra = 0;
 	}
-
-exit:
-
+	wrqu->essid.length = len;
+	wrqu->essid.flags = 1;
 
 	return ret;
 }
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 27bf54b..1259654 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -58,4 +58,4 @@
 obj-$(CONFIG_MTK_THERMAL)	+= mtk_thermal.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)	+= thermal-generic-adc.o
 obj-$(CONFIG_THERMAL_QPNP_ADC_TM)	+= qpnp-adc-tm.o
-obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o
+obj-$(CONFIG_THERMAL_TSENS)	+= msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o tsens1xxx.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 9e96f8a..2c4a63a 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -237,11 +237,17 @@
 	case PM_POST_RESTORE:
 	case PM_POST_SUSPEND:
 		mutex_lock(&cooling_list_lock);
-		mutex_lock(&core_isolate_lock);
 		list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+			mutex_lock(&core_isolate_lock);
 			if (cpufreq_dev->cpufreq_state ==
 				cpufreq_dev->max_level) {
 				cpu = cpumask_any(&cpufreq_dev->allowed_cpus);
+				/*
+				 * Unlock this lock before calling
+				 * schedule_isolate. as this could lead to
+				 * deadlock with hotplug path.
+				 */
+				mutex_unlock(&core_isolate_lock);
 				if (cpu_online(cpu) &&
 					!cpumask_test_and_set_cpu(cpu,
 					&cpus_isolated_by_thermal)) {
@@ -249,9 +255,10 @@
 						cpumask_clear_cpu(cpu,
 						&cpus_isolated_by_thermal);
 				}
+				continue;
 			}
+			mutex_unlock(&core_isolate_lock);
 		}
-		mutex_unlock(&core_isolate_lock);
 		mutex_unlock(&cooling_list_lock);
 
 		atomic_set(&in_suspend, 0);
@@ -727,6 +734,7 @@
 	mutex_lock(&core_isolate_lock);
 	prev_state = cpufreq_device->cpufreq_state;
 	cpufreq_device->cpufreq_state = state;
+	mutex_unlock(&core_isolate_lock);
 	/* If state is the last, isolate the CPU */
 	if (state == cpufreq_device->max_level) {
 		if (cpu_online(cpu) &&
@@ -736,18 +744,11 @@
 				cpumask_clear_cpu(cpu,
 					&cpus_isolated_by_thermal);
 		}
-		mutex_unlock(&core_isolate_lock);
 		return ret;
 	} else if ((prev_state == cpufreq_device->max_level)
 			&& (state < cpufreq_device->max_level)) {
 		if (cpumask_test_and_clear_cpu(cpu, &cpus_pending_online)) {
 			cpu_dev = get_cpu_device(cpu);
-			mutex_unlock(&core_isolate_lock);
-			/*
-			 * Unlock before calling the device_online.
-			 * Else, this will lead to deadlock, since the hp
-			 * online callback will be blocked on this mutex.
-			 */
 			ret = device_online(cpu_dev);
 			if (ret)
 				pr_err("CPU:%d online error:%d\n", cpu, ret);
@@ -757,7 +758,6 @@
 			sched_unisolate_cpu(cpu);
 		}
 	}
-	mutex_unlock(&core_isolate_lock);
 update_frequency:
 	clip_freq = cpufreq_device->freq_table[state];
 	cpufreq_device->clipped_freq = clip_freq;
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index fe0a7c7..c137d3d 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,11 @@
 	return tmdev->ops->hw_init(tmdev);
 }
 
+static int tsens_calib(struct tsens_device *tmdev)
+{
+	return tmdev->ops->calibrate(tmdev);
+}
+
 static int tsens_register_interrupts(struct tsens_device *tmdev)
 {
 	if (tmdev->ops->interrupts_reg)
@@ -82,6 +87,9 @@
 	{	.compatible = "qcom,tsens24xx",
 		.data = &data_tsens24xx,
 	},
+	{	.compatible = "qcom,msm8937-tsens",
+		.data = &data_tsens14xx,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, tsens_table);
@@ -97,6 +105,7 @@
 	struct device_node *of_node = pdev->dev.of_node;
 	const struct of_device_id *id;
 	const struct tsens_data *data;
+	int rc = 0;
 	struct resource *res_tsens_mem;
 
 	if (!of_match_node(tsens_table, of_node)) {
@@ -150,7 +159,27 @@
 		return PTR_ERR(tmdev->tsens_tm_addr);
 	}
 
-	return 0;
+	/* TSENS eeprom register region */
+	res_tsens_mem = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "tsens_eeprom_physical");
+	if (!res_tsens_mem) {
+		pr_debug("Could not get tsens physical address resource\n");
+	} else {
+		tmdev->tsens_calib_addr = devm_ioremap_resource(&pdev->dev,
+								res_tsens_mem);
+		if (IS_ERR(tmdev->tsens_calib_addr)) {
+			dev_err(&pdev->dev, "Failed to IO map TSENS EEPROM registers.\n");
+			rc = PTR_ERR(tmdev->tsens_calib_addr);
+		}  else {
+			rc = tsens_calib(tmdev);
+			if (rc) {
+				pr_err("Error initializing TSENS controller\n");
+				return rc;
+			}
+		}
+	}
+
+	return rc;
 }
 
 static int tsens_thermal_zone_register(struct tsens_device *tmdev)
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index 94c93b5..66f67ce 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -98,13 +98,13 @@
 	void *int_clr_reg;
 	void *min_freq_reg;
 	cpumask_t core_map;
-	struct timer_list poll_timer;
+	struct delayed_work freq_poll_work;
 	unsigned long max_freq;
 	unsigned long min_freq;
 	unsigned long hw_freq_limit;
 	struct device_attribute lmh_freq_attr;
 	struct list_head list;
-	atomic_t is_irq_enabled;
+	bool is_irq_enabled;
 	struct mutex access_lock;
 	struct __limits_cdev_data *cdev_data;
 	struct regulator *isens_reg;
@@ -184,33 +184,37 @@
 	return max_limit;
 }
 
-static void limits_dcvs_poll(unsigned long data)
+static void limits_dcvs_poll(struct work_struct *work)
 {
 	unsigned long max_limit = 0;
-	struct limits_dcvs_hw *hw = (struct limits_dcvs_hw *)data;
+	struct limits_dcvs_hw *hw = container_of(work,
+					struct limits_dcvs_hw,
+					freq_poll_work.work);
 
+	mutex_lock(&hw->access_lock);
 	if (hw->max_freq == UINT_MAX)
 		limits_dcvs_get_freq_limits(cpumask_first(&hw->core_map),
 			&hw->max_freq, &hw->min_freq);
 	max_limit = limits_mitigation_notify(hw);
 	if (max_limit >= hw->max_freq) {
-		del_timer(&hw->poll_timer);
 		writel_relaxed(0xFF, hw->int_clr_reg);
-		atomic_set(&hw->is_irq_enabled, 1);
+		hw->is_irq_enabled = true;
 		enable_irq(hw->irq_num);
 	} else {
-		mod_timer(&hw->poll_timer, jiffies + msecs_to_jiffies(
-			LIMITS_POLLING_DELAY_MS));
+		mod_delayed_work(system_highpri_wq, &hw->freq_poll_work,
+			 msecs_to_jiffies(LIMITS_POLLING_DELAY_MS));
 	}
+	mutex_unlock(&hw->access_lock);
 }
 
 static void lmh_dcvs_notify(struct limits_dcvs_hw *hw)
 {
-	if (atomic_dec_and_test(&hw->is_irq_enabled)) {
+	if (hw->is_irq_enabled) {
+		hw->is_irq_enabled = false;
 		disable_irq_nosync(hw->irq_num);
 		limits_mitigation_notify(hw);
-		mod_timer(&hw->poll_timer, jiffies + msecs_to_jiffies(
-			LIMITS_POLLING_DELAY_MS));
+		mod_delayed_work(system_highpri_wq, &hw->freq_poll_work,
+			 msecs_to_jiffies(LIMITS_POLLING_DELAY_MS));
 	}
 }
 
@@ -218,7 +222,9 @@
 {
 	struct limits_dcvs_hw *hw = data;
 
+	mutex_lock(&hw->access_lock);
 	lmh_dcvs_notify(hw);
+	mutex_unlock(&hw->access_lock);
 
 	return IRQ_HANDLED;
 }
@@ -373,8 +379,8 @@
 	ret = limits_dcvs_write(hw->affinity, LIMITS_SUB_FN_THERMAL,
 				  LIMITS_FREQ_CAP, max_freq,
 				  (max_freq == U32_MAX) ? 0 : 1, 1);
-	mutex_unlock(&hw->access_lock);
 	lmh_dcvs_notify(hw);
+	mutex_unlock(&hw->access_lock);
 
 	return ret;
 }
@@ -626,9 +632,7 @@
 	}
 
 	mutex_init(&hw->access_lock);
-	init_timer_deferrable(&hw->poll_timer);
-	hw->poll_timer.data = (unsigned long)hw;
-	hw->poll_timer.function = limits_dcvs_poll;
+	INIT_DEFERRABLE_WORK(&hw->freq_poll_work, limits_dcvs_poll);
 	hw->osm_hw_reg = devm_ioremap(&pdev->dev, request_reg, 0x4);
 	if (!hw->osm_hw_reg) {
 		pr_err("register remap failed\n");
@@ -645,7 +649,7 @@
 		pr_err("Error getting IRQ number. err:%d\n", hw->irq_num);
 		goto probe_exit;
 	}
-	atomic_set(&hw->is_irq_enabled, 1);
+	hw->is_irq_enabled = true;
 	ret = devm_request_threaded_irq(&pdev->dev, hw->irq_num, NULL,
 		lmh_dcvs_handle_isr, IRQF_TRIGGER_HIGH | IRQF_ONESHOT
 		| IRQF_NO_SUSPEND, hw->sensor_name, hw);
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index ae4741d..885b15c 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -23,10 +23,15 @@
 
 #define DEBUG_SIZE				10
 #define TSENS_MAX_SENSORS			16
+#define TSENS_1x_MAX_SENSORS			11
 #define TSENS_CONTROLLER_ID(n)			(n)
 #define TSENS_CTRL_ADDR(n)			(n)
 #define TSENS_TM_SN_STATUS(n)			((n) + 0xa0)
 
+#define ONE_PT_CALIB		0x1
+#define ONE_PT_CALIB2		0x2
+#define TWO_PT_CALIB		0x3
+
 enum tsens_dbg_type {
 	TSENS_DBG_POLL,
 	TSENS_DBG_LOG_TEMP_READS,
@@ -70,6 +75,8 @@
 	int				high_temp;
 	int				low_temp;
 	int				crit_temp;
+	int				high_adc_code;
+	int				low_adc_code;
 };
 
 struct tsens_sensor {
@@ -79,6 +86,8 @@
 	u32				id;
 	const char			*sensor_name;
 	struct tsens_context		thr_state;
+	int				offset;
+	int				slope;
 };
 
 /**
@@ -93,6 +102,7 @@
 	int (*interrupts_reg)(struct tsens_device *);
 	int (*dbg)(struct tsens_device *, u32, u32, int *);
 	int (*sensor_en)(struct tsens_device *, u32);
+	int (*calibrate)(struct tsens_device *);
 };
 
 struct tsens_irqs {
@@ -116,14 +126,15 @@
 	bool				wd_bark;
 	u32				wd_bark_mask;
 	bool				mtc;
+	bool				valid_status_check;
 };
 
 struct tsens_mtc_sysfs {
-	uint32_t	zone_log;
+	u32			zone_log;
 	int			zone_mtc;
 	int			th1;
 	int			th2;
-	uint32_t	zone_hist;
+	u32			zone_hist;
 };
 
 struct tsens_device {
@@ -134,6 +145,7 @@
 	struct regmap_field		*status_field;
 	void __iomem			*tsens_srot_addr;
 	void __iomem			*tsens_tm_addr;
+	void __iomem			*tsens_calib_addr;
 	const struct tsens_ops		*ops;
 	struct tsens_dbg_context	tsens_dbg;
 	spinlock_t			tsens_crit_lock;
@@ -144,6 +156,7 @@
 };
 
 extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+extern const struct tsens_data data_tsens14xx;
 extern struct list_head tsens_device_list;
 
 #endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
new file mode 100644
index 0000000..e2fad32
--- /dev/null
+++ b/drivers/thermal/tsens1xxx.c
@@ -0,0 +1,654 @@
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/vmalloc.h>
+#include "tsens.h"
+#include "thermal_core.h"
+
+#define TSENS_DRIVER_NAME			"msm-tsens"
+
+#define TSENS_UPPER_LOWER_INTERRUPT_CTRL(n)		(n)
+#define TSENS_INTERRUPT_EN		BIT(0)
+
+#define TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(n)	((n) + 0x04)
+#define TSENS_UPPER_STATUS_CLR		BIT(21)
+#define TSENS_LOWER_STATUS_CLR		BIT(20)
+#define TSENS_UPPER_THRESHOLD_MASK	0xffc00
+#define TSENS_LOWER_THRESHOLD_MASK	0x3ff
+#define TSENS_UPPER_THRESHOLD_SHIFT	10
+
+#define TSENS_S0_STATUS_ADDR(n)		((n) + 0x30)
+#define TSENS_SN_ADDR_OFFSET		0x4
+#define TSENS_SN_STATUS_TEMP_MASK	0x3ff
+#define TSENS_SN_STATUS_LOWER_STATUS	BIT(11)
+#define TSENS_SN_STATUS_UPPER_STATUS	BIT(12)
+#define TSENS_STATUS_ADDR_OFFSET			2
+
+#define TSENS_TRDY_MASK			BIT(0)
+
+#define TSENS_SN_STATUS_ADDR(n)	((n) + 0x44)
+#define TSENS_SN_STATUS_VALID		BIT(14)
+#define TSENS_SN_STATUS_VALID_MASK	0x4000
+#define TSENS_TRDY_ADDR(n)		((n) + 0x84)
+
+#define TSENS_CTRL_ADDR(n)		(n)
+#define TSENS_EN				BIT(0)
+#define TSENS_CTRL_SENSOR_EN_MASK(n)		((n >> 3) & 0x7ff)
+#define TSENS_TRDY_RDY_MIN_TIME		2000
+#define TSENS_TRDY_RDY_MAX_TIME		2100
+#define TSENS_THRESHOLD_MAX_CODE	0x3ff
+#define TSENS_THRESHOLD_MIN_CODE	0x0
+
+/* eeprom layout data for 8937 */
+#define BASE0_MASK	0x000000ff
+#define BASE1_MASK	0xff000000
+#define BASE1_SHIFT	24
+
+#define S0_P1_MASK		0x000001f8
+#define S1_P1_MASK		0x001f8000
+#define S2_P1_MASK_0_4		0xf8000000
+#define S2_P1_MASK_5		0x00000001
+#define S3_P1_MASK		0x00001f80
+#define S4_P1_MASK		0x01f80000
+#define S5_P1_MASK		0x00003f00
+#define S6_P1_MASK		0x03f00000
+#define S7_P1_MASK		0x0000003f
+#define S8_P1_MASK		0x0003f000
+#define S9_P1_MASK		0x0000003f
+#define S10_P1_MASK		0x0003f000
+
+#define S0_P2_MASK		0x00007e00
+#define S1_P2_MASK		0x07e00000
+#define S2_P2_MASK		0x0000007e
+#define S3_P2_MASK		0x0007e000
+#define S4_P2_MASK		0x7e000000
+#define S5_P2_MASK		0x000fc000
+#define S6_P2_MASK		0xfc000000
+#define S7_P2_MASK		0x00000fc0
+#define S8_P2_MASK		0x00fc0000
+#define S9_P2_MASK		0x00000fc0
+#define S10_P2_MASK		0x00fc0000
+
+#define S0_P1_SHIFT     3
+#define S1_P1_SHIFT     15
+#define S2_P1_SHIFT_0_4 27
+#define S2_P1_SHIFT_5   5
+#define S3_P1_SHIFT     7
+#define S4_P1_SHIFT     19
+#define S5_P1_SHIFT     8
+#define S6_P1_SHIFT     20
+#define S8_P1_SHIFT     12
+#define S10_P1_SHIFT    12
+
+#define S0_P2_SHIFT     9
+#define S1_P2_SHIFT     21
+#define S2_P2_SHIFT     1
+#define S3_P2_SHIFT     13
+#define S4_P2_SHIFT     25
+#define S5_P2_SHIFT     14
+#define S6_P2_SHIFT     26
+#define S7_P2_SHIFT     6
+#define S8_P2_SHIFT     18
+#define S9_P2_SHIFT     6
+#define S10_P2_SHIFT    18
+
+#define CAL_SEL_MASK	0x00000007
+
+#define CAL_DEGC_PT1		30
+#define CAL_DEGC_PT2		120
+#define SLOPE_FACTOR		1000
+#define SLOPE_DEFAULT		3200
+
+/*
+ * Use this function on devices where slope and offset calculations
+ * depend on calibration data read from qfprom. On others the slope
+ * and offset values are derived from tz->tzp->slope and tz->tzp->offset
+ * resp.
+ */
+static void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
+			     u32 *p2, u32 mode)
+{
+	int i;
+	int num, den;
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		pr_debug(
+			"sensor%d - data_point1:%#x data_point2:%#x\n",
+			i, p1[i], p2[i]);
+
+		tmdev->sensor[i].slope = SLOPE_DEFAULT;
+		if (mode == TWO_PT_CALIB) {
+			/*
+			 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
+			 *	temp_120_degc - temp_30_degc (x2 - x1)
+			 */
+			num = p2[i] - p1[i];
+			num *= SLOPE_FACTOR;
+			den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
+			tmdev->sensor[i].slope = num / den;
+		}
+
+		tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
+				(CAL_DEGC_PT1 *
+				tmdev->sensor[i].slope);
+		pr_debug("offset:%d\n", tmdev->sensor[i].offset);
+	}
+}
+
+static int code_to_degc(u32 adc_code, const struct tsens_sensor *sensor)
+{
+	int degc, num, den;
+
+	num = (adc_code * SLOPE_FACTOR) - sensor->offset;
+	den = sensor->slope;
+
+	if (num > 0)
+		degc = num + (den / 2);
+	else if (num < 0)
+		degc = num - (den / 2);
+	else
+		degc = num;
+
+	degc /= den;
+
+	return degc;
+}
+
+static int degc_to_code(int degc, const struct tsens_sensor *sensor)
+{
+	int code = ((degc * sensor->slope)
+		+ sensor->offset)/SLOPE_FACTOR;
+
+	if (code > TSENS_THRESHOLD_MAX_CODE)
+		code = TSENS_THRESHOLD_MAX_CODE;
+	else if (code < TSENS_THRESHOLD_MIN_CODE)
+		code = TSENS_THRESHOLD_MIN_CODE;
+	pr_debug("raw_code:0x%x, degc:%d\n",
+			code, degc);
+	return code;
+}
+
+static int calibrate_8937(struct tsens_device *tmdev)
+{
+	int base0 = 0, base1 = 0, i;
+	u32 p1[TSENS_1x_MAX_SENSORS], p2[TSENS_1x_MAX_SENSORS];
+	int mode = 0, tmp = 0;
+	u32 qfprom_cdata[5] = {0, 0, 0, 0, 0};
+
+	qfprom_cdata[0] = readl_relaxed(tmdev->tsens_calib_addr + 0x1D8);
+	qfprom_cdata[1] = readl_relaxed(tmdev->tsens_calib_addr + 0x1DC);
+	qfprom_cdata[2] = readl_relaxed(tmdev->tsens_calib_addr + 0x210);
+	qfprom_cdata[3] = readl_relaxed(tmdev->tsens_calib_addr + 0x214);
+	qfprom_cdata[4] = readl_relaxed(tmdev->tsens_calib_addr + 0x230);
+
+	mode = (qfprom_cdata[2] & CAL_SEL_MASK);
+	pr_debug("calibration mode is %d\n", mode);
+
+	switch (mode) {
+	case TWO_PT_CALIB:
+		base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
+		p2[0] = (qfprom_cdata[2] & S0_P2_MASK) >> S0_P2_SHIFT;
+		p2[1] = (qfprom_cdata[2] & S1_P2_MASK) >> S1_P2_SHIFT;
+		p2[2] = (qfprom_cdata[3] & S2_P2_MASK) >> S2_P2_SHIFT;
+		p2[3] = (qfprom_cdata[3] & S3_P2_MASK) >> S3_P2_SHIFT;
+		p2[4] = (qfprom_cdata[3] & S4_P2_MASK) >> S4_P2_SHIFT;
+		p2[5] = (qfprom_cdata[0] & S5_P2_MASK) >> S5_P2_SHIFT;
+		p2[6] = (qfprom_cdata[0] & S6_P2_MASK) >> S6_P2_SHIFT;
+		p2[7] = (qfprom_cdata[1] & S7_P2_MASK) >> S7_P2_SHIFT;
+		p2[8] = (qfprom_cdata[1] & S8_P2_MASK) >> S8_P2_SHIFT;
+		p2[9] = (qfprom_cdata[4] & S9_P2_MASK) >> S9_P2_SHIFT;
+		p2[10] = (qfprom_cdata[4] & S10_P2_MASK) >> S10_P2_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p2[i] = ((base1 + p2[i]) << 2);
+		/* Fall through */
+	case ONE_PT_CALIB2:
+		base0 = (qfprom_cdata[0] & BASE0_MASK);
+		p1[0] = (qfprom_cdata[2] & S0_P1_MASK) >> S0_P1_SHIFT;
+		p1[1] = (qfprom_cdata[2] & S1_P1_MASK) >> S1_P1_SHIFT;
+		p1[2] = (qfprom_cdata[2] & S2_P1_MASK_0_4) >> S2_P1_SHIFT_0_4;
+		tmp = (qfprom_cdata[3] & S2_P1_MASK_5) << S2_P1_SHIFT_5;
+		p1[2] |= tmp;
+		p1[3] = (qfprom_cdata[3] & S3_P1_MASK) >> S3_P1_SHIFT;
+		p1[4] = (qfprom_cdata[3] & S4_P1_MASK) >> S4_P1_SHIFT;
+		p1[5] = (qfprom_cdata[0] & S5_P1_MASK) >> S5_P1_SHIFT;
+		p1[6] = (qfprom_cdata[0] & S6_P1_MASK) >> S6_P1_SHIFT;
+		p1[7] = (qfprom_cdata[1] & S7_P1_MASK);
+		p1[8] = (qfprom_cdata[1] & S8_P1_MASK) >> S8_P1_SHIFT;
+		p1[9] = (qfprom_cdata[4] & S9_P1_MASK);
+		p1[10] = (qfprom_cdata[4] & S10_P1_MASK) >> S10_P1_SHIFT;
+
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++)
+			p1[i] = (((base0) + p1[i]) << 2);
+		break;
+	default:
+		for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+			p1[i] = 500;
+			p2[i] = 780;
+		}
+		break;
+	}
+
+	compute_intercept_slope(tmdev, p1, p2, mode);
+
+	return 0;
+}
+
+static int tsens1xxx_get_temp(struct tsens_sensor *sensor, int *temp)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int code;
+	void __iomem *sensor_addr;
+	void __iomem *trdy_addr;
+	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
+	bool last_temp_valid = false, last_temp2_valid = false;
+	bool last_temp3_valid = false;
+
+	if (!sensor)
+		return -EINVAL;
+
+	tmdev = sensor->tmdev;
+
+	trdy_addr = TSENS_TRDY_ADDR(tmdev->tsens_tm_addr);
+	sensor_addr = TSENS_SN_STATUS_ADDR(tmdev->tsens_tm_addr);
+
+	code = readl_relaxed(sensor_addr +
+			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+	last_temp = code & TSENS_SN_STATUS_TEMP_MASK;
+
+	if (tmdev->ctrl_data->valid_status_check) {
+		if (code & TSENS_SN_STATUS_VALID)
+			last_temp_valid = true;
+		else {
+			code = readl_relaxed(sensor_addr +
+				(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
+			last_temp2 = code & TSENS_SN_STATUS_TEMP_MASK;
+			if (code & TSENS_SN_STATUS_VALID) {
+				last_temp = last_temp2;
+				last_temp2_valid = true;
+			} else {
+				code = readl_relaxed(sensor_addr +
+					(sensor->hw_id <<
+					TSENS_STATUS_ADDR_OFFSET));
+				last_temp3 = code & TSENS_SN_STATUS_TEMP_MASK;
+				if (code & TSENS_SN_STATUS_VALID) {
+					last_temp = last_temp3;
+					last_temp3_valid = true;
+				}
+			}
+		}
+	}
+
+	if ((tmdev->ctrl_data->valid_status_check) &&
+		(!last_temp_valid && !last_temp2_valid && !last_temp3_valid)) {
+		if (last_temp == last_temp2)
+			last_temp = last_temp2;
+		else if (last_temp2 == last_temp3)
+			last_temp = last_temp3;
+	}
+
+	*temp = code_to_degc(last_temp, sensor);
+
+	return 0;
+}
+
+static int tsens_tz_activate_trip_type(struct tsens_sensor *tm_sensor,
+			int trip, enum thermal_device_mode mode)
+{
+	struct tsens_device *tmdev = NULL;
+	unsigned int reg_cntl, code, hi_code, lo_code, mask;
+
+	/* clear the interrupt and unmask */
+	if (!tm_sensor || trip < 0)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	lo_code = TSENS_THRESHOLD_MIN_CODE;
+	hi_code = TSENS_THRESHOLD_MAX_CODE;
+
+	reg_cntl = readl_relaxed((TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+
+	switch (trip) {
+	case THERMAL_TRIP_CONFIGURABLE_HI:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_th_state = mode;
+
+		code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		mask = TSENS_UPPER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_LOWER_STATUS_CLR))
+			lo_code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		break;
+	case THERMAL_TRIP_CONFIGURABLE_LOW:
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_th_state = mode;
+
+		code = (reg_cntl & TSENS_LOWER_THRESHOLD_MASK);
+		mask = TSENS_LOWER_STATUS_CLR;
+
+		if (!(reg_cntl & TSENS_UPPER_STATUS_CLR))
+			hi_code = (reg_cntl & TSENS_UPPER_THRESHOLD_MASK)
+					>> TSENS_UPPER_THRESHOLD_SHIFT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (mode == THERMAL_DEVICE_DISABLED)
+		writel_relaxed(reg_cntl | mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+			(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	else
+		writel_relaxed(reg_cntl & ~mask,
+		(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tmdev->tsens_tm_addr) +
+		(tm_sensor->hw_id * TSENS_SN_ADDR_OFFSET)));
+	/* Enable the thresholds */
+	mb();
+
+	return 0;
+}
+
+static int tsens1xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
+						int low_temp, int high_temp)
+{
+	unsigned int reg_cntl;
+	unsigned long flags;
+	struct tsens_device *tmdev = NULL;
+	int high_code, low_code, rc = 0;
+
+	if (!tm_sensor)
+		return -EINVAL;
+
+	tmdev = tm_sensor->tmdev;
+	if (!tmdev)
+		return -EINVAL;
+
+	spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+
+	if (high_temp != INT_MAX) {
+		high_code = degc_to_code(high_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_adc_code =
+							high_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.high_temp =
+							high_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					 TSENS_SN_ADDR_OFFSET));
+
+		high_code <<= TSENS_UPPER_THRESHOLD_SHIFT;
+		reg_cntl &= ~TSENS_UPPER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | high_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+
+	if (low_temp != INT_MIN) {
+		low_code = degc_to_code(low_temp, tm_sensor);
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_adc_code =
+							low_code;
+		tmdev->sensor[tm_sensor->hw_id].thr_state.low_temp =
+							low_temp;
+
+		reg_cntl = readl_relaxed(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET));
+
+		reg_cntl &= ~TSENS_LOWER_THRESHOLD_MASK;
+		writel_relaxed(reg_cntl | low_code,
+				(TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR
+					(tmdev->tsens_tm_addr) +
+					(tm_sensor->hw_id *
+					TSENS_SN_ADDR_OFFSET)));
+	}
+	/* Set trip temperature thresholds */
+	mb();
+
+	if (high_temp != INT_MAX) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip high enable error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_HI,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip high disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+	if (low_temp != INT_MIN) {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_ENABLED);
+		if (rc) {
+			pr_err("trip low enable activation error :%d\n", rc);
+			goto fail;
+		}
+	} else {
+		rc = tsens_tz_activate_trip_type(tm_sensor,
+				THERMAL_TRIP_CONFIGURABLE_LOW,
+				THERMAL_DEVICE_DISABLED);
+		if (rc) {
+			pr_err("trip low disable error :%d\n", rc);
+			goto fail;
+		}
+	}
+
+fail:
+	spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+	return rc;
+}
+
+static irqreturn_t tsens_irq_thread(int irq, void *data)
+{
+	struct tsens_device *tm = data;
+	unsigned int i, status, threshold, temp, th_temp;
+	unsigned long flags;
+	void __iomem *sensor_status_addr;
+	void __iomem *sensor_status_ctrl_addr;
+	u32 rc = 0, addr_offset;
+
+	sensor_status_addr = TSENS_SN_STATUS_ADDR(tm->tsens_tm_addr);
+	sensor_status_ctrl_addr =
+		TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(tm->tsens_tm_addr);
+
+	for (i = 0; i < TSENS_1x_MAX_SENSORS; i++) {
+		bool upper_thr = false, lower_thr = false;
+
+		if (IS_ERR(tm->sensor[i].tzd))
+			continue;
+
+		rc = tsens1xxx_get_temp(&tm->sensor[i], &temp);
+		if (rc) {
+			pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
+			continue;
+		}
+
+		spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
+
+		addr_offset = tm->sensor[i].hw_id *
+						TSENS_SN_ADDR_OFFSET;
+		status = readl_relaxed(sensor_status_addr + addr_offset);
+		threshold = readl_relaxed(sensor_status_ctrl_addr +
+								addr_offset);
+
+		if (status & TSENS_SN_STATUS_UPPER_STATUS) {
+			writel_relaxed(threshold | TSENS_UPPER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_UPPER_THRESHOLD_MASK) >>
+					TSENS_UPPER_THRESHOLD_SHIFT,
+					tm->sensor);
+			if (th_temp > temp) {
+				pr_debug("Re-arm high threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_HI,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("high rearm failed");
+			} else {
+				upper_thr = true;
+				tm->sensor[i].thr_state.high_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+
+		if (status & TSENS_SN_STATUS_LOWER_STATUS) {
+			writel_relaxed(threshold | TSENS_LOWER_STATUS_CLR,
+				TSENS_S0_UPPER_LOWER_STATUS_CTRL_ADDR(
+					tm->tsens_tm_addr + addr_offset));
+			th_temp = code_to_degc((threshold &
+					TSENS_LOWER_THRESHOLD_MASK),
+					tm->sensor);
+			if (th_temp < temp) {
+				pr_debug("Re-arm Low threshold\n");
+				rc = tsens_tz_activate_trip_type(
+						&tm->sensor[i],
+						THERMAL_TRIP_CONFIGURABLE_LOW,
+						THERMAL_DEVICE_ENABLED);
+				if (rc)
+					pr_err("low rearm failed");
+			} else {
+				lower_thr = true;
+				tm->sensor[i].thr_state.low_th_state =
+					THERMAL_DEVICE_DISABLED;
+			}
+		}
+		spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
+
+		if (upper_thr || lower_thr) {
+			pr_debug("sensor:%d trigger temp (%d degC)\n",
+				tm->sensor[i].hw_id,
+				code_to_degc((status &
+				TSENS_SN_STATUS_TEMP_MASK),
+				tm->sensor));
+			of_thermal_handle_trip(tm->sensor[i].tzd);
+		}
+	}
+
+	/* Disable monitoring sensor trip threshold for triggered sensor */
+	mb();
+
+	return IRQ_HANDLED;
+}
+
+static int tsens1xxx_hw_sensor_en(struct tsens_device *tmdev,
+					u32 sensor_id)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val, sensor_en;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	srot_val = TSENS_CTRL_SENSOR_EN_MASK(srot_val);
+
+	sensor_en = ((1 << sensor_id) & srot_val);
+
+	return sensor_en;
+}
+
+static int tsens1xxx_hw_init(struct tsens_device *tmdev)
+{
+	void __iomem *srot_addr;
+	unsigned int srot_val;
+
+	srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
+	srot_val = readl_relaxed(srot_addr);
+	if (!(srot_val & TSENS_EN)) {
+		pr_err("TSENS device is not enabled\n");
+		return -ENODEV;
+	}
+
+	writel_relaxed(TSENS_INTERRUPT_EN,
+			TSENS_UPPER_LOWER_INTERRUPT_CTRL(tmdev->tsens_tm_addr));
+
+	spin_lock_init(&tmdev->tsens_upp_low_lock);
+
+	return 0;
+}
+
+static const struct tsens_irqs tsens1xxx_irqs[] = {
+	{ "tsens-upper-lower", tsens_irq_thread},
+};
+
+static int tsens1xxx_register_interrupts(struct tsens_device *tmdev)
+{
+	struct platform_device *pdev;
+	int i, rc;
+
+	if (!tmdev)
+		return -EINVAL;
+
+	pdev = tmdev->pdev;
+
+	for (i = 0; i < ARRAY_SIZE(tsens1xxx_irqs); i++) {
+		int irq;
+
+		irq = platform_get_irq_byname(pdev, tsens1xxx_irqs[i].name);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return irq;
+		}
+
+		rc = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				tsens1xxx_irqs[i].handler,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				tsens1xxx_irqs[i].name, tmdev);
+		if (rc) {
+			dev_err(&pdev->dev, "failed to get irq %s\n",
+					tsens1xxx_irqs[i].name);
+			return rc;
+		}
+		enable_irq_wake(irq);
+	}
+
+	return 0;
+}
+
+static const struct tsens_ops ops_tsens1xxx = {
+	.hw_init		= tsens1xxx_hw_init,
+	.get_temp		= tsens1xxx_get_temp,
+	.set_trips		= tsens1xxx_set_trip_temp,
+	.interrupts_reg		= tsens1xxx_register_interrupts,
+	.sensor_en		= tsens1xxx_hw_sensor_en,
+	.calibrate		= calibrate_8937,
+};
+
+const struct tsens_data data_tsens14xx = {
+	.ops			= &ops_tsens1xxx,
+	.valid_status_check	= true,
+	.mtc			= true,
+};
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index 50c847f..af60a4b 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -59,9 +59,11 @@
 #define TSENS_TM_SCALE_DECI_MILLIDEG		100
 #define TSENS_DEBUG_WDOG_TRIGGER_COUNT		5
 #define TSENS_TM_WATCHDOG_LOG(n)		((n) + 0x13c)
-
 #define TSENS_EN				BIT(0)
 #define TSENS_CTRL_SENSOR_EN_MASK(n)		((n >> 3) & 0xffff)
+#define TSENS_TM_TRDY(n)			((n) + 0xe4)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE	BIT(3)
+#define TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT	3
 
 static void msm_tsens_convert_temp(int last_temp, int *temp)
 {
@@ -79,7 +81,7 @@
 {
 	struct tsens_device *tmdev = NULL;
 	unsigned int code;
-	void __iomem *sensor_addr;
+	void __iomem *sensor_addr, *trdy;
 	int last_temp = 0, last_temp2 = 0, last_temp3 = 0;
 
 	if (!sensor)
@@ -87,6 +89,14 @@
 
 	tmdev = sensor->tmdev;
 	sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr);
+	trdy = TSENS_TM_TRDY(tmdev->tsens_tm_addr);
+
+	code = readl_relaxed_no_log(trdy);
+	if (!((code & TSENS_TM_TRDY_FIRST_ROUND_COMPLETE) >>
+			TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT)) {
+		pr_err("TSENS device first round not complete0x%x\n", code);
+		return -ENODATA;
+	}
 
 	code = readl_relaxed_no_log(sensor_addr +
 			(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index a70356d..521a6e4 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2239,12 +2239,14 @@
 		val &= ~UCR3_AWAKEN;
 	writel(val, sport->port.membase + UCR3);
 
-	val = readl(sport->port.membase + UCR1);
-	if (on)
-		val |= UCR1_RTSDEN;
-	else
-		val &= ~UCR1_RTSDEN;
-	writel(val, sport->port.membase + UCR1);
+	if (sport->have_rtscts) {
+		val = readl(sport->port.membase + UCR1);
+		if (on)
+			val |= UCR1_RTSDEN;
+		else
+			val &= ~UCR1_RTSDEN;
+		writel(val, sport->port.membase + UCR1);
+	}
 }
 
 static int imx_serial_port_suspend_noirq(struct device *dev)
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 185a9e2..563305f 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -111,6 +111,7 @@
 #define DEF_TX_WM		(2)
 #define DEF_FIFO_WIDTH_BITS	(32)
 #define UART_CORE2X_VOTE	(10000)
+#define UART_CONSOLE_CORE2X_VOTE (960)
 
 #define WAKEBYTE_TIMEOUT_MSEC	(2000)
 #define WAIT_XFER_MAX_ITER	(50)
@@ -2367,8 +2368,16 @@
 	}
 	dev_port->wrapper_dev = &wrapper_pdev->dev;
 	dev_port->serial_rsc.wrapper_dev = &wrapper_pdev->dev;
-	ret = geni_se_resources_init(&dev_port->serial_rsc, UART_CORE2X_VOTE,
-					(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
+
+	if (is_console)
+		ret = geni_se_resources_init(&dev_port->serial_rsc,
+			UART_CONSOLE_CORE2X_VOTE,
+			(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
+	else
+		ret = geni_se_resources_init(&dev_port->serial_rsc,
+			UART_CORE2X_VOTE,
+			(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
+
 	if (ret)
 		goto exit_geni_serial_probe;
 
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ea20b2c..34d23cc 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -375,7 +375,7 @@
 
 	res = usb_submit_urb(acm->read_urbs[index], mem_flags);
 	if (res) {
-		if (res != -EPERM) {
+		if (res != -EPERM && res != -ENODEV) {
 			dev_err(&acm->data->dev,
 					"urb %d failed submission with %d\n",
 					index, res);
@@ -1706,6 +1706,9 @@
 	{ USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
 	.driver_info = SINGLE_RX_URB, /* firmware bug */
 	},
+	{ USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */
+	.driver_info = SINGLE_RX_URB,
+	},
 	{ USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 5c4a24d..89bf6b7 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1061,6 +1061,8 @@
 	struct dwc3_trb *trb;
 	int num_trbs = (dep->direction) ? (2 * (req->num_bufs) + 2)
 					: (req->num_bufs + 2);
+	struct scatterlist *sg;
+	struct sg_table *sgt;
 
 	dep->trb_pool = dma_zalloc_coherent(dwc->sysdev,
 				num_trbs * sizeof(struct dwc3_trb),
@@ -1073,6 +1075,19 @@
 	}
 
 	dep->num_trbs = num_trbs;
+	dma_get_sgtable(dwc->sysdev, &req->sgt_trb_xfer_ring, dep->trb_pool,
+		dep->trb_pool_dma, num_trbs * sizeof(struct dwc3_trb));
+
+	sgt = &req->sgt_trb_xfer_ring;
+	dev_dbg(dwc->dev, "%s(): trb_pool:%pK trb_pool_dma:%lx\n",
+		__func__, dep->trb_pool, (unsigned long)dep->trb_pool_dma);
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i)
+		dev_dbg(dwc->dev,
+			"%i: page_link:%lx offset:%x length:%x address:%lx\n",
+			i, sg->page_link, sg->offset, sg->length,
+			(unsigned long)sg->dma_address);
+
 	/* IN direction */
 	if (dep->direction) {
 		for (i = 0; i < num_trbs ; i++) {
@@ -1138,11 +1153,13 @@
 		}
 	}
 
-	pr_debug("%s: Initialized TRB Ring for %s\n", __func__, dep->name);
+	dev_dbg(dwc->dev, "%s: Initialized TRB Ring for %s\n",
+					__func__, dep->name);
 	trb = &dep->trb_pool[0];
 	if (trb) {
 		for (i = 0; i < num_trbs; i++) {
-			pr_debug("TRB(%d): ADDRESS:%lx bpl:%x bph:%x size:%x ctrl:%x\n",
+			dev_dbg(dwc->dev,
+				"TRB %d: ADDR:%lx bpl:%x bph:%x sz:%x ctl:%x\n",
 				i, (unsigned long)dwc3_trb_dma_offset(dep,
 				&dep->trb_pool[i]), trb->bpl, trb->bph,
 				trb->size, trb->ctrl);
@@ -1159,7 +1176,7 @@
 * @usb_ep - pointer to usb_ep instance.
 *
 */
-static void gsi_free_trbs(struct usb_ep *ep)
+static void gsi_free_trbs(struct usb_ep *ep, struct usb_gsi_request *req)
 {
 	struct dwc3_ep *dep = to_dwc3_ep(ep);
 	struct dwc3 *dwc = dep->dwc;
@@ -1176,6 +1193,7 @@
 		dep->trb_pool = NULL;
 		dep->trb_pool_dma = 0;
 	}
+	sg_free_table(&req->sgt_trb_xfer_ring);
 }
 /*
 * Configures GSI EPs. For GSI EPs we need to set interrupter numbers.
@@ -1365,7 +1383,8 @@
 		break;
 	case GSI_EP_OP_FREE_TRBS:
 		dev_dbg(mdwc->dev, "EP_OP_FREE_TRBS for %s\n", ep->name);
-		gsi_free_trbs(ep);
+		request = (struct usb_gsi_request *)op_data;
+		gsi_free_trbs(ep, request);
 		break;
 	case GSI_EP_OP_CONFIG:
 		request = (struct usb_gsi_request *)op_data;
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 4911253..1f75b58 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -76,7 +76,7 @@
 	writel_relaxed(write_val, base + offset - DWC3_GLOBALS_REGS_START);
 
 	/* Read back to see if value was written */
-	tmp = readl_relaxed(base + offset);
+	tmp = readl_relaxed(base + offset - DWC3_GLOBALS_REGS_START);
 
 	dwc3_trace(trace_dwc3_masked_write_readback,
 			"addr %p readback val %08x",
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 598a67d..2bde573 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -10,3 +10,5 @@
 libcomposite-y			+= composite.o functions.o configfs.o u_f.o
 
 obj-$(CONFIG_USB_GADGET)	+= udc/ function/ legacy/
+
+obj-$(CONFIG_USB_CI13XXX_MSM)	+= ci13xxx_msm.o
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
new file mode 100644
index 0000000..d4c243c
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -0,0 +1,556 @@
+/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/ulpi.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "ci13xxx_udc.c"
+
+#define MSM_USB_BASE	(udc->regs)
+
+#define CI13XXX_MSM_MAX_LOG2_ITC	7
+
+struct ci13xxx_udc_context {
+	int irq;
+	void __iomem *regs;
+	int wake_gpio;
+	int wake_irq;
+	bool wake_irq_state;
+	struct pinctrl *ci13xxx_pinctrl;
+	struct timer_list irq_enable_timer;
+	bool irq_disabled;
+};
+
+static struct ci13xxx_udc_context _udc_ctxt;
+#define IRQ_ENABLE_DELAY	(jiffies + msecs_to_jiffies(1000))
+
+static irqreturn_t msm_udc_irq(int irq, void *data)
+{
+	return udc_irq();
+}
+
+static void ci13xxx_msm_suspend(void)
+{
+	struct device *dev = _udc->gadget.dev.parent;
+
+	dev_dbg(dev, "ci13xxx_msm_suspend\n");
+
+	if (_udc_ctxt.wake_irq && !_udc_ctxt.wake_irq_state) {
+		enable_irq_wake(_udc_ctxt.wake_irq);
+		enable_irq(_udc_ctxt.wake_irq);
+		_udc_ctxt.wake_irq_state = true;
+	}
+}
+
+static void ci13xxx_msm_resume(void)
+{
+	struct device *dev = _udc->gadget.dev.parent;
+
+	dev_dbg(dev, "ci13xxx_msm_resume\n");
+
+	if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
+		disable_irq_wake(_udc_ctxt.wake_irq);
+		disable_irq_nosync(_udc_ctxt.wake_irq);
+		_udc_ctxt.wake_irq_state = false;
+	}
+}
+
+static void ci13xxx_msm_disconnect(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct usb_phy *phy = udc->transceiver;
+
+	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+		u32 temp;
+
+		usb_phy_io_write(phy,
+				ULPI_MISC_A_VBUSVLDEXT |
+				ULPI_MISC_A_VBUSVLDEXTSEL,
+				ULPI_CLR(ULPI_MISC_A));
+
+		/* Notify LINK of VBUS LOW */
+		temp = readl_relaxed(USB_USBCMD);
+		temp &= ~USBCMD_SESS_VLD_CTRL;
+		writel_relaxed(temp, USB_USBCMD);
+
+		/*
+		 * Add memory barrier as it is must to complete
+		 * above USB PHY and Link register writes before
+		 * moving ahead with USB peripheral mode enumeration,
+		 * otherwise USB peripheral mode may not work.
+		 */
+		mb();
+	}
+}
+
+/* Link power management will reduce power consumption by
+ * short time HW suspend/resume.
+ */
+static void ci13xxx_msm_set_l1(struct ci13xxx *udc)
+{
+	int temp;
+	struct device *dev = udc->gadget.dev.parent;
+
+	dev_dbg(dev, "Enable link power management\n");
+
+	/* Enable remote wakeup and L1 for IN EPs */
+	writel_relaxed(0xffff0000, USB_L1_EP_CTRL);
+
+	temp = readl_relaxed(USB_L1_CONFIG);
+	temp |= L1_CONFIG_LPM_EN | L1_CONFIG_REMOTE_WAKEUP |
+		L1_CONFIG_GATE_SYS_CLK | L1_CONFIG_PHY_LPM |
+		L1_CONFIG_PLL;
+	writel_relaxed(temp, USB_L1_CONFIG);
+}
+
+static void ci13xxx_msm_connect(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct usb_phy *phy = udc->transceiver;
+
+	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+		int	temp;
+
+		usb_phy_io_write(phy,
+			ULPI_MISC_A_VBUSVLDEXT |
+			ULPI_MISC_A_VBUSVLDEXTSEL,
+			ULPI_SET(ULPI_MISC_A));
+
+		temp = readl_relaxed(USB_GENCONFIG_2);
+		temp |= GENCONFIG_2_SESS_VLD_CTRL_EN;
+		writel_relaxed(temp, USB_GENCONFIG_2);
+
+		temp = readl_relaxed(USB_USBCMD);
+		temp |= USBCMD_SESS_VLD_CTRL;
+		writel_relaxed(temp, USB_USBCMD);
+
+		/*
+		 * Add memory barrier as it is must to complete
+		 * above USB PHY and Link register writes before
+		 * moving ahead with USB peripheral mode enumeration,
+		 * otherwise USB peripheral mode may not work.
+		 */
+		mb();
+	}
+}
+
+static void ci13xxx_msm_reset(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct usb_phy *phy = udc->transceiver;
+	struct device *dev = udc->gadget.dev.parent;
+	int	temp;
+
+	writel_relaxed(0, USB_AHBBURST);
+	writel_relaxed(0x08, USB_AHBMODE);
+
+	/* workaround for rx buffer collision issue */
+	temp = readl_relaxed(USB_GENCONFIG);
+	temp &= ~GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE;
+	temp &= ~GENCONFIG_ULPI_SERIAL_EN;
+	writel_relaxed(temp, USB_GENCONFIG);
+
+	if (udc->gadget.l1_supported)
+		ci13xxx_msm_set_l1(udc);
+
+	if (phy && (phy->flags & ENABLE_SECONDARY_PHY)) {
+		int	temp;
+
+		dev_dbg(dev, "using secondary hsphy\n");
+		temp = readl_relaxed(USB_PHY_CTRL2);
+		temp |= (1<<16);
+		writel_relaxed(temp, USB_PHY_CTRL2);
+
+		/*
+		 * Add memory barrier to make sure above LINK writes are
+		 * complete before moving ahead with USB peripheral mode
+		 * enumeration.
+		 */
+		mb();
+	}
+}
+
+static void ci13xxx_msm_mark_err_event(void)
+{
+	struct ci13xxx *udc = _udc;
+	struct msm_otg *otg;
+
+	if (udc == NULL)
+		return;
+
+	if (udc->transceiver == NULL)
+		return;
+
+	otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+	/* This will trigger hardware reset before next connection */
+	otg->err_event_seen = true;
+}
+
+static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned int event)
+{
+	struct device *dev = udc->gadget.dev.parent;
+
+	switch (event) {
+	case CI13XXX_CONTROLLER_RESET_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+		ci13xxx_msm_reset();
+		break;
+	case CI13XXX_CONTROLLER_DISCONNECT_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_DISCONNECT_EVENT received\n");
+		ci13xxx_msm_disconnect();
+		ci13xxx_msm_resume();
+		break;
+	case CI13XXX_CONTROLLER_CONNECT_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_CONNECT_EVENT received\n");
+		ci13xxx_msm_connect();
+		break;
+	case CI13XXX_CONTROLLER_SUSPEND_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_SUSPEND_EVENT received\n");
+		ci13xxx_msm_suspend();
+		break;
+	case CI13XXX_CONTROLLER_RESUME_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
+		ci13xxx_msm_resume();
+		break;
+	case CI13XXX_CONTROLLER_ERROR_EVENT:
+		dev_info(dev, "CI13XXX_CONTROLLER_ERROR_EVENT received\n");
+		ci13xxx_msm_mark_err_event();
+		break;
+	case CI13XXX_CONTROLLER_UDC_STARTED_EVENT:
+		dev_info(dev,
+			 "CI13XXX_CONTROLLER_UDC_STARTED_EVENT received\n");
+		break;
+	default:
+		dev_dbg(dev, "unknown ci13xxx_udc event\n");
+		break;
+	}
+}
+
+static bool ci13xxx_msm_in_lpm(struct ci13xxx *udc)
+{
+	struct msm_otg *otg;
+
+	if (udc == NULL)
+		return false;
+
+	if (udc->transceiver == NULL)
+		return false;
+
+	otg = container_of(udc->transceiver, struct msm_otg, phy);
+
+	return (atomic_read(&otg->in_lpm) != 0);
+}
+
+
+static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
+{
+	struct ci13xxx *udc = _udc;
+
+	if (udc->transceiver && udc->vbus_active && udc->suspended)
+		usb_phy_set_suspend(udc->transceiver, 0);
+	else if (!udc->suspended)
+		ci13xxx_msm_resume();
+
+	return IRQ_HANDLED;
+}
+
+static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
+	.name			= "ci13xxx_msm",
+	.flags			= CI13XXX_REGS_SHARED |
+				  CI13XXX_REQUIRE_TRANSCEIVER |
+				  CI13XXX_PULLUP_ON_VBUS |
+				  CI13XXX_ZERO_ITC |
+				  CI13XXX_DISABLE_STREAMING,
+	.nz_itc			= 0,
+	.notify_event		= ci13xxx_msm_notify_event,
+	.in_lpm                 = ci13xxx_msm_in_lpm,
+};
+
+static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
+				struct resource *res)
+{
+	int wake_irq;
+	int ret;
+	struct pinctrl_state *set_state;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");
+
+	_udc_ctxt.wake_gpio = res->start;
+	if (_udc_ctxt.ci13xxx_pinctrl) {
+		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+				"ci13xxx_active");
+		if (IS_ERR(set_state)) {
+			pr_err("cannot get ci13xxx pinctrl active state\n");
+			return PTR_ERR(set_state);
+		}
+		pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl, set_state);
+	}
+	gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
+	gpio_direction_input(_udc_ctxt.wake_gpio);
+	wake_irq = gpio_to_irq(_udc_ctxt.wake_gpio);
+	if (wake_irq < 0) {
+		dev_err(&pdev->dev, "could not register USB_RESUME GPIO.\n");
+		return -ENXIO;
+	}
+
+	dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n",
+			_udc_ctxt.wake_gpio, wake_irq);
+	ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
+		IRQF_TRIGGER_RISING | IRQF_ONESHOT, "usb resume", NULL);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n");
+		goto gpio_free;
+	}
+	disable_irq(wake_irq);
+	_udc_ctxt.wake_irq = wake_irq;
+
+	return 0;
+
+gpio_free:
+	gpio_free(_udc_ctxt.wake_gpio);
+	if (_udc_ctxt.ci13xxx_pinctrl) {
+		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+				"ci13xxx_sleep");
+		if (IS_ERR(set_state))
+			pr_err("cannot get ci13xxx pinctrl sleep state\n");
+		else
+			pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+					set_state);
+	}
+	_udc_ctxt.wake_gpio = 0;
+	return ret;
+}
+
+static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
+{
+	struct pinctrl_state *set_state;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");
+
+	if (_udc_ctxt.wake_gpio) {
+		gpio_free(_udc_ctxt.wake_gpio);
+		if (_udc_ctxt.ci13xxx_pinctrl) {
+			set_state =
+				pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
+						"ci13xxx_sleep");
+			if (IS_ERR(set_state))
+				pr_err("cannot get ci13xxx pinctrl sleep state\n");
+			else
+				pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
+						set_state);
+		}
+		_udc_ctxt.wake_gpio = 0;
+	}
+}
+
+static void enable_usb_irq_timer_func(unsigned long data);
+static int ci13xxx_msm_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret;
+	struct ci13xxx_platform_data *pdata = pdev->dev.platform_data;
+	bool is_l1_supported = false;
+
+	dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
+
+	if (pdata) {
+		/* Acceptable values for nz_itc are: 0,1,2,4,8,16,32,64 */
+		if (pdata->log2_itc > CI13XXX_MSM_MAX_LOG2_ITC ||
+			pdata->log2_itc <= 0)
+			ci13xxx_msm_udc_driver.nz_itc = 0;
+		else
+			ci13xxx_msm_udc_driver.nz_itc =
+				1 << (pdata->log2_itc-1);
+
+		is_l1_supported = pdata->l1_supported;
+		/* Set ahb2ahb bypass flag if it is requested. */
+		if (pdata->enable_ahb2ahb_bypass)
+			ci13xxx_msm_udc_driver.flags |=
+				CI13XXX_ENABLE_AHB2AHB_BYPASS;
+
+		/* Clear disable streaming flag if is requested. */
+		if (pdata->enable_streaming)
+			ci13xxx_msm_udc_driver.flags &=
+						~CI13XXX_DISABLE_STREAMING;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get platform resource mem\n");
+		return -ENXIO;
+	}
+
+	_udc_ctxt.regs = ioremap(res->start, resource_size(res));
+	if (!_udc_ctxt.regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		return -ENOMEM;
+	}
+
+	ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, _udc_ctxt.regs);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "udc_probe failed\n");
+		goto iounmap;
+	}
+
+	_udc->gadget.l1_supported = is_l1_supported;
+
+	_udc_ctxt.irq = platform_get_irq(pdev, 0);
+	if (_udc_ctxt.irq < 0) {
+		dev_err(&pdev->dev, "IRQ not found\n");
+		ret = -ENXIO;
+		goto udc_remove;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
+	/* Get pinctrl if target uses pinctrl */
+	_udc_ctxt.ci13xxx_pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(_udc_ctxt.ci13xxx_pinctrl)) {
+		if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) {
+			dev_err(&pdev->dev, "Error encountered while getting pinctrl");
+			ret = PTR_ERR(_udc_ctxt.ci13xxx_pinctrl);
+			goto udc_remove;
+		}
+		dev_dbg(&pdev->dev, "Target does not use pinctrl\n");
+		_udc_ctxt.ci13xxx_pinctrl = NULL;
+	}
+	if (res) {
+		ret = ci13xxx_msm_install_wake_gpio(pdev, res);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "gpio irq install failed\n");
+			goto udc_remove;
+		}
+	}
+
+	ret = request_irq(_udc_ctxt.irq, msm_udc_irq, IRQF_SHARED, pdev->name,
+					  pdev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "request_irq failed\n");
+		goto gpio_uninstall;
+	}
+
+	setup_timer(&_udc_ctxt.irq_enable_timer, enable_usb_irq_timer_func,
+							(unsigned long)NULL);
+
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+
+gpio_uninstall:
+	ci13xxx_msm_uninstall_wake_gpio(pdev);
+udc_remove:
+	udc_remove();
+iounmap:
+	iounmap(_udc_ctxt.regs);
+
+	return ret;
+}
+
+int ci13xxx_msm_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+	free_irq(_udc_ctxt.irq, pdev);
+	ci13xxx_msm_uninstall_wake_gpio(pdev);
+	udc_remove();
+	iounmap(_udc_ctxt.regs);
+	return 0;
+}
+
+void ci13xxx_msm_shutdown(struct platform_device *pdev)
+{
+	ci13xxx_pullup(&_udc->gadget, 0);
+}
+
+void msm_hw_soft_reset(void)
+{
+	struct ci13xxx *udc = _udc;
+
+	hw_device_reset(udc);
+}
+
+void msm_hw_bam_disable(bool bam_disable)
+{
+	u32 val;
+	struct ci13xxx *udc = _udc;
+
+	if (bam_disable)
+		val = readl_relaxed(USB_GENCONFIG) | GENCONFIG_BAM_DISABLE;
+	else
+		val = readl_relaxed(USB_GENCONFIG) & ~GENCONFIG_BAM_DISABLE;
+
+	writel_relaxed(val, USB_GENCONFIG);
+}
+
+void msm_usb_irq_disable(bool disable)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	if (_udc_ctxt.irq_disabled == disable) {
+		pr_debug("Interrupt state already disable = %d\n", disable);
+		if (disable)
+			mod_timer(&_udc_ctxt.irq_enable_timer,
+					IRQ_ENABLE_DELAY);
+		spin_unlock_irqrestore(udc->lock, flags);
+		return;
+	}
+
+	if (disable) {
+		disable_irq_nosync(_udc_ctxt.irq);
+		/* start timer here */
+		pr_debug("%s: Disabling interrupts\n", __func__);
+		mod_timer(&_udc_ctxt.irq_enable_timer, IRQ_ENABLE_DELAY);
+		_udc_ctxt.irq_disabled = true;
+
+	} else {
+		pr_debug("%s: Enabling interrupts\n", __func__);
+		del_timer(&_udc_ctxt.irq_enable_timer);
+		enable_irq(_udc_ctxt.irq);
+		_udc_ctxt.irq_disabled = false;
+	}
+
+	spin_unlock_irqrestore(udc->lock, flags);
+}
+
+static void enable_usb_irq_timer_func(unsigned long data)
+{
+	pr_debug("enabling interrupt from timer\n");
+	msm_usb_irq_disable(false);
+}
+
+static struct platform_driver ci13xxx_msm_driver = {
+	.probe = ci13xxx_msm_probe,
+	.driver = {
+		.name = "msm_hsusb",
+	},
+	.remove = ci13xxx_msm_remove,
+	.shutdown = ci13xxx_msm_shutdown,
+};
+MODULE_ALIAS("platform:msm_hsusb");
+
+static int __init ci13xxx_msm_init(void)
+{
+	return platform_driver_register(&ci13xxx_msm_driver);
+}
+module_init(ci13xxx_msm_init);
+
+static void __exit ci13xxx_msm_exit(void)
+{
+	platform_driver_unregister(&ci13xxx_msm_driver);
+}
+module_exit(ci13xxx_msm_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
new file mode 100644
index 0000000..28aaa1f
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -0,0 +1,3983 @@
+/*
+ * ci13xxx_udc.c - MIPS USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Description: MIPS USB IP core family device controller
+ *              Currently it only supports IP part number CI13412
+ *
+ * This driver is composed of several blocks:
+ * - HW:     hardware interface
+ * - DBG:    debug facilities (optional)
+ * - UTIL:   utilities
+ * - ISR:    interrupts handling
+ * - ENDPT:  endpoint operations (Gadget API)
+ * - GADGET: gadget operations (Gadget API)
+ * - BUS:    bus glue code, bus abstraction layer
+ *
+ * Compile Options
+ * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
+ * - STALL_IN:  non-empty bulk-in pipes cannot be halted
+ *              if defined mass storage compliance succeeds but with warnings
+ *              => case 4: Hi >  Dn
+ *              => case 5: Hi >  Di
+ *              => case 8: Hi <> Do
+ *              if undefined usbtest 13 fails
+ * - TRACE:     enable function tracing (depends on DEBUG)
+ *
+ * Main Features
+ * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
+ * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
+ * - Normal & LPM support
+ *
+ * USBTEST Report
+ * - OK: 0-12, 13 (STALL_IN defined) & 14
+ * - Not Supported: 15 & 16 (ISO)
+ *
+ * TODO List
+ * - OTG
+ * - Isochronous & Interrupt Traffic
+ * - Handle requests which spawns into several TDs
+ * - GET_STATUS(device) - always reports 0
+ * - Gadget API (majority of optional features)
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ratelimit.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/msm_hsusb.h>
+
+#include "ci13xxx_udc.h"
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+
+#define USB_MAX_TIMEOUT		25 /* 25msec timeout */
+#define EP_PRIME_CHECK_DELAY	(jiffies + msecs_to_jiffies(1000))
+#define MAX_PRIME_CHECK_RETRY	3 /*Wait for 3sec for EP prime failure */
+#define EXTRA_ALLOCATION_SIZE	256
+
+/* ctrl register bank access */
+static DEFINE_SPINLOCK(udc_lock);
+
+/* control endpoint description */
+static const struct usb_endpoint_descriptor
+ctrl_endpt_out_desc = {
+	.bLength         = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_OUT,
+	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+static const struct usb_endpoint_descriptor
+ctrl_endpt_in_desc = {
+	.bLength         = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+/* UDC descriptor */
+static struct ci13xxx *_udc;
+
+/* Interrupt statistics */
+#define ISR_MASK   0x1F
+static struct {
+	u32 test;
+	u32 ui;
+	u32 uei;
+	u32 pci;
+	u32 uri;
+	u32 sli;
+	u32 none;
+	struct {
+		u32 cnt;
+		u32 buf[ISR_MASK+1];
+		u32 idx;
+	} hndl;
+} isr_statistics;
+
+/**
+ * ffs_nr: find first (least significant) bit set
+ * @x: the word to search
+ *
+ * This function returns bit number (instead of position)
+ */
+static int ffs_nr(u32 x)
+{
+	int n = ffs(x);
+
+	return n ? n-1 : 32;
+}
+
+/******************************************************************************
+ * HW block
+ *****************************************************************************/
+/* register bank descriptor */
+static struct {
+	unsigned int  lpm;    /* is LPM? */
+	void __iomem *abs;    /* bus map offset */
+	void __iomem *cap;    /* bus map offset + CAP offset + CAP data */
+	size_t        size;   /* bank size */
+} hw_bank;
+
+/* MSM specific */
+#define ABS_AHBBURST        (0x0090UL)
+#define ABS_AHBMODE         (0x0098UL)
+/* UDC register map */
+#define ABS_CAPLENGTH       (0x100UL)
+#define ABS_HCCPARAMS       (0x108UL)
+#define ABS_DCCPARAMS       (0x124UL)
+#define ABS_TESTMODE        (hw_bank.lpm ? 0x0FCUL : 0x138UL)
+/* offset to CAPLENTGH (addr + data) */
+#define CAP_USBCMD          (0x000UL)
+#define CAP_USBSTS          (0x004UL)
+#define CAP_USBINTR         (0x008UL)
+#define CAP_DEVICEADDR      (0x014UL)
+#define CAP_ENDPTLISTADDR   (0x018UL)
+#define CAP_PORTSC          (0x044UL)
+#define CAP_DEVLC           (0x084UL)
+#define CAP_ENDPTPIPEID     (0x0BCUL)
+#define CAP_USBMODE         (hw_bank.lpm ? 0x0C8UL : 0x068UL)
+#define CAP_ENDPTSETUPSTAT  (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
+#define CAP_ENDPTPRIME      (hw_bank.lpm ? 0x0DCUL : 0x070UL)
+#define CAP_ENDPTFLUSH      (hw_bank.lpm ? 0x0E0UL : 0x074UL)
+#define CAP_ENDPTSTAT       (hw_bank.lpm ? 0x0E4UL : 0x078UL)
+#define CAP_ENDPTCOMPLETE   (hw_bank.lpm ? 0x0E8UL : 0x07CUL)
+#define CAP_ENDPTCTRL       (hw_bank.lpm ? 0x0ECUL : 0x080UL)
+#define CAP_LAST            (hw_bank.lpm ? 0x12CUL : 0x0C0UL)
+
+#define REMOTE_WAKEUP_DELAY	msecs_to_jiffies(200)
+
+/* maximum number of enpoints: valid only after hw_device_reset() */
+static unsigned int hw_ep_max;
+static void dbg_usb_op_fail(u8 addr, const char *name,
+				const struct ci13xxx_ep *mep);
+/**
+ * hw_ep_bit: calculates the bit number
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns bit number
+ */
+static inline int hw_ep_bit(int num, int dir)
+{
+	return num + (dir ? 16 : 0);
+}
+
+static int ep_to_bit(int n)
+{
+	int fill = 16 - hw_ep_max / 2;
+
+	if (n >= hw_ep_max / 2)
+		n += fill;
+
+	return n;
+}
+
+/**
+ * hw_aread: reads from register bitfield
+ * @addr: address relative to bus map
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_aread(u32 addr, u32 mask)
+{
+	return ioread32(addr + hw_bank.abs) & mask;
+}
+
+/**
+ * hw_awrite: writes to register bitfield
+ * @addr: address relative to bus map
+ * @mask: bitfield mask
+ * @data: new data
+ */
+static void hw_awrite(u32 addr, u32 mask, u32 data)
+{
+	iowrite32(hw_aread(addr, ~mask) | (data & mask),
+		  addr + hw_bank.abs);
+}
+
+/**
+ * hw_cread: reads from register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_cread(u32 addr, u32 mask)
+{
+	return ioread32(addr + hw_bank.cap) & mask;
+}
+
+/**
+ * hw_cwrite: writes to register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ * @data: new data
+ */
+static void hw_cwrite(u32 addr, u32 mask, u32 data)
+{
+	iowrite32(hw_cread(addr, ~mask) | (data & mask),
+		  addr + hw_bank.cap);
+}
+
+/**
+ * hw_ctest_and_clear: tests & clears register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_ctest_and_clear(u32 addr, u32 mask)
+{
+	u32 reg = hw_cread(addr, mask);
+
+	iowrite32(reg, addr + hw_bank.cap);
+	return reg;
+}
+
+/**
+ * hw_ctest_and_write: tests & writes register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ * @data: new data
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
+{
+	u32 reg = hw_cread(addr, ~0);
+
+	iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap);
+	return (reg & mask) >> ffs_nr(mask);
+}
+
+static int hw_device_init(void __iomem *base)
+{
+	u32 reg;
+
+	/* bank is a module variable */
+	hw_bank.abs = base;
+
+	hw_bank.cap = hw_bank.abs;
+	hw_bank.cap += ABS_CAPLENGTH;
+	hw_bank.cap += ioread8(hw_bank.cap);
+
+	reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN);
+	hw_bank.lpm  = reg;
+	hw_bank.size = hw_bank.cap - hw_bank.abs;
+	hw_bank.size += CAP_LAST;
+	hw_bank.size /= sizeof(u32);
+
+	reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
+	hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */
+
+	if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX)
+		return -ENODEV;
+
+	/* setup lock mode ? */
+
+	/* ENDPTSETUPSTAT is '0' by default */
+
+	/* HCSPARAMS.bf.ppc SHOULD BE zero for device */
+
+	return 0;
+}
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @base: register base address
+ *
+ * This function returns an error code
+ */
+static int hw_device_reset(struct ci13xxx *udc)
+{
+	int delay_count = 25; /* 250 usec */
+
+	/* should flush & stop before reset */
+	hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
+	hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
+
+	hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
+	while (delay_count--  && hw_cread(CAP_USBCMD, USBCMD_RST))
+		udelay(10);
+	if (delay_count < 0)
+		pr_err("USB controller reset failed\n");
+
+	if (udc->udc_driver->notify_event)
+		udc->udc_driver->notify_event(udc,
+			CI13XXX_CONTROLLER_RESET_EVENT);
+
+	/* USBMODE should be configured step by step */
+	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
+	hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
+	hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);  /* HW >= 2.3 */
+
+	/*
+	 * ITC (Interrupt Threshold Control) field is to set the maximum
+	 * rate at which the device controller will issue interrupts.
+	 * The maximum interrupt interval measured in micro frames.
+	 * Valid values are 0, 1, 2, 4, 8, 16, 32, 64. The default value is
+	 * 8 micro frames. If CPU can handle interrupts at faster rate, ITC
+	 * can be set to lesser value to gain performance.
+	 */
+	if (udc->udc_driver->nz_itc)
+		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK,
+			USBCMD_ITC(udc->udc_driver->nz_itc));
+	else if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
+		hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK, USBCMD_ITC(0));
+
+	if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
+		pr_err("cannot enter in device mode");
+		pr_err("lpm = %i", hw_bank.lpm);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * hw_device_state: enables/disables interrupts & starts/stops device (execute
+ *                  without interruption)
+ * @dma: 0 => disable, !0 => enable and set dma engine
+ *
+ * This function returns an error code
+ */
+static int hw_device_state(u32 dma)
+{
+	struct ci13xxx *udc = _udc;
+
+	if (dma) {
+		if (!(udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)) {
+			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
+			pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+				 __func__, hw_cread(CAP_USBMODE, ~0));
+
+		} else {
+			hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
+			pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+				__func__, hw_cread(CAP_USBMODE, ~0));
+		}
+
+		hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
+
+
+		/* Set BIT(31) to enable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+			pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
+
+		/* interrupt, error, port change, reset, sleep/suspend */
+		hw_cwrite(CAP_USBINTR, ~0,
+			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+		hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS);
+	} else {
+		hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
+		hw_cwrite(CAP_USBINTR, ~0, 0);
+		/* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+		if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+			hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+			pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+					__func__, hw_aread(ABS_AHBMODE, ~0));
+		}
+	}
+	return 0;
+}
+
+static void debug_ept_flush_info(int ep_num, int dir)
+{
+	struct ci13xxx *udc = _udc;
+	struct ci13xxx_ep *mep;
+
+	if (dir)
+		mep = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+	else
+		mep = &udc->ci13xxx_ep[ep_num];
+
+	pr_err_ratelimited("USB Registers\n");
+	pr_err_ratelimited("USBCMD:%x\n", hw_cread(CAP_USBCMD, ~0));
+	pr_err_ratelimited("USBSTS:%x\n", hw_cread(CAP_USBSTS, ~0));
+	pr_err_ratelimited("ENDPTLISTADDR:%x\n",
+			hw_cread(CAP_ENDPTLISTADDR, ~0));
+	pr_err_ratelimited("PORTSC:%x\n", hw_cread(CAP_PORTSC, ~0));
+	pr_err_ratelimited("USBMODE:%x\n", hw_cread(CAP_USBMODE, ~0));
+	pr_err_ratelimited("ENDPTSTAT:%x\n", hw_cread(CAP_ENDPTSTAT, ~0));
+
+	dbg_usb_op_fail(0xFF, "FLUSHF", mep);
+}
+/**
+ * hw_ep_flush: flush endpoint fifo (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_flush(int num, int dir)
+{
+	ktime_t start, diff;
+	int n = hw_ep_bit(num, dir);
+	struct ci13xxx_ep *mEp = &_udc->ci13xxx_ep[n];
+
+	/* Flush ep0 even when queue is empty */
+	if (_udc->skip_flush || (num && list_empty(&mEp->qh.queue)))
+		return 0;
+
+	start = ktime_get();
+	do {
+		/* flush any pending transfer */
+		hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
+		while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) {
+			cpu_relax();
+			diff = ktime_sub(ktime_get(), start);
+			if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
+				printk_ratelimited(KERN_ERR
+					"%s: Failed to flush ep#%d %s\n",
+					__func__, num,
+					dir ? "IN" : "OUT");
+				debug_ept_flush_info(num, dir);
+				_udc->skip_flush = true;
+				/* Notify to trigger h/w reset recovery later */
+				if (_udc->udc_driver->notify_event)
+					_udc->udc_driver->notify_event(_udc,
+						CI13XXX_CONTROLLER_ERROR_EVENT);
+				return 0;
+			}
+		}
+	} while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
+
+	return 0;
+}
+
+/**
+ * hw_ep_disable: disables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_disable(int num, int dir)
+{
+	hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32),
+		  dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
+	return 0;
+}
+
+/**
+ * hw_ep_enable: enables endpoint (execute without interruption)
+ * @num:  endpoint number
+ * @dir:  endpoint direction
+ * @type: endpoint type
+ *
+ * This function returns an error code
+ */
+static int hw_ep_enable(int num, int dir, int type)
+{
+	u32 mask, data;
+
+	if (dir) {
+		mask  = ENDPTCTRL_TXT;  /* type    */
+		data  = type << ffs_nr(mask);
+
+		mask |= ENDPTCTRL_TXS;  /* unstall */
+		mask |= ENDPTCTRL_TXR;  /* reset data toggle */
+		data |= ENDPTCTRL_TXR;
+		mask |= ENDPTCTRL_TXE;  /* enable  */
+		data |= ENDPTCTRL_TXE;
+	} else {
+		mask  = ENDPTCTRL_RXT;  /* type    */
+		data  = type << ffs_nr(mask);
+
+		mask |= ENDPTCTRL_RXS;  /* unstall */
+		mask |= ENDPTCTRL_RXR;  /* reset data toggle */
+		data |= ENDPTCTRL_RXR;
+		mask |= ENDPTCTRL_RXE;  /* enable  */
+		data |= ENDPTCTRL_RXE;
+	}
+	hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data);
+
+	/* make sure endpoint is enabled before returning */
+	mb();
+
+	return 0;
+}
+
+/**
+ * hw_ep_get_halt: return endpoint halt status
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns 1 if endpoint halted
+ */
+static int hw_ep_get_halt(int num, int dir)
+{
+	u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+
+	return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0;
+}
+
+/**
+ * hw_test_and_clear_setup_status: test & clear setup status (execute without
+ *                                 interruption)
+ * @n: endpoint number
+ *
+ * This function returns setup status
+ */
+static int hw_test_and_clear_setup_status(int n)
+{
+	n = ep_to_bit(n);
+	return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
+}
+
+/**
+ * hw_ep_prime: primes endpoint (execute without interruption)
+ * @num:     endpoint number
+ * @dir:     endpoint direction
+ * @is_ctrl: true if control endpoint
+ *
+ * This function returns an error code
+ */
+static int hw_ep_prime(int num, int dir, int is_ctrl)
+{
+	int n = hw_ep_bit(num, dir);
+
+	if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+		return -EAGAIN;
+
+	hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
+
+	if (is_ctrl && dir == RX  && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+		return -EAGAIN;
+
+	/* status shoult be tested according with manual but it doesn't work */
+	return 0;
+}
+
+/**
+ * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
+ *                 without interruption)
+ * @num:   endpoint number
+ * @dir:   endpoint direction
+ * @value: true => stall, false => unstall
+ *
+ * This function returns an error code
+ */
+static int hw_ep_set_halt(int num, int dir, int value)
+{
+	u32 addr, mask_xs, mask_xr;
+
+	if (value != 0 && value != 1)
+		return -EINVAL;
+
+	do {
+		if (hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+			return 0;
+
+		addr = CAP_ENDPTCTRL + num * sizeof(u32);
+		mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+		mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
+
+		/* data toggle - reserved for EP0 but it's in ESS */
+		hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr);
+
+	} while (value != hw_ep_get_halt(num, dir));
+
+	return 0;
+}
+
+/**
+ * hw_intr_clear: disables interrupt & clears interrupt status (execute without
+ *                interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_clear(int n)
+{
+	if (n >= REG_BITS)
+		return -EINVAL;
+
+	hw_cwrite(CAP_USBINTR, BIT(n), 0);
+	hw_cwrite(CAP_USBSTS,  BIT(n), BIT(n));
+	return 0;
+}
+
+/**
+ * hw_intr_force: enables interrupt & forces interrupt status (execute without
+ *                interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_force(int n)
+{
+	if (n >= REG_BITS)
+		return -EINVAL;
+
+	hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
+	hw_cwrite(CAP_USBINTR,  BIT(n), BIT(n));
+	hw_cwrite(CAP_USBSTS,   BIT(n), BIT(n));
+	hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0);
+	return 0;
+}
+
+/**
+ * hw_is_port_high_speed: test if port is high speed
+ *
+ * This function returns true if high speed port
+ */
+static int hw_port_is_high_speed(void)
+{
+	return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) :
+		hw_cread(CAP_PORTSC, PORTSC_HSP);
+}
+
+/**
+ * hw_port_test_get: reads port test mode value
+ *
+ * This function returns port test mode value
+ */
+static u8 hw_port_test_get(void)
+{
+	return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+}
+
+/**
+ * hw_port_test_set: writes port test mode (execute without interruption)
+ * @mode: new value
+ *
+ * This function returns an error code
+ */
+static int hw_port_test_set(u8 mode)
+{
+	const u8 TEST_MODE_MAX = 7;
+
+	if (mode > TEST_MODE_MAX)
+		return -EINVAL;
+
+	hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+	return 0;
+}
+
+/**
+ * hw_read_intr_enable: returns interrupt enable register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_enable(void)
+{
+	return hw_cread(CAP_USBINTR, ~0);
+}
+
+/**
+ * hw_read_intr_status: returns interrupt status register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_status(void)
+{
+	return hw_cread(CAP_USBSTS, ~0);
+}
+
+/**
+ * hw_register_read: reads all device registers (execute without interruption)
+ * @buf:  destination buffer
+ * @size: buffer size
+ *
+ * This function returns number of registers read
+ */
+static size_t hw_register_read(u32 *buf, size_t size)
+{
+	unsigned int i;
+
+	if (size > hw_bank.size)
+		size = hw_bank.size;
+
+	for (i = 0; i < size; i++)
+		buf[i] = hw_aread(i * sizeof(u32), ~0);
+
+	return size;
+}
+
+/**
+ * hw_register_write: writes to register
+ * @addr: register address
+ * @data: register value
+ *
+ * This function returns an error code
+ */
+static int hw_register_write(u16 addr, u32 data)
+{
+	/* align */
+	addr /= sizeof(u32);
+
+	if (addr >= hw_bank.size)
+		return -EINVAL;
+
+	/* align */
+	addr *= sizeof(u32);
+
+	hw_awrite(addr, ~0, data);
+	return 0;
+}
+
+/**
+ * hw_test_and_clear_complete: test & clear complete status (execute without
+ *                             interruption)
+ * @n: endpoint number
+ *
+ * This function returns complete status
+ */
+static int hw_test_and_clear_complete(int n)
+{
+	n = ep_to_bit(n);
+	return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
+}
+
+/**
+ * hw_test_and_clear_intr_active: test & clear active interrupts (execute
+ *                                without interruption)
+ *
+ * This function returns active interrutps
+ */
+static u32 hw_test_and_clear_intr_active(void)
+{
+	u32 reg = hw_read_intr_status() & hw_read_intr_enable();
+
+	hw_cwrite(CAP_USBSTS, ~0, reg);
+	return reg;
+}
+
+/**
+ * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
+ *                                interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_clear_setup_guard(void)
+{
+	return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0);
+}
+
+/**
+ * hw_test_and_set_setup_guard: test & set setup guard (execute without
+ *                              interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_set_setup_guard(void)
+{
+	return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
+}
+
+/**
+ * hw_usb_set_address: configures USB address (execute without interruption)
+ * @value: new USB address
+ *
+ * This function returns an error code
+ */
+static int hw_usb_set_address(u8 value)
+{
+	/* advance */
+	hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA,
+		  value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA);
+	return 0;
+}
+
+/**
+ * hw_usb_reset: restart device after a bus reset (execute without
+ *               interruption)
+ *
+ * This function returns an error code
+ */
+static int hw_usb_reset(void)
+{
+	int delay_count = 10; /* 100 usec delay */
+
+	hw_usb_set_address(0);
+
+	/* ESS flushes only at end?!? */
+	hw_cwrite(CAP_ENDPTFLUSH,    ~0, ~0);   /* flush all EPs */
+
+	/* clear complete status */
+	hw_cwrite(CAP_ENDPTCOMPLETE,  0,  0);   /* writes its content */
+
+	/* wait until all bits cleared */
+	while (delay_count-- && hw_cread(CAP_ENDPTPRIME, ~0))
+		udelay(10);
+	if (delay_count < 0)
+		pr_err("ENDPTPRIME is not cleared during bus reset\n");
+
+	/* reset all endpoints ? */
+
+	/*
+	 * reset internal status and wait for further instructions
+	 * no need to verify the port reset status (ESS does it)
+	 */
+
+	return 0;
+}
+
+/******************************************************************************
+ * DBG block
+ *****************************************************************************/
+/**
+ * show_device: prints information about device capabilities and status
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_device(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget *gadget = &udc->gadget;
+	int n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n",
+		       gadget->speed);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n",
+		       gadget->max_speed);
+	/* TODO: Scheduled for removal in 3.8. */
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed      = %d\n",
+		       gadget_is_dualspeed(gadget));
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n",
+		       gadget->is_otg);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n",
+		       gadget->is_a_peripheral);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable      = %d\n",
+		       gadget->b_hnp_enable);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support     = %d\n",
+		       gadget->a_hnp_support);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
+		       gadget->a_alt_hnp_support);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "name              = %s\n",
+		       (gadget->name ? gadget->name : ""));
+
+	return n;
+}
+static DEVICE_ATTR(device, 0400, show_device, NULL);
+
+/**
+ * show_driver: prints information about attached gadget (if any)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct usb_gadget_driver *driver = udc->driver;
+	int n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	if (driver == NULL)
+		return scnprintf(buf, PAGE_SIZE,
+				 "There is no gadget attached!\n");
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n",
+		       (driver->function ? driver->function : ""));
+	n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
+		       driver->max_speed);
+
+	return n;
+}
+static DEVICE_ATTR(driver, 0400, show_driver, NULL);
+
+/* Maximum event message length */
+#define DBG_DATA_MSG   64UL
+
+/* Maximum event messages */
+#define DBG_DATA_MAX   128UL
+
+/* Event buffer descriptor */
+static struct {
+	char		(buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */
+	unsigned int	idx;   /* index */
+	unsigned int	tty;   /* print to console? */
+	rwlock_t	lck;   /* lock */
+} dbg_data = {
+	.idx = 0,
+	.tty = 0,
+	.lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static void dbg_dec(unsigned int *idx)
+{
+	*idx = (*idx - 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static void dbg_inc(unsigned int *idx)
+{
+	*idx = (*idx + 1) & (DBG_DATA_MAX-1);
+}
+
+
+static unsigned int ep_addr_txdbg_mask;
+module_param(ep_addr_txdbg_mask, uint, 0644);
+static unsigned int ep_addr_rxdbg_mask;
+module_param(ep_addr_rxdbg_mask, uint, 0644);
+
+static int allow_dbg_print(u8 addr)
+{
+	int dir, num;
+
+	/* allow bus wide events */
+	if (addr == 0xff)
+		return 1;
+
+	dir = addr & USB_ENDPOINT_DIR_MASK ? TX : RX;
+	num = addr & ~USB_ENDPOINT_DIR_MASK;
+	num = 1 << num;
+
+	if ((dir == TX) && (num & ep_addr_txdbg_mask))
+		return 1;
+	if ((dir == RX) && (num & ep_addr_rxdbg_mask))
+		return 1;
+
+	return 0;
+}
+
+#define TIME_BUF_LEN  20
+/*get_timestamp - returns time of day in us */
+static char *get_timestamp(char *tbuf)
+{
+	unsigned long long t;
+	unsigned long nanosec_rem;
+
+	t = cpu_clock(smp_processor_id());
+	nanosec_rem = do_div(t, 1000000000)/1000;
+	scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
+		nanosec_rem);
+	return tbuf;
+}
+
+/**
+ * dbg_print:  prints the common part of the event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ * @extra:  extra information
+ */
+static void dbg_print(u8 addr, const char *name, int status, const char *extra)
+{
+	unsigned long flags;
+	char tbuf[TIME_BUF_LEN];
+
+	if (!allow_dbg_print(addr))
+		return;
+
+	write_lock_irqsave(&dbg_data.lck, flags);
+
+	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
+		  "%s\t? %02X %-7.7s %4i ?\t%s\n",
+		  get_timestamp(tbuf), addr, name, status, extra);
+
+	dbg_inc(&dbg_data.idx);
+
+	write_unlock_irqrestore(&dbg_data.lck, flags);
+
+	if (dbg_data.tty != 0)
+		pr_notice("%s\t? %02X %-7.7s %4i ?\t%s\n",
+			  get_timestamp(tbuf), addr, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr:   endpoint address
+ * @td:     transfer descriptor
+ * @status: status
+ */
+static void dbg_done(u8 addr, const u32 token, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	scnprintf(msg, sizeof(msg), "%d %02X",
+		  (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
+		  (int)(token & TD_STATUS)      >> ffs_nr(TD_STATUS));
+	dbg_print(addr, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr:   endpoint address
+ * @name:   event name
+ * @status: status
+ */
+static void dbg_event(u8 addr, const char *name, int status)
+{
+	if (name != NULL)
+		dbg_print(addr, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr:   endpoint address
+ * @req:    USB request
+ * @status: status
+ */
+static void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%d %d", !req->no_interrupt, req->length);
+		dbg_print(addr, "QUEUE", status, msg);
+	}
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req:  setup request
+ */
+static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+	char msg[DBG_DATA_MSG];
+
+	if (req != NULL) {
+		scnprintf(msg, sizeof(msg),
+			  "%02X %02X %04X %04X %d", req->bRequestType,
+			  req->bRequest, le16_to_cpu(req->wValue),
+			  le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+		dbg_print(addr, "SETUP", 0, msg);
+	}
+}
+
+/**
+ * dbg_usb_op_fail: prints USB Operation FAIL event
+ * @addr: endpoint address
+ * @mEp:  endpoint structure
+ */
+static void dbg_usb_op_fail(u8 addr, const char *name,
+				const struct ci13xxx_ep *mep)
+{
+	char msg[DBG_DATA_MSG];
+	struct ci13xxx_req *req;
+	struct list_head *ptr = NULL;
+
+	if (mep != NULL) {
+		scnprintf(msg, sizeof(msg),
+			"%s Fail EP%d%s QH:%08X",
+			name, mep->num,
+			mep->dir ? "IN" : "OUT", mep->qh.ptr->cap);
+		dbg_print(addr, name, 0, msg);
+		scnprintf(msg, sizeof(msg),
+				"cap:%08X %08X %08X\n",
+				mep->qh.ptr->curr, mep->qh.ptr->td.next,
+				mep->qh.ptr->td.token);
+		dbg_print(addr, "QHEAD", 0, msg);
+
+		list_for_each(ptr, &mep->qh.queue) {
+			req = list_entry(ptr, struct ci13xxx_req, queue);
+			scnprintf(msg, sizeof(msg),
+					"%pKa:%08X:%08X\n",
+					&req->dma, req->ptr->next,
+					req->ptr->token);
+			dbg_print(addr, "REQ", 0, msg);
+			scnprintf(msg, sizeof(msg), "%08X:%d\n",
+					req->ptr->page[0],
+					req->req.status);
+			dbg_print(addr, "REQPAGE", 0, msg);
+		}
+	}
+}
+
+/**
+ * show_events: displays the event buffer
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_events(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	unsigned long flags;
+	unsigned int i, j, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	read_lock_irqsave(&dbg_data.lck, flags);
+
+	i = dbg_data.idx;
+	for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
+		n += strlen(dbg_data.buf[i]);
+		if (n >= PAGE_SIZE) {
+			n -= strlen(dbg_data.buf[i]);
+			break;
+		}
+	}
+	for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
+		j += scnprintf(buf + j, PAGE_SIZE - j,
+			       "%s", dbg_data.buf[i]);
+
+	read_unlock_irqrestore(&dbg_data.lck, flags);
+
+	return n;
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_events(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	unsigned int tty;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (kstrtouint(buf, 10, &tty) || tty > 1) {
+		dev_err(dev, "<1|0>: enable|disable console log\n");
+		goto done;
+	}
+
+	dbg_data.tty = tty;
+	dev_info(dev, "tty = %u", dbg_data.tty);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(events, 0600, show_events, store_events);
+
+/**
+ * show_inters: interrupt status, enable status and historic
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	u32 intr;
+	unsigned int i, j, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	n += scnprintf(buf + n, PAGE_SIZE - n,
+		       "status = %08x\n", hw_read_intr_status());
+	n += scnprintf(buf + n, PAGE_SIZE - n,
+		       "enable = %08x\n", hw_read_intr_enable());
+
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
+		       isr_statistics.test);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n",
+		       isr_statistics.ui);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
+		       isr_statistics.uei);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
+		       isr_statistics.pci);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
+		       isr_statistics.uri);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
+		       isr_statistics.sli);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
+		       isr_statistics.none);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
+		       isr_statistics.hndl.cnt);
+
+	for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
+		i   &= ISR_MASK;
+		intr = isr_statistics.hndl.buf[i];
+
+		if (USBi_UI  & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "ui  ");
+		intr &= ~USBi_UI;
+		if (USBi_UEI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
+		intr &= ~USBi_UEI;
+		if (USBi_PCI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
+		intr &= ~USBi_PCI;
+		if (USBi_URI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
+		intr &= ~USBi_URI;
+		if (USBi_SLI & intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
+		intr &= ~USBi_SLI;
+		if (intr)
+			n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
+		if (isr_statistics.hndl.buf[i])
+			n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
+	}
+
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return n;
+}
+
+/**
+ * store_inters: enable & force or disable an individual interrutps
+ *                   (to be used for test purposes only)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int en, bit;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
+		dev_err(dev, "<1|0> <bit>: enable|disable interrupt");
+		goto done;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (en) {
+		if (hw_intr_force(bit))
+			dev_err(dev, "invalid bit number\n");
+		else
+			isr_statistics.test++;
+	} else {
+		if (hw_intr_clear(bit))
+			dev_err(dev, "invalid bit number\n");
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(inters, 0600, show_inters, store_inters);
+
+/**
+ * show_port_test: reads port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_port_test(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int mode;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	mode = hw_port_test_get();
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+}
+
+/**
+ * store_port_test: writes port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_port_test(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int mode;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (kstrtouint(buf, 10, &mode)) {
+		dev_err(dev, "<mode>: set port test mode");
+		goto done;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (hw_port_test_set(mode))
+		dev_err(dev, "invalid mode\n");
+	spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(port_test, 0600, show_port_test, store_port_test);
+
+/**
+ * show_qheads: DMA contents of all queue heads
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	unsigned int i, j, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	for (i = 0; i < hw_ep_max/2; i++) {
+		struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+		struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
+
+		n += scnprintf(buf + n, PAGE_SIZE - n,
+			       "EP=%02i: RX=%08X TX=%08X\n",
+			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+		for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
+			n += scnprintf(buf + n, PAGE_SIZE - n,
+				       " %04X:    %08X    %08X\n", j,
+				       *((u32 *)mEpRx->qh.ptr + j),
+				       *((u32 *)mEpTx->qh.ptr + j));
+		}
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return n;
+}
+static DEVICE_ATTR(qheads, 0400, show_qheads, NULL);
+
+/**
+ * show_registers: dumps all registers
+ *
+ * Check "device.h" for details
+ */
+#define DUMP_ENTRIES	512
+static ssize_t show_registers(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	u32 *dump;
+	unsigned int i, k, n = 0;
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
+	if (!dump)
+		return 0;
+
+	spin_lock_irqsave(udc->lock, flags);
+	k = hw_register_read(dump, DUMP_ENTRIES);
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	for (i = 0; i < k; i++) {
+		n += scnprintf(buf + n, PAGE_SIZE - n,
+			       "reg[0x%04X] = 0x%08X\n",
+			       i * (unsigned int)sizeof(u32), dump[i]);
+	}
+	kfree(dump);
+
+	return n;
+}
+
+/**
+ * store_registers: writes value to register address
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_registers(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long addr, data, flags;
+
+	dbg_trace("[%s] %pK, %d\n", __func__, buf, count);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		goto done;
+	}
+
+	if (sscanf(buf, "%li %li", &addr, &data) != 2) {
+		dev_err(dev, "<addr> <data>: write data to register address");
+		goto done;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (hw_register_write(addr, data))
+		dev_err(dev, "invalid address range\n");
+	spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+	return count;
+}
+static DEVICE_ATTR(registers, 0600, show_registers, store_registers);
+
+/**
+ * show_requests: DMA contents of all requests currently queued (all endpts)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	unsigned long flags;
+	struct list_head   *ptr = NULL;
+	struct ci13xxx_req *req = NULL;
+	unsigned int i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+
+	dbg_trace("[%s] %pK\n", __func__, buf);
+	if (attr == NULL || buf == NULL) {
+		dev_err(dev, "[%s] EINVAL\n", __func__);
+		return 0;
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	for (i = 0; i < hw_ep_max; i++)
+		list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+		{
+			req = list_entry(ptr, struct ci13xxx_req, queue);
+
+			n += scnprintf(buf + n, PAGE_SIZE - n,
+					"EP=%02i: TD=%08X %s\n",
+					i % hw_ep_max/2, (u32)req->dma,
+					((i < hw_ep_max/2) ? "RX" : "TX"));
+
+			for (j = 0; j < qSize; j++)
+				n += scnprintf(buf + n, PAGE_SIZE - n,
+						" %04X:    %08X\n", j,
+						*((u32 *)req->ptr + j));
+		}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return n;
+}
+static DEVICE_ATTR(requests, 0400, show_requests, NULL);
+
+/* EP# and Direction */
+static ssize_t prime_ept(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx_ep *mEp;
+	unsigned int ep_num, dir;
+	int n;
+	struct ci13xxx_req *mReq = NULL;
+
+	if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
+		dev_err(dev, "<ep_num> <dir>: prime the ep");
+		goto done;
+	}
+
+	if (dir)
+		mEp = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+	else
+		mEp = &udc->ci13xxx_ep[ep_num];
+
+	n = hw_ep_bit(mEp->num, mEp->dir);
+	mReq =  list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
+	mEp->qh.ptr->td.next   = mReq->dma;
+	mEp->qh.ptr->td.token &= ~TD_STATUS;
+
+	/* Makes sure that above write goes through */
+	wmb();
+
+	hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
+	while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
+		cpu_relax();
+
+	pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s\n", __func__,
+			hw_cread(CAP_ENDPTPRIME, ~0),
+			hw_cread(CAP_ENDPTSTAT, ~0),
+			mEp->num, mEp->dir ? "IN" : "OUT");
+done:
+	return count;
+
+}
+static DEVICE_ATTR(prime, 0200, NULL, prime_ept);
+
+/* EP# and Direction */
+static ssize_t print_dtds(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+	struct ci13xxx_ep *mEp;
+	unsigned int ep_num, dir;
+	int n;
+	struct list_head   *ptr = NULL;
+	struct ci13xxx_req *req = NULL;
+
+	if (sscanf(buf, "%u %u", &ep_num, &dir) != 2) {
+		dev_err(dev, "<ep_num> <dir>: to print dtds");
+		goto done;
+	}
+
+	if (dir)
+		mEp = &udc->ci13xxx_ep[ep_num + hw_ep_max/2];
+	else
+		mEp = &udc->ci13xxx_ep[ep_num];
+
+	n = hw_ep_bit(mEp->num, mEp->dir);
+	pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s dTD_update_fail_count: %lu mEp->dTD_update_fail_count: %lu mEp->dTD_active_re_q_count: %lu mEp->prime_fail_count: %lu\n",
+			__func__,
+			hw_cread(CAP_ENDPTPRIME, ~0),
+			hw_cread(CAP_ENDPTSTAT, ~0),
+			mEp->num, mEp->dir ? "IN" : "OUT",
+			udc->dTD_update_fail_count,
+			mEp->dTD_update_fail_count,
+			mEp->dTD_active_re_q_count,
+			mEp->prime_fail_count);
+
+	pr_info("QH: cap:%08x cur:%08x next:%08x token:%08x\n",
+			mEp->qh.ptr->cap, mEp->qh.ptr->curr,
+			mEp->qh.ptr->td.next, mEp->qh.ptr->td.token);
+
+	list_for_each(ptr, &mEp->qh.queue) {
+		req = list_entry(ptr, struct ci13xxx_req, queue);
+
+		pr_info("\treq:%pKa next:%08x token:%08x page0:%08x status:%d\n",
+				&req->dma, req->ptr->next, req->ptr->token,
+				req->ptr->page[0], req->req.status);
+	}
+done:
+	return count;
+
+}
+static DEVICE_ATTR(dtds, 0200, NULL, print_dtds);
+
+static int ci13xxx_wakeup(struct usb_gadget *_gadget)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+	int ret = 0;
+
+	trace();
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (!udc->gadget.remote_wakeup) {
+		ret = -EOPNOTSUPP;
+		dbg_trace("remote wakeup feature is not enabled\n");
+		goto out;
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_get_sync(&_gadget->dev);
+
+	udc->udc_driver->notify_event(udc,
+		CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT);
+
+	if (udc->transceiver)
+		usb_phy_set_suspend(udc->transceiver, 0);
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
+		ret = -EINVAL;
+		dbg_trace("port is not suspended\n");
+		pm_runtime_put(&_gadget->dev);
+		goto out;
+	}
+	hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
+
+	pm_runtime_mark_last_busy(&_gadget->dev);
+	pm_runtime_put_autosuspend(&_gadget->dev);
+out:
+	spin_unlock_irqrestore(udc->lock, flags);
+	return ret;
+}
+
+static void usb_do_remote_wakeup(struct work_struct *w)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+	bool do_wake;
+
+	/*
+	 * This work can not be canceled from interrupt handler. Check
+	 * if wakeup conditions are still met.
+	 */
+	spin_lock_irqsave(udc->lock, flags);
+	do_wake = udc->suspended && udc->gadget.remote_wakeup;
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	if (do_wake)
+		ci13xxx_wakeup(&udc->gadget);
+}
+
+static ssize_t usb_remote_wakeup(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+
+	ci13xxx_wakeup(&udc->gadget);
+
+	return count;
+}
+static DEVICE_ATTR(wakeup, 0200, 0, usb_remote_wakeup);
+
+/**
+ * dbg_create_files: initializes the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+static int __maybe_unused dbg_create_files(struct device *dev)
+{
+	int retval = 0;
+
+	if (dev == NULL)
+		return -EINVAL;
+	retval = device_create_file(dev, &dev_attr_device);
+	if (retval)
+		goto done;
+	retval = device_create_file(dev, &dev_attr_driver);
+	if (retval)
+		goto rm_device;
+	retval = device_create_file(dev, &dev_attr_events);
+	if (retval)
+		goto rm_driver;
+	retval = device_create_file(dev, &dev_attr_inters);
+	if (retval)
+		goto rm_events;
+	retval = device_create_file(dev, &dev_attr_port_test);
+	if (retval)
+		goto rm_inters;
+	retval = device_create_file(dev, &dev_attr_qheads);
+	if (retval)
+		goto rm_port_test;
+	retval = device_create_file(dev, &dev_attr_registers);
+	if (retval)
+		goto rm_qheads;
+	retval = device_create_file(dev, &dev_attr_requests);
+	if (retval)
+		goto rm_registers;
+	retval = device_create_file(dev, &dev_attr_wakeup);
+	if (retval)
+		goto rm_remote_wakeup;
+	retval = device_create_file(dev, &dev_attr_prime);
+	if (retval)
+		goto rm_prime;
+	retval = device_create_file(dev, &dev_attr_dtds);
+	if (retval)
+		goto rm_dtds;
+
+	return 0;
+
+rm_dtds:
+	device_remove_file(dev, &dev_attr_dtds);
+rm_prime:
+	device_remove_file(dev, &dev_attr_prime);
+rm_remote_wakeup:
+	device_remove_file(dev, &dev_attr_wakeup);
+ rm_registers:
+	device_remove_file(dev, &dev_attr_registers);
+ rm_qheads:
+	device_remove_file(dev, &dev_attr_qheads);
+ rm_port_test:
+	device_remove_file(dev, &dev_attr_port_test);
+ rm_inters:
+	device_remove_file(dev, &dev_attr_inters);
+ rm_events:
+	device_remove_file(dev, &dev_attr_events);
+ rm_driver:
+	device_remove_file(dev, &dev_attr_driver);
+ rm_device:
+	device_remove_file(dev, &dev_attr_device);
+ done:
+	return retval;
+}
+
+/**
+ * dbg_remove_files: destroys the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+static int __maybe_unused dbg_remove_files(struct device *dev)
+{
+	if (dev == NULL)
+		return -EINVAL;
+	device_remove_file(dev, &dev_attr_requests);
+	device_remove_file(dev, &dev_attr_registers);
+	device_remove_file(dev, &dev_attr_qheads);
+	device_remove_file(dev, &dev_attr_port_test);
+	device_remove_file(dev, &dev_attr_inters);
+	device_remove_file(dev, &dev_attr_events);
+	device_remove_file(dev, &dev_attr_driver);
+	device_remove_file(dev, &dev_attr_device);
+	device_remove_file(dev, &dev_attr_wakeup);
+	return 0;
+}
+
+/******************************************************************************
+ * UTIL block
+ *****************************************************************************/
+/**
+ * _usb_addr: calculates endpoint address from direction & number
+ * @ep:  endpoint
+ */
+static inline u8 _usb_addr(struct ci13xxx_ep *ep)
+{
+	return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
+}
+
+static void ep_prime_timer_func(unsigned long data)
+{
+	struct ci13xxx_ep *mep = (struct ci13xxx_ep *)data;
+	struct ci13xxx_req *req;
+	struct list_head *ptr = NULL;
+	int n = hw_ep_bit(mep->num, mep->dir);
+	unsigned long flags;
+
+
+	spin_lock_irqsave(mep->lock, flags);
+
+	if (_udc && (!_udc->vbus_active || _udc->suspended)) {
+		pr_debug("ep%d%s prime timer when vbus_active=%d,suspend=%d\n",
+			mep->num, mep->dir ? "IN" : "OUT",
+			_udc->vbus_active, _udc->suspended);
+		goto out;
+	}
+
+	if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
+		goto out;
+
+	if (list_empty(&mep->qh.queue))
+		goto out;
+
+	req = list_entry(mep->qh.queue.next, struct ci13xxx_req, queue);
+
+	/* clean speculative fetches on req->ptr->token */
+	mb();
+	if (!(TD_STATUS_ACTIVE & req->ptr->token))
+		goto out;
+
+	mep->prime_timer_count++;
+	if (mep->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
+		mep->prime_timer_count = 0;
+		pr_info("ep%d dir:%s QH:cap:%08x cur:%08x next:%08x tkn:%08x\n",
+				mep->num, mep->dir ? "IN" : "OUT",
+				mep->qh.ptr->cap, mep->qh.ptr->curr,
+				mep->qh.ptr->td.next, mep->qh.ptr->td.token);
+		list_for_each(ptr, &mep->qh.queue) {
+			req = list_entry(ptr, struct ci13xxx_req, queue);
+			pr_info("\treq:%pKa:%08xtkn:%08xpage0:%08xsts:%d\n",
+					&req->dma, req->ptr->next,
+					req->ptr->token, req->ptr->page[0],
+					req->req.status);
+		}
+		dbg_usb_op_fail(0xFF, "PRIMEF", mep);
+		mep->prime_fail_count++;
+	} else {
+		mod_timer(&mep->prime_timer, EP_PRIME_CHECK_DELAY);
+	}
+
+	spin_unlock_irqrestore(mep->lock, flags);
+	return;
+
+out:
+	mep->prime_timer_count = 0;
+	spin_unlock_irqrestore(mep->lock, flags);
+
+}
+
+/**
+ * _hardware_queue: configures a request at hardware level
+ * @gadget: gadget
+ * @mEp:    endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+	unsigned int i;
+	int ret = 0;
+	unsigned int length = mReq->req.length;
+	struct ci13xxx *udc = _udc;
+
+	trace("%pK, %pK", mEp, mReq);
+
+	/* don't queue twice */
+	if (mReq->req.status == -EALREADY)
+		return -EALREADY;
+
+	mReq->req.status = -EALREADY;
+	if (length && mReq->req.dma == DMA_ERROR_CODE) {
+		mReq->req.dma = dma_map_single(mEp->device, mReq->req.buf,
+					length, mEp->dir ? DMA_TO_DEVICE :
+					DMA_FROM_DEVICE);
+		if (mReq->req.dma == 0)
+			return -ENOMEM;
+
+		mReq->map = 1;
+	}
+
+	if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
+		mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
+					   &mReq->zdma);
+		if (mReq->zptr == NULL) {
+			if (mReq->map) {
+				dma_unmap_single(mEp->device, mReq->req.dma,
+					length, mEp->dir ? DMA_TO_DEVICE :
+					DMA_FROM_DEVICE);
+				mReq->req.dma = DMA_ERROR_CODE;
+				mReq->map     = 0;
+			}
+			return -ENOMEM;
+		}
+		memset(mReq->zptr, 0, sizeof(*mReq->zptr));
+		mReq->zptr->next    = TD_TERMINATE;
+		mReq->zptr->token   = TD_STATUS_ACTIVE;
+		if (!mReq->req.no_interrupt)
+			mReq->zptr->token   |= TD_IOC;
+	}
+
+	/*
+	 * TD configuration
+	 * TODO - handle requests which spawns into several TDs
+	 */
+	memset(mReq->ptr, 0, sizeof(*mReq->ptr));
+	mReq->ptr->token    = length << ffs_nr(TD_TOTAL_BYTES);
+	mReq->ptr->token   &= TD_TOTAL_BYTES;
+	mReq->ptr->token   |= TD_STATUS_ACTIVE;
+	if (mReq->zptr) {
+		mReq->ptr->next    = mReq->zdma;
+	} else {
+		mReq->ptr->next    = TD_TERMINATE;
+		if (!mReq->req.no_interrupt)
+			mReq->ptr->token  |= TD_IOC;
+	}
+
+	/* MSM Specific: updating the request as required for
+	 * SPS mode. Enable MSM DMA engine according
+	 * to the UDC private data in the request.
+	 */
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			mReq->ptr->token = TD_STATUS_ACTIVE;
+			if (mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER)
+				mReq->ptr->next = TD_TERMINATE;
+			else
+				mReq->ptr->next = MSM_ETD_TYPE | mReq->dma;
+			if (!mReq->req.no_interrupt)
+				mReq->ptr->token |= MSM_ETD_IOC;
+		}
+		mReq->req.dma = 0;
+	}
+
+	mReq->ptr->page[0]  = mReq->req.dma;
+	for (i = 1; i < 5; i++)
+		mReq->ptr->page[i] = (mReq->req.dma + i * CI13XXX_PAGE_SIZE) &
+							~TD_RESERVED_MASK;
+	/* Makes sure that above write goes through */
+	wmb();
+
+	/* Remote Wakeup */
+	if (udc->suspended) {
+		if (!udc->gadget.remote_wakeup) {
+			mReq->req.status = -EAGAIN;
+
+			dev_dbg(mEp->device, "%s: queue failed (suspend).",
+					__func__);
+			dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+					__func__, mEp->num);
+
+			return -EAGAIN;
+		}
+
+		usb_phy_set_suspend(udc->transceiver, 0);
+		schedule_delayed_work(&udc->rw_work, REMOTE_WAKEUP_DELAY);
+	}
+
+	if (!list_empty(&mEp->qh.queue)) {
+		struct ci13xxx_req *mReqPrev;
+		int n = hw_ep_bit(mEp->num, mEp->dir);
+		int tmp_stat;
+		ktime_t start, diff;
+
+		mReqPrev = list_entry(mEp->qh.queue.prev,
+				struct ci13xxx_req, queue);
+		if (mReqPrev->zptr)
+			mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+		else
+			mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+		/* Makes sure that above write goes through */
+		wmb();
+		if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
+			goto done;
+		start = ktime_get();
+		do {
+			hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
+			tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
+			diff = ktime_sub(ktime_get(), start);
+			/* poll for max. 100ms */
+			if (ktime_to_ms(diff) > USB_MAX_TIMEOUT) {
+				if (hw_cread(CAP_USBCMD, USBCMD_ATDTW))
+					break;
+				printk_ratelimited(KERN_ERR
+				"%s:queue failed ep#%d %s\n",
+				 __func__, mEp->num, mEp->dir ? "IN" : "OUT");
+				return -EAGAIN;
+			}
+		} while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
+		hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
+		if (tmp_stat)
+			goto done;
+	}
+
+	/* Hardware may leave few TDs unprocessed, check and reprime with 1st */
+	if (!list_empty(&mEp->qh.queue)) {
+		struct ci13xxx_req *mReq_active, *mReq_next;
+		u32 i = 0;
+
+		/* Nothing to be done if hardware already finished this TD */
+		if ((TD_STATUS_ACTIVE & mReq->ptr->token) == 0)
+			goto done;
+
+		/* Iterate forward to find first TD with ACTIVE bit set */
+		mReq_active = mReq;
+		list_for_each_entry(mReq_next, &mEp->qh.queue, queue) {
+			i++;
+			mEp->dTD_active_re_q_count++;
+			if (TD_STATUS_ACTIVE & mReq_next->ptr->token) {
+				mReq_active = mReq_next;
+				dbg_event(_usb_addr(mEp), "ReQUE",
+					  mReq_next->ptr->token);
+				pr_debug("!!ReQ(%u-%u-%x)-%u!!\n", mEp->num,
+					 mEp->dir, mReq_next->ptr->token, i);
+				break;
+			}
+		}
+
+		/*  QH configuration */
+		mEp->qh.ptr->td.next = mReq_active->dma;
+		mEp->qh.ptr->td.token &= ~TD_STATUS;
+		goto prime;
+	}
+
+	/*  QH configuration */
+	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
+
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			mEp->qh.ptr->td.next   |= MSM_ETD_TYPE;
+			i = hw_cread(CAP_ENDPTPIPEID +
+						 mEp->num * sizeof(u32), ~0);
+			/* Read current value of this EPs pipe id */
+			i = (mEp->dir == TX) ?
+				((i >> MSM_TX_PIPE_ID_OFS) & MSM_PIPE_ID_MASK) :
+					(i & MSM_PIPE_ID_MASK);
+			/*
+			 * If requested pipe id is different from current,
+			 * then write it
+			 */
+			if (i != (mReq->req.udc_priv & MSM_PIPE_ID_MASK)) {
+				if (mEp->dir == TX)
+					hw_cwrite(
+						CAP_ENDPTPIPEID +
+							mEp->num * sizeof(u32),
+						MSM_PIPE_ID_MASK <<
+							MSM_TX_PIPE_ID_OFS,
+						(mReq->req.udc_priv &
+						 MSM_PIPE_ID_MASK)
+							<< MSM_TX_PIPE_ID_OFS);
+				else
+					hw_cwrite(
+						CAP_ENDPTPIPEID +
+							mEp->num * sizeof(u32),
+						MSM_PIPE_ID_MASK,
+						mReq->req.udc_priv &
+							MSM_PIPE_ID_MASK);
+			}
+		}
+	}
+
+	mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
+	mEp->qh.ptr->cap |=  QH_ZLT;
+
+prime:
+	/* Makes sure that above write goes through */
+	wmb();   /* synchronize before ep prime */
+
+	ret = hw_ep_prime(mEp->num, mEp->dir,
+			   mEp->type == USB_ENDPOINT_XFER_CONTROL);
+	if (!ret)
+		mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+
+done:
+	return ret;
+}
+
+/**
+ * _hardware_dequeue: handles a request at hardware level
+ * @gadget: gadget
+ * @mEp:    endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+	trace("%pK, %pK", mEp, mReq);
+
+	if (mReq->req.status != -EALREADY)
+		return -EINVAL;
+
+	/* clean speculative fetches on req->ptr->token */
+	mb();
+
+	if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+		return -EBUSY;
+
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID)
+		if ((mReq->req.udc_priv & MSM_SPS_MODE) &&
+			(mReq->req.udc_priv & MSM_IS_FINITE_TRANSFER))
+			return -EBUSY;
+	if (mReq->zptr) {
+		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+			return -EBUSY;
+
+		/* The controller may access this dTD one more time.
+		 * Defer freeing this to next zero length dTD completion.
+		 * It is safe to assume that controller will no longer
+		 * access the previous dTD after next dTD completion.
+		 */
+		if (mEp->last_zptr)
+			dma_pool_free(mEp->td_pool, mEp->last_zptr,
+					mEp->last_zdma);
+		mEp->last_zptr = mReq->zptr;
+		mEp->last_zdma = mReq->zdma;
+
+		mReq->zptr = NULL;
+	}
+
+	mReq->req.status = 0;
+
+	if (mReq->map) {
+		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
+				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		mReq->req.dma = DMA_ERROR_CODE;
+		mReq->map     = 0;
+	}
+
+	mReq->req.status = mReq->ptr->token & TD_STATUS;
+	if ((TD_STATUS_HALTED & mReq->req.status) != 0)
+		mReq->req.status = -1;
+	else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
+		mReq->req.status = -1;
+	else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
+		mReq->req.status = -1;
+
+	mReq->req.actual   = mReq->ptr->token & TD_TOTAL_BYTES;
+	mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+	mReq->req.actual   = mReq->req.length - mReq->req.actual;
+	mReq->req.actual   = mReq->req.status ? 0 : mReq->req.actual;
+
+	return mReq->req.actual;
+}
+
+/**
+ * purge_rw_queue: Purge requests pending at the remote-wakeup
+ * queue and send them to the HW.
+ *
+ * Go over all of the endpoints and push any pending requests to
+ * the HW queue.
+ */
+static void purge_rw_queue(struct ci13xxx *udc)
+{
+	int i;
+	struct ci13xxx_ep  *mEp  = NULL;
+	struct ci13xxx_req *mReq = NULL;
+
+	/*
+	 * Go over all of the endpoints and push any pending requests to
+	 * the HW queue.
+	 */
+	for (i = 0; i < hw_ep_max; i++) {
+		mEp = &udc->ci13xxx_ep[i];
+
+		while (!list_empty(&udc->ci13xxx_ep[i].rw_queue)) {
+			int retval;
+
+			/* pop oldest request */
+			mReq = list_entry(udc->ci13xxx_ep[i].rw_queue.next,
+					  struct ci13xxx_req, queue);
+
+			list_del_init(&mReq->queue);
+
+			retval = _hardware_enqueue(mEp, mReq);
+
+			if (retval != 0) {
+				dbg_event(_usb_addr(mEp), "QUEUE", retval);
+				mReq->req.status = retval;
+				if (mReq->req.complete != NULL) {
+					if (mEp->type ==
+					    USB_ENDPOINT_XFER_CONTROL)
+						mReq->req.complete(
+							&(_udc->ep0in.ep),
+							&mReq->req);
+					else
+						mReq->req.complete(
+							&mEp->ep,
+							&mReq->req);
+				}
+				retval = 0;
+			}
+
+			if (!retval)
+				list_add_tail(&mReq->queue, &mEp->qh.queue);
+			else if (mEp->multi_req)
+				mEp->multi_req = false;
+
+		}
+	}
+
+	udc->rw_pending = false;
+}
+
+/**
+ * restore_original_req: Restore original req's attributes
+ * @mReq: Request
+ *
+ * This function restores original req's attributes.  Call
+ * this function before completing the large req (>16K).
+ */
+static void restore_original_req(struct ci13xxx_req *mReq)
+{
+	mReq->req.buf = mReq->multi.buf;
+	mReq->req.length = mReq->multi.len;
+	if (!mReq->req.status)
+		mReq->req.actual = mReq->multi.actual;
+
+	mReq->multi.len = 0;
+	mReq->multi.actual = 0;
+	mReq->multi.buf = NULL;
+}
+
+/**
+ * release_ep_request: Free and endpoint request and release
+ * resources
+ * @mReq: request
+ * @mEp: endpoint
+ *
+ */
+static void release_ep_request(struct ci13xxx_ep  *mEp,
+			       struct ci13xxx_req *mReq)
+{
+	struct ci13xxx_ep *mEpTemp = mEp;
+
+	unsigned int val;
+
+	/* MSM Specific: Clear end point specific register */
+	if (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID) {
+		if (mReq->req.udc_priv & MSM_SPS_MODE) {
+			val = hw_cread(CAP_ENDPTPIPEID +
+				mEp->num * sizeof(u32),
+				~0);
+
+			if (val != MSM_EP_PIPE_ID_RESET_VAL)
+				hw_cwrite(
+					CAP_ENDPTPIPEID +
+					 mEp->num * sizeof(u32),
+					~0, MSM_EP_PIPE_ID_RESET_VAL);
+		}
+	}
+	mReq->req.status = -ESHUTDOWN;
+
+	if (mReq->map) {
+		dma_unmap_single(mEp->device, mReq->req.dma,
+			mReq->req.length,
+			mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		mReq->req.dma = DMA_ERROR_CODE;
+		mReq->map     = 0;
+	}
+
+	if (mReq->zptr) {
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+		mReq->zdma = 0;
+	}
+
+	if (mEp->multi_req) {
+		restore_original_req(mReq);
+		mEp->multi_req = false;
+	}
+
+	if (mReq->req.complete != NULL) {
+		spin_unlock(mEp->lock);
+		if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+			mReq->req.length)
+			mEpTemp = &_udc->ep0in;
+		mReq->req.complete(&mEpTemp->ep, &mReq->req);
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mReq->req.complete = NULL;
+		spin_lock(mEp->lock);
+	}
+}
+
+/**
+ * _ep_nuke: dequeues all endpoint requests
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int _ep_nuke(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	trace("%pK", mEp);
+
+	if (mEp == NULL)
+		return -EINVAL;
+
+	del_timer(&mEp->prime_timer);
+	mEp->prime_timer_count = 0;
+
+	hw_ep_flush(mEp->num, mEp->dir);
+
+	while (!list_empty(&mEp->qh.queue)) {
+		/* pop oldest request */
+		struct ci13xxx_req *mReq =
+			list_entry(mEp->qh.queue.next,
+				   struct ci13xxx_req, queue);
+		list_del_init(&mReq->queue);
+
+		release_ep_request(mEp, mReq);
+	}
+
+	/* Clear the requests pending at the remote-wakeup queue */
+	while (!list_empty(&mEp->rw_queue)) {
+
+		/* pop oldest request */
+		struct ci13xxx_req *mReq =
+			list_entry(mEp->rw_queue.next,
+				   struct ci13xxx_req, queue);
+
+		list_del_init(&mReq->queue);
+
+		release_ep_request(mEp, mReq);
+	}
+
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+		mEp->last_zptr = NULL;
+		mEp->last_zdma = 0;
+	}
+
+	return 0;
+}
+
+/**
+ * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
+ * @gadget: gadget
+ *
+ * This function returns an error code
+ */
+static int _gadget_stop_activity(struct usb_gadget *gadget)
+{
+	struct ci13xxx    *udc = container_of(gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+
+	trace("%pK", gadget);
+
+	if (gadget == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(udc->lock, flags);
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->gadget.remote_wakeup = 0;
+	udc->suspended = 0;
+	udc->configured = 0;
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	udc->driver->disconnect(gadget);
+
+	spin_lock_irqsave(udc->lock, flags);
+	_ep_nuke(&udc->ep0out);
+	_ep_nuke(&udc->ep0in);
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	return 0;
+}
+
+/******************************************************************************
+ * ISR block
+ *****************************************************************************/
+/**
+ * isr_reset_handler: USB reset interrupt handler
+ * @udc: UDC device
+ *
+ * This function resets USB engine after a bus reset occurred
+ */
+static void isr_reset_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+	int retval;
+
+	trace("%pK", udc);
+
+	if (udc == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	dbg_event(0xFF, "BUS RST", 0);
+
+	spin_unlock(udc->lock);
+
+	if (udc->suspended) {
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+			CI13XXX_CONTROLLER_RESUME_EVENT);
+		if (udc->transceiver)
+			usb_phy_set_suspend(udc->transceiver, 0);
+		udc->driver->resume(&udc->gadget);
+		udc->suspended = 0;
+	}
+
+	/*stop charging upon reset */
+	if (udc->transceiver)
+		usb_phy_set_power(udc->transceiver, 100);
+
+	retval = _gadget_stop_activity(&udc->gadget);
+	if (retval)
+		goto done;
+
+	if (udc->rw_pending)
+		purge_rw_queue(udc);
+
+	_udc->skip_flush = false;
+	retval = hw_usb_reset();
+	if (retval)
+		goto done;
+
+	spin_lock(udc->lock);
+
+ done:
+	if (retval)
+		err("error: %i", retval);
+}
+
+/**
+ * isr_resume_handler: USB PCI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_resume_handler(struct ci13xxx *udc)
+{
+	udc->gadget.speed = hw_port_is_high_speed() ?
+		USB_SPEED_HIGH : USB_SPEED_FULL;
+	if (udc->suspended) {
+		spin_unlock(udc->lock);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+			  CI13XXX_CONTROLLER_RESUME_EVENT);
+		if (udc->transceiver)
+			usb_phy_set_suspend(udc->transceiver, 0);
+		udc->suspended = 0;
+		udc->driver->resume(&udc->gadget);
+		spin_lock(udc->lock);
+
+		if (udc->rw_pending)
+			purge_rw_queue(udc);
+
+	}
+}
+
+/**
+ * isr_resume_handler: USB SLI interrupt handler
+ * @udc: UDC device
+ *
+ */
+static void isr_suspend_handler(struct ci13xxx *udc)
+{
+	if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+		udc->vbus_active) {
+		if (udc->suspended == 0) {
+			spin_unlock(udc->lock);
+			udc->driver->suspend(&udc->gadget);
+			if (udc->udc_driver->notify_event)
+				udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_SUSPEND_EVENT);
+			if (udc->transceiver)
+				usb_phy_set_suspend(udc->transceiver, 1);
+			spin_lock(udc->lock);
+			udc->suspended = 1;
+		}
+	}
+}
+
+/**
+ * isr_get_status_complete: get_status request complete function
+ * @ep:  endpoint
+ * @req: request handled
+ *
+ * Caller must release lock
+ */
+static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	trace("%pK, %pK", ep, req);
+
+	if (ep == NULL || req == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	if (req->status)
+		err("GET_STATUS failed");
+}
+
+/**
+ * isr_get_status_response: get_status request response
+ * @udc: udc struct
+ * @setup: setup request packet
+ *
+ * This function returns an error code
+ */
+static int isr_get_status_response(struct ci13xxx *udc,
+				   struct usb_ctrlrequest *setup)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	struct ci13xxx_ep *mEp = &udc->ep0in;
+	struct usb_request *req = udc->status;
+	int dir, num, retval;
+
+	trace("%pK, %pK", mEp, setup);
+
+	if (mEp == NULL || setup == NULL)
+		return -EINVAL;
+
+	req->complete = isr_get_status_complete;
+	req->length   = 2;
+	req->buf      = udc->status_buf;
+
+	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+		/* Assume that device is bus powered for now. */
+		*((u16 *)req->buf) = _udc->gadget.remote_wakeup << 1;
+		retval = 0;
+	} else if ((setup->bRequestType & USB_RECIP_MASK) ==
+							USB_RECIP_ENDPOINT) {
+		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
+			TX : RX;
+		num =  le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+		*((u16 *)req->buf) = hw_ep_get_halt(num, dir);
+	}
+	/* else do nothing; reserved for future use */
+
+	spin_unlock(mEp->lock);
+	retval = usb_ep_queue(&mEp->ep, req, GFP_ATOMIC);
+	spin_lock(mEp->lock);
+	return retval;
+}
+
+/**
+ * isr_setup_status_complete: setup_status request complete function
+ * @ep:  endpoint
+ * @req: request handled
+ *
+ * Caller must release lock. Put the port in test mode if test mode
+ * feature is selected.
+ */
+static void
+isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx *udc = req->context;
+	unsigned long flags;
+
+	trace("%pK, %pK", ep, req);
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (udc->test_mode)
+		hw_port_test_set(udc->test_mode);
+	spin_unlock_irqrestore(udc->lock, flags);
+}
+
+/**
+ * isr_setup_status_phase: queues the status phase of a setup transation
+ * @udc: udc struct
+ *
+ * This function returns an error code
+ */
+static int isr_setup_status_phase(struct ci13xxx *udc)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	int retval;
+	struct ci13xxx_ep *mEp;
+
+	trace("%pK", udc);
+
+	mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
+	udc->status->context = udc;
+	udc->status->complete = isr_setup_status_complete;
+	udc->status->length = 0;
+
+	spin_unlock(mEp->lock);
+	retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
+	spin_lock(mEp->lock);
+
+	return retval;
+}
+
+/**
+ * isr_tr_complete_low: transaction complete low level handler
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+	struct ci13xxx_req *mReq, *mReqTemp;
+	struct ci13xxx_ep *mEpTemp = mEp;
+	int retval = 0;
+	int req_dequeue = 1;
+	struct ci13xxx *udc = _udc;
+
+	trace("%pK", mEp);
+
+	if (list_empty(&mEp->qh.queue))
+		return 0;
+
+	del_timer(&mEp->prime_timer);
+	mEp->prime_timer_count = 0;
+	list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
+			queue) {
+dequeue:
+		retval = _hardware_dequeue(mEp, mReq);
+		if (retval < 0) {
+			/*
+			 * FIXME: don't know exact delay
+			 * required for HW to update dTD status
+			 * bits. This is a temporary workaround till
+			 * HW designers come back on this.
+			 */
+			if (retval == -EBUSY && req_dequeue &&
+				(mEp->dir == 0 || mEp->num == 0)) {
+				req_dequeue = 0;
+				udc->dTD_update_fail_count++;
+				mEp->dTD_update_fail_count++;
+				udelay(10);
+				goto dequeue;
+			}
+			break;
+		}
+		req_dequeue = 0;
+
+		if (mEp->multi_req) { /* Large request in progress */
+			unsigned int remain_len;
+
+			mReq->multi.actual += mReq->req.actual;
+			remain_len = mReq->multi.len - mReq->multi.actual;
+			if (mReq->req.status || !remain_len ||
+				(mReq->req.actual != mReq->req.length)) {
+				restore_original_req(mReq);
+				mEp->multi_req = false;
+			} else {
+				mReq->req.buf = mReq->multi.buf +
+						mReq->multi.actual;
+				mReq->req.length = min_t(unsigned int,
+							remain_len,
+							4 * CI13XXX_PAGE_SIZE);
+
+				mReq->req.status = -EINPROGRESS;
+				mReq->req.actual = 0;
+				list_del_init(&mReq->queue);
+				retval = _hardware_enqueue(mEp, mReq);
+				if (retval) {
+					err("Large req failed in middle");
+					mReq->req.status = retval;
+					restore_original_req(mReq);
+					mEp->multi_req = false;
+					goto done;
+				} else {
+					list_add_tail(&mReq->queue,
+						&mEp->qh.queue);
+					return 0;
+				}
+			}
+		}
+		list_del_init(&mReq->queue);
+done:
+
+		dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+
+		if (mReq->req.complete != NULL) {
+			spin_unlock(mEp->lock);
+			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+					mReq->req.length)
+				mEpTemp = &_udc->ep0in;
+			mReq->req.complete(&mEpTemp->ep, &mReq->req);
+			spin_lock(mEp->lock);
+		}
+	}
+
+	if (retval == -EBUSY)
+		retval = 0;
+	if (retval < 0)
+		dbg_event(_usb_addr(mEp), "DONE", retval);
+
+	return retval;
+}
+
+/**
+ * isr_tr_complete_handler: transaction complete interrupt handler
+ * @udc: UDC descriptor
+ *
+ * This function handles traffic events
+ */
+static void isr_tr_complete_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+	unsigned int i;
+	u8 tmode = 0;
+
+	trace("%pK", udc);
+
+	if (udc == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp  = &udc->ci13xxx_ep[i];
+		int type, num, dir, err = -EINVAL;
+		struct usb_ctrlrequest req;
+
+		if (mEp->desc == NULL)
+			continue;   /* not configured */
+
+		if (hw_test_and_clear_complete(i)) {
+			err = isr_tr_complete_low(mEp);
+			if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+				if (err > 0)   /* needs status phase */
+					err = isr_setup_status_phase(udc);
+				if (err < 0) {
+					dbg_event(_usb_addr(mEp),
+						  "ERROR", err);
+					spin_unlock(udc->lock);
+					if (usb_ep_set_halt(&mEp->ep))
+						err("error: ep_set_halt");
+					spin_lock(udc->lock);
+				}
+			}
+		}
+
+		if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
+		    !hw_test_and_clear_setup_status(i))
+			continue;
+
+		if (i != 0) {
+			warn("ctrl traffic received at endpoint");
+			continue;
+		}
+
+		/*
+		 * Flush data and handshake transactions of previous
+		 * setup packet.
+		 */
+		_ep_nuke(&udc->ep0out);
+		_ep_nuke(&udc->ep0in);
+
+		/* read_setup_packet */
+		do {
+			hw_test_and_set_setup_guard();
+			memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
+			/* Ensure buffer is read before acknowledging to h/w */
+			mb();
+		} while (!hw_test_and_clear_setup_guard());
+
+		type = req.bRequestType;
+
+		udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
+
+		dbg_setup(_usb_addr(mEp), &req);
+
+		switch (req.bRequest) {
+		case USB_REQ_CLEAR_FEATURE:
+			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+					le16_to_cpu(req.wValue) ==
+					USB_ENDPOINT_HALT) {
+				if (req.wLength != 0)
+					break;
+				num  = le16_to_cpu(req.wIndex);
+				dir = num & USB_ENDPOINT_DIR_MASK;
+				num &= USB_ENDPOINT_NUMBER_MASK;
+				if (dir) /* TX */
+					num += hw_ep_max/2;
+				if (!udc->ci13xxx_ep[num].wedge) {
+					spin_unlock(udc->lock);
+					err = usb_ep_clear_halt(
+						&udc->ci13xxx_ep[num].ep);
+					spin_lock(udc->lock);
+					if (err)
+						break;
+				}
+				err = isr_setup_status_phase(udc);
+			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
+					le16_to_cpu(req.wValue) ==
+					USB_DEVICE_REMOTE_WAKEUP) {
+				if (req.wLength != 0)
+					break;
+				udc->gadget.remote_wakeup = 0;
+				err = isr_setup_status_phase(udc);
+			} else {
+				goto delegate;
+			}
+			break;
+		case USB_REQ_GET_STATUS:
+			if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   &&
+			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
+			    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
+				goto delegate;
+			if (le16_to_cpu(req.wLength) != 2 ||
+			    le16_to_cpu(req.wValue)  != 0)
+				break;
+			err = isr_get_status_response(udc, &req);
+			break;
+		case USB_REQ_SET_ADDRESS:
+			if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
+				goto delegate;
+			if (le16_to_cpu(req.wLength) != 0 ||
+			    le16_to_cpu(req.wIndex)  != 0)
+				break;
+			err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
+			if (err)
+				break;
+			err = isr_setup_status_phase(udc);
+			break;
+		case USB_REQ_SET_CONFIGURATION:
+			if (type == (USB_DIR_OUT|USB_TYPE_STANDARD))
+				udc->configured = !!req.wValue;
+			goto delegate;
+		case USB_REQ_SET_FEATURE:
+			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+					le16_to_cpu(req.wValue) ==
+					USB_ENDPOINT_HALT) {
+				if (req.wLength != 0)
+					break;
+				num  = le16_to_cpu(req.wIndex);
+				dir = num & USB_ENDPOINT_DIR_MASK;
+				num &= USB_ENDPOINT_NUMBER_MASK;
+				if (dir) /* TX */
+					num += hw_ep_max/2;
+
+				spin_unlock(udc->lock);
+				err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
+				spin_lock(udc->lock);
+				if (!err)
+					isr_setup_status_phase(udc);
+			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
+				if (req.wLength != 0)
+					break;
+				switch (le16_to_cpu(req.wValue)) {
+				case USB_DEVICE_REMOTE_WAKEUP:
+					udc->gadget.remote_wakeup = 1;
+					err = isr_setup_status_phase(udc);
+					break;
+				case USB_DEVICE_TEST_MODE:
+					tmode = le16_to_cpu(req.wIndex) >> 8;
+					switch (tmode) {
+					case TEST_J:
+					case TEST_K:
+					case TEST_SE0_NAK:
+					case TEST_PACKET:
+					case TEST_FORCE_EN:
+						udc->test_mode = tmode;
+						err = isr_setup_status_phase(
+								udc);
+						break;
+					default:
+						break;
+					}
+				default:
+					goto delegate;
+				}
+			} else {
+				goto delegate;
+			}
+			break;
+		default:
+delegate:
+			if (req.wLength == 0)   /* no data phase */
+				udc->ep0_dir = TX;
+
+			spin_unlock(udc->lock);
+			err = udc->driver->setup(&udc->gadget, &req);
+			spin_lock(udc->lock);
+			break;
+		}
+
+		if (err < 0) {
+			dbg_event(_usb_addr(mEp), "ERROR", err);
+
+			spin_unlock(udc->lock);
+			if (usb_ep_set_halt(&mEp->ep))
+				err("error: ep_set_halt");
+			spin_lock(udc->lock);
+		}
+	}
+}
+
+/******************************************************************************
+ * ENDPT block
+ *****************************************************************************/
+/**
+ * ep_enable: configure endpoint, making it usable
+ *
+ * Check usb_ep_enable() at "usb_gadget.h" for details
+ */
+static int ep_enable(struct usb_ep *ep,
+		     const struct usb_endpoint_descriptor *desc)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	int retval = 0;
+	unsigned long flags;
+	unsigned int mult = 0;
+
+	trace("ep = %pK, desc = %pK", ep, desc);
+
+	if (ep == NULL || desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	/* only internal SW should enable ctrl endpts */
+
+	mEp->desc = desc;
+
+	if (!list_empty(&mEp->qh.queue))
+		warn("enabling a non-empty endpoint!");
+
+	mEp->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
+	mEp->num  = usb_endpoint_num(desc);
+	mEp->type = usb_endpoint_type(desc);
+
+	mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+
+	dbg_event(_usb_addr(mEp), "ENABLE", 0);
+
+	mEp->qh.ptr->cap = 0;
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+		mEp->qh.ptr->cap |=  QH_IOS;
+	} else if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
+		mEp->qh.ptr->cap &= ~QH_MULT;
+		mult = ((mEp->ep.maxpacket >> QH_MULT_SHIFT) + 1) & 0x03;
+		mEp->qh.ptr->cap |= (mult << ffs_nr(QH_MULT));
+	} else {
+		mEp->qh.ptr->cap |= QH_ZLT;
+	}
+
+	mEp->qh.ptr->cap |=
+		(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+	mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */
+
+	/* complete all the updates to ept->head before enabling endpoint*/
+	mb();
+
+	/*
+	 * Enable endpoints in the HW other than ep0 as ep0
+	 * is always enabled
+	 */
+	if (mEp->num)
+		retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_disable: endpoint is no longer usable
+ *
+ * Check usb_ep_disable() at "usb_gadget.h" for details
+ */
+static int ep_disable(struct usb_ep *ep)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	int direction, retval = 0;
+	unsigned long flags;
+
+	trace("%pK", ep);
+
+	if (ep == NULL)
+		return -EINVAL;
+	else if (mEp->desc == NULL)
+		return -EBUSY;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	/* only internal SW should disable ctrl endpts */
+
+	direction = mEp->dir;
+	do {
+		dbg_event(_usb_addr(mEp), "DISABLE", 0);
+
+		retval |= _ep_nuke(mEp);
+		retval |= hw_ep_disable(mEp->num, mEp->dir);
+
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+	} while (mEp->dir != direction);
+
+	mEp->desc = NULL;
+	mEp->ep.desc = NULL;
+	mEp->ep.maxpacket = USHRT_MAX;
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_alloc_request: allocate a request object to use with this endpoint
+ *
+ * Check usb_ep_alloc_request() at "usb_gadget.h" for details
+ */
+static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep, struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = NULL;
+
+	trace("%pK, %i", ep, gfp_flags);
+
+	if (ep == NULL) {
+		err("EINVAL");
+		return NULL;
+	}
+
+	mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
+	if (mReq != NULL) {
+		INIT_LIST_HEAD(&mReq->queue);
+		mReq->req.dma = DMA_ERROR_CODE;
+
+		mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
+					   &mReq->dma);
+		if (mReq->ptr == NULL) {
+			kfree(mReq);
+			mReq = NULL;
+		}
+	}
+
+	dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
+
+	return (mReq == NULL) ? NULL : &mReq->req;
+}
+
+/**
+ * ep_free_request: frees a request object
+ *
+ * Check usb_ep_free_request() at "usb_gadget.h" for details
+ */
+static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	unsigned long flags;
+
+	trace("%pK, %pK", ep, req);
+
+	if (ep == NULL || req == NULL) {
+		err("EINVAL");
+		return;
+	} else if (!list_empty(&mReq->queue)) {
+		err("EBUSY");
+		return;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	if (mReq->ptr)
+		dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
+	kfree(mReq);
+
+	dbg_event(_usb_addr(mEp), "FREE", 0);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Check usb_ep_queue()* at usb_gadget.h" for details
+ */
+static int ep_queue(struct usb_ep *ep, struct usb_request *req,
+		    gfp_t __maybe_unused gfp_flags)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	int retval = 0;
+	unsigned long flags;
+	struct ci13xxx *udc = _udc;
+
+	trace("%pK, %pK, %X", ep, req, gfp_flags);
+
+	if (ep == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+	if (req == NULL || mEp->desc == NULL) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+	if (!udc->softconnect) {
+		retval = -ENODEV;
+		goto done;
+	}
+
+	if (!udc->configured && mEp->type !=
+		USB_ENDPOINT_XFER_CONTROL) {
+		trace("usb is not configured ept #%d, ept name#%s\n",
+			mEp->num, mEp->ep.name);
+		retval = -ESHUTDOWN;
+		goto done;
+	}
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+		if (req->length)
+			mEp = (_udc->ep0_dir == RX) ?
+				&_udc->ep0out : &_udc->ep0in;
+		if (!list_empty(&mEp->qh.queue)) {
+			_ep_nuke(mEp);
+			retval = -EOVERFLOW;
+			warn("endpoint ctrl %X nuked", _usb_addr(mEp));
+		}
+	}
+
+	if (ep->endless && udc->gadget.speed == USB_SPEED_FULL) {
+		err("Queueing endless req is not supported for FS");
+		retval = -EINVAL;
+		goto done;
+	}
+
+	/* first nuke then test link, e.g. previous status has not sent */
+	if (!list_empty(&mReq->queue)) {
+		retval = -EBUSY;
+		err("request already in queue");
+		goto done;
+	}
+	if (mEp->multi_req) {
+		retval = -EAGAIN;
+		err("Large request is in progress. come again");
+		goto done;
+	}
+
+	if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
+		if (!list_empty(&mEp->qh.queue)) {
+			retval = -EAGAIN;
+			err("Queue is busy. Large req is not allowed");
+			goto done;
+		}
+		if ((mEp->type != USB_ENDPOINT_XFER_BULK) ||
+				(mEp->dir != RX)) {
+			retval = -EINVAL;
+			err("Larger req is supported only for Bulk OUT");
+			goto done;
+		}
+		mEp->multi_req = true;
+		mReq->multi.len = req->length;
+		mReq->multi.buf = req->buf;
+		req->length = (4 * CI13XXX_PAGE_SIZE);
+	}
+
+	dbg_queue(_usb_addr(mEp), req, retval);
+
+	/* push request */
+	mReq->req.status = -EINPROGRESS;
+	mReq->req.actual = 0;
+
+	if (udc->rw_pending) {
+		list_add_tail(&mReq->queue, &mEp->rw_queue);
+		retval = 0;
+		goto done;
+	}
+
+	if (udc->suspended) {
+		/* Remote Wakeup */
+		if (!udc->gadget.remote_wakeup) {
+
+			dev_dbg(mEp->device, "%s: queue failed (suspend).",
+					__func__);
+			dev_dbg(mEp->device, "%s: Remote wakeup is not supported. ept #%d\n",
+					__func__, mEp->num);
+			mEp->multi_req = false;
+
+			retval = -EAGAIN;
+			goto done;
+		}
+
+		list_add_tail(&mReq->queue, &mEp->rw_queue);
+
+		udc->rw_pending = true;
+		schedule_delayed_work(&udc->rw_work,
+				      REMOTE_WAKEUP_DELAY);
+
+		retval = 0;
+		goto done;
+	}
+
+	retval = _hardware_enqueue(mEp, mReq);
+
+	if (retval == -EALREADY) {
+		dbg_event(_usb_addr(mEp), "QUEUE", retval);
+		retval = 0;
+	}
+	if (!retval)
+		list_add_tail(&mReq->queue, &mEp->qh.queue);
+	else if (mEp->multi_req)
+		mEp->multi_req = false;
+
+ done:
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
+ *
+ * Check usb_ep_dequeue() at "usb_gadget.h" for details
+ */
+static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep);
+	struct ci13xxx_ep *mEpTemp = mEp;
+	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+
+	trace("%pK, %pK", ep, req);
+
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		dev_err(udc->transceiver->dev,
+				"%s: Unable to dequeue while in LPM\n",
+				__func__);
+		return -EAGAIN;
+	}
+
+	if (ep == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+	/*
+	 * Only ep0 IN is exposed to composite.  When a req is dequeued
+	 * on ep0, check both ep0 IN and ep0 OUT queues.
+	 */
+	if (req == NULL || mReq->req.status != -EALREADY ||
+		mEp->desc == NULL || list_empty(&mReq->queue) ||
+		(list_empty(&mEp->qh.queue) && ((mEp->type !=
+			USB_ENDPOINT_XFER_CONTROL) ||
+			list_empty(&_udc->ep0out.qh.queue)))) {
+		spin_unlock_irqrestore(mEp->lock, flags);
+		return -EINVAL;
+	}
+
+	dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
+
+	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+		hw_ep_flush(_udc->ep0out.num, RX);
+		hw_ep_flush(_udc->ep0in.num, TX);
+	} else {
+		hw_ep_flush(mEp->num, mEp->dir);
+	}
+
+	/* pop request */
+	list_del_init(&mReq->queue);
+	if (mReq->map) {
+		dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
+				 mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		mReq->req.dma = DMA_ERROR_CODE;
+		mReq->map     = 0;
+	}
+	req->status = -ECONNRESET;
+
+	if (mEp->last_zptr) {
+		dma_pool_free(mEp->td_pool, mEp->last_zptr, mEp->last_zdma);
+		mEp->last_zptr = NULL;
+		mEp->last_zdma = 0;
+	}
+
+	if (mReq->zptr) {
+		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+		mReq->zptr = NULL;
+		mReq->zdma = 0;
+	}
+
+	if (mEp->multi_req) {
+		restore_original_req(mReq);
+		mEp->multi_req = false;
+	}
+
+	if (mReq->req.complete != NULL) {
+		spin_unlock(mEp->lock);
+		if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+				mReq->req.length)
+			mEpTemp = &_udc->ep0in;
+		mReq->req.complete(&mEpTemp->ep, &mReq->req);
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mReq->req.complete = NULL;
+		spin_lock(mEp->lock);
+	}
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return 0;
+}
+
+static int is_sps_req(struct ci13xxx_req *mReq)
+{
+	return (CI13XX_REQ_VENDOR_ID(mReq->req.udc_priv) == MSM_VENDOR_ID &&
+			mReq->req.udc_priv & MSM_SPS_MODE);
+}
+
+/**
+ * ep_set_halt: sets the endpoint halt feature
+ *
+ * Check usb_ep_set_halt() at "usb_gadget.h" for details
+ */
+static int ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	struct ci13xxx *udc = _udc;
+	int direction, retval = 0;
+	unsigned long flags;
+
+	trace("%pK, %i", ep, value);
+
+	if (ep == NULL || mEp->desc == NULL)
+		return -EINVAL;
+
+	if (udc->suspended) {
+		dev_err(udc->transceiver->dev,
+			"%s: Unable to halt EP while suspended\n", __func__);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+#ifndef STALL_IN
+	/* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
+	if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
+		!list_empty(&mEp->qh.queue) &&
+		!is_sps_req(list_entry(mEp->qh.queue.next, struct ci13xxx_req,
+							   queue))){
+		spin_unlock_irqrestore(mEp->lock, flags);
+		return -EAGAIN;
+	}
+#endif
+
+	direction = mEp->dir;
+	do {
+		dbg_event(_usb_addr(mEp), "HALT", value);
+		retval |= hw_ep_set_halt(mEp->num, mEp->dir, value);
+
+		if (!value)
+			mEp->wedge = 0;
+
+		if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+			mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+	} while (mEp->dir != direction);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+	return retval;
+}
+
+/**
+ * ep_set_wedge: sets the halt feature and ignores clear requests
+ *
+ * Check usb_ep_set_wedge() at "usb_gadget.h" for details
+ */
+static int ep_set_wedge(struct usb_ep *ep)
+{
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	unsigned long flags;
+
+	trace("%pK", ep);
+
+	if (ep == NULL || mEp->desc == NULL)
+		return -EINVAL;
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	dbg_event(_usb_addr(mEp), "WEDGE", 0);
+	mEp->wedge = 1;
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+
+	return usb_ep_set_halt(ep);
+}
+
+/**
+ * ep_fifo_flush: flushes contents of a fifo
+ *
+ * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
+ */
+static void ep_fifo_flush(struct usb_ep *ep)
+{
+	struct ci13xxx *udc = _udc;
+	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+	unsigned long flags;
+
+	trace("%pK", ep);
+
+	if (ep == NULL) {
+		err("%02X: -EINVAL", _usb_addr(mEp));
+		return;
+	}
+
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		dev_err(udc->transceiver->dev,
+				"%s: Unable to fifo_flush while in LPM\n",
+				__func__);
+		return;
+	}
+
+	spin_lock_irqsave(mEp->lock, flags);
+
+	dbg_event(_usb_addr(mEp), "FFLUSH", 0);
+	/*
+	 * _ep_nuke() takes care of flushing the endpoint.
+	 * some function drivers expect udc to retire all
+	 * pending requests upon flushing an endpoint.  There
+	 * is no harm in doing it.
+	 */
+	_ep_nuke(mEp);
+
+	spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * Endpoint-specific part of the API to the USB controller hardware
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_ep_ops usb_ep_ops = {
+	.enable	       = ep_enable,
+	.disable       = ep_disable,
+	.alloc_request = ep_alloc_request,
+	.free_request  = ep_free_request,
+	.queue	       = ep_queue,
+	.dequeue       = ep_dequeue,
+	.set_halt      = ep_set_halt,
+	.set_wedge     = ep_set_wedge,
+	.fifo_flush    = ep_fifo_flush,
+};
+
+/******************************************************************************
+ * GADGET block
+ *****************************************************************************/
+static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+	int gadget_ready = 0;
+
+	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
+		return -EOPNOTSUPP;
+
+	spin_lock_irqsave(udc->lock, flags);
+	udc->vbus_active = is_active;
+	if (udc->driver)
+		gadget_ready = 1;
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	if (!gadget_ready)
+		return 0;
+
+	if (is_active) {
+		hw_device_reset(udc);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_CONNECT_EVENT);
+		/* Enable BAM (if needed) before starting controller */
+		if (udc->softconnect) {
+			dbg_event(0xFF, "BAM EN2",
+				_gadget->bam2bam_func_enabled);
+			msm_usb_bam_enable(CI_CTRL,
+				_gadget->bam2bam_func_enabled);
+			hw_device_state(udc->ep0out.qh.dma);
+		}
+	} else {
+		hw_device_state(0);
+		_gadget_stop_activity(&udc->gadget);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_DISCONNECT_EVENT);
+	}
+
+	return 0;
+}
+
+#define VBUS_DRAW_BUF_LEN 10
+#define MAX_OVERRIDE_VBUS_ALLOWED 900	/* 900 mA */
+static char vbus_draw_mA[VBUS_DRAW_BUF_LEN];
+module_param_string(vbus_draw_mA, vbus_draw_mA, VBUS_DRAW_BUF_LEN, 0644);
+
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned int mA)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned int override_mA = 0;
+
+	/* override param to draw more current if battery draining faster */
+	if ((mA == CONFIG_USB_GADGET_VBUS_DRAW) &&
+		(vbus_draw_mA[0] != '\0')) {
+		if ((!kstrtoint(vbus_draw_mA, 10, &override_mA)) &&
+				(override_mA <= MAX_OVERRIDE_VBUS_ALLOWED)) {
+			mA = override_mA;
+		}
+	}
+
+	if (udc->transceiver)
+		return usb_phy_set_power(udc->transceiver, mA);
+	return -ENOTSUPP;
+}
+
+static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_active)
+{
+	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(udc->lock, flags);
+	udc->softconnect = is_active;
+	if (((udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) &&
+			!udc->vbus_active) || !udc->driver) {
+		spin_unlock_irqrestore(udc->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_get_sync(&_gadget->dev);
+
+	/* Enable BAM (if needed) before starting controller */
+	if (is_active) {
+		dbg_event(0xFF, "BAM EN1", _gadget->bam2bam_func_enabled);
+		msm_usb_bam_enable(CI_CTRL, _gadget->bam2bam_func_enabled);
+	}
+
+	spin_lock_irqsave(udc->lock, flags);
+	if (!udc->vbus_active) {
+		spin_unlock_irqrestore(udc->lock, flags);
+		pm_runtime_put_sync(&_gadget->dev);
+		return 0;
+	}
+	if (is_active) {
+		spin_unlock(udc->lock);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_CONNECT_EVENT);
+		spin_lock(udc->lock);
+		hw_device_state(udc->ep0out.qh.dma);
+	} else {
+		hw_device_state(0);
+	}
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_mark_last_busy(&_gadget->dev);
+	pm_runtime_put_autosuspend(&_gadget->dev);
+
+	return 0;
+}
+
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver);
+static int ci13xxx_stop(struct usb_gadget *gadget);
+
+/**
+ * Device operations part of the API to the USB controller hardware,
+ * which don't involve endpoints (or i/o)
+ * Check  "usb_gadget.h" for details
+ */
+static const struct usb_gadget_ops usb_gadget_ops = {
+	.vbus_session	= ci13xxx_vbus_session,
+	.wakeup		= ci13xxx_wakeup,
+	.vbus_draw	= ci13xxx_vbus_draw,
+	.pullup		= ci13xxx_pullup,
+	.udc_start	= ci13xxx_start,
+	.udc_stop	= ci13xxx_stop,
+};
+
+/**
+ * ci13xxx_start: register a gadget driver
+ * @gadget: our gadget
+ * @driver: the driver being registered
+ *
+ * Interrupts are enabled here.
+ */
+static int ci13xxx_start(struct usb_gadget *gadget,
+			 struct usb_gadget_driver *driver)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+	int retval = -ENOMEM;
+
+	trace("%pK", driver);
+
+	if (driver             == NULL ||
+	    driver->setup      == NULL ||
+	    driver->disconnect == NULL)
+		return -EINVAL;
+	else if (udc         == NULL)
+		return -ENODEV;
+	else if (udc->driver != NULL)
+		return -EBUSY;
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	info("hw_ep_max = %d", hw_ep_max);
+
+	udc->gadget.dev.driver = NULL;
+
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	pm_runtime_get_sync(&udc->gadget.dev);
+
+	udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
+	retval = usb_ep_enable(&udc->ep0out.ep);
+	if (retval)
+		goto pm_put;
+
+	udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
+	retval = usb_ep_enable(&udc->ep0in.ep);
+	if (retval)
+		goto pm_put;
+	udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_KERNEL);
+	if (!udc->status) {
+		retval = -ENOMEM;
+		goto pm_put;
+	}
+
+	udc->status_buf = kzalloc(2 + udc->gadget.extra_buf_alloc,
+				GFP_KERNEL); /* for GET_STATUS */
+	if (!udc->status_buf) {
+		usb_ep_free_request(&udc->ep0in.ep, udc->status);
+		retval = -ENOMEM;
+		goto pm_put;
+	}
+	spin_lock_irqsave(udc->lock, flags);
+
+	udc->gadget.ep0 = &udc->ep0in.ep;
+	/* bind gadget */
+	driver->driver.bus     = NULL;
+	udc->gadget.dev.driver = &driver->driver;
+
+	udc->driver = driver;
+	if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
+		if (udc->vbus_active) {
+			if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
+				hw_device_reset(udc);
+		} else {
+			goto done;
+		}
+	}
+
+	if (!udc->softconnect)
+		goto done;
+
+	retval = hw_device_state(udc->ep0out.qh.dma);
+
+done:
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	if (udc->udc_driver->notify_event)
+		udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_UDC_STARTED_EVENT);
+pm_put:
+	pm_runtime_put(&udc->gadget.dev);
+
+	return retval;
+}
+
+/**
+ * ci13xxx_stop: unregister a gadget driver
+ *
+ * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
+ */
+static int ci13xxx_stop(struct usb_gadget *gadget)
+{
+	struct ci13xxx *udc = _udc;
+	unsigned long flags;
+
+	spin_lock_irqsave(udc->lock, flags);
+
+	if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
+			udc->vbus_active) {
+		hw_device_state(0);
+		spin_unlock_irqrestore(udc->lock, flags);
+		_gadget_stop_activity(&udc->gadget);
+		spin_lock_irqsave(udc->lock, flags);
+	}
+
+	spin_unlock_irqrestore(udc->lock, flags);
+
+	usb_ep_free_request(&udc->ep0in.ep, udc->status);
+	kfree(udc->status_buf);
+
+	return 0;
+}
+
+/******************************************************************************
+ * BUS block
+ *****************************************************************************/
+/**
+ * udc_irq: global interrupt handler
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * It locks access to registers
+ */
+static irqreturn_t udc_irq(void)
+{
+	struct ci13xxx *udc = _udc;
+	irqreturn_t retval;
+	u32 intr;
+
+	trace();
+
+	if (udc == NULL) {
+		err("ENODEV");
+		return IRQ_HANDLED;
+	}
+
+	spin_lock(udc->lock);
+
+	if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
+		spin_unlock(udc->lock);
+		return IRQ_NONE;
+	}
+
+	if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
+		if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
+				USBMODE_CM_DEVICE) {
+			spin_unlock(udc->lock);
+			return IRQ_NONE;
+		}
+	}
+	intr = hw_test_and_clear_intr_active();
+	if (intr) {
+		isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
+		isr_statistics.hndl.idx &= ISR_MASK;
+		isr_statistics.hndl.cnt++;
+
+		/* order defines priority - do NOT change it */
+		if (USBi_URI & intr) {
+			isr_statistics.uri++;
+			if (!hw_cread(CAP_PORTSC, PORTSC_PR))
+				pr_info("%s: USB reset interrupt is delayed\n",
+								__func__);
+			isr_reset_handler(udc);
+		}
+		if (USBi_PCI & intr) {
+			isr_statistics.pci++;
+			isr_resume_handler(udc);
+		}
+		if (USBi_UEI & intr)
+			isr_statistics.uei++;
+		if (USBi_UI  & intr) {
+			isr_statistics.ui++;
+			isr_tr_complete_handler(udc);
+		}
+		if (USBi_SLI & intr) {
+			isr_suspend_handler(udc);
+			isr_statistics.sli++;
+		}
+		retval = IRQ_HANDLED;
+	} else {
+		isr_statistics.none++;
+		retval = IRQ_NONE;
+	}
+	spin_unlock(udc->lock);
+
+	return retval;
+}
+
+static void destroy_eps(struct ci13xxx *ci)
+{
+	int i;
+
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &ci->ci13xxx_ep[i];
+
+		dma_pool_free(ci->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+	}
+}
+
+/**
+ * udc_probe: parent probe must call this to initialize UDC
+ * @dev:  parent device
+ * @regs: registers base address
+ * @name: driver name
+ *
+ * This function returns an error code
+ * No interrupts active, the IRQ has not been requested yet
+ * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
+ */
+static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
+		void __iomem *regs)
+{
+	struct ci13xxx *udc;
+	struct ci13xxx_platform_data *pdata;
+	int retval = 0, i, j;
+
+	trace("%pK, %pK, %pK", dev, regs, driver->name);
+
+	if (dev == NULL || regs == NULL || driver == NULL ||
+			driver->name == NULL)
+		return -EINVAL;
+
+	udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
+	if (udc == NULL)
+		return -ENOMEM;
+
+	udc->lock = &udc_lock;
+	udc->regs = regs;
+	udc->udc_driver = driver;
+
+	udc->gadget.ops          = &usb_gadget_ops;
+	udc->gadget.speed        = USB_SPEED_UNKNOWN;
+	udc->gadget.max_speed    = USB_SPEED_HIGH;
+	udc->gadget.is_otg       = 0;
+	udc->gadget.name         = driver->name;
+
+	/* alloc resources */
+	udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
+				       sizeof(struct ci13xxx_qh),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->qh_pool == NULL) {
+		retval = -ENOMEM;
+		goto free_udc;
+	}
+
+	udc->td_pool = dma_pool_create("ci13xxx_td", dev,
+				       sizeof(struct ci13xxx_td),
+				       64, CI13XXX_PAGE_SIZE);
+	if (udc->td_pool == NULL) {
+		retval = -ENOMEM;
+		goto free_qh_pool;
+	}
+
+	INIT_DELAYED_WORK(&udc->rw_work, usb_do_remote_wakeup);
+
+	retval = hw_device_init(regs);
+	if (retval < 0)
+		goto free_qh_pool;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	for (i = 0; i < hw_ep_max; i++) {
+		struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
+		INIT_LIST_HEAD(&mEp->ep.ep_list);
+		INIT_LIST_HEAD(&mEp->rw_queue);
+		setup_timer(&mEp->prime_timer, ep_prime_timer_func,
+			(unsigned long) mEp);
+	}
+
+	for (i = 0; i < hw_ep_max/2; i++) {
+		for (j = RX; j <= TX; j++) {
+			int k = i + j * hw_ep_max/2;
+			struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
+
+			scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+					(j == TX)  ? "in" : "out");
+
+			mEp->lock         = udc->lock;
+			mEp->device       = &udc->gadget.dev;
+			mEp->td_pool      = udc->td_pool;
+
+			mEp->ep.name      = mEp->name;
+			mEp->ep.ops       = &usb_ep_ops;
+			usb_ep_set_maxpacket_limit(&mEp->ep,
+				k ? USHRT_MAX : CTRL_PAYLOAD_MAX);
+
+			INIT_LIST_HEAD(&mEp->qh.queue);
+			mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+					&mEp->qh.dma);
+			if (mEp->qh.ptr == NULL)
+				retval = -ENOMEM;
+			else
+				memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+			/* skip ep0 out and in endpoints  */
+			if (i == 0)
+				continue;
+
+			list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+		}
+	}
+
+	if (retval)
+		goto free_dma_pools;
+
+	udc->gadget.ep0 = &udc->ep0in.ep;
+
+	pdata = dev->platform_data;
+	if (pdata) {
+		if (pdata->enable_axi_prefetch)
+			udc->gadget.extra_buf_alloc = EXTRA_ALLOCATION_SIZE;
+	}
+
+	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (udc->transceiver == NULL) {
+			retval = -ENODEV;
+			goto destroy_eps;
+		}
+	}
+
+	if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
+		retval = hw_device_reset(udc);
+		if (retval)
+			goto put_transceiver;
+	}
+
+	if (udc->transceiver) {
+		retval = otg_set_peripheral(udc->transceiver->otg,
+						&udc->gadget);
+		if (retval)
+			goto put_transceiver;
+	}
+
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval)
+		goto remove_trans;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	retval = dbg_create_files(&udc->gadget.dev);
+	if (retval) {
+		pr_err("Registering sysfs files for debug failed!!!!\n");
+		goto del_udc;
+	}
+#endif
+
+	pm_runtime_no_callbacks(&udc->gadget.dev);
+	pm_runtime_set_active(&udc->gadget.dev);
+	pm_runtime_enable(&udc->gadget.dev);
+
+	/* Use delayed LPM especially for composition-switch in LPM (suspend) */
+	pm_runtime_set_autosuspend_delay(&udc->gadget.dev, 2000);
+	pm_runtime_use_autosuspend(&udc->gadget.dev);
+
+	_udc = udc;
+	return retval;
+
+del_udc:
+	usb_del_gadget_udc(&udc->gadget);
+remove_trans:
+	if (udc->transceiver)
+		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+
+	err("error = %i", retval);
+put_transceiver:
+	if (udc->transceiver)
+		usb_put_phy(udc->transceiver);
+destroy_eps:
+	destroy_eps(udc);
+free_dma_pools:
+	dma_pool_destroy(udc->td_pool);
+free_qh_pool:
+	dma_pool_destroy(udc->qh_pool);
+free_udc:
+	kfree(udc);
+	_udc = NULL;
+	return retval;
+}
+
+/**
+ * udc_remove: parent remove must call this to remove UDC
+ *
+ * No interrupts active, the IRQ has been released
+ */
+static void udc_remove(void)
+{
+	struct ci13xxx *udc = _udc;
+
+	if (udc == NULL) {
+		err("EINVAL");
+		return;
+	}
+
+	usb_del_gadget_udc(&udc->gadget);
+
+	if (udc->transceiver) {
+		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+		usb_put_phy(udc->transceiver);
+	}
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+	dbg_remove_files(&udc->gadget.dev);
+#endif
+	destroy_eps(udc);
+	dma_pool_destroy(udc->td_pool);
+	dma_pool_destroy(udc->qh_pool);
+
+	kfree(udc);
+	_udc = NULL;
+}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
new file mode 100644
index 0000000..8c93080
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -0,0 +1,282 @@
+/*
+ * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Description: MIPS USB IP core family device controller
+ *              Structures, registers and logging macros
+ */
+
+#ifndef _CI13XXX_h_
+#define _CI13XXX_h_
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+#define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
+#define ENDPT_MAX          (32)
+#define CTRL_PAYLOAD_MAX   (64)
+#define RX        (0)  /* similar to USB_DIR_OUT but can be used as an index */
+#define TX        (1)  /* similar to USB_DIR_IN  but can be used as an index */
+
+/* UDC private data:
+ *  16MSb - Vendor ID | 16 LSb Vendor private data
+ */
+#define CI13XX_REQ_VENDOR_ID(id)  (id & 0xFFFF0000UL)
+
+#define MSM_ETD_TYPE			BIT(1)
+#define MSM_EP_PIPE_ID_RESET_VAL	0x1F001F
+
+/******************************************************************************
+ * STRUCTURES
+ *****************************************************************************/
+/* DMA layout of transfer descriptors */
+struct ci13xxx_td {
+	/* 0 */
+	u32 next;
+#define TD_TERMINATE          BIT(0)
+#define TD_ADDR_MASK          (0xFFFFFFEUL << 5)
+	/* 1 */
+	u32 token;
+#define TD_STATUS             (0x00FFUL <<  0)
+#define TD_STATUS_TR_ERR      BIT(3)
+#define TD_STATUS_DT_ERR      BIT(5)
+#define TD_STATUS_HALTED      BIT(6)
+#define TD_STATUS_ACTIVE      BIT(7)
+#define TD_MULTO              (0x0003UL << 10)
+#define TD_IOC                BIT(15)
+#define TD_TOTAL_BYTES        (0x7FFFUL << 16)
+	/* 2 */
+	u32 page[5];
+#define TD_CURR_OFFSET        (0x0FFFUL <<  0)
+#define TD_FRAME_NUM          (0x07FFUL <<  0)
+#define TD_RESERVED_MASK      (0x0FFFUL <<  0)
+} __packed __aligned(4);
+
+/* DMA layout of queue heads */
+struct ci13xxx_qh {
+	/* 0 */
+	u32 cap;
+#define QH_IOS                BIT(15)
+#define QH_MAX_PKT            (0x07FFUL << 16)
+#define QH_ZLT                BIT(29)
+#define QH_MULT               (0x0003UL << 30)
+#define QH_MULT_SHIFT         11
+	/* 1 */
+	u32 curr;
+	/* 2 - 8 */
+	struct ci13xxx_td        td;
+	/* 9 */
+	u32 RESERVED;
+	struct usb_ctrlrequest   setup;
+} __packed __aligned(4);
+
+/* cache of larger request's original attributes */
+struct ci13xxx_multi_req {
+	unsigned int	     len;
+	unsigned int	     actual;
+	void                *buf;
+};
+
+/* Extension of usb_request */
+struct ci13xxx_req {
+	struct usb_request   req;
+	unsigned int	     map;
+	struct list_head     queue;
+	struct ci13xxx_td   *ptr;
+	dma_addr_t           dma;
+	struct ci13xxx_td   *zptr;
+	dma_addr_t           zdma;
+	struct ci13xxx_multi_req multi;
+};
+
+/* Extension of usb_ep */
+struct ci13xxx_ep {
+	struct usb_ep                          ep;
+	const struct usb_endpoint_descriptor  *desc;
+	u8                                     dir;
+	u8                                     num;
+	u8                                     type;
+	char                                   name[16];
+	struct {
+		struct list_head   queue;
+		struct ci13xxx_qh *ptr;
+		dma_addr_t         dma;
+	}                                      qh;
+	struct list_head                       rw_queue;
+	int                                    wedge;
+
+	/* global resources */
+	spinlock_t                            *lock;
+	struct device                         *device;
+	struct dma_pool                       *td_pool;
+	struct ci13xxx_td                     *last_zptr;
+	dma_addr_t                            last_zdma;
+	unsigned long                         dTD_update_fail_count;
+	unsigned long                         dTD_active_re_q_count;
+	unsigned long			      prime_fail_count;
+	int				      prime_timer_count;
+	struct timer_list		      prime_timer;
+
+	bool                                  multi_req;
+};
+
+struct ci13xxx;
+struct ci13xxx_udc_driver {
+	const char	*name;
+	unsigned long	 flags;
+	unsigned int nz_itc;
+#define CI13XXX_REGS_SHARED		BIT(0)
+#define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
+#define CI13XXX_PULLUP_ON_VBUS		BIT(2)
+#define CI13XXX_DISABLE_STREAMING	BIT(3)
+#define CI13XXX_ZERO_ITC		BIT(4)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS	BIT(6)
+
+#define CI13XXX_CONTROLLER_RESET_EVENT			0
+#define CI13XXX_CONTROLLER_CONNECT_EVENT		1
+#define CI13XXX_CONTROLLER_SUSPEND_EVENT		2
+#define CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT		3
+#define CI13XXX_CONTROLLER_RESUME_EVENT		4
+#define CI13XXX_CONTROLLER_DISCONNECT_EVENT		5
+#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT		6
+#define CI13XXX_CONTROLLER_ERROR_EVENT			7
+
+	void	(*notify_event)(struct ci13xxx *udc, unsigned int event);
+	bool    (*in_lpm)(struct ci13xxx *udc);
+};
+
+/* CI13XXX UDC descriptor & global resources */
+struct ci13xxx {
+	spinlock_t		  *lock;      /* ctrl register bank access */
+	void __iomem              *regs;      /* registers address space */
+
+	struct dma_pool           *qh_pool;   /* DMA pool for queue heads */
+	struct dma_pool           *td_pool;   /* DMA pool for transfer descs */
+	struct usb_request        *status;    /* ep0 status request */
+	void                      *status_buf;/* GET_STATUS buffer */
+
+	struct usb_gadget          gadget;     /* USB slave device */
+	struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
+	u32                        ep0_dir;    /* ep0 direction */
+#define ep0out ci13xxx_ep[0]
+#define ep0in  ci13xxx_ep[hw_ep_max / 2]
+	u8                         suspended;  /* suspended by the host */
+	u8                         configured;  /* is device configured */
+	u8                         test_mode;  /* the selected test mode */
+	bool                       rw_pending; /* Remote wakeup pending flag */
+	struct delayed_work        rw_work;    /* remote wakeup delayed work */
+	struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
+	struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
+	int                        vbus_active; /* is VBUS active */
+	int                        softconnect; /* is pull-up enable allowed */
+	unsigned long dTD_update_fail_count;
+	struct usb_phy            *transceiver; /* Transceiver struct */
+	bool                      skip_flush;   /*
+						 * skip flushing remaining EP
+						 * upon flush timeout for the
+						 * first EP.
+						 */
+};
+
+/******************************************************************************
+ * REGISTERS
+ *****************************************************************************/
+/* register size */
+#define REG_BITS   (32)
+
+/* HCCPARAMS */
+#define HCCPARAMS_LEN         BIT(17)
+
+/* DCCPARAMS */
+#define DCCPARAMS_DEN         (0x1F << 0)
+#define DCCPARAMS_DC          BIT(7)
+
+/* TESTMODE */
+#define TESTMODE_FORCE        BIT(0)
+
+/* AHB_MODE */
+#define AHB2AHB_BYPASS	      BIT(31)
+
+/* USBCMD */
+#define USBCMD_RS             BIT(0)
+#define USBCMD_RST            BIT(1)
+#define USBCMD_SUTW           BIT(13)
+#define USBCMD_ATDTW          BIT(14)
+
+/* USBSTS & USBINTR */
+#define USBi_UI               BIT(0)
+#define USBi_UEI              BIT(1)
+#define USBi_PCI              BIT(2)
+#define USBi_URI              BIT(6)
+#define USBi_SLI              BIT(8)
+
+/* DEVICEADDR */
+#define DEVICEADDR_USBADRA    BIT(24)
+#define DEVICEADDR_USBADR     (0x7FUL << 25)
+
+/* PORTSC */
+#define PORTSC_FPR            BIT(6)
+#define PORTSC_SUSP           BIT(7)
+#define PORTSC_PR             BIT(8)
+#define PORTSC_HSP            BIT(9)
+#define PORTSC_PTC            (0x0FUL << 16)
+
+/* DEVLC */
+#define DEVLC_PSPD            (0x03UL << 25)
+#define    DEVLC_PSPD_HS      (0x02UL << 25)
+
+/* USBMODE */
+#define USBMODE_CM            (0x03UL <<  0)
+#define    USBMODE_CM_IDLE    (0x00UL <<  0)
+#define    USBMODE_CM_DEVICE  (0x02UL <<  0)
+#define    USBMODE_CM_HOST    (0x03UL <<  0)
+#define USBMODE_SLOM          BIT(3)
+#define USBMODE_SDIS          BIT(4)
+#define USBCMD_ITC(n)         (n << 16) /* n = 0, 1, 2, 4, 8, 16, 32, 64 */
+#define USBCMD_ITC_MASK       (0xFF << 16)
+
+/* ENDPTCTRL */
+#define ENDPTCTRL_RXS         BIT(0)
+#define ENDPTCTRL_RXT         (0x03UL <<  2)
+#define ENDPTCTRL_RXR         BIT(6)         /* reserved for port 0 */
+#define ENDPTCTRL_RXE         BIT(7)
+#define ENDPTCTRL_TXS         BIT(16)
+#define ENDPTCTRL_TXT         (0x03UL << 18)
+#define ENDPTCTRL_TXR         BIT(22)        /* reserved for port 0 */
+#define ENDPTCTRL_TXE         BIT(23)
+
+/******************************************************************************
+ * LOGGING
+ *****************************************************************************/
+#define ci13xxx_printk(level, format, args...) \
+do { \
+	if (_udc == NULL) \
+		printk(level "[%s] " format "\n", __func__, ## args); \
+	else \
+		dev_printk(level, _udc->gadget.dev.parent, \
+			   "[%s] " format "\n", __func__, ## args); \
+} while (0)
+
+#ifndef err
+#define err(format, args...)    ci13xxx_printk(KERN_ERR, format, ## args)
+#endif
+
+#define warn(format, args...)   ci13xxx_printk(KERN_WARNING, format, ## args)
+#define info(format, args...)   ci13xxx_printk(KERN_INFO, format, ## args)
+
+#ifdef TRACE
+#define trace(format, args...)      ci13xxx_printk(KERN_DEBUG, format, ## args)
+#define dbg_trace(format, args...)  dev_dbg(dev, format, ##args)
+#else
+#define trace(format, args...)      do {} while (0)
+#define dbg_trace(format, args...)  do {} while (0)
+#endif
+
+#endif	/* _CI13XXX_h_ */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4aee8c8..0fec59c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -167,7 +167,6 @@
 			struct usb_function *f,
 			struct usb_ep *_ep)
 {
-	struct usb_composite_dev	*cdev = get_gadget_data(g);
 	struct usb_endpoint_descriptor *chosen_desc = NULL;
 	struct usb_descriptor_header **speed_desc = NULL;
 
@@ -246,8 +245,12 @@
 			_ep->maxburst = comp_desc->bMaxBurst + 1;
 			break;
 		default:
-			if (comp_desc->bMaxBurst != 0)
+			if (comp_desc->bMaxBurst != 0) {
+				struct usb_composite_dev *cdev;
+
+				cdev = get_gadget_data(g);
 				ERROR(cdev, "ep0 bMaxBurst must be 0\n");
+			}
 			_ep->maxburst = 1;
 			break;
 		}
diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index 9f7a29a..05a66b2 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -158,6 +158,13 @@
 	.bInterval =		4, /* poll 1 per millisecond */
 };
 
+static struct usb_ss_ep_comp_descriptor ss_as_in_comp_desc = {
+	 .bLength =		 sizeof(ss_as_in_comp_desc),
+	 .bDescriptorType =	 USB_DT_SS_ENDPOINT_COMP,
+
+	 .wBytesPerInterval =	cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+};
+
 /* Standard ISO IN Endpoint Descriptor for highspeed */
 static struct usb_endpoint_descriptor fs_as_in_ep_desc  = {
 	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
@@ -198,6 +205,26 @@
 	NULL,
 };
 
+static struct usb_descriptor_header *ss_audio_desc[] = {
+	(struct usb_descriptor_header *)&ac_interface_desc,
+	(struct usb_descriptor_header *)&ac_header_desc,
+
+	(struct usb_descriptor_header *)&input_terminal_desc,
+	(struct usb_descriptor_header *)&output_terminal_desc,
+	(struct usb_descriptor_header *)&feature_unit_desc,
+
+	(struct usb_descriptor_header *)&as_interface_alt_0_desc,
+	(struct usb_descriptor_header *)&as_interface_alt_1_desc,
+	(struct usb_descriptor_header *)&as_header_desc,
+
+	(struct usb_descriptor_header *)&as_type_i_desc,
+
+	(struct usb_descriptor_header *)&hs_as_in_ep_desc,
+	(struct usb_descriptor_header *)&ss_as_in_comp_desc,
+	(struct usb_descriptor_header *)&as_iso_in_desc,
+	NULL,
+};
+
 static struct usb_descriptor_header *fs_audio_desc[] = {
 	(struct usb_descriptor_header *)&ac_interface_desc,
 	(struct usb_descriptor_header *)&ac_header_desc,
@@ -673,6 +700,7 @@
 
 	f->fs_descriptors = fs_audio_desc;
 	f->hs_descriptors = hs_audio_desc;
+	f->ss_descriptors = ss_audio_desc;
 
 	for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) {
 		req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE);
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 37903f9..41aa62d 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -307,6 +307,10 @@
 	in_params->data_buff_base_len = d_port->in_request.buf_len *
 					d_port->in_request.num_bufs;
 	in_params->data_buff_base_addr_iova = d_port->in_request.dma;
+	in_params->sgt_xfer_rings = &d_port->in_request.sgt_trb_xfer_ring;
+	in_params->sgt_data_buff = &d_port->in_request.sgt_data_buff;
+	log_event_dbg("%s(): IN: sgt_xfer_rings:%pK sgt_data_buff:%pK\n",
+		__func__, in_params->sgt_xfer_rings, in_params->sgt_data_buff);
 	in_params->xfer_scratch.const_buffer_size =
 		gsi_channel_info.const_buffer_size;
 	in_params->xfer_scratch.depcmd_low_addr =
@@ -344,6 +348,13 @@
 			d_port->out_request.num_bufs;
 		out_params->data_buff_base_addr_iova =
 			d_port->out_request.dma;
+		out_params->sgt_xfer_rings =
+			&d_port->out_request.sgt_trb_xfer_ring;
+		out_params->sgt_data_buff = &d_port->out_request.sgt_data_buff;
+		log_event_dbg("%s(): OUT: sgt_xfer_rings:%pK sgt_data_buff:%pK\n",
+			__func__, out_params->sgt_xfer_rings,
+			out_params->sgt_data_buff);
+
 		out_params->xfer_scratch.last_trb_addr_iova =
 			gsi_channel_info.last_trb_addr;
 		out_params->xfer_scratch.const_buffer_size =
@@ -497,10 +508,12 @@
 	gsi->d_port.in_channel_handle = -EINVAL;
 	gsi->d_port.out_channel_handle = -EINVAL;
 
-	usb_gsi_ep_op(gsi->d_port.in_ep, NULL, GSI_EP_OP_FREE_TRBS);
+	usb_gsi_ep_op(gsi->d_port.in_ep, &gsi->d_port.in_request,
+							GSI_EP_OP_FREE_TRBS);
 
 	if (gsi->d_port.out_ep)
-		usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_FREE_TRBS);
+		usb_gsi_ep_op(gsi->d_port.out_ep, &gsi->d_port.out_request,
+							GSI_EP_OP_FREE_TRBS);
 
 	/* free buffers allocated with each TRB */
 	gsi_free_trb_buffer(gsi);
@@ -1642,11 +1655,10 @@
 
 	buf = (rndis_init_msg_type *)req->buf;
 	if (buf->MessageType == RNDIS_MSG_INIT) {
-		gsi->d_port.in_aggr_size = min_t(u32, gsi->d_port.in_aggr_size,
-						gsi->params->dl_max_xfer_size);
-		log_event_dbg("RNDIS host dl_aggr_size:%d in_aggr_size:%d\n",
-				gsi->params->dl_max_xfer_size,
-				gsi->d_port.in_aggr_size);
+		/* honor host dl aggr size */
+		gsi->d_port.in_aggr_size = gsi->params->dl_max_xfer_size;
+		log_event_dbg("RNDIS host dl_aggr_size:%d\n",
+				gsi->params->dl_max_xfer_size);
 	}
 }
 
@@ -1945,6 +1957,11 @@
 			ret = -ENOMEM;
 			goto fail1;
 		}
+
+		dma_get_sgtable(dev->parent,
+			&gsi->d_port.in_request.sgt_data_buff,
+			gsi->d_port.in_request.buf_base_addr,
+			gsi->d_port.in_request.dma, len_in);
 	}
 
 	if (gsi->d_port.out_ep && !gsi->d_port.out_request.buf_base_addr) {
@@ -1964,6 +1981,11 @@
 			ret = -ENOMEM;
 			goto fail;
 		}
+
+		dma_get_sgtable(dev->parent,
+			&gsi->d_port.out_request.sgt_data_buff,
+			gsi->d_port.out_request.buf_base_addr,
+			gsi->d_port.out_request.dma, len_out);
 	}
 
 	log_event_dbg("finished allocating trb's buffer\n");
@@ -1994,6 +2016,7 @@
 			gsi->d_port.out_request.buf_base_addr,
 			gsi->d_port.out_request.dma);
 		gsi->d_port.out_request.buf_base_addr = NULL;
+		sg_free_table(&gsi->d_port.out_request.sgt_data_buff);
 	}
 
 	if (gsi->d_port.in_ep &&
@@ -2004,6 +2027,7 @@
 			gsi->d_port.in_request.buf_base_addr,
 			gsi->d_port.in_request.dma);
 		gsi->d_port.in_request.buf_base_addr = NULL;
+		sg_free_table(&gsi->d_port.in_request.sgt_data_buff);
 	}
 }
 
@@ -2540,7 +2564,7 @@
 		info.out_epname = "gsi-epout";
 		info.in_req_buf_len = GSI_IN_BUFF_SIZE;
 		gsi->d_port.in_aggr_size = GSI_IN_RNDIS_AGGR_SIZE;
-		info.in_req_num_buf = GSI_NUM_IN_BUFFERS;
+		info.in_req_num_buf = GSI_NUM_IN_RNDIS_BUFFERS;
 		gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE;
 		info.out_req_buf_len = GSI_OUT_AGGR_SIZE;
 		info.out_req_num_buf = GSI_NUM_OUT_BUFFERS;
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index 58a7706..71bea5e 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -34,13 +34,13 @@
 #define GSI_MAX_CTRL_PKT_SIZE 4096
 #define GSI_CTRL_DTR (1 << 0)
 
-
+#define GSI_NUM_IN_RNDIS_BUFFERS 50
 #define GSI_NUM_IN_BUFFERS 15
 #define GSI_IN_BUFF_SIZE 2048
 #define GSI_NUM_OUT_BUFFERS 14
 #define GSI_OUT_AGGR_SIZE 24576
 
-#define GSI_IN_RNDIS_AGGR_SIZE 9216
+#define GSI_IN_RNDIS_AGGR_SIZE 16384
 #define GSI_IN_MBIM_AGGR_SIZE 16384
 #define GSI_IN_RMNET_AGGR_SIZE 16384
 #define GSI_ECM_AGGR_SIZE 2048
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index cb00ada..9625248 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -31,13 +31,43 @@
 	struct gserial			port;
 	u8				data_id;
 	u8				port_num;
+	spinlock_t			lock;
+
+	struct usb_ep			*notify;
+	struct usb_request		*notify_req;
+
+	u8				online;
+	u8				pending;
+	struct usb_cdc_line_coding	port_line_coding;
+
+	/* SetControlLineState request */
+	u16				port_handshake_bits;
+#define ACM_CTRL_RTS	(1 << 1)	/* unused with full duplex */
+#define ACM_CTRL_DTR	(1 << 0)	/* host is ready for data r/w */
+
+	/* SerialState notification */
+	u16				serial_state;
+#define ACM_CTRL_OVERRUN	(1 << 6)
+#define ACM_CTRL_PARITY		(1 << 5)
+#define ACM_CTRL_FRAMING	(1 << 4)
+#define ACM_CTRL_RI		(1 << 3)
+#define ACM_CTRL_BRK		(1 << 2)
+#define ACM_CTRL_DSR		(1 << 1)
+#define ACM_CTRL_DCD		(1 << 0)
 };
 
+static inline struct f_gser *port_to_gser(struct gserial *p)
+{
+	return container_of(p, struct f_gser, port);
+}
+
 static inline struct f_gser *func_to_gser(struct usb_function *f)
 {
 	return container_of(f, struct f_gser, port.func);
 }
 
+#define GS_LOG2_NOTIFY_INTERVAL		5	/* 1 << 5 == 32 msec */
+#define GS_NOTIFY_MAXPACKET		10	/* notification + 2 bytes */
 /*-------------------------------------------------------------------------*/
 
 /* interface descriptor: */
@@ -46,15 +76,55 @@
 	.bLength =		USB_DT_INTERFACE_SIZE,
 	.bDescriptorType =	USB_DT_INTERFACE,
 	/* .bInterfaceNumber = DYNAMIC */
-	.bNumEndpoints =	2,
+	.bNumEndpoints =	3,
 	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
 	.bInterfaceSubClass =	0,
 	.bInterfaceProtocol =	0,
 	/* .iInterface = DYNAMIC */
 };
 
+static struct usb_cdc_header_desc gser_header_desc  = {
+	.bLength =		sizeof(gser_header_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
+	.bcdCDC =		cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor
+gser_call_mgmt_descriptor  = {
+	.bLength =		sizeof(gser_call_mgmt_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+	.bmCapabilities =	0,
+	/* .bDataInterface = DYNAMIC */
+};
+
+static struct usb_cdc_acm_descriptor gser_descriptor  = {
+	.bLength =		sizeof(gser_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+	.bmCapabilities =	USB_CDC_CAP_LINE,
+};
+
+static struct usb_cdc_union_desc gser_union_desc  = {
+	.bLength =		sizeof(gser_union_desc),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
+	/* .bMasterInterface0 =	DYNAMIC */
+	/* .bSlaveInterface0 =	DYNAMIC */
+};
+
 /* full speed support: */
 
+static struct usb_endpoint_descriptor gser_fs_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		1 << GS_LOG2_NOTIFY_INTERVAL,
+};
+
 static struct usb_endpoint_descriptor gser_fs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -71,12 +141,25 @@
 
 static struct usb_descriptor_header *gser_fs_function[] = {
 	(struct usb_descriptor_header *) &gser_interface_desc,
+	(struct usb_descriptor_header *) &gser_header_desc,
+	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &gser_descriptor,
+	(struct usb_descriptor_header *) &gser_union_desc,
+	(struct usb_descriptor_header *) &gser_fs_notify_desc,
 	(struct usb_descriptor_header *) &gser_fs_in_desc,
 	(struct usb_descriptor_header *) &gser_fs_out_desc,
 	NULL,
 };
 
 /* high speed support: */
+static struct usb_endpoint_descriptor gser_hs_notify_desc  = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
+};
 
 static struct usb_endpoint_descriptor gser_hs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
@@ -94,6 +177,11 @@
 
 static struct usb_descriptor_header *gser_hs_function[] = {
 	(struct usb_descriptor_header *) &gser_interface_desc,
+	(struct usb_descriptor_header *) &gser_header_desc,
+	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &gser_descriptor,
+	(struct usb_descriptor_header *) &gser_union_desc,
+	(struct usb_descriptor_header *) &gser_hs_notify_desc,
 	(struct usb_descriptor_header *) &gser_hs_in_desc,
 	(struct usb_descriptor_header *) &gser_hs_out_desc,
 	NULL,
@@ -118,8 +206,33 @@
 	.bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
 };
 
+static struct usb_endpoint_descriptor gser_ss_notify_desc  = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
+};
+
+static struct usb_ss_ep_comp_descriptor gser_ss_notify_comp_desc = {
+	.bLength =		sizeof(gser_ss_notify_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(GS_NOTIFY_MAXPACKET),
+};
+
 static struct usb_descriptor_header *gser_ss_function[] = {
 	(struct usb_descriptor_header *) &gser_interface_desc,
+	(struct usb_descriptor_header *) &gser_header_desc,
+	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &gser_descriptor,
+	(struct usb_descriptor_header *) &gser_union_desc,
+	(struct usb_descriptor_header *) &gser_ss_notify_desc,
+	(struct usb_descriptor_header *) &gser_ss_notify_comp_desc,
 	(struct usb_descriptor_header *) &gser_ss_in_desc,
 	(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
 	(struct usb_descriptor_header *) &gser_ss_out_desc,
@@ -130,7 +243,7 @@
 /* string descriptors: */
 
 static struct usb_string gser_string_defs[] = {
-	[0].s = "Generic Serial",
+	[0].s = "DUN over Serial",
 	{  } /* end of list */
 };
 
@@ -145,13 +258,131 @@
 };
 
 /*-------------------------------------------------------------------------*/
+static void gser_complete_set_line_coding(struct usb_ep *ep,
+					struct usb_request *req)
+{
+	struct f_gser            *gser = ep->driver_data;
+	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
+
+	if (req->status != 0) {
+		dev_dbg(&cdev->gadget->dev, "gser ttyGS%d completion, err %d\n",
+				gser->port_num, req->status);
+		return;
+	}
+
+	/* normal completion */
+	if (req->actual != sizeof(gser->port_line_coding)) {
+		dev_dbg(&cdev->gadget->dev, "gser ttyGS%d short resp, len %d\n",
+				gser->port_num, req->actual);
+		usb_ep_set_halt(ep);
+	} else {
+		struct usb_cdc_line_coding *value = req->buf;
+
+		gser->port_line_coding = *value;
+	}
+}
+
+static int
+gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+	struct f_gser            *gser = func_to_gser(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct usb_request       *req = cdev->req;
+	int                      value = -EOPNOTSUPP;
+	u16                      w_index = le16_to_cpu(ctrl->wIndex);
+	u16                      w_value = le16_to_cpu(ctrl->wValue);
+	u16                      w_length = le16_to_cpu(ctrl->wLength);
+
+
+	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+	/* SET_LINE_CODING ... just read and save what the host sends */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_SET_LINE_CODING:
+		if (w_length != sizeof(struct usb_cdc_line_coding))
+			goto invalid;
+
+		value = w_length;
+		cdev->gadget->ep0->driver_data = gser;
+		req->complete = gser_complete_set_line_coding;
+		break;
+
+	/* GET_LINE_CODING ... return what host sent, or initial value */
+	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_GET_LINE_CODING:
+		value = min_t(unsigned int, w_length,
+				sizeof(struct usb_cdc_line_coding));
+		memcpy(req->buf, &gser->port_line_coding, value);
+		break;
+
+	/* SET_CONTROL_LINE_STATE ... save what the host sent */
+	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+			| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
+
+		value = 0;
+		gser->port_handshake_bits = w_value;
+		pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d RST:%d\n",
+			__func__, w_value & ACM_CTRL_DTR ? 1 : 0,
+			w_value & ACM_CTRL_RTS ? 1 : 0);
+
+		if (gser->port.notify_modem)
+			gser->port.notify_modem(&gser->port, 0, w_value);
+
+		break;
+
+	default:
+invalid:
+		dev_dbg(&cdev->gadget->dev,
+			"invalid control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+	}
+
+	/* respond with data transfer or status phase? */
+	if (value >= 0) {
+		dev_dbg(&cdev->gadget->dev,
+			"gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
+			gser->port_num, ctrl->bRequestType, ctrl->bRequest,
+			w_value, w_index, w_length);
+		req->zero = 0;
+		req->length = value;
+		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0)
+			ERROR(cdev, "gser response on ttyGS%d, err %d\n",
+					gser->port_num, value);
+	}
+
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
 
 static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_gser		*gser = func_to_gser(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
+	int rc = 0;
 
 	/* we know alt == 0, so this is an activation or a reset */
+	if (gser->notify->driver_data) {
+		dev_dbg(&cdev->gadget->dev,
+			"reset generic ctl ttyGS%d\n", gser->port_num);
+		usb_ep_disable(gser->notify);
+	}
+
+	if (!gser->notify->desc) {
+		if (config_ep_by_speed(cdev->gadget, f, gser->notify)) {
+			gser->notify->desc = NULL;
+			return -EINVAL;
+		}
+	}
+
+	rc = usb_ep_enable(gser->notify);
+	if (rc) {
+		ERROR(cdev, "can't enable %s, result %d\n",
+			gser->notify->name, rc);
+		return rc;
+	}
+	gser->notify->driver_data = gser;
 
 	if (gser->port.in->enabled) {
 		dev_dbg(&cdev->gadget->dev,
@@ -169,7 +400,9 @@
 		}
 	}
 	gserial_connect(&gser->port, gser->port_num);
-	return 0;
+	gser->online = 1;
+
+	return rc;
 }
 
 static void gser_disable(struct usb_function *f)
@@ -180,6 +413,178 @@
 	dev_dbg(&cdev->gadget->dev,
 		"generic ttyGS%d deactivated\n", gser->port_num);
 	gserial_disconnect(&gser->port);
+	usb_ep_disable(gser->notify);
+	gser->notify->driver_data = NULL;
+	gser->online = 0;
+}
+
+static int gser_notify(struct f_gser *gser, u8 type, u16 value,
+		void *data, unsigned int length)
+{
+	struct usb_ep			*ep = gser->notify;
+	struct usb_request		*req;
+	struct usb_cdc_notification	*notify;
+	const unsigned int		len = sizeof(*notify) + length;
+	void                            *buf;
+	int                             status;
+	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
+
+	req = gser->notify_req;
+	gser->notify_req = NULL;
+	gser->pending = false;
+
+	req->length = len;
+	notify = req->buf;
+	buf = notify + 1;
+
+	notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
+			| USB_RECIP_INTERFACE;
+	notify->bNotificationType = type;
+	notify->wValue = cpu_to_le16(value);
+	notify->wIndex = cpu_to_le16(gser->data_id);
+	notify->wLength = cpu_to_le16(length);
+	memcpy(buf, data, length);
+
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (status < 0) {
+		ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n",
+				gser->port_num, status);
+		gser->notify_req = req;
+	}
+
+	return status;
+}
+
+static int gser_notify_serial_state(struct f_gser *gser)
+{
+	int		status;
+	unsigned long	flags;
+	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
+
+	spin_lock_irqsave(&gser->lock, flags);
+	if (gser->notify_req) {
+		DBG(cdev, "gser ttyGS%d serial state %04x\n",
+				gser->port_num, gser->serial_state);
+		status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE,
+				0, &gser->serial_state,
+				sizeof(gser->serial_state));
+	} else {
+		gser->pending = true;
+		status = 0;
+	}
+
+	spin_unlock_irqrestore(&gser->lock, flags);
+	return status;
+}
+
+static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_gser *gser = req->context;
+	u8            doit = false;
+	unsigned long flags;
+
+	/* on this call path we do NOT hold the port spinlock,
+	 * which is why ACM needs its own spinlock
+	 */
+
+	spin_lock_irqsave(&gser->lock, flags);
+	if (req->status != -ESHUTDOWN)
+		doit = gser->pending;
+
+	gser->notify_req = req;
+	spin_unlock_irqrestore(&gser->lock, flags);
+
+	if (doit && gser->online)
+		gser_notify_serial_state(gser);
+}
+
+static void gser_connect(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
+	gser_notify_serial_state(gser);
+}
+
+static unsigned int gser_get_dtr(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	if (gser->port_handshake_bits & ACM_CTRL_DTR)
+		return 1;
+	else
+		return 0;
+}
+
+static unsigned int gser_get_rts(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	if (gser->port_handshake_bits & ACM_CTRL_RTS)
+		return 1;
+	else
+		return 0;
+}
+
+static unsigned int gser_send_carrier_detect(struct gserial *port,
+	unsigned int yes)
+{
+	u16	state;
+	struct f_gser *gser = port_to_gser(port);
+
+	state = gser->serial_state;
+	state &= ~ACM_CTRL_DCD;
+	if (yes)
+		state |= ACM_CTRL_DCD;
+
+	gser->serial_state = state;
+	return gser_notify_serial_state(gser);
+}
+
+static unsigned int gser_send_ring_indicator(struct gserial *port,
+	unsigned int yes)
+{
+	u16	state;
+	struct f_gser *gser = port_to_gser(port);
+
+	state = gser->serial_state;
+	state &= ~ACM_CTRL_RI;
+	if (yes)
+		state |= ACM_CTRL_RI;
+
+	gser->serial_state = state;
+	return gser_notify_serial_state(gser);
+}
+
+static void gser_disconnect(struct gserial *port)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
+	gser_notify_serial_state(gser);
+}
+
+static int gser_send_break(struct gserial *port, int duration)
+{
+	u16	state;
+	struct f_gser *gser = port_to_gser(port);
+
+	state = gser->serial_state;
+	state &= ~ACM_CTRL_BRK;
+	if (duration)
+		state |= ACM_CTRL_BRK;
+
+	gser->serial_state = state;
+	return gser_notify_serial_state(gser);
+}
+
+static int gser_send_modem_ctrl_bits(struct gserial *port, int ctrl_bits)
+{
+	struct f_gser *gser = port_to_gser(port);
+
+	gser->serial_state = ctrl_bits;
+
+	return gser_notify_serial_state(gser);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -225,6 +630,21 @@
 		goto fail;
 	gser->port.out = ep;
 
+	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
+	if (!ep)
+		goto fail;
+	gser->notify = ep;
+	ep->driver_data = cdev;	/* claim */
+	/* allocate notification */
+	gser->notify_req = gs_alloc_req(ep,
+			sizeof(struct usb_cdc_notification) + 2,
+			GFP_KERNEL);
+	if (!gser->notify_req)
+		goto fail;
+
+	gser->notify_req->complete = gser_notify_complete;
+	gser->notify_req->context = gser;
+
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
@@ -235,6 +655,15 @@
 	gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
 	gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
 
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		gser_hs_notify_desc.bEndpointAddress =
+				gser_fs_notify_desc.bEndpointAddress;
+	}
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		gser_ss_notify_desc.bEndpointAddress =
+				gser_fs_notify_desc.bEndpointAddress;
+	}
+
 	status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
 			gser_ss_function, NULL);
 	if (status)
@@ -247,6 +676,18 @@
 	return 0;
 
 fail:
+	if (gser->notify_req)
+		gs_free_req(gser->notify, gser->notify_req);
+
+	/* we might as well release our claims on endpoints */
+	if (gser->notify)
+		gser->notify->driver_data = NULL;
+	/* we might as well release our claims on endpoints */
+	if (gser->port.out)
+		gser->port.out->driver_data = NULL;
+	if (gser->port.in)
+		gser->port.in->driver_data = NULL;
+
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 
 	return status;
@@ -327,7 +768,10 @@
 
 static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
 {
+	struct f_gser *gser = func_to_gser(f);
+
 	usb_free_all_descriptors(f);
+	gs_free_req(gser->notify, gser->notify_req);
 }
 
 static struct usb_function *gser_alloc(struct usb_function_instance *fi)
@@ -342,6 +786,7 @@
 
 	opts = container_of(fi, struct f_serial_opts, func_inst);
 
+	spin_lock_init(&gser->lock);
 	gser->port_num = opts->port_num;
 
 	gser->port.func.name = "gser";
@@ -351,6 +796,15 @@
 	gser->port.func.set_alt = gser_set_alt;
 	gser->port.func.disable = gser_disable;
 	gser->port.func.free_func = gser_free;
+	gser->port.func.setup = gser_setup;
+	gser->port.connect = gser_connect;
+	gser->port.get_dtr = gser_get_dtr;
+	gser->port.get_rts = gser_get_rts;
+	gser->port.send_carrier_detect = gser_send_carrier_detect;
+	gser->port.send_ring_indicator = gser_send_ring_indicator;
+	gser->port.send_modem_ctrl_bits = gser_send_modem_ctrl_bits;
+	gser->port.disconnect = gser_disconnect;
+	gser->port.send_break = gser_send_break;
 
 	return &gser->port.func;
 }
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index cb1ecfa..54220a5 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -382,15 +382,20 @@
 
 static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
 {
-	int	status;
+	int	status = 0;
 
 	spin_lock(&dev->req_lock);
-	status = prealloc(&dev->tx_reqs, link->in_ep, n);
-	if (status < 0)
-		goto fail;
-	status = prealloc(&dev->rx_reqs, link->out_ep, n);
-	if (status < 0)
-		goto fail;
+	if (link->in_ep) {
+		status = prealloc(&dev->tx_reqs, link->in_ep, n);
+			if (status < 0)
+			goto fail;
+	}
+
+	if (link->out_ep) {
+		status = prealloc(&dev->rx_reqs, link->out_ep, n);
+		if (status < 0)
+			goto fail;
+	}
 	goto done;
 fail:
 	DBG(dev, "can't alloc requests\n");
@@ -838,16 +843,24 @@
 		 * their own pace; the network stack can handle old packets.
 		 * For the moment we leave this here, since it works.
 		 */
-		in = link->in_ep->desc;
-		out = link->out_ep->desc;
-		usb_ep_disable(link->in_ep);
-		usb_ep_disable(link->out_ep);
-		if (netif_carrier_ok(net)) {
-			DBG(dev, "host still using in/out endpoints\n");
-			link->in_ep->desc = in;
-			link->out_ep->desc = out;
-			usb_ep_enable(link->in_ep);
-			usb_ep_enable(link->out_ep);
+		if (link->in_ep) {
+			in = link->in_ep->desc;
+			usb_ep_disable(link->in_ep);
+			if (netif_carrier_ok(net)) {
+				DBG(dev, "host still using in endpoints\n");
+				link->in_ep->desc = in;
+				usb_ep_enable(link->in_ep);
+			}
+		}
+
+		if (link->out_ep) {
+			out = link->out_ep->desc;
+			usb_ep_disable(link->out_ep);
+			if (netif_carrier_ok(net)) {
+				DBG(dev, "host still using out endpoints\n");
+				link->out_ep->desc = out;
+				usb_ep_enable(link->out_ep);
+			}
 		}
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -1201,20 +1214,24 @@
 	if (!dev)
 		return ERR_PTR(-EINVAL);
 
-	link->in_ep->driver_data = dev;
-	result = usb_ep_enable(link->in_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n",
-			link->in_ep->name, result);
-		goto fail0;
+	if (link->in_ep) {
+		link->in_ep->driver_data = dev;
+		result = usb_ep_enable(link->in_ep);
+		if (result != 0) {
+			DBG(dev, "enable %s --> %d\n",
+				link->in_ep->name, result);
+			goto fail0;
+		}
 	}
 
-	link->out_ep->driver_data = dev;
-	result = usb_ep_enable(link->out_ep);
-	if (result != 0) {
-		DBG(dev, "enable %s --> %d\n",
-			link->out_ep->name, result);
-		goto fail1;
+	if (link->out_ep) {
+		link->out_ep->driver_data = dev;
+		result = usb_ep_enable(link->out_ep);
+		if (result != 0) {
+			DBG(dev, "enable %s --> %d\n",
+				link->out_ep->name, result);
+			goto fail1;
+		}
 	}
 
 	if (result == 0)
@@ -1252,9 +1269,11 @@
 
 	/* on error, disable any endpoints  */
 	} else {
-		(void) usb_ep_disable(link->out_ep);
+		if (link->out_ep)
+			(void) usb_ep_disable(link->out_ep);
 fail1:
-		(void) usb_ep_disable(link->in_ep);
+		if (link->in_ep)
+			(void) usb_ep_disable(link->in_ep);
 	}
 fail0:
 	/* caller is responsible for cleanup on error */
@@ -1295,41 +1314,45 @@
 	 * of all pending i/o.  then free the request objects
 	 * and forget about the endpoints.
 	 */
-	usb_ep_disable(link->in_ep);
-	spin_lock(&dev->req_lock);
-	while (!list_empty(&dev->tx_reqs)) {
-		req = container_of(dev->tx_reqs.next,
-					struct usb_request, list);
-		list_del(&req->list);
-
-		spin_unlock(&dev->req_lock);
-		if (link->multi_pkt_xfer)
-			kfree(req->buf);
-		usb_ep_free_request(link->in_ep, req);
+	if (link->in_ep) {
+		usb_ep_disable(link->in_ep);
 		spin_lock(&dev->req_lock);
-	}
-	spin_unlock(&dev->req_lock);
-	link->in_ep->desc = NULL;
+		while (!list_empty(&dev->tx_reqs)) {
+			req = container_of(dev->tx_reqs.next,
+						struct usb_request, list);
+			list_del(&req->list);
 
-	usb_ep_disable(link->out_ep);
-	spin_lock(&dev->req_lock);
-	while (!list_empty(&dev->rx_reqs)) {
-		req = container_of(dev->rx_reqs.next,
-					struct usb_request, list);
-		list_del(&req->list);
-
+			spin_unlock(&dev->req_lock);
+			if (link->multi_pkt_xfer)
+				kfree(req->buf);
+			usb_ep_free_request(link->in_ep, req);
+			spin_lock(&dev->req_lock);
+		}
 		spin_unlock(&dev->req_lock);
-		usb_ep_free_request(link->out_ep, req);
-		spin_lock(&dev->req_lock);
+		link->in_ep->desc = NULL;
 	}
-	spin_unlock(&dev->req_lock);
 
-	spin_lock(&dev->rx_frames.lock);
-	while ((skb = __skb_dequeue(&dev->rx_frames)))
-		dev_kfree_skb_any(skb);
-	spin_unlock(&dev->rx_frames.lock);
+	if (link->out_ep) {
+		usb_ep_disable(link->out_ep);
+		spin_lock(&dev->req_lock);
+		while (!list_empty(&dev->rx_reqs)) {
+			req = container_of(dev->rx_reqs.next,
+						struct usb_request, list);
+			list_del(&req->list);
 
-	link->out_ep->desc = NULL;
+			spin_unlock(&dev->req_lock);
+			usb_ep_free_request(link->out_ep, req);
+			spin_lock(&dev->req_lock);
+		}
+		spin_unlock(&dev->req_lock);
+
+		spin_lock(&dev->rx_frames.lock);
+		while ((skb = __skb_dequeue(&dev->rx_frames)))
+			dev_kfree_skb_any(skb);
+		spin_unlock(&dev->rx_frames.lock);
+
+		link->out_ep->desc = NULL;
+	}
 
 	/* finish forgetting about this USB link episode */
 	dev->header_len = 0;
diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h
index c20210c..f367dc5 100644
--- a/drivers/usb/gadget/function/u_serial.h
+++ b/drivers/usb/gadget/function/u_serial.h
@@ -45,11 +45,23 @@
 
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
+	u16				serial_state;
+
+	/* control signal callbacks*/
+	unsigned int (*get_dtr)(struct gserial *p);
+	unsigned int (*get_rts)(struct gserial *p);
 
 	/* notification callbacks */
 	void (*connect)(struct gserial *p);
 	void (*disconnect)(struct gserial *p);
 	int (*send_break)(struct gserial *p, int duration);
+	unsigned int (*send_carrier_detect)(struct gserial *p,
+			unsigned int yes);
+	unsigned int (*send_ring_indicator)(struct gserial *p,
+			unsigned int yes);
+	int (*send_modem_ctrl_bits)(struct gserial *p, int ctrl_bits);
+	/* notification changes to modem */
+	void (*notify_modem)(void *gser, u8 portno, int ctrl_bits);
 };
 
 /* utilities to allocate/free request and buffer */
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 658b8da..42028cc 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -389,6 +389,21 @@
 	  dynamically linked module called "udc-xilinx" and force all
 	  gadget drivers to also be dynamically linked.
 
+config USB_CI13XXX_MSM
+	tristate "MIPS USB CI13xxx for MSM"
+	select USB_MSM_OTG
+	help
+	  MSM SoC has chipidea USB controller.  This driver uses
+	  ci13xxx_udc core.
+	  This driver depends on OTG driver for PHY initialization,
+	  clock management, powering up VBUS, and power management.
+	  This driver is not supported on boards like trout which
+	  has an external PHY.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "ci13xxx_msm" and force all
+	  gadget drivers to also be dynamically linked.
+
 #
 # LAST -- dummy/emulated controller
 #
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 26bfa73..72176a8 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -964,7 +964,7 @@
 		return 0;
 
 	/* "high bandwidth" works only at high speed */
-	if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11))
+	if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp_mult(desc) > 1)
 		return 0;
 
 	switch (type) {
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ae8a727..ac704d4 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -769,6 +769,10 @@
 		usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
 
 	spin_lock_irq(&xhci->lock);
+	if (!HCD_HW_ACCESSIBLE(hcd)) {
+		spin_unlock_irq(&xhci->lock);
+		return;
+	}
 	xhci_halt(xhci);
 	/* Workaround for spurious wakeups at shutdown with HSW */
 	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 17e8edb..4e223f5 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -253,4 +253,15 @@
 	  the high-speed PHY which is usually paired with either the ChipIdea or
 	  Synopsys DWC3 USB IPs on MSM SOCs. This driver expects to configure the
 	  PHY with a dedicated register I/O memory region.
+
+config USB_MSM_OTG
+	tristate "Qualcomm Technologies, Inc. on-chip USB OTG controller support"
+	depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
+	select USB_PHY
+	help
+	  Enable this to support the USB OTG transceiver on Qualcomm chips. It
+	  handles PHY initialization, clock management, and workarounds
+	  required after resetting the hardware and power management.
+	  This driver is required even for peripheral only or host only
+	  mode configurations.
 endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 285659d..7e9ffa0 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -31,3 +31,4 @@
 obj-$(CONFIG_USB_MSM_SSPHY_QMP)     	+= phy-msm-ssusb-qmp.o
 obj-$(CONFIG_MSM_QUSB_PHY)              += phy-msm-qusb.o phy-msm-qusb-v2.o
 obj-$(CONFIG_MSM_HSUSB_PHY)		+= phy-msm-snps-hs.o
+obj-$(CONFIG_USB_MSM_OTG)		+= phy-msm-usb.o
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index cce17e0..19f3f18 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * 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
@@ -26,6 +26,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/usb/phy.h>
 #include <linux/reset.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/debugfs.h>
 #include <linux/hrtimer.h>
 
@@ -146,8 +147,65 @@
 	u8			tune[5];
 
 	struct hrtimer		timer;
+	int			soc_min_rev;
 };
 
+#ifdef CONFIG_NVMEM
+/* Parse qfprom data for deciding on errata work-arounds */
+static long qfprom_read(struct device *dev, const char *name)
+{
+	struct nvmem_cell *cell;
+	ssize_t len = 0;
+	u32 *buf, val = 0;
+	long err = 0;
+
+	cell = nvmem_cell_get(dev, name);
+	if (IS_ERR(cell)) {
+		err = PTR_ERR(cell);
+		dev_err(dev, "failed opening nvmem cell err : %ld\n", err);
+		/* If entry does not exist, then that is not an error */
+		if (err == -ENOENT)
+			err = 0;
+		return err;
+	}
+
+	buf = (u32 *)nvmem_cell_read(cell, &len);
+	if (IS_ERR(buf) || !len) {
+		dev_err(dev, "Failed reading nvmem cell, err: %u, bytes fetched: %zd\n",
+				*buf, len);
+		if (!IS_ERR(buf)) {
+			kfree(buf);
+			err = -EINVAL;
+		} else {
+			err = PTR_ERR(buf);
+		}
+	} else {
+		val = *buf;
+		kfree(buf);
+	}
+
+	nvmem_cell_put(cell);
+	return err ? err : (long) val;
+}
+
+/* Reads the SoC version */
+static int qusb_phy_get_socrev(struct device *dev, struct qusb_phy *qphy)
+{
+	qphy->soc_min_rev  = qfprom_read(dev, "minor_rev");
+	if (qphy->soc_min_rev < 0)
+		dev_err(dev, "failed getting soc_min_rev, err : %d\n",
+				qphy->soc_min_rev);
+
+	return qphy->soc_min_rev;
+};
+#else
+/* Reads the SoC version */
+static int qusb_phy_get_socrev(struct device *dev, struct qusb_phy *qphy)
+{
+	return 0;
+}
+#endif
+
 static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
 {
 	dev_dbg(qphy->phy.dev, "%s(): clocks_enabled:%d on:%d\n",
@@ -766,6 +824,7 @@
 			return ret;
 		}
 		qphy->dpdm_enable = true;
+		qusb_phy_reset(qphy);
 	}
 
 	return ret;
@@ -1125,6 +1184,11 @@
 		return PTR_ERR(qphy->vdda18);
 	}
 
+	ret = qusb_phy_get_socrev(&pdev->dev, qphy);
+	if (ret == -EPROBE_DEFER) {
+		dev_err(&pdev->dev, "SoC version rd: fail: defer for now\n");
+		return ret;
+	}
 	qphy->pinctrl = devm_pinctrl_get(dev);
 	if (IS_ERR(qphy->pinctrl)) {
 		ret = PTR_ERR(qphy->pinctrl);
@@ -1159,7 +1223,14 @@
 	qphy->phy.type			= USB_PHY_TYPE_USB2;
 	qphy->phy.notify_connect        = qusb_phy_notify_connect;
 	qphy->phy.notify_disconnect     = qusb_phy_notify_disconnect;
-	qphy->phy.disable_chirp		= qusb_phy_disable_chirp;
+
+	/*
+	 * qusb_phy_disable_chirp is not required if soc version is
+	 * mentioned and is not base version.
+	 */
+	if (qphy->soc_min_rev == 0)
+		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);
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index fd84889..3482c93 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -422,6 +422,28 @@
 
 static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
 {
+	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
+
+	if (phy->suspended && suspend) {
+		dev_dbg(uphy->dev, "%s: USB PHY is already suspended\n",
+			__func__);
+		return 0;
+	}
+
+	if (suspend) { /* Bus suspend */
+		if (phy->cable_connected ||
+			(phy->phy.flags & PHY_HOST_MODE)) {
+			msm_hsphy_enable_clocks(phy, false);
+		} else {/* Cable disconnect */
+			msm_hsphy_enable_clocks(phy, false);
+			msm_hsphy_enable_power(phy, false);
+		}
+		phy->suspended = true;
+	} else { /* Bus resume and cable connect */
+			msm_hsphy_enable_clocks(phy, true);
+			phy->suspended = false;
+		}
+
 	return 0;
 }
 
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index 8134579..ad3bbf7 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -112,6 +112,7 @@
 	struct usb_phy		phy;
 	void __iomem		*base;
 	void __iomem		*vls_clamp_reg;
+	void __iomem		*pcs_clamp_enable_reg;
 	void __iomem		*tcsr_usb3_dp_phymode;
 
 	struct regulator	*vdd;
@@ -187,6 +188,8 @@
 	case USB_PHY_TYPE_USB3_OR_DP:
 	case USB_PHY_TYPE_USB3:
 		writel_relaxed(!!val, phy->vls_clamp_reg);
+		if (phy->pcs_clamp_enable_reg)
+			writel_relaxed(!val, phy->pcs_clamp_enable_reg);
 		break;
 	default:
 		break;
@@ -892,6 +895,16 @@
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+			"pcs_clamp_enable_reg");
+	if (res) {
+		phy->pcs_clamp_enable_reg = devm_ioremap_resource(dev, res);
+		if (IS_ERR(phy->pcs_clamp_enable_reg)) {
+			dev_err(dev, "err getting pcs_clamp_enable_reg address.\n");
+			return PTR_ERR(phy->pcs_clamp_enable_reg);
+		}
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 			"tcsr_usb3_dp_phymode");
 	if (res) {
 		phy->tcsr_usb3_dp_phymode = devm_ioremap_resource(dev, res);
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
new file mode 100644
index 0000000..c5cdddc
--- /dev/null
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -0,0 +1,5473 @@
+/* Copyright (c) 2009-2018, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pm_runtime.h>
+#include <linux/suspend.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/irqchip/msm-mpm-irq.h>
+#include <linux/pm_wakeup.h>
+#include <linux/reset.h>
+#include <linux/extcon.h>
+#include <soc/qcom/scm.h>
+
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/msm_hsusb.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/qpnp/qpnp-adc.h>
+
+#include <linux/msm-bus.h>
+
+/**
+ * Requested USB votes for BUS bandwidth
+ *
+ * USB_NO_PERF_VOTE     BUS Vote for inactive USB session or disconnect
+ * USB_MAX_PERF_VOTE    Maximum BUS bandwidth vote
+ * USB_MIN_PERF_VOTE    Minimum BUS bandwidth vote (for some hw same as NO_PERF)
+ *
+ */
+enum usb_bus_vote {
+	USB_NO_PERF_VOTE = 0,
+	USB_MAX_PERF_VOTE,
+	USB_MIN_PERF_VOTE,
+};
+
+/**
+ * Supported USB modes
+ *
+ * USB_PERIPHERAL       Only peripheral mode is supported.
+ * USB_HOST             Only host mode is supported.
+ * USB_OTG              OTG mode is supported.
+ *
+ */
+enum usb_mode_type {
+	USB_NONE = 0,
+	USB_PERIPHERAL,
+	USB_HOST,
+	USB_OTG,
+};
+
+/**
+ * OTG control
+ *
+ * OTG_NO_CONTROL	Id/VBUS notifications not required. Useful in host
+ *                      only configuration.
+ * OTG_PHY_CONTROL	Id/VBUS notifications comes form USB PHY.
+ * OTG_PMIC_CONTROL	Id/VBUS notifications comes from PMIC hardware.
+ * OTG_USER_CONTROL	Id/VBUS notifcations comes from User via sysfs.
+ *
+ */
+enum otg_control_type {
+	OTG_NO_CONTROL = 0,
+	OTG_PHY_CONTROL,
+	OTG_PMIC_CONTROL,
+	OTG_USER_CONTROL,
+};
+
+/**
+ * PHY used in
+ *
+ * INVALID_PHY			Unsupported PHY
+ * CI_PHY                      Chipidea PHY
+ * SNPS_PICO_PHY               Synopsis Pico PHY
+ * SNPS_FEMTO_PHY              Synopsis Femto PHY
+ * QUSB_ULPI_PHY
+ *
+ */
+enum msm_usb_phy_type {
+	INVALID_PHY = 0,
+	CI_PHY,			/* not supported */
+	SNPS_PICO_PHY,
+	SNPS_FEMTO_PHY,
+	QUSB_ULPI_PHY,
+};
+
+#define IDEV_CHG_MAX	1500
+#define IUNIT		100
+#define IDEV_HVDCP_CHG_MAX	1800
+
+/**
+ * Used different VDDCX voltage values
+ */
+enum usb_vdd_value {
+	VDD_NONE = 0,
+	VDD_MIN,
+	VDD_MAX,
+	VDD_VAL_MAX,
+};
+
+/**
+ * struct msm_otg_platform_data - platform device data
+ *              for msm_otg driver.
+ * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as
+ *              "do not overwrite default value at this address".
+ * @vbus_power: VBUS power on/off routine.It should return result
+ *		as success(zero value) or failure(non-zero value).
+ * @power_budget: VBUS power budget in mA (0 will be treated as 500mA).
+ * @mode: Supported mode (OTG/peripheral/host).
+ * @otg_control: OTG switch controlled by user/Id pin
+ * @default_mode: Default operational mode. Applicable only if
+ *              OTG switch is controller by user.
+ * @pmic_id_irq: IRQ number assigned for PMIC USB ID line.
+ * @mpm_otgsessvld_int: MPM wakeup pin assigned for OTG SESSVLD
+ *              interrupt. Used when .otg_control == OTG_PHY_CONTROL.
+ * @mpm_dpshv_int: MPM wakeup pin assigned for DP SHV interrupt.
+ *		Used during host bus suspend.
+ * @mpm_dmshv_int: MPM wakeup pin assigned for DM SHV interrupt.
+ *		Used during host bus suspend.
+ * @disable_reset_on_disconnect: perform USB PHY and LINK reset
+ *              on USB cable disconnection.
+ * @pnoc_errata_fix: workaround needed for PNOC hardware bug that
+ *              affects USB performance.
+ * @enable_lpm_on_suspend: Enable the USB core to go into Low
+ *              Power Mode, when USB bus is suspended but cable
+ *              is connected.
+ * @core_clk_always_on_workaround: Don't disable core_clk when
+ *              USB enters LPM.
+ * @delay_lpm_on_disconnect: Use a delay before entering LPM
+ *              upon USB cable disconnection.
+ * @enable_sec_phy: Use second HSPHY with USB2 core
+ * @bus_scale_table: parameters for bus bandwidth requirements
+ * @log2_itc: value of 2^(log2_itc-1) will be used as the
+ *              interrupt threshold (ITC), when log2_itc is
+ *              between 1 to 7.
+ * @l1_supported: enable link power management support.
+ * @dpdm_pulldown_added: Indicates whether pull down resistors are
+ *		connected on data lines or not.
+ * @vddmin_gpio: dedictaed gpio in the platform that is used for
+ *		pullup the D+ line in case of bus suspend with
+ *		phy retention.
+ * @enable_ahb2ahb_bypass: Indicates whether enable AHB2AHB BYPASS
+ *		mode with controller in device mode.
+ * @bool disable_retention_with_vdd_min: Indicates whether to enable
+		allowing VDDmin without putting PHY into retention.
+ * @bool enable_phy_id_pullup: Indicates whether phy id pullup is
+		enabled or not.
+ * @usb_id_gpio: Gpio used for USB ID detection.
+ * @hub_reset_gpio: Gpio used for hub reset.
+ * @switch_sel_gpio: Gpio used for controlling switch that
+		routing D+/D- from the USB HUB to the USB jack type B
+		for peripheral mode.
+ * @bool phy_dvdd_always_on: PHY DVDD is supplied by always on PMIC LDO.
+ * @bool emulation: Indicates whether we are running on emulation platform.
+ * @bool enable_streaming: Indicates whether streaming to be enabled by default.
+ * @bool enable_axi_prefetch: Indicates whether AXI Prefetch interface is used
+		for improving data performance.
+ * @bool enable_sdp_typec_current_limit: Indicates whether type-c current for
+		sdp charger to be limited.
+ * @usbeth_reset_gpio: Gpio used for external usb-to-eth reset.
+ */
+struct msm_otg_platform_data {
+	int *phy_init_seq;
+	int phy_init_sz;
+	int (*vbus_power)(bool on);
+	unsigned int power_budget;
+	enum usb_mode_type mode;
+	enum otg_control_type otg_control;
+	enum usb_mode_type default_mode;
+	enum msm_usb_phy_type phy_type;
+	int pmic_id_irq;
+	unsigned int mpm_otgsessvld_int;
+	unsigned int mpm_dpshv_int;
+	unsigned int mpm_dmshv_int;
+	bool disable_reset_on_disconnect;
+	bool pnoc_errata_fix;
+	bool enable_lpm_on_dev_suspend;
+	bool core_clk_always_on_workaround;
+	bool delay_lpm_on_disconnect;
+	bool dp_manual_pullup;
+	bool enable_sec_phy;
+	struct msm_bus_scale_pdata *bus_scale_table;
+	int log2_itc;
+	bool l1_supported;
+	bool dpdm_pulldown_added;
+	int vddmin_gpio;
+	bool enable_ahb2ahb_bypass;
+	bool disable_retention_with_vdd_min;
+	bool enable_phy_id_pullup;
+	int usb_id_gpio;
+	int hub_reset_gpio;
+	int usbeth_reset_gpio;
+	int switch_sel_gpio;
+	bool phy_dvdd_always_on;
+	bool emulation;
+	bool enable_streaming;
+	bool enable_axi_prefetch;
+	bool enable_sdp_typec_current_limit;
+	bool vbus_low_as_hostmode;
+};
+
+#define USB_CHG_BLOCK_ULPI	1
+
+#define USB_REQUEST_5V		1
+#define USB_REQUEST_9V		2
+/**
+ * struct msm_usb_chg_info - MSM USB charger block details.
+ * @chg_block_type: The type of charger block. QSCRATCH/ULPI.
+ * @page_offset: USB charger register base may not be aligned to
+ *              PAGE_SIZE.  The kernel driver aligns the base
+ *              address and use it for memory mapping.  This
+ *              page_offset is used by user space to calaculate
+ *              the corret charger register base address.
+ * @length: The length of the charger register address space.
+ */
+struct msm_usb_chg_info {
+	uint32_t chg_block_type;
+	__kernel_off_t page_offset;
+	size_t length;
+};
+
+/* Get the MSM USB charger block information */
+#define MSM_USB_EXT_CHG_INFO _IOW('M', 0, struct msm_usb_chg_info)
+
+/* Vote against USB hardware low power mode */
+#define MSM_USB_EXT_CHG_BLOCK_LPM _IOW('M', 1, int)
+
+/* To tell kernel about voltage being voted */
+#define MSM_USB_EXT_CHG_VOLTAGE_INFO _IOW('M', 2, int)
+
+/* To tell kernel about voltage request result */
+#define MSM_USB_EXT_CHG_RESULT _IOW('M', 3, int)
+
+/* To tell kernel whether charger connected is external charger or not */
+#define MSM_USB_EXT_CHG_TYPE _IOW('M', 4, int)
+
+#define MSM_USB_BASE	(motg->regs)
+#define MSM_USB_PHY_CSR_BASE (motg->phy_csr_regs)
+
+#define DRIVER_NAME	"msm_otg"
+
+#define CHG_RECHECK_DELAY	(jiffies + msecs_to_jiffies(2000))
+#define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
+#define USB_PHY_3P3_VOL_MIN	3050000 /* uV */
+#define USB_PHY_3P3_VOL_MAX	3300000 /* uV */
+#define USB_PHY_3P3_HPM_LOAD	50000	/* uA */
+#define USB_PHY_3P3_LPM_LOAD	4000	/* uA */
+
+#define USB_PHY_1P8_VOL_MIN	1800000 /* uV */
+#define USB_PHY_1P8_VOL_MAX	1800000 /* uV */
+#define USB_PHY_1P8_HPM_LOAD	50000	/* uA */
+#define USB_PHY_1P8_LPM_LOAD	4000	/* uA */
+
+#define USB_PHY_VDD_DIG_VOL_NONE	0 /*uV */
+#define USB_PHY_VDD_DIG_VOL_MIN	1045000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MAX	1320000 /* uV */
+
+#define USB_SUSPEND_DELAY_TIME	(500 * HZ/1000) /* 500 msec */
+
+#define USB_DEFAULT_SYSTEM_CLOCK 80000000	/* 80 MHz */
+
+#define PM_QOS_SAMPLE_SEC	2
+#define PM_QOS_THRESHOLD	400
+
+#define MICRO_5V 5000000
+#define MICRO_9V 9000000
+
+#define SDP_CURRENT_UA 500000
+#define CDP_CURRENT_UA 1500000
+#define DCP_CURRENT_UA 1500000
+#define HVDCP_CURRENT_UA 3000000
+
+enum msm_otg_phy_reg_mode {
+	USB_PHY_REG_OFF,
+	USB_PHY_REG_ON,
+	USB_PHY_REG_LPM_ON,
+	USB_PHY_REG_LPM_OFF,
+	USB_PHY_REG_3P3_ON,
+	USB_PHY_REG_3P3_OFF,
+};
+
+static char *override_phy_init;
+module_param(override_phy_init, charp, 0644);
+MODULE_PARM_DESC(override_phy_init,
+	"Override HSUSB PHY Init Settings");
+
+unsigned int lpm_disconnect_thresh = 1000;
+module_param(lpm_disconnect_thresh, uint, 0644);
+MODULE_PARM_DESC(lpm_disconnect_thresh,
+	"Delay before entering LPM on USB disconnect");
+
+static bool floated_charger_enable;
+module_param(floated_charger_enable, bool, 0644);
+MODULE_PARM_DESC(floated_charger_enable,
+	"Whether to enable floated charger");
+
+/* by default debugging is enabled */
+static unsigned int enable_dbg_log = 1;
+module_param(enable_dbg_log, uint, 0644);
+MODULE_PARM_DESC(enable_dbg_log, "Debug buffer events");
+
+/* Max current to be drawn for HVDCP charger */
+static int hvdcp_max_current = IDEV_HVDCP_CHG_MAX;
+module_param(hvdcp_max_current, int, 0644);
+MODULE_PARM_DESC(hvdcp_max_current, "max current drawn for HVDCP charger");
+
+/* Max current to be drawn for DCP charger */
+static int dcp_max_current = IDEV_CHG_MAX;
+module_param(dcp_max_current, int, 0644);
+MODULE_PARM_DESC(dcp_max_current, "max current drawn for DCP charger");
+
+static DECLARE_COMPLETION(pmic_vbus_init);
+static struct msm_otg *the_msm_otg;
+static bool debug_bus_voting_enabled;
+
+static struct regulator *hsusb_3p3;
+static struct regulator *hsusb_1p8;
+static struct regulator *hsusb_vdd;
+static struct regulator *vbus_otg;
+static struct power_supply *psy;
+
+static int vdd_val[VDD_VAL_MAX];
+static u32 bus_freqs[USB_NOC_NUM_VOTE][USB_NUM_BUS_CLOCKS]  /*bimc,snoc,pcnoc*/;
+static char bus_clkname[USB_NUM_BUS_CLOCKS][20] = {"bimc_clk", "snoc_clk",
+						"pcnoc_clk"};
+static bool bus_clk_rate_set;
+
+static void dbg_inc(unsigned int *idx)
+{
+	*idx = (*idx + 1) & (DEBUG_MAX_MSG-1);
+}
+
+static void
+msm_otg_dbg_log_event(struct usb_phy *phy, char *event, int d1, int d2)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	unsigned long flags;
+	unsigned long long t;
+	unsigned long nanosec;
+
+	if (!enable_dbg_log)
+		return;
+
+	write_lock_irqsave(&motg->dbg_lock, flags);
+	t = cpu_clock(smp_processor_id());
+	nanosec = do_div(t, 1000000000)/1000;
+	scnprintf(motg->buf[motg->dbg_idx], DEBUG_MSG_LEN,
+			"[%5lu.%06lu]: %s :%d:%d",
+			(unsigned long)t, nanosec, event, d1, d2);
+
+	motg->dbg_idx++;
+	motg->dbg_idx = motg->dbg_idx % DEBUG_MAX_MSG;
+	write_unlock_irqrestore(&motg->dbg_lock, flags);
+}
+
+static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
+{
+	int rc = 0;
+
+	if (init) {
+		hsusb_3p3 = devm_regulator_get(motg->phy.dev, "HSUSB_3p3");
+		if (IS_ERR(hsusb_3p3)) {
+			dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
+			return PTR_ERR(hsusb_3p3);
+		}
+
+		rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
+				USB_PHY_3P3_VOL_MAX);
+		if (rc) {
+			dev_err(motg->phy.dev, "unable to set voltage level for hsusb 3p3\n"
+									);
+			return rc;
+		}
+		hsusb_1p8 = devm_regulator_get(motg->phy.dev, "HSUSB_1p8");
+		if (IS_ERR(hsusb_1p8)) {
+			dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
+			rc = PTR_ERR(hsusb_1p8);
+			goto put_3p3_lpm;
+		}
+		rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
+				USB_PHY_1P8_VOL_MAX);
+		if (rc) {
+			dev_err(motg->phy.dev, "unable to set voltage level for hsusb 1p8\n"
+									);
+			goto put_1p8;
+		}
+
+		return 0;
+	}
+
+put_1p8:
+	regulator_set_voltage(hsusb_1p8, 0, USB_PHY_1P8_VOL_MAX);
+put_3p3_lpm:
+	regulator_set_voltage(hsusb_3p3, 0, USB_PHY_3P3_VOL_MAX);
+	return rc;
+}
+
+static int msm_hsusb_config_vddcx(int high)
+{
+	struct msm_otg *motg = the_msm_otg;
+	int max_vol = vdd_val[VDD_MAX];
+	int min_vol;
+	int ret;
+
+	min_vol = vdd_val[!!high];
+	ret = regulator_set_voltage(hsusb_vdd, min_vol, max_vol);
+	if (ret) {
+		pr_err("%s: unable to set the voltage for regulator HSUSB_VDDCX\n",
+								__func__);
+		return ret;
+	}
+
+	pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
+	msm_otg_dbg_log_event(&motg->phy, "CONFIG VDDCX", min_vol, max_vol);
+
+	return ret;
+}
+
+static int msm_hsusb_ldo_enable(struct msm_otg *motg,
+	enum msm_otg_phy_reg_mode mode)
+{
+	int ret = 0;
+
+	if (IS_ERR(hsusb_1p8)) {
+		pr_err("%s: HSUSB_1p8 is not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	if (IS_ERR(hsusb_3p3)) {
+		pr_err("%s: HSUSB_3p3 is not initialized\n", __func__);
+		return -ENODEV;
+	}
+
+	switch (mode) {
+	case USB_PHY_REG_ON:
+		ret = regulator_set_load(hsusb_1p8, USB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator HSUSB_1p8\n",
+								__func__);
+			return ret;
+		}
+
+		ret = regulator_enable(hsusb_1p8);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to enable the hsusb 1p8\n",
+				__func__);
+			regulator_set_load(hsusb_1p8, 0);
+			return ret;
+		}
+
+	/* fall through */
+	case USB_PHY_REG_3P3_ON:
+		ret = regulator_set_load(hsusb_3p3, USB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator HSUSB_3p3\n",
+								__func__);
+			if (mode == USB_PHY_REG_ON) {
+				regulator_set_load(hsusb_1p8, 0);
+				regulator_disable(hsusb_1p8);
+			}
+			return ret;
+		}
+
+		ret = regulator_enable(hsusb_3p3);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to enable the hsusb 3p3\n",
+				__func__);
+			regulator_set_load(hsusb_3p3, 0);
+			if (mode == USB_PHY_REG_ON) {
+				regulator_set_load(hsusb_1p8, 0);
+				regulator_disable(hsusb_1p8);
+			}
+			return ret;
+		}
+
+		break;
+
+	case USB_PHY_REG_OFF:
+		ret = regulator_disable(hsusb_1p8);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to disable the hsusb 1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_load(hsusb_1p8, 0);
+		if (ret < 0)
+			pr_err("%s: Unable to set LPM of the regulator HSUSB_1p8\n",
+								__func__);
+
+	/* fall through */
+	case USB_PHY_REG_3P3_OFF:
+		ret = regulator_disable(hsusb_3p3);
+		if (ret) {
+			dev_err(motg->phy.dev, "%s: unable to disable the hsusb 3p3\n",
+				 __func__);
+			return ret;
+		}
+		ret = regulator_set_load(hsusb_3p3, 0);
+		if (ret < 0)
+			pr_err("%s: Unable to set LPM of the regulator HSUSB_3p3\n",
+								__func__);
+
+		break;
+
+	case USB_PHY_REG_LPM_ON:
+		ret = regulator_set_load(hsusb_1p8, USB_PHY_1P8_LPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set LPM of the regulator: HSUSB_1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_load(hsusb_3p3, USB_PHY_3P3_LPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set LPM of the regulator: HSUSB_3p3\n",
+				__func__);
+			regulator_set_load(hsusb_1p8, USB_PHY_REG_ON);
+			return ret;
+		}
+
+		break;
+
+	case USB_PHY_REG_LPM_OFF:
+		ret = regulator_set_load(hsusb_1p8, USB_PHY_1P8_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator: HSUSB_1p8\n",
+				__func__);
+			return ret;
+		}
+
+		ret = regulator_set_load(hsusb_3p3, USB_PHY_3P3_HPM_LOAD);
+		if (ret < 0) {
+			pr_err("%s: Unable to set HPM of the regulator: HSUSB_3p3\n",
+				__func__);
+			regulator_set_load(hsusb_1p8, USB_PHY_REG_ON);
+			return ret;
+		}
+
+		break;
+
+	default:
+		pr_err("%s: Unsupported mode (%d).", __func__, mode);
+		return -ENOTSUPP;
+	}
+
+	pr_debug("%s: USB reg mode (%d) (OFF/HPM/LPM)\n", __func__, mode);
+	msm_otg_dbg_log_event(&motg->phy, "USB REG MODE", mode, ret);
+	return ret < 0 ? ret : 0;
+}
+
+static int ulpi_read(struct usb_phy *phy, u32 reg)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	int cnt = 0;
+
+	if (motg->pdata->emulation)
+		return 0;
+
+	if (motg->pdata->phy_type == QUSB_ULPI_PHY && reg > 0x3F) {
+		pr_debug("%s: ULPI vendor-specific reg 0x%02x not supported\n",
+			__func__, reg);
+		return 0;
+	}
+
+	/* initiate read operation */
+	writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while (cnt < ULPI_IO_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+		dev_err(phy->dev, "ulpi_read: timeout %08x\n",
+			readl_relaxed(USB_ULPI_VIEWPORT));
+		dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
+			readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
+		return -ETIMEDOUT;
+	}
+	return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
+}
+
+static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	int cnt = 0;
+
+	if (motg->pdata->emulation)
+		return 0;
+
+	if (motg->pdata->phy_type == QUSB_ULPI_PHY && reg > 0x3F) {
+		pr_debug("%s: ULPI vendor-specific reg 0x%02x not supported\n",
+			__func__, reg);
+		return 0;
+	}
+
+	/* initiate write operation */
+	writel_relaxed(ULPI_RUN | ULPI_WRITE |
+	       ULPI_ADDR(reg) | ULPI_DATA(val),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while (cnt < ULPI_IO_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+		dev_err(phy->dev, "ulpi_write: timeout\n");
+		dev_err(phy->dev, "PORTSC: %08x USBCMD: %08x\n",
+			readl_relaxed(USB_PORTSC), readl_relaxed(USB_USBCMD));
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static struct usb_phy_io_ops msm_otg_io_ops = {
+	.read = ulpi_read,
+	.write = ulpi_write,
+};
+
+static void ulpi_init(struct msm_otg *motg)
+{
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int aseq[10];
+	int *seq = NULL;
+
+	if (override_phy_init) {
+		pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
+				override_phy_init);
+		get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
+		seq = &aseq[1];
+	} else {
+		seq = pdata->phy_init_seq;
+	}
+
+	if (!seq)
+		return;
+
+	while (seq[0] >= 0) {
+		if (override_phy_init)
+			pr_debug("ulpi: write 0x%02x to 0x%02x\n",
+					seq[0], seq[1]);
+
+		dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
+				seq[0], seq[1]);
+		msm_otg_dbg_log_event(&motg->phy, "ULPI WRITE", seq[0], seq[1]);
+		ulpi_write(&motg->phy, seq[0], seq[1]);
+		seq += 2;
+	}
+}
+
+static int msm_otg_phy_clk_reset(struct msm_otg *motg)
+{
+	int ret;
+
+	if (!motg->phy_reset_clk)
+		return 0;
+
+	if (motg->sleep_clk)
+		clk_disable_unprepare(motg->sleep_clk);
+	if (motg->phy_csr_clk)
+		clk_disable_unprepare(motg->phy_csr_clk);
+
+	ret = reset_control_assert(motg->phy_reset);
+	if (ret) {
+		pr_err("phy_reset_clk assert failed %d\n", ret);
+		return ret;
+	}
+	/*
+	 * As per databook, 10 usec delay is required between
+	 * PHY POR assert and de-assert.
+	 */
+	usleep_range(10, 15);
+	ret = reset_control_deassert(motg->phy_reset);
+	if (ret) {
+		pr_err("phy_reset_clk de-assert failed %d\n", ret);
+		return ret;
+	}
+	/*
+	 * As per databook, it takes 75 usec for PHY to stabilize
+	 * after the reset.
+	 */
+	usleep_range(80, 100);
+
+	if (motg->phy_csr_clk)
+		clk_prepare_enable(motg->phy_csr_clk);
+	if (motg->sleep_clk)
+		clk_prepare_enable(motg->sleep_clk);
+
+	return 0;
+}
+
+static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
+{
+	int ret;
+
+	if (assert) {
+		/* Using asynchronous block reset to the hardware */
+		dev_dbg(motg->phy.dev, "block_reset ASSERT\n");
+		clk_disable_unprepare(motg->pclk);
+		clk_disable_unprepare(motg->core_clk);
+		ret = reset_control_assert(motg->core_reset);
+		if (ret)
+			dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
+	} else {
+		dev_dbg(motg->phy.dev, "block_reset DEASSERT\n");
+		ret = reset_control_deassert(motg->core_reset);
+		ndelay(200);
+		ret = clk_prepare_enable(motg->core_clk);
+		WARN(ret, "USB core_clk enable failed\n");
+		ret = clk_prepare_enable(motg->pclk);
+		WARN(ret, "USB pclk enable failed\n");
+		if (ret)
+			dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
+	}
+	return ret;
+}
+
+static int msm_otg_phy_reset(struct msm_otg *motg)
+{
+	u32 val;
+	int ret;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	/*
+	 * AHB2AHB Bypass mode shouldn't be enable before doing
+	 * async clock reset. If it is enable, disable the same.
+	 */
+	val = readl_relaxed(USB_AHBMODE);
+	if (val & AHB2AHB_BYPASS) {
+		pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
+						__func__, val);
+		val &= ~AHB2AHB_BYPASS_BIT_MASK;
+		writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
+		pr_err("%s(): AHBMODE: %x\n", __func__,
+				readl_relaxed(USB_AHBMODE));
+	}
+
+	ret = msm_otg_link_clk_reset(motg, 1);
+	if (ret)
+		return ret;
+
+	msm_otg_phy_clk_reset(motg);
+
+	/* wait for 1ms delay as suggested in HPG. */
+	usleep_range(1000, 1200);
+
+	ret = msm_otg_link_clk_reset(motg, 0);
+	if (ret)
+		return ret;
+
+	if (pdata && pdata->enable_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+							USB_PHY_CTRL2);
+	val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
+	writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+	dev_info(motg->phy.dev, "phy_reset: success\n");
+	msm_otg_dbg_log_event(&motg->phy, "PHY RESET SUCCESS",
+			motg->inputs, motg->phy.otg->state);
+	return 0;
+}
+
+#define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
+static int msm_otg_link_reset(struct msm_otg *motg)
+{
+	int cnt = 0;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	writel_relaxed(USBCMD_RESET, USB_USBCMD);
+	while (cnt < LINK_RESET_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
+			break;
+		udelay(1);
+		cnt++;
+	}
+	if (cnt >= LINK_RESET_TIMEOUT_USEC)
+		return -ETIMEDOUT;
+
+	/* select ULPI phy */
+	writel_relaxed(0x80000000, USB_PORTSC);
+	writel_relaxed(0x0, USB_AHBBURST);
+	writel_relaxed(0x08, USB_AHBMODE);
+
+	if (pdata && pdata->enable_sec_phy)
+		writel_relaxed(readl_relaxed(USB_PHY_CTRL2) | (1<<16),
+								USB_PHY_CTRL2);
+	return 0;
+}
+
+#define QUSB2PHY_PORT_POWERDOWN		0xB4
+#define QUSB2PHY_PORT_UTMI_CTRL2	0xC4
+
+static void msm_usb_phy_reset(struct msm_otg *motg)
+{
+	u32 val;
+	int ret, *seq;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		/* Assert USB PHY_PON */
+		val =  readl_relaxed(motg->usb_phy_ctrl_reg);
+		val &= ~PHY_POR_BIT_MASK;
+		val |= PHY_POR_ASSERT;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+
+		/* wait for minimum 10 microseconds as
+		 * suggested in HPG.
+		 */
+		usleep_range(10, 15);
+
+		/* Deassert USB PHY_PON */
+		val =  readl_relaxed(motg->usb_phy_ctrl_reg);
+		val &= ~PHY_POR_BIT_MASK;
+		val |= PHY_POR_DEASSERT;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case QUSB_ULPI_PHY:
+		ret = reset_control_assert(motg->phy_reset);
+		if (ret) {
+			pr_err("phy_reset_clk assert failed %d\n", ret);
+			break;
+		}
+
+		/* need to delay 10us for PHY to reset */
+		usleep_range(10, 20);
+
+		ret = reset_control_deassert(motg->phy_reset);
+		if (ret) {
+			pr_err("phy_reset_clk de-assert failed %d\n", ret);
+			break;
+		}
+
+		/* Ensure that RESET operation is completed. */
+		mb();
+
+		writel_relaxed(0x23,
+				motg->phy_csr_regs + QUSB2PHY_PORT_POWERDOWN);
+		writel_relaxed(0x0,
+				motg->phy_csr_regs + QUSB2PHY_PORT_UTMI_CTRL2);
+
+		/* Program tuning parameters for PHY */
+		seq = motg->pdata->phy_init_seq;
+		if (seq) {
+			while (seq[0] >= 0) {
+				writel_relaxed(seq[1],
+						motg->phy_csr_regs + seq[0]);
+				seq += 2;
+			}
+		}
+
+		/* ensure above writes are completed before re-enabling PHY */
+		wmb();
+		writel_relaxed(0x22,
+				motg->phy_csr_regs + QUSB2PHY_PORT_POWERDOWN);
+		break;
+	case SNPS_FEMTO_PHY:
+		if (!motg->phy_por_clk) {
+			pr_err("phy_por_clk missing\n");
+			break;
+		}
+		ret = reset_control_assert(motg->phy_por_reset);
+		if (ret) {
+			pr_err("phy_por_clk assert failed %d\n", ret);
+			break;
+		}
+		/*
+		 * The Femto PHY is POR reset in the following scenarios.
+		 *
+		 * 1. After overriding the parameter registers.
+		 * 2. Low power mode exit from PHY retention.
+		 *
+		 * Ensure that SIDDQ is cleared before bringing the PHY
+		 * out of reset.
+		 *
+		 */
+
+		val = readb_relaxed(USB_PHY_CSR_PHY_CTRL_COMMON0);
+		val &= ~SIDDQ;
+		writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL_COMMON0);
+
+		/*
+		 * As per databook, 10 usec delay is required between
+		 * PHY POR assert and de-assert.
+		 */
+		usleep_range(10, 20);
+		ret = reset_control_deassert(motg->phy_por_reset);
+		if (ret) {
+			pr_err("phy_por_clk de-assert failed %d\n", ret);
+			break;
+		}
+		/*
+		 * As per databook, it takes 75 usec for PHY to stabilize
+		 * after the reset.
+		 */
+		usleep_range(80, 100);
+		break;
+	default:
+		break;
+	}
+	/* Ensure that RESET operation is completed. */
+	mb();
+}
+
+static int msm_otg_reset(struct usb_phy *phy)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int ret;
+	u32 val = 0;
+	u32 ulpi_val = 0;
+
+	msm_otg_dbg_log_event(&motg->phy, "USB RESET", phy->otg->state,
+			get_pm_runtime_counter(phy->dev));
+	/*
+	 * USB PHY and Link reset also reset the USB BAM.
+	 * Thus perform reset operation only once to avoid
+	 * USB BAM reset on other cases e.g. USB cable disconnections.
+	 * If hardware reported error then it must be reset for recovery.
+	 */
+	if (motg->err_event_seen)
+		dev_info(phy->dev, "performing USB h/w reset for recovery\n");
+	else if (pdata->disable_reset_on_disconnect && motg->reset_counter)
+		return 0;
+
+	motg->reset_counter++;
+
+	disable_irq(motg->irq);
+	if (motg->phy_irq)
+		disable_irq(motg->phy_irq);
+
+	ret = msm_otg_phy_reset(motg);
+	if (ret) {
+		dev_err(phy->dev, "phy_reset failed\n");
+		if (motg->phy_irq)
+			enable_irq(motg->phy_irq);
+
+		enable_irq(motg->irq);
+		return ret;
+	}
+
+	if (motg->phy_irq)
+		enable_irq(motg->phy_irq);
+
+	enable_irq(motg->irq);
+	ret = msm_otg_link_reset(motg);
+	if (ret) {
+		dev_err(phy->dev, "link reset failed\n");
+		return ret;
+	}
+
+	msleep(100);
+
+	/* Reset USB PHY after performing USB Link RESET */
+	msm_usb_phy_reset(motg);
+
+	/* Program USB PHY Override registers. */
+	ulpi_init(motg);
+
+	/*
+	 * It is required to reset USB PHY after programming
+	 * the USB PHY Override registers to get the new
+	 * values into effect.
+	 */
+	msm_usb_phy_reset(motg);
+
+	if (pdata->otg_control == OTG_PHY_CONTROL) {
+		val = readl_relaxed(USB_OTGSC);
+		if (pdata->mode == USB_OTG) {
+			ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
+			val |= OTGSC_IDIE | OTGSC_BSVIE;
+		} else if (pdata->mode == USB_PERIPHERAL) {
+			ulpi_val = ULPI_INT_SESS_VALID;
+			val |= OTGSC_BSVIE;
+		}
+		writel_relaxed(val, USB_OTGSC);
+		ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
+		ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
+	} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+		ulpi_write(phy, OTG_COMP_DISABLE,
+			ULPI_SET(ULPI_PWR_CLK_MNG_REG));
+		if (motg->phy_irq)
+			writeb_relaxed(USB_PHY_ID_MASK,
+				USB2_PHY_USB_PHY_INTERRUPT_MASK1);
+	}
+
+	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)
+		writel_relaxed(readl_relaxed(USB_OTGSC) & ~(OTGSC_IDPU),
+				USB_OTGSC);
+
+	msm_otg_dbg_log_event(&motg->phy, "USB RESET DONE", phy->otg->state,
+			get_pm_runtime_counter(phy->dev));
+
+	if (pdata->enable_axi_prefetch)
+		writel_relaxed(readl_relaxed(USB_HS_APF_CTRL) | (APF_CTRL_EN),
+							USB_HS_APF_CTRL);
+
+	/*
+	 * Disable USB BAM as block reset resets USB BAM registers.
+	 */
+	msm_usb_bam_enable(CI_CTRL, false);
+
+	return 0;
+}
+
+static void msm_otg_kick_sm_work(struct msm_otg *motg)
+{
+	if (atomic_read(&motg->in_lpm))
+		motg->resume_pending = true;
+
+	/* For device mode, resume now. Let pm_resume handle other cases */
+	if (atomic_read(&motg->pm_suspended) &&
+			motg->phy.otg->state != OTG_STATE_B_SUSPEND) {
+		motg->sm_work_pending = true;
+	} else if (!motg->sm_work_pending) {
+		/* process event only if previous one is not pending */
+		queue_work(motg->otg_wq, &motg->sm_work);
+	}
+}
+
+/*
+ * UDC calls usb_phy_set_suspend() to notify during bus suspend/resume.
+ * Update relevant state-machine inputs and queue sm_work.
+ * LPM enter/exit doesn't happen directly from this routine.
+ */
+
+static int msm_otg_set_suspend(struct usb_phy *phy, int suspend)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+
+	pr_debug("%s(%d) in %s state\n", __func__, suspend,
+				usb_otg_state_string(phy->otg->state));
+	msm_otg_dbg_log_event(phy, "SET SUSPEND", suspend, phy->otg->state);
+
+	if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+		return 0;
+
+	if (suspend) {
+		/* called in suspend interrupt context */
+		pr_debug("peripheral bus suspend\n");
+		msm_otg_dbg_log_event(phy, "PERIPHERAL BUS SUSPEND",
+				motg->inputs, phy->otg->state);
+
+		set_bit(A_BUS_SUSPEND, &motg->inputs);
+	} else {
+		/* host resume or remote-wakeup */
+		pr_debug("peripheral bus resume\n");
+		msm_otg_dbg_log_event(phy, "PERIPHERAL BUS RESUME",
+				motg->inputs, phy->otg->state);
+
+		clear_bit(A_BUS_SUSPEND, &motg->inputs);
+	}
+	/* use kick_sm_work to handle race with pm_resume */
+	msm_otg_kick_sm_work(motg);
+
+	return 0;
+}
+
+static int msm_otg_bus_freq_set(struct msm_otg *motg, enum usb_noc_mode mode)
+{
+	int i, ret;
+	long rate;
+
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		rate = bus_freqs[mode][i];
+		if (!rate) {
+			pr_debug("%s rate not available\n", bus_clkname[i]);
+			continue;
+		}
+
+		ret = clk_set_rate(motg->bus_clks[i], rate);
+		if (ret) {
+			pr_err("%s set rate failed: %d\n", bus_clkname[i], ret);
+			return ret;
+		}
+		pr_debug("%s set to %lu Hz\n", bus_clkname[i],
+			 clk_get_rate(motg->bus_clks[i]));
+		msm_otg_dbg_log_event(&motg->phy, "OTG BUS FREQ SET", i, rate);
+	}
+
+	bus_clk_rate_set = true;
+
+	return 0;
+}
+
+static int msm_otg_bus_freq_get(struct msm_otg *motg)
+{
+	struct device *dev = motg->phy.dev;
+	struct device_node *np = dev->of_node;
+	int len = 0, i, count = USB_NUM_BUS_CLOCKS;
+
+	if (!np)
+		return -EINVAL;
+
+	/* SVS requires extra set of frequencies for perf_mode sysfs node */
+	if (motg->default_noc_mode == USB_NOC_SVS_VOTE)
+		count *= 2;
+
+	len = of_property_count_elems_of_size(np, "qcom,bus-clk-rate",
+							sizeof(len));
+	if (!len || (len != count)) {
+		pr_err("Invalid bus rate:%d %u\n", len, motg->default_noc_mode);
+		return -EINVAL;
+	}
+	of_property_read_u32_array(np, "qcom,bus-clk-rate", bus_freqs[0],
+				   count);
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		if (bus_freqs[0][i] == 0) {
+			motg->bus_clks[i] = NULL;
+			pr_debug("%s not available\n", bus_clkname[i]);
+			continue;
+		}
+
+		motg->bus_clks[i] = devm_clk_get(dev, bus_clkname[i]);
+		if (IS_ERR(motg->bus_clks[i])) {
+			pr_err("%s get failed\n", bus_clkname[i]);
+			return PTR_ERR(motg->bus_clks[i]);
+		}
+	}
+	return 0;
+}
+
+static void msm_otg_bus_clks_enable(struct msm_otg *motg)
+{
+	int i;
+	int ret;
+
+	if (!bus_clk_rate_set || motg->bus_clks_enabled)
+		return;
+
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		if (motg->bus_clks[i] == NULL)
+			continue;
+		ret = clk_prepare_enable(motg->bus_clks[i]);
+		if (ret) {
+			pr_err("%s enable rate failed: %d\n", bus_clkname[i],
+				ret);
+			goto err_clk_en;
+		}
+	}
+	motg->bus_clks_enabled = true;
+	return;
+err_clk_en:
+	for (--i; i >= 0; --i) {
+		if (motg->bus_clks[i] != NULL)
+			clk_disable_unprepare(motg->bus_clks[i]);
+	}
+}
+
+static void msm_otg_bus_clks_disable(struct msm_otg *motg)
+{
+	int i;
+
+	if (!bus_clk_rate_set || !motg->bus_clks_enabled)
+		return;
+
+	for (i = 0; i < USB_NUM_BUS_CLOCKS; i++) {
+		if (motg->bus_clks[i] != NULL)
+			clk_disable_unprepare(motg->bus_clks[i]);
+	}
+	motg->bus_clks_enabled = false;
+}
+
+static void msm_otg_bus_vote(struct msm_otg *motg, enum usb_bus_vote vote)
+{
+	int ret;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	msm_otg_dbg_log_event(&motg->phy, "BUS VOTE", vote,
+						motg->phy.otg->state);
+	/* Check if target allows min_vote to be same as no_vote */
+	if (pdata->bus_scale_table &&
+	    vote >= pdata->bus_scale_table->num_usecases)
+		vote = USB_NO_PERF_VOTE;
+
+	if (motg->bus_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+			motg->bus_perf_client, vote);
+		if (ret)
+			dev_err(motg->phy.dev, "%s: Failed to vote (%d)\n"
+				   "for bus bw %d\n", __func__, vote, ret);
+	}
+
+	if (vote == USB_MAX_PERF_VOTE)
+		msm_otg_bus_clks_enable(motg);
+	else
+		msm_otg_bus_clks_disable(motg);
+}
+
+static void msm_otg_enable_phy_hv_int(struct msm_otg *motg)
+{
+	bool bsv_id_hv_int = false;
+	bool dp_dm_hv_int = false;
+	u32 val;
+
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL ||
+				motg->phy_irq)
+		bsv_id_hv_int = true;
+	if (motg->host_bus_suspend || motg->device_bus_suspend)
+		dp_dm_hv_int = true;
+
+	if (!bsv_id_hv_int && !dp_dm_hv_int)
+		return;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		if (bsv_id_hv_int)
+			val |= (PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+		if (dp_dm_hv_int)
+			val |= PHY_CLAMP_DPDMSE_EN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		if (bsv_id_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL1);
+			val |= ID_HV_CLAMP_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL1);
+		}
+
+		if (dp_dm_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL3);
+			val |= CLAMP_MPM_DPSE_DMSE_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL3);
+		}
+		break;
+	default:
+		break;
+	}
+	pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n",
+			__func__, bsv_id_hv_int, dp_dm_hv_int);
+	msm_otg_dbg_log_event(&motg->phy, "PHY HV INTR ENABLED",
+			bsv_id_hv_int, dp_dm_hv_int);
+}
+
+static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
+{
+	bool bsv_id_hv_int = false;
+	bool dp_dm_hv_int = false;
+	u32 val;
+
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL ||
+				motg->phy_irq)
+		bsv_id_hv_int = true;
+	if (motg->host_bus_suspend || motg->device_bus_suspend)
+		dp_dm_hv_int = true;
+
+	if (!bsv_id_hv_int && !dp_dm_hv_int)
+		return;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		if (bsv_id_hv_int)
+			val &= ~(PHY_IDHV_INTEN | PHY_OTGSESSVLDHV_INTEN);
+		if (dp_dm_hv_int)
+			val &= ~PHY_CLAMP_DPDMSE_EN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		if (bsv_id_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL1);
+			val &= ~ID_HV_CLAMP_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL1);
+		}
+
+		if (dp_dm_hv_int) {
+			val = readb_relaxed(USB_PHY_CSR_PHY_CTRL3);
+			val &= ~CLAMP_MPM_DPSE_DMSE_EN_N;
+			writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL3);
+		}
+		break;
+	default:
+		break;
+	}
+	pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n",
+			__func__, bsv_id_hv_int, dp_dm_hv_int);
+	msm_otg_dbg_log_event(&motg->phy, "PHY HV INTR DISABLED",
+			bsv_id_hv_int, dp_dm_hv_int);
+}
+
+static void msm_otg_enter_phy_retention(struct msm_otg *motg)
+{
+	u32 val;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		val &= ~PHY_RETEN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		/* Retention is supported via SIDDQ */
+		val = readb_relaxed(USB_PHY_CSR_PHY_CTRL_COMMON0);
+		val |= SIDDQ;
+		writeb_relaxed(val, USB_PHY_CSR_PHY_CTRL_COMMON0);
+		break;
+	default:
+		break;
+	}
+	pr_debug("USB PHY is in retention\n");
+	msm_otg_dbg_log_event(&motg->phy, "USB PHY ENTER RETENTION",
+			motg->pdata->phy_type, 0);
+}
+
+static void msm_otg_exit_phy_retention(struct msm_otg *motg)
+{
+	int val;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		val = readl_relaxed(motg->usb_phy_ctrl_reg);
+		val |= PHY_RETEN;
+		writel_relaxed(val, motg->usb_phy_ctrl_reg);
+		break;
+	case SNPS_FEMTO_PHY:
+		/*
+		 * It is required to do USB block reset to bring Femto PHY out
+		 * of retention.
+		 */
+		msm_otg_reset(&motg->phy);
+		break;
+	default:
+		break;
+	}
+	pr_debug("USB PHY is exited from retention\n");
+	msm_otg_dbg_log_event(&motg->phy, "USB PHY EXIT RETENTION",
+			motg->pdata->phy_type, 0);
+}
+
+static void msm_id_status_w(struct work_struct *w);
+static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data)
+{
+	struct msm_otg *motg = data;
+
+	msm_otg_dbg_log_event(&motg->phy, "PHY ID IRQ",
+			atomic_read(&motg->in_lpm), motg->phy.otg->state);
+	if (atomic_read(&motg->in_lpm)) {
+		pr_debug("PHY ID IRQ in LPM\n");
+		motg->phy_irq_pending = true;
+		msm_otg_kick_sm_work(motg);
+	} else {
+		pr_debug("PHY ID IRQ outside LPM\n");
+		msm_id_status_w(&motg->id_status_work.work);
+	}
+
+	return IRQ_HANDLED;
+}
+
+#define PHY_SUSPEND_TIMEOUT_USEC (5 * 1000)
+#define PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC 100
+#define PHY_RESUME_TIMEOUT_USEC	(100 * 1000)
+
+#define PHY_SUSPEND_RETRIES_MAX 3
+
+static void msm_otg_set_vbus_state(int online);
+static void msm_otg_perf_vote_update(struct msm_otg *motg, bool perf_mode);
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_otg_suspend(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	struct usb_bus *bus = phy->otg->host;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int cnt;
+	bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
+	bool floated_charger, sm_work_busy;
+	u32 cmd_val;
+	u32 portsc, config2;
+	u32 func_ctrl;
+	int phcd_retry_cnt = 0, ret;
+	unsigned int phy_suspend_timeout;
+
+	cnt = 0;
+	msm_otg_dbg_log_event(phy, "LPM ENTER START",
+			motg->inputs, phy->otg->state);
+
+	if (atomic_read(&motg->in_lpm))
+		return 0;
+
+	cancel_delayed_work_sync(&motg->perf_vote_work);
+
+	disable_irq(motg->irq);
+	if (motg->phy_irq)
+		disable_irq(motg->phy_irq);
+lpm_start:
+	host_bus_suspend = phy->otg->host && !test_bit(ID, &motg->inputs);
+	device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
+		test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+		motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
+
+	if (host_bus_suspend)
+		msm_otg_perf_vote_update(motg, false);
+	/*
+	 * Allow putting PHY into SIDDQ with wall charger connected in
+	 * case of external charger detection.
+	 */
+	dcp = (motg->chg_type == USB_DCP_CHARGER) && !motg->is_ext_chg_dcp;
+	prop_charger = motg->chg_type == USB_NONCOMPLIANT_CHARGER;
+	floated_charger = motg->chg_type == USB_FLOATED_CHARGER;
+
+	/* !BSV, but its handling is in progress by otg sm_work */
+	sm_work_busy = !test_bit(B_SESS_VLD, &motg->inputs) &&
+			phy->otg->state == OTG_STATE_B_PERIPHERAL;
+
+	/* Perform block reset to recover from UDC error events on disconnect */
+	if (motg->err_event_seen)
+		msm_otg_reset(phy);
+
+	/* Enable line state difference wakeup fix for only device and host
+	 * bus suspend scenarios.  Otherwise PHY can not be suspended when
+	 * a charger that pulls DP/DM high is connected.
+	 */
+	config2 = readl_relaxed(USB_GENCONFIG_2);
+	if (device_bus_suspend)
+		config2 |= GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
+	else
+		config2 &= ~GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN;
+	writel_relaxed(config2, USB_GENCONFIG_2);
+
+	/*
+	 * Abort suspend when,
+	 * 1. charging detection in progress due to cable plug-in
+	 * 2. host mode activation in progress due to Micro-A cable insertion
+	 * 3. !BSV, but its handling is in progress by otg sm_work
+	 * Don't abort suspend in case of dcp detected by PMIC
+	 */
+
+	if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
+		!dcp && !motg->is_ext_chg_dcp && !prop_charger &&
+			!floated_charger) || sm_work_busy) {
+		msm_otg_dbg_log_event(phy, "LPM ENTER ABORTED",
+				motg->inputs, motg->chg_type);
+		enable_irq(motg->irq);
+		if (motg->phy_irq)
+			enable_irq(motg->phy_irq);
+		return -EBUSY;
+	}
+
+	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
+		/* put the controller in non-driving mode */
+		func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+		func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+		func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+		ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+		ulpi_write(phy, ULPI_IFC_CTRL_AUTORESUME,
+						ULPI_CLR(ULPI_IFC_CTRL));
+	}
+
+	/*
+	 * PHY suspend sequence as mentioned in the databook.
+	 *
+	 * Device bus suspend: The controller may abort PHY suspend if
+	 * there is an incoming reset or resume from the host. If PHCD
+	 * is not set within 100 usec. Abort the LPM sequence.
+	 *
+	 * Host bus suspend: If the peripheral is attached, PHY is already
+	 * put into suspend along with the peripheral bus suspend. poll for
+	 * PHCD upto 5 msec. If the peripheral is not attached i.e entering
+	 * LPM with Micro-A cable, set the PHCD and poll for it for 5 msec.
+	 *
+	 * No cable connected: Set the PHCD to suspend the PHY. Poll for PHCD
+	 * upto 5 msec.
+	 *
+	 * The controller aborts PHY suspend only in device bus suspend case.
+	 * In other cases, it is observed that PHCD may not get set within
+	 * the timeout. If so, set the PHCD again and poll for it before
+	 * reset recovery.
+	 */
+
+phcd_retry:
+	if (device_bus_suspend)
+		phy_suspend_timeout = PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC;
+	else
+		phy_suspend_timeout = PHY_SUSPEND_TIMEOUT_USEC;
+
+	cnt = 0;
+	portsc = readl_relaxed(USB_PORTSC);
+	if (!(portsc & PORTSC_PHCD)) {
+		writel_relaxed(portsc | PORTSC_PHCD,
+				USB_PORTSC);
+		while (cnt < phy_suspend_timeout) {
+			if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
+				break;
+			udelay(1);
+			cnt++;
+		}
+	}
+
+	if (cnt >= phy_suspend_timeout) {
+		if (phcd_retry_cnt > PHY_SUSPEND_RETRIES_MAX) {
+			msm_otg_dbg_log_event(phy, "PHY SUSPEND FAILED",
+				phcd_retry_cnt, phy->otg->state);
+			dev_err(phy->dev, "PHY suspend failed\n");
+			ret = -EBUSY;
+			goto phy_suspend_fail;
+		}
+
+		if (device_bus_suspend) {
+			dev_dbg(phy->dev, "PHY suspend aborted\n");
+			ret = -EBUSY;
+			goto phy_suspend_fail;
+		} else {
+			if (phcd_retry_cnt++ < PHY_SUSPEND_RETRIES_MAX) {
+				dev_dbg(phy->dev, "PHY suspend retry\n");
+				goto phcd_retry;
+			} else {
+				dev_err(phy->dev, "reset attempt during PHY suspend\n");
+				phcd_retry_cnt++;
+				motg->reset_counter = 0;
+				msm_otg_reset(phy);
+				goto lpm_start;
+			}
+		}
+	}
+
+	/*
+	 * PHY has capability to generate interrupt asynchronously in low
+	 * power mode (LPM). This interrupt is level triggered. So USB IRQ
+	 * line must be disabled till async interrupt enable bit is cleared
+	 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
+	 * block data communication from PHY.
+	 *
+	 * PHY retention mode is disallowed while entering to LPM with wall
+	 * charger connected.  But PHY is put into suspend mode. Hence
+	 * enable asynchronous interrupt to detect charger disconnection when
+	 * PMIC notifications are unavailable.
+	 */
+	cmd_val = readl_relaxed(USB_USBCMD);
+	if (host_bus_suspend || device_bus_suspend ||
+		(motg->pdata->otg_control == OTG_PHY_CONTROL))
+		cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
+	else
+		cmd_val |= ULPI_STP_CTRL;
+	writel_relaxed(cmd_val, USB_USBCMD);
+
+	/*
+	 * BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
+	 * PHY retention and collapse can not happen with VDP_SRC enabled.
+	 */
+
+
+	/*
+	 * We come here in 3 scenarios.
+	 *
+	 * (1) No cable connected (out of session):
+	 *	- BSV/ID HV interrupts are enabled for PHY based detection.
+	 *	- PHY is put in retention.
+	 *	- If allowed (PMIC based detection), PHY is power collapsed.
+	 *	- DVDD (CX/MX) minimization and XO shutdown are allowed.
+	 *	- The wakeup is through VBUS/ID interrupt from PHY/PMIC/user.
+	 * (2) USB wall charger:
+	 *	- BSV/ID HV interrupts are enabled for PHY based detection.
+	 *	- For BC1.2 compliant charger, retention is not allowed to
+	 *	keep VDP_SRC on. XO shutdown is allowed.
+	 *	- The wakeup is through VBUS/ID interrupt from PHY/PMIC/user.
+	 * (3) Device/Host Bus suspend (if LPM is enabled):
+	 *	- BSV/ID HV interrupts are enabled for PHY based detection.
+	 *	- D+/D- MPM pin are configured to wakeup from line state
+	 *	change through PHY HV interrupts. PHY HV interrupts are
+	 *	also enabled. If MPM pins are not available, retention and
+	 *	XO is not allowed.
+	 *	- PHY is put into retention only if a gpio is used to keep
+	 *	the D+ pull-up. ALLOW_BUS_SUSPEND_WITHOUT_REWORK capability
+	 *	is set means, PHY can enable D+ pull-up or D+/D- pull-down
+	 *	without any re-work and PHY should not be put into retention.
+	 *	- DVDD (CX/MX) minimization and XO shutdown is allowed if
+	 *	ALLOW_BUS_SUSPEND_WITHOUT_REWORK is set (PHY DVDD is supplied
+	 *	via PMIC LDO) or board level re-work is present.
+	 *	- The wakeup is through VBUS/ID interrupt from PHY/PMIC/user
+	 *	or USB link asynchronous interrupt for line state change.
+	 *
+	 */
+	motg->host_bus_suspend = host_bus_suspend;
+	motg->device_bus_suspend = device_bus_suspend;
+
+	if (motg->caps & ALLOW_PHY_RETENTION && !device_bus_suspend && !dcp &&
+		 (!host_bus_suspend || (motg->caps &
+		ALLOW_BUS_SUSPEND_WITHOUT_REWORK) ||
+		  ((motg->caps & ALLOW_HOST_PHY_RETENTION)
+		&& (pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS))))) {
+		msm_otg_enable_phy_hv_int(motg);
+		if ((!host_bus_suspend || !(motg->caps &
+			ALLOW_BUS_SUSPEND_WITHOUT_REWORK)) &&
+			!(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
+			msm_otg_enter_phy_retention(motg);
+			motg->lpm_flags |= PHY_RETENTIONED;
+		}
+	} else if (device_bus_suspend && !dcp &&
+			(pdata->mpm_dpshv_int || pdata->mpm_dmshv_int)) {
+		/* DP DM HV interrupts are used for bus resume from XO off */
+		msm_otg_enable_phy_hv_int(motg);
+		if (motg->caps & ALLOW_PHY_RETENTION && pdata->vddmin_gpio) {
+
+			/*
+			 * This is HW WA needed when PHY_CLAMP_DPDMSE_EN is
+			 * enabled and we put the phy in retention mode.
+			 * Without this WA, the async_irq will be fired right
+			 * after suspending whithout any bus resume.
+			 */
+			config2 = readl_relaxed(USB_GENCONFIG_2);
+			config2 &= ~GENCONFIG_2_DPSE_DMSE_HV_INTR_EN;
+			writel_relaxed(config2, USB_GENCONFIG_2);
+
+			msm_otg_enter_phy_retention(motg);
+			motg->lpm_flags |= PHY_RETENTIONED;
+			gpio_direction_output(pdata->vddmin_gpio, 1);
+		}
+	}
+
+	/* Ensure that above operation is completed before turning off clocks */
+	mb();
+	/* Consider clocks on workaround flag only in case of bus suspend */
+	if (!(phy->otg->state == OTG_STATE_B_PERIPHERAL &&
+			test_bit(A_BUS_SUSPEND, &motg->inputs)) ||
+			!motg->pdata->core_clk_always_on_workaround) {
+		clk_disable_unprepare(motg->pclk);
+		clk_disable_unprepare(motg->core_clk);
+		if (motg->phy_csr_clk)
+			clk_disable_unprepare(motg->phy_csr_clk);
+		motg->lpm_flags |= CLOCKS_DOWN;
+	}
+
+	/* usb phy no more require TCXO clock, hence vote for TCXO disable */
+	if (!host_bus_suspend || (motg->caps &
+		ALLOW_BUS_SUSPEND_WITHOUT_REWORK) ||
+		((motg->caps & ALLOW_HOST_PHY_RETENTION) &&
+		(pdata->dpdm_pulldown_added || !(portsc & PORTSC_CCS)))) {
+		if (motg->xo_clk) {
+			clk_disable_unprepare(motg->xo_clk);
+			motg->lpm_flags |= XO_SHUTDOWN;
+		}
+	}
+
+	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
+			!host_bus_suspend && !dcp && !device_bus_suspend) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
+		motg->lpm_flags |= PHY_PWR_COLLAPSED;
+	} else if (motg->caps & ALLOW_PHY_REGULATORS_LPM &&
+			!host_bus_suspend && !device_bus_suspend && !dcp) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_ON);
+		motg->lpm_flags |= PHY_REGULATORS_LPM;
+	}
+
+	if (motg->lpm_flags & PHY_RETENTIONED ||
+		(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
+		regulator_disable(hsusb_vdd);
+		msm_hsusb_config_vddcx(0);
+	}
+
+	if (device_may_wakeup(phy->dev)) {
+		if (host_bus_suspend || device_bus_suspend) {
+			enable_irq_wake(motg->async_irq);
+			enable_irq_wake(motg->irq);
+		}
+
+		if (motg->phy_irq)
+			enable_irq_wake(motg->phy_irq);
+		if (motg->pdata->pmic_id_irq)
+			enable_irq_wake(motg->pdata->pmic_id_irq);
+		if (motg->ext_id_irq)
+			enable_irq_wake(motg->ext_id_irq);
+		if (pdata->otg_control == OTG_PHY_CONTROL &&
+			pdata->mpm_otgsessvld_int)
+			msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 1);
+		if ((host_bus_suspend || device_bus_suspend) &&
+				pdata->mpm_dpshv_int)
+			msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 1);
+		if ((host_bus_suspend || device_bus_suspend) &&
+				pdata->mpm_dmshv_int)
+			msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 1);
+	}
+	if (bus)
+		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+	msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+
+	atomic_set(&motg->in_lpm, 1);
+
+	/* Enable ASYNC IRQ during LPM */
+	enable_irq(motg->async_irq);
+	if (motg->phy_irq)
+		enable_irq(motg->phy_irq);
+
+	enable_irq(motg->irq);
+	pm_relax(&motg->pdev->dev);
+
+	dev_dbg(phy->dev, "LPM caps = %lu flags = %lu\n",
+			motg->caps, motg->lpm_flags);
+	dev_info(phy->dev, "USB in low power mode\n");
+	msm_otg_dbg_log_event(phy, "LPM ENTER DONE",
+			motg->caps, motg->lpm_flags);
+
+	if (motg->err_event_seen) {
+		motg->err_event_seen = false;
+		if (motg->vbus_state != test_bit(B_SESS_VLD, &motg->inputs))
+			msm_otg_set_vbus_state(motg->vbus_state);
+		if (motg->id_state != test_bit(ID, &motg->inputs))
+			msm_id_status_w(&motg->id_status_work.work);
+	}
+
+	return 0;
+
+phy_suspend_fail:
+	enable_irq(motg->irq);
+	if (motg->phy_irq)
+		enable_irq(motg->phy_irq);
+	return ret;
+}
+
+static int msm_otg_resume(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	struct usb_bus *bus = phy->otg->host;
+	struct usb_hcd *hcd = bus_to_hcd(phy->otg->host);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	int cnt = 0;
+	unsigned int temp;
+	unsigned int ret;
+	u32 func_ctrl;
+
+	msm_otg_dbg_log_event(phy, "LPM EXIT START", motg->inputs,
+							phy->otg->state);
+	if (!atomic_read(&motg->in_lpm)) {
+		msm_otg_dbg_log_event(phy, "USB NOT IN LPM",
+				atomic_read(&motg->in_lpm), phy->otg->state);
+		return 0;
+	}
+
+	disable_irq(motg->irq);
+	pm_stay_awake(&motg->pdev->dev);
+
+	/*
+	 * If we are resuming from the device bus suspend, restore
+	 * the max performance bus vote. Otherwise put a minimum
+	 * bus vote to satisfy the requirement for enabling clocks.
+	 */
+
+	if (motg->device_bus_suspend && debug_bus_voting_enabled)
+		msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+	else
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+
+	/* Vote for TCXO when waking up the phy */
+	if (motg->lpm_flags & XO_SHUTDOWN) {
+		if (motg->xo_clk)
+			clk_prepare_enable(motg->xo_clk);
+		motg->lpm_flags &= ~XO_SHUTDOWN;
+	}
+
+	if (motg->lpm_flags & CLOCKS_DOWN) {
+		if (motg->phy_csr_clk) {
+			ret = clk_prepare_enable(motg->phy_csr_clk);
+			WARN(ret, "USB phy_csr_clk enable failed\n");
+		}
+		ret = clk_prepare_enable(motg->core_clk);
+		WARN(ret, "USB core_clk enable failed\n");
+		ret = clk_prepare_enable(motg->pclk);
+		WARN(ret, "USB pclk enable failed\n");
+		motg->lpm_flags &= ~CLOCKS_DOWN;
+	}
+
+	if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
+		motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
+	} else if (motg->lpm_flags & PHY_REGULATORS_LPM) {
+		msm_hsusb_ldo_enable(motg, USB_PHY_REG_LPM_OFF);
+		motg->lpm_flags &= ~PHY_REGULATORS_LPM;
+	}
+
+	if (motg->lpm_flags & PHY_RETENTIONED ||
+		(motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)) {
+		msm_hsusb_config_vddcx(1);
+		ret = regulator_enable(hsusb_vdd);
+		WARN(ret, "hsusb_vdd LDO enable failed\n");
+		msm_otg_disable_phy_hv_int(motg);
+		msm_otg_exit_phy_retention(motg);
+		motg->lpm_flags &= ~PHY_RETENTIONED;
+		if (pdata->vddmin_gpio && motg->device_bus_suspend)
+			gpio_direction_input(pdata->vddmin_gpio);
+	} else if (motg->device_bus_suspend) {
+		msm_otg_disable_phy_hv_int(motg);
+	}
+
+	temp = readl_relaxed(USB_USBCMD);
+	temp &= ~ASYNC_INTR_CTRL;
+	temp &= ~ULPI_STP_CTRL;
+	writel_relaxed(temp, USB_USBCMD);
+
+	/*
+	 * PHY comes out of low power mode (LPM) in case of wakeup
+	 * from asynchronous interrupt.
+	 */
+	if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+		goto skip_phy_resume;
+
+	writel_relaxed(readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
+
+	while (cnt < PHY_RESUME_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
+		/*
+		 * This is a fatal error. Reset the link and
+		 * PHY. USB state can not be restored. Re-insertion
+		 * of USB cable is the only way to get USB working.
+		 */
+		dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n"
+									);
+		msm_otg_reset(phy);
+	}
+
+skip_phy_resume:
+	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED) {
+		/* put the controller in normal mode */
+		func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+		func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+		func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+		ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+	}
+
+	if (device_may_wakeup(phy->dev)) {
+		if (motg->host_bus_suspend || motg->device_bus_suspend) {
+			disable_irq_wake(motg->async_irq);
+			disable_irq_wake(motg->irq);
+		}
+
+		if (motg->phy_irq)
+			disable_irq_wake(motg->phy_irq);
+		if (motg->pdata->pmic_id_irq)
+			disable_irq_wake(motg->pdata->pmic_id_irq);
+		if (motg->ext_id_irq)
+			disable_irq_wake(motg->ext_id_irq);
+		if (pdata->otg_control == OTG_PHY_CONTROL &&
+			pdata->mpm_otgsessvld_int)
+			msm_mpm_set_pin_wake(pdata->mpm_otgsessvld_int, 0);
+		if ((motg->host_bus_suspend || motg->device_bus_suspend) &&
+			pdata->mpm_dpshv_int)
+			msm_mpm_set_pin_wake(pdata->mpm_dpshv_int, 0);
+		if ((motg->host_bus_suspend || motg->device_bus_suspend) &&
+			pdata->mpm_dmshv_int)
+			msm_mpm_set_pin_wake(pdata->mpm_dmshv_int, 0);
+	}
+	if (bus)
+		set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
+
+	atomic_set(&motg->in_lpm, 0);
+
+	if (motg->async_int) {
+		/* Match the disable_irq call from ISR */
+		enable_irq(motg->async_int);
+		motg->async_int = 0;
+	}
+	enable_irq(motg->irq);
+
+	/* Enable ASYNC_IRQ only during LPM */
+	disable_irq(motg->async_irq);
+
+	if (motg->phy_irq_pending) {
+		motg->phy_irq_pending = false;
+		msm_id_status_w(&motg->id_status_work.work);
+	}
+
+	if (motg->host_bus_suspend) {
+		usb_hcd_resume_root_hub(hcd);
+		schedule_delayed_work(&motg->perf_vote_work,
+			msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
+	}
+
+	dev_info(phy->dev, "USB exited from low power mode\n");
+	msm_otg_dbg_log_event(phy, "LPM EXIT DONE",
+			motg->caps, motg->lpm_flags);
+
+	return 0;
+}
+#endif
+
+static void msm_otg_notify_host_mode(struct msm_otg *motg, bool host_mode)
+{
+	if (!psy) {
+		pr_err("No USB power supply registered!\n");
+		return;
+	}
+
+	motg->host_mode = host_mode;
+	power_supply_changed(psy);
+}
+
+static int msm_otg_notify_chg_type(struct msm_otg *motg)
+{
+	static int charger_type;
+	union power_supply_propval pval = {0};
+
+	/*
+	 * TODO
+	 * Unify OTG driver charger types and power supply charger types
+	 */
+	if (charger_type == motg->chg_type)
+		return 0;
+
+	if (motg->chg_type == USB_SDP_CHARGER)
+		charger_type = POWER_SUPPLY_TYPE_USB;
+	else if (motg->chg_type == USB_CDP_CHARGER)
+		charger_type = POWER_SUPPLY_TYPE_USB_CDP;
+	else if (motg->chg_type == USB_DCP_CHARGER ||
+			motg->chg_type == USB_NONCOMPLIANT_CHARGER ||
+			motg->chg_type == USB_FLOATED_CHARGER)
+		charger_type = POWER_SUPPLY_TYPE_USB_DCP;
+	else
+		charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
+
+	if (!psy) {
+		pr_err("No USB power supply registered!\n");
+		return -EINVAL;
+	}
+
+	pr_debug("setting usb power supply type %d\n", charger_type);
+	msm_otg_dbg_log_event(&motg->phy, "SET USB PWR SUPPLY TYPE",
+			motg->chg_type, charger_type);
+	pval.intval = charger_type;
+	power_supply_set_property(psy, POWER_SUPPLY_PROP_TYPE, &pval);
+	return 0;
+}
+
+static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned int mA)
+{
+	union power_supply_propval pval = {0};
+	bool enable;
+	int limit;
+
+	if (!psy) {
+		dev_dbg(motg->phy.dev, "no usb power supply registered\n");
+		goto psy_error;
+	}
+
+	if (motg->cur_power == 0 && mA > 2) {
+		/* Enable charging */
+		enable = true;
+		limit = 1000 * mA;
+	} else if (motg->cur_power >= 0 && (mA == 0 || mA == 2)) {
+		/* Disable charging */
+		enable = false;
+		/* Set max current limit in uA */
+		limit = 1000 * mA;
+	} else {
+		enable = true;
+		/* Current has changed (100/2 --> 500) */
+		limit = 1000 * mA;
+	}
+
+	pval.intval = enable;
+	if (power_supply_set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval))
+		goto psy_error;
+
+	pval.intval = limit;
+	if (power_supply_set_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX,
+									&pval))
+		goto psy_error;
+
+	power_supply_changed(psy);
+	return 0;
+
+psy_error:
+	dev_dbg(motg->phy.dev, "power supply error when setting property\n");
+	return -ENXIO;
+}
+
+static void msm_otg_set_online_status(struct msm_otg *motg)
+{
+	union power_supply_propval pval = {0};
+
+	if (!psy) {
+		dev_dbg(motg->phy.dev, "no usb power supply registered\n");
+		return;
+	}
+
+	/* Set power supply online status to false */
+	pval.intval = false;
+	if (power_supply_set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval))
+		dev_dbg(motg->phy.dev, "error setting power supply property\n");
+}
+
+static void msm_otg_notify_charger(struct msm_otg *motg, unsigned int mA)
+{
+	struct usb_gadget *g = motg->phy.otg->gadget;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	if (g && g->is_a_peripheral)
+		return;
+
+	dev_dbg(motg->phy.dev, "Requested curr from USB = %u, max-type-c:%u\n",
+					mA, motg->typec_current_max);
+	/* Save bc1.2 max_curr if type-c charger later moves to diff mode */
+	motg->bc1p2_current_max = mA;
+
+	/*
+	 * Limit type-c charger current to 500 for SDP charger to avoid more
+	 * current drawn than 500 with Hosts that don't support type C due to
+	 * non compliant type-c to standard A cables.
+	 */
+	if (pdata->enable_sdp_typec_current_limit &&
+			(motg->chg_type == USB_SDP_CHARGER) &&
+					motg->typec_current_max > 500)
+		motg->typec_current_max = 500;
+
+	/* Override mA if type-c charger used (use hvdcp/bc1.2 if it is 500) */
+	if (motg->typec_current_max > 500 && mA < motg->typec_current_max)
+		mA = motg->typec_current_max;
+
+	if (msm_otg_notify_chg_type(motg))
+		dev_err(motg->phy.dev,
+			"Failed notifying %d charger type to PMIC\n",
+							motg->chg_type);
+
+	/*
+	 * This condition will be true when usb cable is disconnected
+	 * during bootup before enumeration. Check charger type also
+	 * to avoid clearing online flag in case of valid charger.
+	 */
+	if (motg->online && motg->cur_power == 0 && mA == 0 &&
+			(motg->chg_type == USB_INVALID_CHARGER))
+		msm_otg_set_online_status(motg);
+
+	if (motg->cur_power == mA)
+		return;
+
+	dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
+	msm_otg_dbg_log_event(&motg->phy, "AVAIL CURR FROM USB",
+			mA, motg->chg_type);
+
+	msm_otg_notify_power_supply(motg, mA);
+
+	motg->cur_power = mA;
+}
+
+static int msm_otg_set_power(struct usb_phy *phy, unsigned int mA)
+{
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
+
+	/*
+	 * Gadget driver uses set_power method to notify about the
+	 * available current based on suspend/configured states.
+	 *
+	 * IDEV_CHG can be drawn irrespective of suspend/un-configured
+	 * states when CDP/ACA is connected.
+	 */
+	if (motg->chg_type == USB_SDP_CHARGER)
+		msm_otg_notify_charger(motg, mA);
+
+	return 0;
+}
+
+static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on);
+
+static void msm_otg_perf_vote_update(struct msm_otg *motg, bool perf_mode)
+{
+	static bool curr_perf_mode;
+	int ret, latency = motg->pm_qos_latency;
+	long clk_rate;
+
+	if (curr_perf_mode == perf_mode)
+		return;
+
+	if (perf_mode) {
+		if (latency)
+			pm_qos_update_request(&motg->pm_qos_req_dma, latency);
+		msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+		clk_rate = motg->core_clk_rate;
+	} else {
+		if (latency)
+			pm_qos_update_request(&motg->pm_qos_req_dma,
+						PM_QOS_DEFAULT_VALUE);
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+		clk_rate = motg->core_clk_svs_rate;
+	}
+
+	if (clk_rate) {
+		ret = clk_set_rate(motg->core_clk, clk_rate);
+		if (ret)
+			dev_err(motg->phy.dev, "sys_clk set_rate fail:%d %ld\n",
+					ret, clk_rate);
+	}
+	curr_perf_mode = perf_mode;
+	pr_debug("%s: latency updated to: %d, core_freq to: %ld\n", __func__,
+					latency, clk_rate);
+}
+
+static void msm_otg_perf_vote_work(struct work_struct *w)
+{
+	struct msm_otg *motg = container_of(w, struct msm_otg,
+						perf_vote_work.work);
+	unsigned int curr_sample_int_count;
+	bool in_perf_mode = false;
+
+	curr_sample_int_count = motg->usb_irq_count;
+	motg->usb_irq_count = 0;
+
+	if (curr_sample_int_count >= PM_QOS_THRESHOLD)
+		in_perf_mode = true;
+
+	msm_otg_perf_vote_update(motg, in_perf_mode);
+	pr_debug("%s: in_perf_mode:%u, interrupts in last sample:%u\n",
+		 __func__, in_perf_mode, curr_sample_int_count);
+
+	schedule_delayed_work(&motg->perf_vote_work,
+			msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
+}
+
+static void msm_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	struct usb_hcd *hcd;
+	u32 val;
+
+	if (!otg->host)
+		return;
+
+	hcd = bus_to_hcd(otg->host);
+
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartHost GET",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+	pm_runtime_get_sync(otg->usb_phy->dev);
+	if (on) {
+		dev_dbg(otg->usb_phy->dev, "host on\n");
+		msm_otg_dbg_log_event(&motg->phy, "HOST ON",
+				motg->inputs, otg->state);
+		msm_hsusb_vbus_power(motg, 1);
+		msm_otg_reset(&motg->phy);
+
+		if (pdata->otg_control == OTG_PHY_CONTROL)
+			ulpi_write(otg->usb_phy, OTG_COMP_DISABLE,
+				ULPI_SET(ULPI_PWR_CLK_MNG_REG));
+
+		if (pdata->enable_axi_prefetch) {
+			val = readl_relaxed(USB_HS_APF_CTRL);
+			val &= ~APF_CTRL_EN;
+			writel_relaxed(val, USB_HS_APF_CTRL);
+		}
+		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+#ifdef CONFIG_SMP
+		motg->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ;
+		motg->pm_qos_req_dma.irq = motg->irq;
+#endif
+		pm_qos_add_request(&motg->pm_qos_req_dma,
+				PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+		/* start in perf mode for better performance initially */
+		msm_otg_perf_vote_update(motg, true);
+		schedule_delayed_work(&motg->perf_vote_work,
+				msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC));
+	} else {
+		dev_dbg(otg->usb_phy->dev, "host off\n");
+		msm_otg_dbg_log_event(&motg->phy, "HOST OFF",
+				motg->inputs, otg->state);
+		msm_hsusb_vbus_power(motg, 0);
+
+		cancel_delayed_work_sync(&motg->perf_vote_work);
+		msm_otg_perf_vote_update(motg, false);
+		pm_qos_remove_request(&motg->pm_qos_req_dma);
+
+		pm_runtime_disable(&hcd->self.root_hub->dev);
+		pm_runtime_barrier(&hcd->self.root_hub->dev);
+		usb_remove_hcd(hcd);
+		msm_otg_reset(&motg->phy);
+
+		if (pdata->enable_axi_prefetch)
+			writel_relaxed(readl_relaxed(USB_HS_APF_CTRL)
+					| (APF_CTRL_EN), USB_HS_APF_CTRL);
+
+		/* HCD core reset all bits of PORTSC. select ULPI phy */
+		writel_relaxed(0x80000000, USB_PORTSC);
+
+		if (pdata->otg_control == OTG_PHY_CONTROL)
+			ulpi_write(otg->usb_phy, OTG_COMP_DISABLE,
+				ULPI_CLR(ULPI_PWR_CLK_MNG_REG));
+	}
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartHost PUT",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+
+	pm_runtime_mark_last_busy(otg->usb_phy->dev);
+	pm_runtime_put_autosuspend(otg->usb_phy->dev);
+}
+
+static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
+{
+	int ret;
+	static bool vbus_is_on;
+
+	msm_otg_dbg_log_event(&motg->phy, "VBUS POWER", on, vbus_is_on);
+	if (vbus_is_on == on)
+		return;
+
+	if (motg->pdata->vbus_power) {
+		ret = motg->pdata->vbus_power(on);
+		if (!ret)
+			vbus_is_on = on;
+		return;
+	}
+
+	if (!vbus_otg) {
+		pr_err("vbus_otg is NULL.");
+		return;
+	}
+
+	/*
+	 * if entering host mode tell the charger to not draw any current
+	 * from usb before turning on the boost.
+	 * if exiting host mode disable the boost before enabling to draw
+	 * current from the source.
+	 */
+	if (on) {
+		msm_otg_notify_host_mode(motg, on);
+		ret = regulator_enable(vbus_otg);
+		if (ret) {
+			pr_err("unable to enable vbus_otg\n");
+			return;
+		}
+		vbus_is_on = true;
+	} else {
+		ret = regulator_disable(vbus_otg);
+		if (ret) {
+			pr_err("unable to disable vbus_otg\n");
+			return;
+		}
+		msm_otg_notify_host_mode(motg, on);
+		vbus_is_on = false;
+	}
+}
+
+static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+	struct usb_hcd *hcd;
+
+	/*
+	 * Fail host registration if this board can support
+	 * only peripheral configuration.
+	 */
+	if (motg->pdata->mode == USB_PERIPHERAL) {
+		dev_info(otg->usb_phy->dev, "Host mode is not supported\n");
+		return -ENODEV;
+	}
+
+	if (!motg->pdata->vbus_power && host) {
+		vbus_otg = devm_regulator_get(motg->phy.dev, "vbus_otg");
+		if (IS_ERR(vbus_otg)) {
+			msm_otg_dbg_log_event(&motg->phy,
+					"UNABLE TO GET VBUS_OTG",
+					otg->state, 0);
+			pr_err("Unable to get vbus_otg\n");
+			return PTR_ERR(vbus_otg);
+		}
+	}
+
+	if (!host) {
+		if (otg->state == OTG_STATE_A_HOST) {
+			msm_otg_start_host(otg, 0);
+			otg->host = NULL;
+			otg->state = OTG_STATE_UNDEFINED;
+			queue_work(motg->otg_wq, &motg->sm_work);
+		} else {
+			otg->host = NULL;
+		}
+
+		return 0;
+	}
+
+	hcd = bus_to_hcd(host);
+	hcd->power_budget = motg->pdata->power_budget;
+
+	otg->host = host;
+	dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
+	msm_otg_dbg_log_event(&motg->phy, "HOST DRIVER REGISTERED",
+			hcd->power_budget, motg->pdata->mode);
+
+	/*
+	 * Kick the state machine work, if peripheral is not supported
+	 * or peripheral is already registered with us.
+	 */
+	if (motg->pdata->mode == USB_HOST || otg->gadget)
+		queue_work(motg->otg_wq, &motg->sm_work);
+
+	return 0;
+}
+
+static void msm_otg_start_peripheral(struct usb_otg *otg, int on)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	struct pinctrl_state *set_state;
+	int ret;
+
+	if (!otg->gadget)
+		return;
+
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartPeri GET",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+	pm_runtime_get_sync(otg->usb_phy->dev);
+	if (on) {
+		dev_dbg(otg->usb_phy->dev, "gadget on\n");
+		msm_otg_dbg_log_event(&motg->phy, "GADGET ON",
+				motg->inputs, otg->state);
+
+		/* Configure BUS performance parameters for MAX bandwidth */
+		if (debug_bus_voting_enabled)
+			msm_otg_bus_vote(motg, USB_MAX_PERF_VOTE);
+		/* bump up usb core_clk to default */
+		clk_set_rate(motg->core_clk, motg->core_clk_rate);
+
+		usb_gadget_vbus_connect(otg->gadget);
+
+		/*
+		 * Request VDD min gpio, if need to support VDD
+		 * minimazation during peripheral bus suspend.
+		 */
+		if (pdata->vddmin_gpio) {
+			if (motg->phy_pinctrl) {
+				set_state =
+					pinctrl_lookup_state(motg->phy_pinctrl,
+							"hsusb_active");
+				if (IS_ERR(set_state)) {
+					pr_err("cannot get phy pinctrl active state\n");
+				} else {
+					pinctrl_select_state(motg->phy_pinctrl,
+								set_state);
+				}
+			}
+
+			ret = gpio_request(pdata->vddmin_gpio,
+					"MSM_OTG_VDD_MIN_GPIO");
+			if (ret < 0) {
+				dev_err(otg->usb_phy->dev, "gpio req failed for vdd min:%d\n",
+						ret);
+				pdata->vddmin_gpio = 0;
+			}
+		}
+	} else {
+		dev_dbg(otg->usb_phy->dev, "gadget off\n");
+		msm_otg_dbg_log_event(&motg->phy, "GADGET OFF",
+			motg->inputs, otg->state);
+		usb_gadget_vbus_disconnect(otg->gadget);
+		clear_bit(A_BUS_SUSPEND, &motg->inputs);
+		/* Configure BUS performance parameters to default */
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+
+		if (pdata->vddmin_gpio) {
+			gpio_free(pdata->vddmin_gpio);
+			if (motg->phy_pinctrl) {
+				set_state =
+					pinctrl_lookup_state(motg->phy_pinctrl,
+							"hsusb_sleep");
+				if (IS_ERR(set_state))
+					pr_err("cannot get phy pinctrl sleep state\n");
+				else
+					pinctrl_select_state(motg->phy_pinctrl,
+						set_state);
+			}
+		}
+	}
+	msm_otg_dbg_log_event(&motg->phy, "PM RT: StartPeri PUT",
+				     get_pm_runtime_counter(motg->phy.dev), 0);
+	pm_runtime_mark_last_busy(otg->usb_phy->dev);
+	pm_runtime_put_autosuspend(otg->usb_phy->dev);
+}
+
+static int msm_otg_set_peripheral(struct usb_otg *otg,
+					struct usb_gadget *gadget)
+{
+	struct msm_otg *motg = container_of(otg->usb_phy, struct msm_otg, phy);
+
+	/*
+	 * Fail peripheral registration if this board can support
+	 * only host configuration.
+	 */
+	if (motg->pdata->mode == USB_HOST) {
+		dev_info(otg->usb_phy->dev, "Peripheral mode is not supported\n");
+		return -ENODEV;
+	}
+
+	if (!gadget) {
+		if (otg->state == OTG_STATE_B_PERIPHERAL) {
+			msm_otg_dbg_log_event(&motg->phy,
+				"PM RUNTIME: PERIPHERAL GET1",
+				get_pm_runtime_counter(otg->usb_phy->dev), 0);
+			msm_otg_start_peripheral(otg, 0);
+			otg->gadget = NULL;
+			otg->state = OTG_STATE_UNDEFINED;
+			queue_work(motg->otg_wq, &motg->sm_work);
+		} else {
+			otg->gadget = NULL;
+		}
+
+		return 0;
+	}
+	otg->gadget = gadget;
+	dev_dbg(otg->usb_phy->dev, "peripheral driver registered w/ tranceiver\n");
+	msm_otg_dbg_log_event(&motg->phy, "PERIPHERAL DRIVER REGISTERED",
+			otg->state, motg->pdata->mode);
+
+	/*
+	 * Kick the state machine work, if host is not supported
+	 * or host is already registered with us.
+	 */
+	if (motg->pdata->mode == USB_PERIPHERAL || otg->host)
+		queue_work(motg->otg_wq, &motg->sm_work);
+
+	return 0;
+}
+
+static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
+{
+	unsigned long flags;
+	bool id;
+	int ret;
+
+	if (!motg->pdata->pmic_id_irq)
+		return -ENODEV;
+
+	local_irq_save(flags);
+	ret = irq_get_irqchip_state(motg->pdata->pmic_id_irq,
+					IRQCHIP_STATE_LINE_LEVEL, &id);
+	local_irq_restore(flags);
+
+	/*
+	 * If we can not read ID line state for some reason, treat
+	 * it as float. This would prevent MHL discovery and kicking
+	 * host mode unnecessarily.
+	 */
+	if (ret < 0)
+		return true;
+
+	return !!id;
+}
+
+static bool msm_otg_read_phy_id_state(struct msm_otg *motg)
+{
+	u8 val;
+
+	/*
+	 * clear the pending/outstanding interrupts and
+	 * read the ID status from the SRC_STATUS register.
+	 */
+	writeb_relaxed(USB_PHY_ID_MASK, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1);
+
+	writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD);
+	/*
+	 * Databook says 200 usec delay is required for
+	 * clearing the interrupts.
+	 */
+	udelay(200);
+	writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD);
+
+	val = readb_relaxed(USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS);
+	if (val & USB_PHY_IDDIG_1_0)
+		return false; /* ID is grounded */
+	else
+		return true;
+}
+
+static void msm_otg_chg_check_timer_func(unsigned long data)
+{
+	struct msm_otg *motg = (struct msm_otg *) data;
+	struct usb_otg *otg = motg->phy.otg;
+
+	if (atomic_read(&motg->in_lpm) ||
+		!test_bit(B_SESS_VLD, &motg->inputs) ||
+		otg->state != OTG_STATE_B_PERIPHERAL ||
+		otg->gadget->speed != USB_SPEED_UNKNOWN) {
+		dev_dbg(otg->usb_phy->dev, "Nothing to do in chg_check_timer\n");
+		return;
+	}
+
+	if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
+		dev_dbg(otg->usb_phy->dev, "DCP is detected as SDP\n");
+		msm_otg_dbg_log_event(&motg->phy, "DCP IS DETECTED AS SDP",
+				otg->state, 0);
+		set_bit(B_FALSE_SDP, &motg->inputs);
+		queue_work(motg->otg_wq, &motg->sm_work);
+	}
+}
+
+static bool msm_chg_check_secondary_det(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	u32 chg_det;
+	bool ret = false;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+	case SNPS_FEMTO_PHY:
+		chg_det = ulpi_read(phy, 0x87);
+		ret = chg_det & 1;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static void msm_chg_enable_secondary_det(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+	case SNPS_FEMTO_PHY:
+		/*
+		 * Configure DM as current source, DP as current sink
+		 * and enable battery charging comparators.
+		 */
+		ulpi_write(phy, 0x8, 0x85);
+		ulpi_write(phy, 0x2, 0x85);
+		ulpi_write(phy, 0x1, 0x85);
+		break;
+	default:
+		break;
+	}
+}
+
+static bool msm_chg_check_primary_det(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	u32 chg_det;
+	bool ret = false;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+	case SNPS_FEMTO_PHY:
+		chg_det = ulpi_read(phy, 0x87);
+		ret = chg_det & 1;
+		/* Turn off VDP_SRC */
+		ulpi_write(phy, 0x3, 0x86);
+		msleep(20);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static void msm_chg_enable_primary_det(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+	case SNPS_FEMTO_PHY:
+		/*
+		 * Configure DP as current source, DM as current sink
+		 * and enable battery charging comparators.
+		 */
+		ulpi_write(phy, 0x2, 0x85);
+		ulpi_write(phy, 0x1, 0x85);
+		break;
+	default:
+		break;
+	}
+}
+
+static bool msm_chg_check_dcd(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	u32 line_state;
+	bool ret = false;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+	case SNPS_FEMTO_PHY:
+		line_state = ulpi_read(phy, 0x87);
+		ret = line_state & 2;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+static void msm_chg_disable_dcd(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		ulpi_write(phy, 0x10, 0x86);
+		break;
+	case SNPS_FEMTO_PHY:
+		ulpi_write(phy, 0x10, 0x86);
+		/*
+		 * Disable the Rdm_down after
+		 * the DCD is completed.
+		 */
+		ulpi_write(phy, 0x04, 0x0C);
+		break;
+	default:
+		break;
+	}
+}
+
+static void msm_chg_enable_dcd(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+		/* Data contact detection enable */
+		ulpi_write(phy, 0x10, 0x85);
+		break;
+	case SNPS_FEMTO_PHY:
+		/*
+		 * Idp_src and Rdm_down are de-coupled
+		 * on Femto PHY. If Idp_src alone is
+		 * enabled, DCD timeout is observed with
+		 * wall charger. But a genuine DCD timeout
+		 * may be incorrectly interpreted. Also
+		 * BC1.2 compliance testers expect Rdm_down
+		 * to enabled during DCD. Enable Rdm_down
+		 * explicitly before enabling the DCD.
+		 */
+		ulpi_write(phy, 0x04, 0x0B);
+		ulpi_write(phy, 0x10, 0x85);
+		break;
+	default:
+		break;
+	}
+}
+
+static void msm_chg_block_on(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	u32 func_ctrl;
+
+	/* put the controller in non-driving mode */
+	func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+	func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+	func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+	ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+	case SNPS_FEMTO_PHY:
+		/* disable DP and DM pull down resistors */
+		ulpi_write(phy, 0x6, 0xC);
+		/* Clear charger detecting control bits */
+		ulpi_write(phy, 0x1F, 0x86);
+		/* Clear alt interrupt latch and enable bits */
+		ulpi_write(phy, 0x1F, 0x92);
+		ulpi_write(phy, 0x1F, 0x95);
+		udelay(100);
+		break;
+	default:
+		break;
+	}
+}
+
+static void msm_chg_block_off(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	u32 func_ctrl;
+
+	switch (motg->pdata->phy_type) {
+	case SNPS_PICO_PHY:
+	case SNPS_FEMTO_PHY:
+		/* Clear charger detecting control bits */
+		ulpi_write(phy, 0x3F, 0x86);
+		/* Clear alt interrupt latch and enable bits */
+		ulpi_write(phy, 0x1F, 0x92);
+		ulpi_write(phy, 0x1F, 0x95);
+		/* re-enable DP and DM pull down resistors */
+		ulpi_write(phy, 0x6, 0xB);
+		break;
+	default:
+		break;
+	}
+
+	/* put the controller in normal mode */
+	func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
+	func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+	func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+	ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
+}
+
+static const char *chg_to_string(enum usb_chg_type chg_type)
+{
+	switch (chg_type) {
+	case USB_SDP_CHARGER:		return "USB_SDP_CHARGER";
+	case USB_DCP_CHARGER:		return "USB_DCP_CHARGER";
+	case USB_CDP_CHARGER:		return "USB_CDP_CHARGER";
+	case USB_NONCOMPLIANT_CHARGER:	return "USB_NONCOMPLIANT_CHARGER";
+	case USB_FLOATED_CHARGER:	return "USB_FLOATED_CHARGER";
+	default:			return "INVALID_CHARGER";
+	}
+}
+
+#define MSM_CHG_DCD_TIMEOUT		(750 * HZ/1000) /* 750 msec */
+#define MSM_CHG_DCD_POLL_TIME		(50 * HZ/1000) /* 50 msec */
+#define MSM_CHG_PRIMARY_DET_TIME	(50 * HZ/1000) /* TVDPSRC_ON */
+#define MSM_CHG_SECONDARY_DET_TIME	(50 * HZ/1000) /* TVDMSRC_ON */
+static void msm_chg_detect_work(struct work_struct *w)
+{
+	struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
+	struct usb_phy *phy = &motg->phy;
+	bool is_dcd = false, tmout, vout;
+	static bool dcd;
+	u32 line_state, dm_vlgc;
+	unsigned long delay;
+
+	dev_dbg(phy->dev, "chg detection work\n");
+	msm_otg_dbg_log_event(phy, "CHG DETECTION WORK",
+			motg->chg_state, get_pm_runtime_counter(phy->dev));
+
+	switch (motg->chg_state) {
+	case USB_CHG_STATE_UNDEFINED:
+	case USB_CHG_STATE_IN_PROGRESS:
+		msm_chg_block_on(motg);
+		msm_chg_enable_dcd(motg);
+		motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
+		motg->dcd_time = 0;
+		delay = MSM_CHG_DCD_POLL_TIME;
+		break;
+	case USB_CHG_STATE_WAIT_FOR_DCD:
+		is_dcd = msm_chg_check_dcd(motg);
+		motg->dcd_time += MSM_CHG_DCD_POLL_TIME;
+		tmout = motg->dcd_time >= MSM_CHG_DCD_TIMEOUT;
+		if (is_dcd || tmout) {
+			if (is_dcd)
+				dcd = true;
+			else
+				dcd = false;
+			msm_chg_disable_dcd(motg);
+			msm_chg_enable_primary_det(motg);
+			delay = MSM_CHG_PRIMARY_DET_TIME;
+			motg->chg_state = USB_CHG_STATE_DCD_DONE;
+		} else {
+			delay = MSM_CHG_DCD_POLL_TIME;
+		}
+		break;
+	case USB_CHG_STATE_DCD_DONE:
+		vout = msm_chg_check_primary_det(motg);
+		line_state = readl_relaxed(USB_PORTSC) & PORTSC_LS;
+		dm_vlgc = line_state & PORTSC_LS_DM;
+		if (vout && !dm_vlgc) { /* VDAT_REF < DM < VLGC */
+			if (line_state) { /* DP > VLGC */
+				motg->chg_type = USB_NONCOMPLIANT_CHARGER;
+				motg->chg_state = USB_CHG_STATE_DETECTED;
+				delay = 0;
+			} else {
+				msm_chg_enable_secondary_det(motg);
+				delay = MSM_CHG_SECONDARY_DET_TIME;
+				motg->chg_state = USB_CHG_STATE_PRIMARY_DONE;
+			}
+		} else { /* DM < VDAT_REF || DM > VLGC */
+			if (line_state) /* DP > VLGC or/and DM > VLGC */
+				motg->chg_type = USB_NONCOMPLIANT_CHARGER;
+			else if (!dcd && floated_charger_enable)
+				motg->chg_type = USB_FLOATED_CHARGER;
+			else
+				motg->chg_type = USB_SDP_CHARGER;
+
+			motg->chg_state = USB_CHG_STATE_DETECTED;
+			delay = 0;
+			goto state_detected;
+		}
+		break;
+	case USB_CHG_STATE_PRIMARY_DONE:
+		vout = msm_chg_check_secondary_det(motg);
+		if (vout)
+			motg->chg_type = USB_DCP_CHARGER;
+		else
+			motg->chg_type = USB_CDP_CHARGER;
+		motg->chg_state = USB_CHG_STATE_SECONDARY_DONE;
+		/* fall through */
+	case USB_CHG_STATE_SECONDARY_DONE:
+		motg->chg_state = USB_CHG_STATE_DETECTED;
+	case USB_CHG_STATE_DETECTED:
+state_detected:
+		/*
+		 * Notify the charger type to power supply
+		 * owner as soon as we determine the charger.
+		 */
+		if (motg->chg_type == USB_DCP_CHARGER && motg->ext_chg_opened) {
+			init_completion(&motg->ext_chg_wait);
+			motg->ext_chg_active = DEFAULT;
+		}
+		msm_otg_notify_chg_type(motg);
+		msm_chg_block_off(motg);
+
+		/* Enable VDP_SRC in case of DCP charger */
+		if (motg->chg_type == USB_DCP_CHARGER)
+			ulpi_write(phy, 0x2, 0x85);
+
+		dev_dbg(phy->dev, "chg_type = %s\n",
+			chg_to_string(motg->chg_type));
+		msm_otg_dbg_log_event(phy, "CHG WORK PUT: CHG_TYPE",
+			motg->chg_type, get_pm_runtime_counter(phy->dev));
+		/* to match _get from sm_work before starting chg_det_work */
+		pm_runtime_mark_last_busy(phy->dev);
+		pm_runtime_put_autosuspend(phy->dev);
+
+		queue_work(motg->otg_wq, &motg->sm_work);
+		return;
+	default:
+		return;
+	}
+
+	msm_otg_dbg_log_event(phy, "CHG WORK: QUEUE", motg->chg_type, delay);
+	queue_delayed_work(motg->otg_wq, &motg->chg_work, delay);
+}
+
+#define VBUS_INIT_TIMEOUT	msecs_to_jiffies(5000)
+
+/*
+ * We support OTG, Peripheral only and Host only configurations. In case
+ * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen
+ * via Id pin status or user request (debugfs). Id/BSV interrupts are not
+ * enabled when switch is controlled by user and default mode is supplied
+ * by board file, which can be changed by userspace later.
+ */
+static void msm_otg_init_sm(struct msm_otg *motg)
+{
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	u32 otgsc = readl_relaxed(USB_OTGSC);
+	int ret;
+
+	switch (pdata->mode) {
+	case USB_OTG:
+		if (pdata->otg_control == OTG_USER_CONTROL) {
+			if (pdata->default_mode == USB_HOST) {
+				clear_bit(ID, &motg->inputs);
+			} else if (pdata->default_mode == USB_PERIPHERAL) {
+				set_bit(ID, &motg->inputs);
+				set_bit(B_SESS_VLD, &motg->inputs);
+			} else {
+				set_bit(ID, &motg->inputs);
+				clear_bit(B_SESS_VLD, &motg->inputs);
+			}
+		} else if (pdata->otg_control == OTG_PHY_CONTROL) {
+			if (otgsc & OTGSC_ID)
+				set_bit(ID, &motg->inputs);
+			else
+				clear_bit(ID, &motg->inputs);
+			if (otgsc & OTGSC_BSV)
+				set_bit(B_SESS_VLD, &motg->inputs);
+			else
+				clear_bit(B_SESS_VLD, &motg->inputs);
+		} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+			if (pdata->pmic_id_irq) {
+				if (msm_otg_read_pmic_id_state(motg))
+					set_bit(ID, &motg->inputs);
+				else
+					clear_bit(ID, &motg->inputs);
+			} else if (motg->ext_id_irq) {
+				if (gpio_get_value(pdata->usb_id_gpio))
+					set_bit(ID, &motg->inputs);
+				else
+					clear_bit(ID, &motg->inputs);
+			} else if (motg->phy_irq) {
+				if (msm_otg_read_phy_id_state(motg))
+					set_bit(ID, &motg->inputs);
+				else
+					clear_bit(ID, &motg->inputs);
+			}
+			/*
+			 * VBUS initial state is reported after PMIC
+			 * driver initialization. Wait for it.
+			 */
+			ret = wait_for_completion_timeout(&pmic_vbus_init,
+							  VBUS_INIT_TIMEOUT);
+			if (!ret) {
+				dev_dbg(motg->phy.dev, "%s: timeout waiting for PMIC VBUS\n",
+					__func__);
+				msm_otg_dbg_log_event(&motg->phy,
+					"PMIC VBUS WAIT TMOUT", motg->inputs,
+							motg->phy.otg->state);
+				clear_bit(B_SESS_VLD, &motg->inputs);
+				pmic_vbus_init.done = 1;
+			}
+		}
+		break;
+	case USB_HOST:
+		clear_bit(ID, &motg->inputs);
+		break;
+	case USB_PERIPHERAL:
+		set_bit(ID, &motg->inputs);
+		if (pdata->otg_control == OTG_PHY_CONTROL) {
+			if (otgsc & OTGSC_BSV)
+				set_bit(B_SESS_VLD, &motg->inputs);
+			else
+				clear_bit(B_SESS_VLD, &motg->inputs);
+		} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+			/*
+			 * VBUS initial state is reported after PMIC
+			 * driver initialization. Wait for it.
+			 */
+			ret = wait_for_completion_timeout(&pmic_vbus_init,
+							  VBUS_INIT_TIMEOUT);
+			if (!ret) {
+				dev_dbg(motg->phy.dev, "%s: timeout waiting for PMIC VBUS\n",
+					__func__);
+				msm_otg_dbg_log_event(&motg->phy,
+					"PMIC VBUS WAIT TMOUT", motg->inputs,
+							motg->phy.otg->state);
+				clear_bit(B_SESS_VLD, &motg->inputs);
+				pmic_vbus_init.done = 1;
+			}
+		} else if (pdata->otg_control == OTG_USER_CONTROL) {
+			set_bit(ID, &motg->inputs);
+			set_bit(B_SESS_VLD, &motg->inputs);
+		}
+		break;
+	default:
+		break;
+	}
+	msm_otg_dbg_log_event(&motg->phy, "SM INIT", pdata->mode, motg->inputs);
+	if (motg->id_state != USB_ID_GROUND)
+		motg->id_state = (test_bit(ID, &motg->inputs)) ? USB_ID_FLOAT :
+							USB_ID_GROUND;
+}
+
+static void msm_otg_wait_for_ext_chg_done(struct msm_otg *motg)
+{
+	struct usb_phy *phy = &motg->phy;
+	unsigned long t;
+
+	/*
+	 * Defer next cable connect event till external charger
+	 * detection is completed.
+	 */
+
+	if (motg->ext_chg_active == ACTIVE) {
+
+do_wait:
+		pr_debug("before msm_otg ext chg wait\n");
+		msm_otg_dbg_log_event(&motg->phy, "EXT CHG: WAIT", 0, 0);
+
+		t = wait_for_completion_timeout(&motg->ext_chg_wait,
+				msecs_to_jiffies(3000));
+		msm_otg_dbg_log_event(&motg->phy, "EXT CHG: DONE", t, 0);
+
+		if (!t)
+			pr_err("msm_otg ext chg wait timeout\n");
+		else if (motg->ext_chg_active == ACTIVE)
+			goto do_wait;
+		else
+			pr_debug("msm_otg ext chg wait done\n");
+	}
+
+	if (motg->ext_chg_opened) {
+		if (phy->flags & ENABLE_DP_MANUAL_PULLUP) {
+			ulpi_write(phy, ULPI_MISC_A_VBUSVLDEXT |
+					ULPI_MISC_A_VBUSVLDEXTSEL,
+					ULPI_CLR(ULPI_MISC_A));
+		}
+		/* clear charging register bits */
+		ulpi_write(phy, 0x3F, 0x86);
+		/* re-enable DP and DM pull-down resistors*/
+		ulpi_write(phy, 0x6, 0xB);
+	}
+}
+
+static void msm_otg_sm_work(struct work_struct *w)
+{
+	struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
+	struct usb_otg *otg = motg->phy.otg;
+	struct device *dev = otg->usb_phy->dev;
+	bool work = 0, dcp;
+	int ret;
+
+	pr_debug("%s work\n", usb_otg_state_string(otg->state));
+	msm_otg_dbg_log_event(&motg->phy, "SM WORK:",
+			otg->state, motg->inputs);
+
+	/* Just resume h/w if reqd, pm_count is handled based on state/inputs */
+	if (motg->resume_pending) {
+		pm_runtime_get_sync(otg->usb_phy->dev);
+		if (atomic_read(&motg->in_lpm)) {
+			dev_err(dev, "SM WORK: USB is in LPM\n");
+			msm_otg_dbg_log_event(&motg->phy,
+					"SM WORK: USB IS IN LPM",
+					otg->state, motg->inputs);
+			msm_otg_resume(motg);
+		}
+		motg->resume_pending = false;
+		pm_runtime_put_noidle(otg->usb_phy->dev);
+	}
+
+	switch (otg->state) {
+	case OTG_STATE_UNDEFINED:
+		pm_runtime_get_sync(otg->usb_phy->dev);
+		msm_otg_reset(otg->usb_phy);
+		/* Add child device only after block reset */
+		ret = of_platform_populate(motg->pdev->dev.of_node, NULL, NULL,
+					&motg->pdev->dev);
+		if (ret)
+			dev_dbg(&motg->pdev->dev, "failed to add BAM core\n");
+
+		msm_otg_init_sm(motg);
+		otg->state = OTG_STATE_B_IDLE;
+		if (!test_bit(B_SESS_VLD, &motg->inputs) &&
+				test_bit(ID, &motg->inputs)) {
+			msm_otg_dbg_log_event(&motg->phy,
+				"PM RUNTIME: UNDEF PUT",
+				get_pm_runtime_counter(otg->usb_phy->dev), 0);
+			pm_runtime_put_sync(otg->usb_phy->dev);
+			break;
+		}
+		pm_runtime_put(otg->usb_phy->dev);
+		/* FALL THROUGH */
+	case OTG_STATE_B_IDLE:
+		if (!test_bit(ID, &motg->inputs) && otg->host) {
+			pr_debug("!id\n");
+			msm_otg_dbg_log_event(&motg->phy, "!ID",
+					motg->inputs, otg->state);
+
+			msm_otg_start_host(otg, 1);
+			otg->state = OTG_STATE_A_HOST;
+		} else if (test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("b_sess_vld\n");
+			msm_otg_dbg_log_event(&motg->phy, "B_SESS_VLD",
+					motg->inputs, otg->state);
+			switch (motg->chg_state) {
+			case USB_CHG_STATE_UNDEFINED:
+				/* put at the end of chg_det or disconnect */
+				pm_runtime_get_sync(otg->usb_phy->dev);
+				msm_otg_dbg_log_event(&motg->phy, "PM CHG GET",
+						get_pm_runtime_counter(dev), 0);
+				motg->chg_state = USB_CHG_STATE_IN_PROGRESS;
+				msm_chg_detect_work(&motg->chg_work.work);
+				break;
+			case USB_CHG_STATE_DETECTED:
+				switch (motg->chg_type) {
+				case USB_DCP_CHARGER:
+					/* fall through */
+				case USB_NONCOMPLIANT_CHARGER:
+					msm_otg_notify_charger(motg,
+							dcp_max_current);
+					if (!motg->is_ext_chg_dcp)
+						otg->state =
+							OTG_STATE_B_CHARGER;
+					break;
+				case USB_FLOATED_CHARGER:
+					msm_otg_notify_charger(motg,
+							IDEV_CHG_MAX);
+					otg->state = OTG_STATE_B_CHARGER;
+					break;
+				case USB_CDP_CHARGER:
+					msm_otg_notify_charger(motg,
+							IDEV_CHG_MAX);
+					/* fall through */
+				case USB_SDP_CHARGER:
+					pm_runtime_get_sync(otg->usb_phy->dev);
+					msm_otg_start_peripheral(otg, 1);
+					otg->state =
+						OTG_STATE_B_PERIPHERAL;
+					mod_timer(&motg->chg_check_timer,
+							CHG_RECHECK_DELAY);
+					break;
+				default:
+					break;
+				}
+				break;
+			default:
+				break;
+			}
+		} else {
+			pr_debug("chg_work cancel");
+			msm_otg_dbg_log_event(&motg->phy, "CHG_WORK CANCEL",
+					motg->inputs, otg->state);
+			del_timer_sync(&motg->chg_check_timer);
+			clear_bit(B_FALSE_SDP, &motg->inputs);
+			cancel_delayed_work_sync(&motg->chg_work);
+			/*
+			 * Find out whether chg_w couldn't start or finished.
+			 * In both the cases, runtime ref_count vote is missing
+			 */
+			if (motg->chg_state == USB_CHG_STATE_UNDEFINED ||
+			    motg->chg_state == USB_CHG_STATE_DETECTED) {
+				msm_otg_dbg_log_event(&motg->phy, "RT !CHG GET",
+				  get_pm_runtime_counter(otg->usb_phy->dev), 0);
+				pm_runtime_get_sync(dev);
+			}
+
+			dcp = (motg->chg_type == USB_DCP_CHARGER);
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			msm_otg_notify_charger(motg, 0);
+			if (dcp) {
+				if (motg->ext_chg_active == DEFAULT)
+					motg->ext_chg_active = INACTIVE;
+				msm_otg_wait_for_ext_chg_done(motg);
+				/* Turn off VDP_SRC */
+				ulpi_write(otg->usb_phy, 0x2, 0x86);
+			}
+			msm_chg_block_off(motg);
+			msm_otg_dbg_log_event(&motg->phy, "RT: CHG A PUT",
+				get_pm_runtime_counter(otg->usb_phy->dev), 0);
+			/* Delay used only if autosuspend enabled */
+			pm_runtime_mark_last_busy(dev);
+			pm_runtime_put_autosuspend(dev);
+		}
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (test_bit(B_SESS_VLD, &motg->inputs) &&
+				test_bit(B_FALSE_SDP, &motg->inputs)) {
+			pr_debug("B_FALSE_SDP\n");
+			msm_otg_start_peripheral(otg, 0);
+			motg->chg_type = USB_DCP_CHARGER;
+			clear_bit(B_FALSE_SDP, &motg->inputs);
+			otg->state = OTG_STATE_B_IDLE;
+			msm_otg_dbg_log_event(&motg->phy, "B_FALSE_SDP PUT",
+				get_pm_runtime_counter(dev), motg->inputs);
+			pm_runtime_put_sync(dev);
+			/* schedule work to update charging current */
+			work = 1;
+		} else if (!test_bit(B_SESS_VLD, &motg->inputs)) {
+			msm_otg_start_peripheral(otg, 0);
+			msm_otg_dbg_log_event(&motg->phy, "RT PM: B_PERI A PUT",
+				get_pm_runtime_counter(dev), 0);
+			/* _put for _get done on cable connect in B_IDLE */
+			pm_runtime_put_noidle(dev);
+			/* Schedule work to finish cable disconnect processing*/
+			otg->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else if (test_bit(A_BUS_SUSPEND, &motg->inputs)) {
+			pr_debug("a_bus_suspend\n");
+			msm_otg_dbg_log_event(&motg->phy,
+				"BUS_SUSPEND: PM RT PUT",
+				get_pm_runtime_counter(dev), 0);
+			otg->state = OTG_STATE_B_SUSPEND;
+			/* _get on connect in B_IDLE or host resume in B_SUSP */
+			pm_runtime_mark_last_busy(dev);
+			pm_runtime_put_autosuspend(dev);
+		}
+		break;
+	case OTG_STATE_B_SUSPEND:
+		if (!test_bit(B_SESS_VLD, &motg->inputs)) {
+			msm_otg_start_peripheral(otg, 0);
+			otg->state = OTG_STATE_B_IDLE;
+			/* Schedule work to finish cable disconnect processing*/
+			work = 1;
+		} else if (!test_bit(A_BUS_SUSPEND, &motg->inputs)) {
+			pr_debug("!a_bus_suspend\n");
+			otg->state = OTG_STATE_B_PERIPHERAL;
+			msm_otg_dbg_log_event(&motg->phy,
+				"BUS_RESUME: PM RT GET",
+				get_pm_runtime_counter(dev), 0);
+			pm_runtime_get_sync(dev);
+		}
+		break;
+
+	case OTG_STATE_B_CHARGER:
+		if (test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("BSV set again\n");
+			msm_otg_dbg_log_event(&motg->phy, "BSV SET AGAIN",
+					motg->inputs, otg->state);
+		} else if (!test_bit(B_SESS_VLD, &motg->inputs)) {
+			otg->state = OTG_STATE_B_IDLE;
+			work = 1;
+		}
+		break;
+	case OTG_STATE_A_HOST:
+		if (test_bit(ID, &motg->inputs)) {
+			msm_otg_start_host(otg, 0);
+			otg->state = OTG_STATE_B_IDLE;
+			work = 1;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (work)
+		queue_work(motg->otg_wq, &motg->sm_work);
+}
+
+static irqreturn_t msm_otg_irq(int irq, void *data)
+{
+	struct msm_otg *motg = data;
+	struct usb_otg *otg = motg->phy.otg;
+	u32 otgsc = 0;
+	bool work = 0;
+
+	if (atomic_read(&motg->in_lpm)) {
+		pr_debug("OTG IRQ: %d in LPM\n", irq);
+		msm_otg_dbg_log_event(&motg->phy, "OTG IRQ IS IN LPM",
+				irq, otg->state);
+		/*Ignore interrupt if one interrupt already seen in LPM*/
+		if (motg->async_int)
+			return IRQ_HANDLED;
+
+		disable_irq_nosync(irq);
+		motg->async_int = irq;
+		msm_otg_kick_sm_work(motg);
+
+		return IRQ_HANDLED;
+	}
+	motg->usb_irq_count++;
+
+	otgsc = readl_relaxed(USB_OTGSC);
+	if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
+		return IRQ_NONE;
+
+	if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) {
+		if (otgsc & OTGSC_ID) {
+			dev_dbg(otg->usb_phy->dev, "ID set\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID SET",
+				motg->inputs, otg->state);
+			set_bit(ID, &motg->inputs);
+		} else {
+			dev_dbg(otg->usb_phy->dev, "ID clear\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID CLEAR",
+					motg->inputs, otg->state);
+			clear_bit(ID, &motg->inputs);
+		}
+		work = 1;
+	} else if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
+		if (otgsc & OTGSC_BSV) {
+			dev_dbg(otg->usb_phy->dev, "BSV set\n");
+			msm_otg_dbg_log_event(&motg->phy, "BSV SET",
+					motg->inputs, otg->state);
+			set_bit(B_SESS_VLD, &motg->inputs);
+		} else {
+			dev_dbg(otg->usb_phy->dev, "BSV clear\n");
+			msm_otg_dbg_log_event(&motg->phy, "BSV CLEAR",
+					motg->inputs, otg->state);
+			clear_bit(B_SESS_VLD, &motg->inputs);
+			clear_bit(A_BUS_SUSPEND, &motg->inputs);
+		}
+		work = 1;
+	}
+	if (work)
+		queue_work(motg->otg_wq, &motg->sm_work);
+
+	writel_relaxed(otgsc, USB_OTGSC);
+
+	return IRQ_HANDLED;
+}
+
+static void msm_otg_set_vbus_state(int online)
+{
+	struct msm_otg *motg = the_msm_otg;
+	static bool init;
+
+	motg->vbus_state = online;
+
+	if (motg->err_event_seen)
+		return;
+
+	if (online) {
+		pr_debug("PMIC: BSV set\n");
+		msm_otg_dbg_log_event(&motg->phy, "PMIC: BSV SET",
+				init, motg->inputs);
+		if (test_and_set_bit(B_SESS_VLD, &motg->inputs) && init)
+			return;
+	} else {
+		pr_debug("PMIC: BSV clear\n");
+		msm_otg_dbg_log_event(&motg->phy, "PMIC: BSV CLEAR",
+				init, motg->inputs);
+		motg->is_ext_chg_dcp = false;
+		if (!test_and_clear_bit(B_SESS_VLD, &motg->inputs) && init)
+			return;
+	}
+
+	/* do not queue state m/c work if id is grounded */
+	if (!test_bit(ID, &motg->inputs) &&
+		!motg->pdata->vbus_low_as_hostmode) {
+		/*
+		 * state machine work waits for initial VBUS
+		 * completion in UNDEFINED state.  Process
+		 * the initial VBUS event in ID_GND state.
+		 */
+		if (init)
+			return;
+	}
+
+	if (!init) {
+		init = true;
+		if (pmic_vbus_init.done &&
+				test_bit(B_SESS_VLD, &motg->inputs)) {
+			pr_debug("PMIC: BSV came late\n");
+			msm_otg_dbg_log_event(&motg->phy, "PMIC: BSV CAME LATE",
+					init, motg->inputs);
+			goto out;
+		}
+
+		if (motg->pdata->vbus_low_as_hostmode &&
+			!test_bit(B_SESS_VLD, &motg->inputs)) {
+			motg->id_state = USB_ID_GROUND;
+			clear_bit(ID, &motg->inputs);
+		}
+		complete(&pmic_vbus_init);
+		pr_debug("PMIC: BSV init complete\n");
+		msm_otg_dbg_log_event(&motg->phy, "PMIC: BSV INIT COMPLETE",
+				init, motg->inputs);
+		return;
+	}
+
+out:
+	if (motg->is_ext_chg_dcp) {
+		if (test_bit(B_SESS_VLD, &motg->inputs)) {
+			msm_otg_notify_charger(motg, IDEV_CHG_MAX);
+		} else {
+			motg->is_ext_chg_dcp = false;
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
+			msm_otg_notify_charger(motg, 0);
+		}
+		return;
+	}
+
+	msm_otg_dbg_log_event(&motg->phy, "CHECK VBUS EVENT DURING SUSPEND",
+			atomic_read(&motg->pm_suspended),
+			motg->sm_work_pending);
+
+	/* Move to host mode on vbus low if required */
+	if (motg->pdata->vbus_low_as_hostmode) {
+		if (!test_bit(B_SESS_VLD, &motg->inputs))
+			clear_bit(ID, &motg->inputs);
+		else
+			set_bit(ID, &motg->inputs);
+	}
+	msm_otg_kick_sm_work(motg);
+}
+
+static void msm_id_status_w(struct work_struct *w)
+{
+	struct msm_otg *motg = container_of(w, struct msm_otg,
+						id_status_work.work);
+	int work = 0;
+
+	dev_dbg(motg->phy.dev, "ID status_w\n");
+
+	if (motg->pdata->pmic_id_irq)
+		motg->id_state = msm_otg_read_pmic_id_state(motg);
+	else if (motg->ext_id_irq)
+		motg->id_state = gpio_get_value(motg->pdata->usb_id_gpio);
+	else if (motg->phy_irq)
+		motg->id_state = msm_otg_read_phy_id_state(motg);
+
+	if (motg->err_event_seen)
+		return;
+
+	if (motg->id_state) {
+		if (gpio_is_valid(motg->pdata->switch_sel_gpio))
+			gpio_direction_input(motg->pdata->switch_sel_gpio);
+		if (!test_and_set_bit(ID, &motg->inputs)) {
+			pr_debug("ID set\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID SET",
+					motg->inputs, motg->phy.otg->state);
+			work = 1;
+		}
+	} else {
+		if (gpio_is_valid(motg->pdata->switch_sel_gpio))
+			gpio_direction_output(motg->pdata->switch_sel_gpio, 1);
+		if (test_and_clear_bit(ID, &motg->inputs)) {
+			pr_debug("ID clear\n");
+			msm_otg_dbg_log_event(&motg->phy, "ID CLEAR",
+					motg->inputs, motg->phy.otg->state);
+			work = 1;
+		}
+	}
+
+	if (work && (motg->phy.otg->state != OTG_STATE_UNDEFINED)) {
+		msm_otg_dbg_log_event(&motg->phy,
+				"CHECK ID EVENT DURING SUSPEND",
+				atomic_read(&motg->pm_suspended),
+				motg->sm_work_pending);
+		msm_otg_kick_sm_work(motg);
+	}
+}
+
+#define MSM_ID_STATUS_DELAY	5 /* 5msec */
+static irqreturn_t msm_id_irq(int irq, void *data)
+{
+	struct msm_otg *motg = data;
+
+	/*schedule delayed work for 5msec for ID line state to settle*/
+	queue_delayed_work(motg->otg_wq, &motg->id_status_work,
+			msecs_to_jiffies(MSM_ID_STATUS_DELAY));
+
+	return IRQ_HANDLED;
+}
+
+int msm_otg_pm_notify(struct notifier_block *notify_block,
+					unsigned long mode, void *unused)
+{
+	struct msm_otg *motg = container_of(
+		notify_block, struct msm_otg, pm_notify);
+
+	dev_dbg(motg->phy.dev, "OTG PM notify:%lx, sm_pending:%u\n", mode,
+					motg->sm_work_pending);
+	msm_otg_dbg_log_event(&motg->phy, "PM NOTIFY",
+			mode, motg->sm_work_pending);
+
+	switch (mode) {
+	case PM_POST_SUSPEND:
+		/* OTG sm_work can be armed now */
+		atomic_set(&motg->pm_suspended, 0);
+
+		/* Handle any deferred wakeup events from USB during suspend */
+		if (motg->sm_work_pending) {
+			motg->sm_work_pending = false;
+			queue_work(motg->otg_wq, &motg->sm_work);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static int msm_otg_mode_show(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+	struct usb_otg *otg = motg->phy.otg;
+
+	switch (otg->state) {
+	case OTG_STATE_A_HOST:
+		seq_puts(s, "host\n");
+		break;
+	case OTG_STATE_B_IDLE:
+	case OTG_STATE_B_PERIPHERAL:
+	case OTG_STATE_B_SUSPEND:
+		seq_puts(s, "peripheral\n");
+		break;
+	default:
+		seq_puts(s, "none\n");
+		break;
+	}
+
+	return 0;
+}
+
+static int msm_otg_mode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_mode_show, inode->i_private);
+}
+
+static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct seq_file *s = file->private_data;
+	struct msm_otg *motg = s->private;
+	char buf[16];
+	struct usb_phy *phy = &motg->phy;
+	int status = count;
+	enum usb_mode_type req_mode;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+		status = -EFAULT;
+		goto out;
+	}
+
+	if (!strncmp(buf, "host", 4)) {
+		req_mode = USB_HOST;
+	} else if (!strncmp(buf, "peripheral", 10)) {
+		req_mode = USB_PERIPHERAL;
+	} else if (!strncmp(buf, "none", 4)) {
+		req_mode = USB_NONE;
+	} else {
+		status = -EINVAL;
+		goto out;
+	}
+
+	switch (req_mode) {
+	case USB_NONE:
+		switch (phy->otg->state) {
+		case OTG_STATE_A_HOST:
+		case OTG_STATE_B_PERIPHERAL:
+		case OTG_STATE_B_SUSPEND:
+			set_bit(ID, &motg->inputs);
+			clear_bit(B_SESS_VLD, &motg->inputs);
+			break;
+		default:
+			goto out;
+		}
+		break;
+	case USB_PERIPHERAL:
+		switch (phy->otg->state) {
+		case OTG_STATE_B_IDLE:
+		case OTG_STATE_A_HOST:
+			set_bit(ID, &motg->inputs);
+			set_bit(B_SESS_VLD, &motg->inputs);
+			break;
+		default:
+			goto out;
+		}
+		break;
+	case USB_HOST:
+		switch (phy->otg->state) {
+		case OTG_STATE_B_IDLE:
+		case OTG_STATE_B_PERIPHERAL:
+		case OTG_STATE_B_SUSPEND:
+			clear_bit(ID, &motg->inputs);
+			break;
+		default:
+			goto out;
+		}
+		break;
+	default:
+		goto out;
+	}
+
+	motg->id_state = (test_bit(ID, &motg->inputs)) ? USB_ID_FLOAT :
+							USB_ID_GROUND;
+	queue_work(motg->otg_wq, &motg->sm_work);
+out:
+	return status;
+}
+
+const struct file_operations msm_otg_mode_fops = {
+	.open = msm_otg_mode_open,
+	.read = seq_read,
+	.write = msm_otg_mode_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int msm_otg_show_otg_state(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+	struct usb_phy *phy = &motg->phy;
+
+	seq_printf(s, "%s\n", usb_otg_state_string(phy->otg->state));
+	return 0;
+}
+
+static int msm_otg_otg_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_show_otg_state, inode->i_private);
+}
+
+const struct file_operations msm_otg_state_fops = {
+	.open = msm_otg_otg_state_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int msm_otg_show_chg_type(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+
+	seq_printf(s, "%s\n", chg_to_string(motg->chg_type));
+	return 0;
+}
+
+static int msm_otg_chg_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_show_chg_type, inode->i_private);
+}
+
+const struct file_operations msm_otg_chg_fops = {
+	.open = msm_otg_chg_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int msm_otg_bus_show(struct seq_file *s, void *unused)
+{
+	if (debug_bus_voting_enabled)
+		seq_puts(s, "enabled\n");
+	else
+		seq_puts(s, "disabled\n");
+
+	return 0;
+}
+
+static int msm_otg_bus_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_bus_show, inode->i_private);
+}
+
+static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char buf[8];
+	struct seq_file *s = file->private_data;
+	struct msm_otg *motg = s->private;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "enable", 6)) {
+		/* Do not vote here. Let OTG statemachine decide when to vote */
+		debug_bus_voting_enabled = true;
+	} else {
+		debug_bus_voting_enabled = false;
+		msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+	}
+
+	return count;
+}
+
+static int msm_otg_dbg_buff_show(struct seq_file *s, void *unused)
+{
+	struct msm_otg *motg = s->private;
+	unsigned long	flags;
+	unsigned int	i;
+
+	read_lock_irqsave(&motg->dbg_lock, flags);
+
+	i = motg->dbg_idx;
+	if (strnlen(motg->buf[i], DEBUG_MSG_LEN))
+		seq_printf(s, "%s\n", motg->buf[i]);
+	for (dbg_inc(&i); i != motg->dbg_idx;  dbg_inc(&i)) {
+		if (!strnlen(motg->buf[i], DEBUG_MSG_LEN))
+			continue;
+		seq_printf(s, "%s\n", motg->buf[i]);
+	}
+	read_unlock_irqrestore(&motg->dbg_lock, flags);
+
+	return 0;
+}
+
+static int msm_otg_dbg_buff_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_dbg_buff_show, inode->i_private);
+}
+
+const struct file_operations msm_otg_dbg_buff_fops = {
+	.open = msm_otg_dbg_buff_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int msm_otg_dpdm_regulator_enable(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	struct msm_otg *motg = rdev_get_drvdata(rdev);
+
+	if (!motg->rm_pulldown) {
+		ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_3P3_ON);
+		if (!ret) {
+			motg->rm_pulldown = true;
+			msm_otg_dbg_log_event(&motg->phy, "RM Pulldown",
+					motg->rm_pulldown, 0);
+		}
+	}
+
+	return ret;
+}
+
+static int msm_otg_dpdm_regulator_disable(struct regulator_dev *rdev)
+{
+	int ret = 0;
+	struct msm_otg *motg = rdev_get_drvdata(rdev);
+
+	if (motg->rm_pulldown) {
+		ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_3P3_OFF);
+		if (!ret) {
+			motg->rm_pulldown = false;
+			msm_otg_dbg_log_event(&motg->phy, "RM Pulldown",
+					motg->rm_pulldown, 0);
+		}
+	}
+
+	return ret;
+}
+
+static int msm_otg_dpdm_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct msm_otg *motg = rdev_get_drvdata(rdev);
+
+	return motg->rm_pulldown;
+}
+
+static struct regulator_ops msm_otg_dpdm_regulator_ops = {
+	.enable		= msm_otg_dpdm_regulator_enable,
+	.disable	= msm_otg_dpdm_regulator_disable,
+	.is_enabled	= msm_otg_dpdm_regulator_is_enabled,
+};
+
+static int usb_phy_regulator_init(struct msm_otg *motg)
+{
+	struct device *dev = motg->phy.dev;
+	struct regulator_config cfg = {};
+	struct regulator_init_data *init_data;
+
+	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
+	if (!init_data)
+		return -ENOMEM;
+
+	init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+	motg->dpdm_rdesc.owner = THIS_MODULE;
+	motg->dpdm_rdesc.type = REGULATOR_VOLTAGE;
+	motg->dpdm_rdesc.ops = &msm_otg_dpdm_regulator_ops;
+	motg->dpdm_rdesc.name = kbasename(dev->of_node->full_name);
+
+	cfg.dev = dev;
+	cfg.init_data = init_data;
+	cfg.driver_data = motg;
+	cfg.of_node = dev->of_node;
+
+	motg->dpdm_rdev = devm_regulator_register(dev, &motg->dpdm_rdesc, &cfg);
+	if (IS_ERR(motg->dpdm_rdev))
+		return PTR_ERR(motg->dpdm_rdev);
+
+	return 0;
+}
+
+const struct file_operations msm_otg_bus_fops = {
+	.open = msm_otg_bus_open,
+	.read = seq_read,
+	.write = msm_otg_bus_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct dentry *msm_otg_dbg_root;
+
+static int msm_otg_debugfs_init(struct msm_otg *motg)
+{
+	struct dentry *msm_otg_dentry;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
+
+	if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root))
+		return -ENODEV;
+
+	if ((pdata->mode == USB_OTG || pdata->mode == USB_PERIPHERAL) &&
+		pdata->otg_control == OTG_USER_CONTROL) {
+
+		msm_otg_dentry = debugfs_create_file("mode", 0644,
+			msm_otg_dbg_root, motg, &msm_otg_mode_fops);
+
+		if (!msm_otg_dentry) {
+			debugfs_remove(msm_otg_dbg_root);
+			msm_otg_dbg_root = NULL;
+			return -ENODEV;
+		}
+	}
+
+	msm_otg_dentry = debugfs_create_file("chg_type", 0444, msm_otg_dbg_root,
+						motg, &msm_otg_chg_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
+
+	msm_otg_dentry = debugfs_create_file("bus_voting", 0644,
+			msm_otg_dbg_root, motg, &msm_otg_bus_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
+
+	msm_otg_dentry = debugfs_create_file("otg_state", 0444,
+			msm_otg_dbg_root, motg, &msm_otg_state_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
+
+	msm_otg_dentry = debugfs_create_file("dbg_buff", 0444,
+			msm_otg_dbg_root, motg, &msm_otg_dbg_buff_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void msm_otg_debugfs_cleanup(void)
+{
+	debugfs_remove_recursive(msm_otg_dbg_root);
+}
+
+static ssize_t
+set_msm_otg_perf_mode(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct msm_otg *motg = the_msm_otg;
+	int ret;
+	long clk_rate;
+
+	pr_debug("%s: enable:%d\n", __func__, !strncasecmp(buf, "enable", 6));
+
+	if (!strncasecmp(buf, "enable", 6)) {
+		clk_rate = motg->core_clk_nominal_rate;
+		msm_otg_bus_freq_set(motg, USB_NOC_NOM_VOTE);
+	} else {
+		clk_rate = motg->core_clk_svs_rate;
+		msm_otg_bus_freq_set(motg, USB_NOC_SVS_VOTE);
+	}
+
+	if (clk_rate) {
+		pr_debug("Set usb sys_clk rate:%ld\n", clk_rate);
+		ret = clk_set_rate(motg->core_clk, clk_rate);
+		if (ret)
+			pr_err("sys_clk set_rate fail:%d %ld\n", ret, clk_rate);
+		msm_otg_dbg_log_event(&motg->phy, "OTG PERF SET",
+							clk_rate, ret);
+	} else {
+		pr_err("usb sys_clk rate is undefined\n");
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(perf_mode, 0200, NULL, set_msm_otg_perf_mode);
+
+#define MSM_OTG_CMD_ID		0x09
+#define MSM_OTG_DEVICE_ID	0x04
+#define MSM_OTG_VMID_IDX	0xFF
+#define MSM_OTG_MEM_TYPE	0x02
+struct msm_otg_scm_cmd_buf {
+	unsigned int device_id;
+	unsigned int vmid_idx;
+	unsigned int mem_type;
+} __attribute__ ((__packed__));
+
+static void msm_otg_pnoc_errata_fix(struct msm_otg *motg)
+{
+	int ret;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+	struct msm_otg_scm_cmd_buf cmd_buf;
+
+	if (!pdata->pnoc_errata_fix)
+		return;
+
+	dev_dbg(motg->phy.dev, "applying fix for pnoc h/w issue\n");
+
+	cmd_buf.device_id = MSM_OTG_DEVICE_ID;
+	cmd_buf.vmid_idx = MSM_OTG_VMID_IDX;
+	cmd_buf.mem_type = MSM_OTG_MEM_TYPE;
+
+	ret = scm_call(SCM_SVC_MP, MSM_OTG_CMD_ID, &cmd_buf,
+				sizeof(cmd_buf), NULL, 0);
+
+	if (ret)
+		dev_err(motg->phy.dev, "scm command failed to update VMIDMT\n");
+}
+
+static u64 msm_otg_dma_mask = DMA_BIT_MASK(32);
+static struct platform_device *msm_otg_add_pdev(
+		struct platform_device *ofdev, const char *name)
+{
+	struct platform_device *pdev;
+	const struct resource *res = ofdev->resource;
+	unsigned int num = ofdev->num_resources;
+	int retval;
+	struct ci13xxx_platform_data ci_pdata;
+	struct msm_otg_platform_data *otg_pdata;
+	struct msm_otg *motg;
+
+	pdev = platform_device_alloc(name, -1);
+	if (!pdev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	pdev->dev.dma_mask = &msm_otg_dma_mask;
+	pdev->dev.parent = &ofdev->dev;
+
+	if (num) {
+		retval = platform_device_add_resources(pdev, res, num);
+		if (retval)
+			goto error;
+	}
+
+	if (!strcmp(name, "msm_hsusb")) {
+		otg_pdata =
+			(struct msm_otg_platform_data *)
+				ofdev->dev.platform_data;
+		motg = platform_get_drvdata(ofdev);
+		ci_pdata.log2_itc = otg_pdata->log2_itc;
+		ci_pdata.usb_core_id = 0;
+		ci_pdata.l1_supported = otg_pdata->l1_supported;
+		ci_pdata.enable_ahb2ahb_bypass =
+				otg_pdata->enable_ahb2ahb_bypass;
+		ci_pdata.enable_streaming = otg_pdata->enable_streaming;
+		ci_pdata.enable_axi_prefetch = otg_pdata->enable_axi_prefetch;
+		retval = platform_device_add_data(pdev, &ci_pdata,
+			sizeof(ci_pdata));
+		if (retval)
+			goto error;
+	}
+
+	retval = platform_device_add(pdev);
+	if (retval)
+		goto error;
+
+	return pdev;
+
+error:
+	platform_device_put(pdev);
+	return ERR_PTR(retval);
+}
+
+static int msm_otg_setup_devices(struct platform_device *ofdev,
+		enum usb_mode_type mode, bool init)
+{
+	const char *gadget_name = "msm_hsusb";
+	const char *host_name = "msm_hsusb_host";
+	static struct platform_device *gadget_pdev;
+	static struct platform_device *host_pdev;
+	int retval = 0;
+
+	if (!init) {
+		if (gadget_pdev) {
+			platform_device_unregister(gadget_pdev);
+			device_remove_file(&gadget_pdev->dev,
+					   &dev_attr_perf_mode);
+		}
+		if (host_pdev)
+			platform_device_unregister(host_pdev);
+		return 0;
+	}
+
+	switch (mode) {
+	case USB_OTG:
+		/* fall through */
+	case USB_PERIPHERAL:
+		gadget_pdev = msm_otg_add_pdev(ofdev, gadget_name);
+		if (IS_ERR(gadget_pdev)) {
+			retval = PTR_ERR(gadget_pdev);
+			break;
+		}
+		if (device_create_file(&gadget_pdev->dev, &dev_attr_perf_mode))
+			dev_err(&gadget_pdev->dev, "perf_mode file failed\n");
+		if (mode == USB_PERIPHERAL)
+			break;
+		/* fall through */
+	case USB_HOST:
+		host_pdev = msm_otg_add_pdev(ofdev, host_name);
+		if (IS_ERR(host_pdev)) {
+			retval = PTR_ERR(host_pdev);
+			if (mode == USB_OTG) {
+				platform_device_unregister(gadget_pdev);
+				device_remove_file(&gadget_pdev->dev,
+						   &dev_attr_perf_mode);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return retval;
+}
+
+static int msm_otg_ext_chg_open(struct inode *inode, struct file *file)
+{
+	struct msm_otg *motg = the_msm_otg;
+
+	pr_debug("msm_otg ext chg open\n");
+	msm_otg_dbg_log_event(&motg->phy, "EXT CHG: OPEN",
+			motg->inputs, motg->phy.otg->state);
+
+	motg->ext_chg_opened = true;
+	file->private_data = (void *)motg;
+	return 0;
+}
+
+static long
+msm_otg_ext_chg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct msm_otg *motg = file->private_data;
+	struct msm_usb_chg_info info = {0};
+	int ret = 0, val;
+
+	msm_otg_dbg_log_event(&motg->phy, "EXT CHG: IOCTL", cmd, 0);
+	switch (cmd) {
+	case MSM_USB_EXT_CHG_INFO:
+		info.chg_block_type = USB_CHG_BLOCK_ULPI;
+		info.page_offset = motg->io_res->start & ~PAGE_MASK;
+		/* mmap() works on PAGE granularity */
+		info.length = PAGE_SIZE;
+
+		if (copy_to_user((void __user *)arg, &info, sizeof(info))) {
+			pr_err("%s: copy to user failed\n\n", __func__);
+			ret = -EFAULT;
+		}
+		break;
+	case MSM_USB_EXT_CHG_BLOCK_LPM:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+		pr_debug("%s: LPM block request %d\n", __func__, val);
+		msm_otg_dbg_log_event(&motg->phy, "LPM BLOCK REQ", val, 0);
+		if (val) { /* block LPM */
+			if (motg->chg_type == USB_DCP_CHARGER) {
+				motg->ext_chg_active = ACTIVE;
+				msm_otg_dbg_log_event(&motg->phy,
+				      "PM RUNTIME: EXT_CHG GET",
+				      get_pm_runtime_counter(motg->phy.dev), 0);
+				pm_runtime_get_sync(motg->phy.dev);
+			} else {
+				motg->ext_chg_active = INACTIVE;
+				complete(&motg->ext_chg_wait);
+				ret = -ENODEV;
+			}
+		} else {
+			motg->ext_chg_active = INACTIVE;
+			complete(&motg->ext_chg_wait);
+			/*
+			 * If usb cable is disconnected and then userspace
+			 * calls ioctl to unblock low power mode, make sure
+			 * otg_sm work for usb disconnect is processed first
+			 * followed by decrementing the PM usage counters.
+			 */
+			flush_work(&motg->sm_work);
+			msm_otg_dbg_log_event(&motg->phy,
+				"PM RUNTIME: EXT_CHG PUT",
+				get_pm_runtime_counter(motg->phy.dev), 0);
+			pm_runtime_put_sync(motg->phy.dev);
+		}
+		break;
+	case MSM_USB_EXT_CHG_VOLTAGE_INFO:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+		msm_otg_dbg_log_event(&motg->phy, "EXT CHG: VOL REQ", cmd, val);
+
+		if (val == USB_REQUEST_5V)
+			pr_debug("%s:voting 5V voltage request\n", __func__);
+		else if (val == USB_REQUEST_9V)
+			pr_debug("%s:voting 9V voltage request\n", __func__);
+		break;
+	case MSM_USB_EXT_CHG_RESULT:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+		msm_otg_dbg_log_event(&motg->phy, "EXT CHG: VOL REQ", cmd, val);
+
+		if (!val)
+			pr_debug("%s:voltage request successful\n", __func__);
+		else
+			pr_debug("%s:voltage request failed\n", __func__);
+		break;
+	case MSM_USB_EXT_CHG_TYPE:
+		if (get_user(val, (int __user *)arg)) {
+			pr_err("%s: get_user failed\n\n", __func__);
+			ret = -EFAULT;
+			break;
+		}
+		msm_otg_dbg_log_event(&motg->phy, "EXT CHG: VOL REQ", cmd, val);
+
+		if (val)
+			pr_debug("%s:charger is external charger\n", __func__);
+		else
+			pr_debug("%s:charger is not ext charger\n", __func__);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int msm_otg_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct msm_otg *motg = file->private_data;
+	unsigned long vsize = vma->vm_end - vma->vm_start;
+	int ret;
+
+	if (vma->vm_pgoff || vsize > PAGE_SIZE)
+		return -EINVAL;
+
+	vma->vm_pgoff = __phys_to_pfn(motg->io_res->start);
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+				 vsize, vma->vm_page_prot);
+	if (ret < 0) {
+		pr_err("%s: failed with return val %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int msm_otg_ext_chg_release(struct inode *inode, struct file *file)
+{
+	struct msm_otg *motg = file->private_data;
+
+	pr_debug("msm_otg ext chg release\n");
+	msm_otg_dbg_log_event(&motg->phy, "EXT CHG: RELEASE",
+			motg->inputs, motg->phy.otg->state);
+
+	motg->ext_chg_opened = false;
+
+	return 0;
+}
+
+static const struct file_operations msm_otg_ext_chg_fops = {
+	.owner = THIS_MODULE,
+	.open = msm_otg_ext_chg_open,
+	.unlocked_ioctl = msm_otg_ext_chg_ioctl,
+	.mmap = msm_otg_ext_chg_mmap,
+	.release = msm_otg_ext_chg_release,
+};
+
+static int msm_otg_setup_ext_chg_cdev(struct msm_otg *motg)
+{
+	int ret;
+
+	if (motg->pdata->enable_sec_phy || motg->pdata->mode == USB_HOST ||
+			motg->pdata->otg_control != OTG_PMIC_CONTROL) {
+		pr_debug("usb ext chg is not supported by msm otg\n");
+		return -ENODEV;
+	}
+
+	ret = alloc_chrdev_region(&motg->ext_chg_dev, 0, 1, "usb_ext_chg");
+	if (ret < 0) {
+		pr_err("Fail to allocate usb ext char dev region\n");
+		return ret;
+	}
+	motg->ext_chg_class = class_create(THIS_MODULE, "msm_ext_chg");
+	if (ret < 0) {
+		pr_err("Fail to create usb ext chg class\n");
+		goto unreg_chrdev;
+	}
+	cdev_init(&motg->ext_chg_cdev, &msm_otg_ext_chg_fops);
+	motg->ext_chg_cdev.owner = THIS_MODULE;
+
+	ret = cdev_add(&motg->ext_chg_cdev, motg->ext_chg_dev, 1);
+	if (ret < 0) {
+		pr_err("Fail to add usb ext chg cdev\n");
+		goto destroy_class;
+	}
+	motg->ext_chg_device = device_create(motg->ext_chg_class,
+					NULL, motg->ext_chg_dev, NULL,
+					"usb_ext_chg");
+	if (IS_ERR(motg->ext_chg_device)) {
+		pr_err("Fail to create usb ext chg device\n");
+		ret = PTR_ERR(motg->ext_chg_device);
+		motg->ext_chg_device = NULL;
+		goto del_cdev;
+	}
+
+	init_completion(&motg->ext_chg_wait);
+	pr_debug("msm otg ext chg cdev setup success\n");
+	return 0;
+
+del_cdev:
+	cdev_del(&motg->ext_chg_cdev);
+destroy_class:
+	class_destroy(motg->ext_chg_class);
+unreg_chrdev:
+	unregister_chrdev_region(motg->ext_chg_dev, 1);
+
+	return ret;
+}
+
+static ssize_t dpdm_pulldown_enable_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct msm_otg *motg = the_msm_otg;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", pdata->dpdm_pulldown_added ?
+							"enabled" : "disabled");
+}
+
+static ssize_t dpdm_pulldown_enable_store(struct device *dev,
+		struct device_attribute *attr, const char
+		*buf, size_t size)
+{
+	struct msm_otg *motg = the_msm_otg;
+	struct msm_otg_platform_data *pdata = motg->pdata;
+
+	if (!strncasecmp(buf, "enable", 6)) {
+		pdata->dpdm_pulldown_added = true;
+		return size;
+	} else if (!strncasecmp(buf, "disable", 7)) {
+		pdata->dpdm_pulldown_added = false;
+		return size;
+	}
+
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(dpdm_pulldown_enable, 0644,
+		dpdm_pulldown_enable_show, dpdm_pulldown_enable_store);
+
+static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
+				void *ptr)
+{
+	struct msm_otg *motg = container_of(nb, struct msm_otg, vbus_nb);
+
+	if (event)
+		set_bit(B_SESS_VLD, &motg->inputs);
+	else
+		clear_bit(B_SESS_VLD, &motg->inputs);
+
+	queue_work(motg->otg_wq, &motg->sm_work);
+
+	return NOTIFY_DONE;
+}
+
+static int msm_otg_id_notifier(struct notifier_block *nb, unsigned long event,
+				void *ptr)
+{
+	struct msm_otg *motg = container_of(nb, struct msm_otg, id_nb);
+
+	if (event)
+		clear_bit(ID, &motg->inputs);
+	else
+		set_bit(ID, &motg->inputs);
+
+	queue_work(motg->otg_wq, &motg->sm_work);
+
+	return NOTIFY_DONE;
+}
+
+static int msm_otg_extcon_register(struct msm_otg *motg)
+{
+	struct device_node *node = motg->pdev->dev.of_node;
+	struct extcon_dev *edev;
+	int ret = 0;
+
+	if (!of_property_read_bool(node, "extcon"))
+		return 0;
+
+	edev = extcon_get_edev_by_phandle(&motg->pdev->dev, 0);
+	if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV)
+		return PTR_ERR(edev);
+
+	if (!IS_ERR(edev)) {
+		motg->extcon_vbus = edev;
+		motg->vbus_nb.notifier_call = msm_otg_vbus_notifier;
+		ret = extcon_register_notifier(edev, EXTCON_USB,
+							&motg->vbus_nb);
+		if (ret < 0) {
+			dev_err(&motg->pdev->dev, "failed to register notifier for USB\n");
+			return ret;
+		}
+	}
+
+	if (of_count_phandle_with_args(node, "extcon", NULL) > 1) {
+		edev = extcon_get_edev_by_phandle(&motg->pdev->dev, 1);
+		if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV) {
+			ret = PTR_ERR(edev);
+			goto err;
+		}
+	}
+
+	if (!IS_ERR(edev)) {
+		motg->extcon_id = edev;
+		motg->id_nb.notifier_call = msm_otg_id_notifier;
+		ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
+							&motg->id_nb);
+		if (ret < 0) {
+			dev_err(&motg->pdev->dev, "failed to register notifier for USB-HOST\n");
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	if (motg->extcon_vbus)
+		extcon_unregister_notifier(motg->extcon_vbus, EXTCON_USB,
+								&motg->vbus_nb);
+
+	return ret;
+}
+
+struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_otg_platform_data *pdata;
+	int len = 0;
+	int res_gpio;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	len = of_property_count_elems_of_size(node,
+			"qcom,hsusb-otg-phy-init-seq", sizeof(len));
+	if (len > 0) {
+		pdata->phy_init_seq = devm_kzalloc(&pdev->dev,
+						len * sizeof(len), GFP_KERNEL);
+		if (!pdata->phy_init_seq)
+			return NULL;
+		of_property_read_u32_array(node, "qcom,hsusb-otg-phy-init-seq",
+				pdata->phy_init_seq, len);
+	}
+	of_property_read_u32(node, "qcom,hsusb-otg-power-budget",
+				&pdata->power_budget);
+	of_property_read_u32(node, "qcom,hsusb-otg-mode",
+				&pdata->mode);
+	of_property_read_u32(node, "qcom,hsusb-otg-otg-control",
+				&pdata->otg_control);
+	of_property_read_u32(node, "qcom,hsusb-otg-default-mode",
+				&pdata->default_mode);
+	of_property_read_u32(node, "qcom,hsusb-otg-phy-type",
+				&pdata->phy_type);
+	pdata->disable_reset_on_disconnect = of_property_read_bool(node,
+				"qcom,hsusb-otg-disable-reset");
+	pdata->pnoc_errata_fix = of_property_read_bool(node,
+				"qcom,hsusb-otg-pnoc-errata-fix");
+	pdata->enable_lpm_on_dev_suspend = of_property_read_bool(node,
+				"qcom,hsusb-otg-lpm-on-dev-suspend");
+	pdata->core_clk_always_on_workaround = of_property_read_bool(node,
+				"qcom,hsusb-otg-clk-always-on-workaround");
+	pdata->delay_lpm_on_disconnect = of_property_read_bool(node,
+				"qcom,hsusb-otg-delay-lpm");
+	pdata->dp_manual_pullup = of_property_read_bool(node,
+				"qcom,dp-manual-pullup");
+	pdata->enable_sec_phy = of_property_read_bool(node,
+					"qcom,usb2-enable-hsphy2");
+	of_property_read_u32(node, "qcom,hsusb-log2-itc",
+				&pdata->log2_itc);
+
+	of_property_read_u32(node, "qcom,hsusb-otg-mpm-dpsehv-int",
+				&pdata->mpm_dpshv_int);
+	of_property_read_u32(node, "qcom,hsusb-otg-mpm-dmsehv-int",
+				&pdata->mpm_dmshv_int);
+	pdata->pmic_id_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
+	if (pdata->pmic_id_irq < 0)
+		pdata->pmic_id_irq = 0;
+
+	pdata->hub_reset_gpio = of_get_named_gpio(
+			node, "qcom,hub-reset-gpio", 0);
+	if (!gpio_is_valid(pdata->hub_reset_gpio))
+		pr_debug("hub_reset_gpio is not available\n");
+
+	pdata->usbeth_reset_gpio = of_get_named_gpio(
+			node, "qcom,usbeth-reset-gpio", 0);
+	if (!gpio_is_valid(pdata->usbeth_reset_gpio))
+		pr_debug("usbeth_reset_gpio is not available\n");
+
+	pdata->switch_sel_gpio =
+			of_get_named_gpio(node, "qcom,sw-sel-gpio", 0);
+	if (!gpio_is_valid(pdata->switch_sel_gpio))
+		pr_debug("switch_sel_gpio is not available\n");
+
+	pdata->usb_id_gpio =
+			of_get_named_gpio(node, "qcom,usbid-gpio", 0);
+	if (!gpio_is_valid(pdata->usb_id_gpio))
+		pr_debug("usb_id_gpio is not available\n");
+
+	pdata->l1_supported = of_property_read_bool(node,
+				"qcom,hsusb-l1-supported");
+	pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
+				"qcom,ahb-async-bridge-bypass");
+	pdata->disable_retention_with_vdd_min = of_property_read_bool(node,
+				"qcom,disable-retention-with-vdd-min");
+	pdata->enable_phy_id_pullup = of_property_read_bool(node,
+				"qcom,enable-phy-id-pullup");
+	pdata->phy_dvdd_always_on = of_property_read_bool(node,
+				"qcom,phy-dvdd-always-on");
+
+	res_gpio = of_get_named_gpio(node, "qcom,hsusb-otg-vddmin-gpio", 0);
+	if (!gpio_is_valid(res_gpio))
+		res_gpio = 0;
+	pdata->vddmin_gpio = res_gpio;
+
+	pdata->emulation = of_property_read_bool(node,
+						"qcom,emulation");
+
+	pdata->enable_streaming = of_property_read_bool(node,
+					"qcom,boost-sysclk-with-streaming");
+
+	pdata->enable_axi_prefetch = of_property_read_bool(node,
+						"qcom,axi-prefetch-enable");
+
+	pdata->enable_sdp_typec_current_limit = of_property_read_bool(node,
+					"qcom,enable-sdp-typec-current-limit");
+	pdata->vbus_low_as_hostmode = of_property_read_bool(node,
+					"qcom,vbus-low-as-hostmode");
+	return pdata;
+}
+
+static int msm_otg_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	int len = 0;
+	u32 tmp[3];
+	struct resource *res;
+	struct msm_otg *motg;
+	struct usb_phy *phy;
+	struct msm_otg_platform_data *pdata;
+	void __iomem *tcsr;
+	int id_irq = 0;
+
+	dev_info(&pdev->dev, "msm_otg probe\n");
+
+	motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL);
+	if (!motg) {
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	/*
+	 * USB Core is running its protocol engine based on CORE CLK,
+	 * CORE CLK  must be running at >55Mhz for correct HSUSB
+	 * operation and USB core cannot tolerate frequency changes on
+	 * CORE CLK. For such USB cores, vote for maximum clk frequency
+	 * on pclk source
+	 */
+	motg->core_clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(motg->core_clk)) {
+		ret = PTR_ERR(motg->core_clk);
+		motg->core_clk = NULL;
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to get core_clk\n");
+		goto free_motg;
+	}
+
+	motg->core_reset = devm_reset_control_get(&pdev->dev, "core_reset");
+	if (IS_ERR(motg->core_reset)) {
+		dev_err(&pdev->dev, "failed to get core_reset\n");
+		ret = PTR_ERR(motg->core_reset);
+		goto put_core_clk;
+	}
+
+	/*
+	 * USB Core CLK can run at max freq if streaming is enabled. Hence,
+	 * get Max supported clk frequency for USB Core CLK and request to set
+	 * the same. Otherwise set USB Core CLK to defined default value.
+	 */
+	if (of_property_read_u32(pdev->dev.of_node,
+					"qcom,max-nominal-sysclk-rate", &ret)) {
+		ret = -EINVAL;
+		goto put_core_clk;
+	} else {
+		motg->core_clk_nominal_rate = clk_round_rate(motg->core_clk,
+							     ret);
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node,
+					"qcom,max-svs-sysclk-rate", &ret)) {
+		dev_dbg(&pdev->dev, "core_clk svs freq not specified\n");
+	} else {
+		motg->core_clk_svs_rate = clk_round_rate(motg->core_clk, ret);
+	}
+
+	motg->default_noc_mode = USB_NOC_NOM_VOTE;
+	if (of_property_read_bool(pdev->dev.of_node, "qcom,default-mode-svs")) {
+		motg->core_clk_rate = motg->core_clk_svs_rate;
+		motg->default_noc_mode = USB_NOC_SVS_VOTE;
+	} else if (of_property_read_bool(pdev->dev.of_node,
+					"qcom,boost-sysclk-with-streaming")) {
+		motg->core_clk_rate = motg->core_clk_nominal_rate;
+	} else {
+		motg->core_clk_rate = clk_round_rate(motg->core_clk,
+						USB_DEFAULT_SYSTEM_CLOCK);
+	}
+
+	if (IS_ERR_VALUE(motg->core_clk_rate)) {
+		dev_err(&pdev->dev, "fail to get core clk max freq.\n");
+	} else {
+		ret = clk_set_rate(motg->core_clk, motg->core_clk_rate);
+		if (ret)
+			dev_err(&pdev->dev, "fail to set core_clk freq:%d\n",
+									ret);
+	}
+
+	motg->pclk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(motg->pclk)) {
+		ret = PTR_ERR(motg->pclk);
+		motg->pclk = NULL;
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "failed to get iface_clk\n");
+		goto put_core_clk;
+	}
+
+	motg->xo_clk = clk_get(&pdev->dev, "xo");
+	if (IS_ERR(motg->xo_clk)) {
+		ret = PTR_ERR(motg->xo_clk);
+		motg->xo_clk = NULL;
+		if (ret == -EPROBE_DEFER)
+			goto put_pclk;
+	}
+
+	/*
+	 * On few platforms USB PHY is fed with sleep clk.
+	 * Hence don't fail probe.
+	 */
+	motg->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
+	if (IS_ERR(motg->sleep_clk)) {
+		ret = PTR_ERR(motg->sleep_clk);
+		motg->sleep_clk = NULL;
+		if (ret == -EPROBE_DEFER)
+			goto put_xo_clk;
+		else
+			dev_dbg(&pdev->dev, "failed to get sleep_clk\n");
+	} else {
+		ret = clk_prepare_enable(motg->sleep_clk);
+		if (ret) {
+			dev_err(&pdev->dev, "%s failed to vote sleep_clk%d\n",
+						__func__, ret);
+			goto put_xo_clk;
+		}
+	}
+
+	/*
+	 * If present, phy_reset_clk is used to reset the PHY, ULPI bridge
+	 * and CSR Wrapper. This is a reset only clock.
+	 */
+
+	if (of_property_match_string(pdev->dev.of_node,
+			"clock-names", "phy_reset_clk") >= 0) {
+		motg->phy_reset_clk = devm_clk_get(&pdev->dev, "phy_reset_clk");
+		if (IS_ERR(motg->phy_reset_clk)) {
+			ret = PTR_ERR(motg->phy_reset_clk);
+			goto disable_sleep_clk;
+		}
+
+		motg->phy_reset = devm_reset_control_get(&pdev->dev,
+								"phy_reset");
+		if (IS_ERR(motg->phy_reset)) {
+			dev_err(&pdev->dev, "failed to get phy_reset\n");
+			ret = PTR_ERR(motg->phy_reset);
+			goto disable_sleep_clk;
+		}
+	}
+
+	/*
+	 * If present, phy_por_clk is used to assert/de-assert phy POR
+	 * input. This is a reset only clock. phy POR must be asserted
+	 * after overriding the parameter registers via CSR wrapper or
+	 * ULPI bridge.
+	 */
+	if (of_property_match_string(pdev->dev.of_node,
+				"clock-names", "phy_por_clk") >= 0) {
+		motg->phy_por_clk = devm_clk_get(&pdev->dev, "phy_por_clk");
+		if (IS_ERR(motg->phy_por_clk)) {
+			ret = PTR_ERR(motg->phy_por_clk);
+			goto disable_sleep_clk;
+		}
+
+		motg->phy_por_reset = devm_reset_control_get(&pdev->dev,
+							"phy_por_reset");
+		if (IS_ERR(motg->phy_por_reset)) {
+			dev_err(&pdev->dev, "failed to get phy_por_reset\n");
+			ret = PTR_ERR(motg->phy_por_reset);
+			goto disable_sleep_clk;
+		}
+	}
+
+	/*
+	 * If present, phy_csr_clk is required for accessing PHY
+	 * CSR registers via AHB2PHY interface.
+	 */
+	if (of_property_match_string(pdev->dev.of_node,
+				"clock-names", "phy_csr_clk") >= 0) {
+		motg->phy_csr_clk = devm_clk_get(&pdev->dev, "phy_csr_clk");
+		if (IS_ERR(motg->phy_csr_clk)) {
+			ret = PTR_ERR(motg->phy_csr_clk);
+			goto disable_sleep_clk;
+		} else {
+			ret = clk_prepare_enable(motg->phy_csr_clk);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"fail to enable phy csr clk %d\n", ret);
+				goto disable_sleep_clk;
+			}
+		}
+	}
+
+	of_property_read_u32(pdev->dev.of_node, "qcom,pm-qos-latency",
+				&motg->pm_qos_latency);
+
+	pdata = msm_otg_dt_to_pdata(pdev);
+	if (!pdata) {
+		ret = -ENOMEM;
+		goto disable_phy_csr_clk;
+	}
+	pdev->dev.platform_data = pdata;
+
+	pdata->bus_scale_table = msm_bus_cl_get_pdata(pdev);
+	if (!pdata->bus_scale_table)
+		dev_dbg(&pdev->dev, "bus scaling is disabled\n");
+
+	if (pdata->phy_type == QUSB_ULPI_PHY) {
+		if (of_property_match_string(pdev->dev.of_node,
+					"clock-names", "phy_ref_clk") >= 0) {
+			motg->phy_ref_clk = devm_clk_get(&pdev->dev,
+						"phy_ref_clk");
+			if (IS_ERR(motg->phy_ref_clk)) {
+				ret = PTR_ERR(motg->phy_ref_clk);
+				goto disable_phy_csr_clk;
+			} else {
+				ret = clk_prepare_enable(motg->phy_ref_clk);
+				if (ret) {
+					dev_err(&pdev->dev,
+						"fail to enable phy ref clk %d\n",
+						ret);
+					goto disable_phy_csr_clk;
+				}
+			}
+		}
+	}
+
+	motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
+							GFP_KERNEL);
+	if (!motg->phy.otg) {
+		ret = -ENOMEM;
+		goto disable_phy_csr_clk;
+	}
+
+	the_msm_otg = motg;
+	motg->pdata = pdata;
+	phy = &motg->phy;
+	phy->dev = &pdev->dev;
+	motg->pdev = pdev;
+	motg->dbg_idx = 0;
+	motg->dbg_lock = __RW_LOCK_UNLOCKED(lck);
+
+	if (motg->pdata->bus_scale_table) {
+		motg->bus_perf_client =
+		    msm_bus_scale_register_client(motg->pdata->bus_scale_table);
+		if (!motg->bus_perf_client) {
+			dev_err(motg->phy.dev, "%s: Failed to register BUS\n"
+						"scaling client!!\n", __func__);
+		} else {
+			debug_bus_voting_enabled = true;
+			/* Some platforms require BUS vote to control clocks */
+			msm_otg_bus_vote(motg, USB_MIN_PERF_VOTE);
+		}
+	}
+
+	ret = msm_otg_bus_freq_get(motg);
+	if (ret) {
+		pr_err("failed to get noc clocks: %d\n", ret);
+	} else {
+		ret = msm_otg_bus_freq_set(motg, motg->default_noc_mode);
+		if (ret)
+			pr_err("failed to vote explicit noc rates: %d\n", ret);
+	}
+
+	/* initialize reset counter */
+	motg->reset_counter = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get core iomem resource\n");
+		ret = -ENODEV;
+		goto devote_bus_bw;
+	}
+
+	motg->io_res = res;
+	motg->regs = ioremap(res->start, resource_size(res));
+	if (!motg->regs) {
+		dev_err(&pdev->dev, "core iomem ioremap failed\n");
+		ret = -ENOMEM;
+		goto devote_bus_bw;
+	}
+	dev_info(&pdev->dev, "OTG regs = %pK\n", motg->regs);
+
+	if (pdata->enable_sec_phy) {
+		res = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "tcsr");
+		if (!res) {
+			dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
+		} else {
+			tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
+				resource_size(res));
+			if (!tcsr) {
+				dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
+			} else {
+				/* Enable USB2 on secondary HSPHY. */
+				writel_relaxed(0x1, tcsr);
+				/*
+				 * Ensure that TCSR write is completed before
+				 * USB registers initialization.
+				 */
+				mb();
+			}
+		}
+	}
+
+	if (pdata->enable_sec_phy)
+		motg->usb_phy_ctrl_reg = USB_PHY_CTRL2;
+	else
+		motg->usb_phy_ctrl_reg = USB_PHY_CTRL;
+
+	/*
+	 * The USB PHY wrapper provides a register interface
+	 * through AHB2PHY for performing PHY related operations
+	 * like retention, HV interrupts and overriding parameter
+	 * registers etc. The registers start at 4 byte boundary
+	 * but only the first byte is valid and remaining are not
+	 * used. Relaxed versions of readl/writel should be used.
+	 *
+	 * The link does not have any PHY specific registers.
+	 * Hence set motg->usb_phy_ctrl_reg to.
+	 */
+	if (motg->pdata->phy_type == SNPS_FEMTO_PHY ||
+		pdata->phy_type == QUSB_ULPI_PHY) {
+		res = platform_get_resource_byname(pdev,
+				IORESOURCE_MEM, "phy_csr");
+		if (!res) {
+			dev_err(&pdev->dev, "PHY CSR IOMEM missing!\n");
+			ret = -ENODEV;
+			goto free_regs;
+		}
+		motg->phy_csr_regs = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(motg->phy_csr_regs)) {
+			ret = PTR_ERR(motg->phy_csr_regs);
+			dev_err(&pdev->dev, "PHY CSR ioremap failed!\n");
+			goto free_regs;
+		}
+		motg->usb_phy_ctrl_reg = 0;
+	}
+
+	motg->irq = platform_get_irq(pdev, 0);
+	if (!motg->irq) {
+		dev_err(&pdev->dev, "platform_get_irq failed\n");
+		ret = -ENODEV;
+		goto free_regs;
+	}
+
+	motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
+	if (motg->async_irq < 0) {
+		dev_err(&pdev->dev, "platform_get_irq for async_int failed\n");
+		motg->async_irq = 0;
+		goto free_regs;
+	}
+
+	if (motg->xo_clk) {
+		ret = clk_prepare_enable(motg->xo_clk);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"%s failed to vote for TCXO %d\n",
+					__func__, ret);
+			goto free_xo_handle;
+		}
+	}
+
+
+	clk_prepare_enable(motg->pclk);
+
+	hsusb_vdd = devm_regulator_get(motg->phy.dev, "hsusb_vdd_dig");
+	if (IS_ERR(hsusb_vdd)) {
+		hsusb_vdd = devm_regulator_get(motg->phy.dev, "HSUSB_VDDCX");
+		if (IS_ERR(hsusb_vdd)) {
+			dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
+			ret = PTR_ERR(hsusb_vdd);
+			goto devote_xo_handle;
+		}
+	}
+
+	len = of_property_count_elems_of_size(pdev->dev.of_node,
+			"qcom,vdd-voltage-level", sizeof(len));
+	if (len > 0) {
+		if (len == sizeof(tmp) / sizeof(len)) {
+			of_property_read_u32_array(pdev->dev.of_node,
+					"qcom,vdd-voltage-level",
+					tmp, len);
+			vdd_val[0] = tmp[0];
+			vdd_val[1] = tmp[1];
+			vdd_val[2] = tmp[2];
+		} else {
+			dev_dbg(&pdev->dev,
+				"Using default hsusb vdd config.\n");
+			goto devote_xo_handle;
+		}
+	} else {
+		goto devote_xo_handle;
+	}
+
+	ret = msm_hsusb_config_vddcx(1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
+		goto devote_xo_handle;
+	}
+
+	ret = regulator_enable(hsusb_vdd);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
+		goto free_config_vddcx;
+	}
+
+	ret = msm_hsusb_ldo_init(motg, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
+		goto free_hsusb_vdd;
+	}
+
+	/* Get pinctrl if target uses pinctrl */
+	motg->phy_pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(motg->phy_pinctrl)) {
+		if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) {
+			dev_err(&pdev->dev, "Error encountered while getting pinctrl");
+			ret = PTR_ERR(motg->phy_pinctrl);
+			goto free_ldo_init;
+		}
+		dev_dbg(&pdev->dev, "Target does not use pinctrl\n");
+		motg->phy_pinctrl = NULL;
+	}
+
+	ret = msm_hsusb_ldo_enable(motg, USB_PHY_REG_ON);
+	if (ret) {
+		dev_err(&pdev->dev, "hsusb vreg enable failed\n");
+		goto free_ldo_init;
+	}
+	clk_prepare_enable(motg->core_clk);
+
+	/* Check if USB mem_type change is needed to workaround PNOC hw issue */
+	msm_otg_pnoc_errata_fix(motg);
+
+	writel_relaxed(0, USB_USBINTR);
+	writel_relaxed(0, USB_OTGSC);
+	/* Ensure that above STOREs are completed before enabling interrupts */
+	mb();
+
+	motg->id_state = USB_ID_FLOAT;
+	set_bit(ID, &motg->inputs);
+	INIT_WORK(&motg->sm_work, msm_otg_sm_work);
+	INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
+	INIT_DELAYED_WORK(&motg->id_status_work, msm_id_status_w);
+	INIT_DELAYED_WORK(&motg->perf_vote_work, msm_otg_perf_vote_work);
+	setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
+				(unsigned long) motg);
+	motg->otg_wq = alloc_ordered_workqueue("k_otg", 0);
+	if (!motg->otg_wq) {
+		pr_err("%s: Unable to create workqueue otg_wq\n",
+			__func__);
+		goto disable_core_clk;
+	}
+
+	ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
+					"msm_otg", motg);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq failed\n");
+		goto destroy_wq;
+	}
+
+	motg->phy_irq = platform_get_irq_byname(pdev, "phy_irq");
+	if (motg->phy_irq < 0) {
+		dev_dbg(&pdev->dev, "phy_irq is not present\n");
+		motg->phy_irq = 0;
+	} else {
+
+		/* clear all interrupts before enabling the IRQ */
+		writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR0);
+		writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1);
+
+		writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD);
+		/*
+		 * Databook says 200 usec delay is required for
+		 * clearing the interrupts.
+		 */
+		udelay(200);
+		writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD);
+
+		ret = request_irq(motg->phy_irq, msm_otg_phy_irq_handler,
+				IRQF_TRIGGER_RISING, "msm_otg_phy_irq", motg);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "phy_irq request fail %d\n", ret);
+			goto free_irq;
+		}
+	}
+
+	ret = request_irq(motg->async_irq, msm_otg_irq,
+				IRQF_TRIGGER_RISING, "msm_otg", motg);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+		goto free_phy_irq;
+	}
+	disable_irq(motg->async_irq);
+
+	if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
+		msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
+
+	if (pdata->mpm_dpshv_int)
+		msm_mpm_enable_pin(pdata->mpm_dpshv_int, 1);
+	if (pdata->mpm_dmshv_int)
+		msm_mpm_enable_pin(pdata->mpm_dmshv_int, 1);
+
+	phy->init = msm_otg_reset;
+	phy->set_power = msm_otg_set_power;
+	phy->set_suspend = msm_otg_set_suspend;
+	phy->dbg_event = msm_otg_dbg_log_event;
+
+	phy->io_ops = &msm_otg_io_ops;
+
+	phy->otg->usb_phy = &motg->phy;
+	phy->otg->set_host = msm_otg_set_host;
+	phy->otg->set_peripheral = msm_otg_set_peripheral;
+	if (pdata->dp_manual_pullup)
+		phy->flags |= ENABLE_DP_MANUAL_PULLUP;
+
+	if (pdata->enable_sec_phy)
+		phy->flags |= ENABLE_SECONDARY_PHY;
+
+	ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
+	if (ret) {
+		dev_err(&pdev->dev, "usb_add_phy failed\n");
+		goto free_async_irq;
+	}
+
+	ret = usb_phy_regulator_init(motg);
+	if (ret) {
+		dev_err(&pdev->dev, "usb_phy_regulator_init failed\n");
+		goto remove_phy;
+	}
+
+	if (motg->pdata->mode == USB_OTG &&
+		motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+		!motg->phy_irq) {
+
+		if (gpio_is_valid(motg->pdata->usb_id_gpio)) {
+			/* usb_id_gpio request */
+			ret = gpio_request(motg->pdata->usb_id_gpio,
+							"USB_ID_GPIO");
+			if (ret < 0) {
+				dev_err(&pdev->dev, "gpio req failed for id\n");
+				motg->pdata->usb_id_gpio = 0;
+				goto remove_phy;
+			}
+
+			/*
+			 * The following code implements switch between the HOST
+			 * mode to device mode when used different HW components
+			 * on the same port: USB HUB and the usb jack type B
+			 * for device mode In this case HUB should be gone
+			 * only once out of reset at the boot time and after
+			 * that always stay on
+			 */
+			if (gpio_is_valid(motg->pdata->hub_reset_gpio)) {
+				ret = devm_gpio_request(&pdev->dev,
+						motg->pdata->hub_reset_gpio,
+						"qcom,hub-reset-gpio");
+				if (ret < 0) {
+					dev_err(&pdev->dev, "gpio req failed for hub reset\n");
+					goto remove_phy;
+				}
+				gpio_direction_output(
+					motg->pdata->hub_reset_gpio, 1);
+			}
+
+			if (gpio_is_valid(motg->pdata->switch_sel_gpio)) {
+				ret = devm_gpio_request(&pdev->dev,
+						motg->pdata->switch_sel_gpio,
+						"qcom,sw-sel-gpio");
+				if (ret < 0) {
+					dev_err(&pdev->dev, "gpio req failed for switch sel\n");
+					goto remove_phy;
+				}
+				if (gpio_get_value(motg->pdata->usb_id_gpio))
+					gpio_direction_input(
+						motg->pdata->switch_sel_gpio);
+
+				else
+					gpio_direction_output(
+					    motg->pdata->switch_sel_gpio,
+					    1);
+			}
+
+			/* usb_id_gpio to irq */
+			id_irq = gpio_to_irq(motg->pdata->usb_id_gpio);
+			motg->ext_id_irq = id_irq;
+		} else if (motg->pdata->pmic_id_irq) {
+			id_irq = motg->pdata->pmic_id_irq;
+		}
+
+		if (id_irq) {
+			ret = request_irq(id_irq,
+					  msm_id_irq,
+					  IRQF_TRIGGER_RISING |
+					  IRQF_TRIGGER_FALLING,
+					  "msm_otg", motg);
+			if (ret) {
+				dev_err(&pdev->dev, "request irq failed for ID\n");
+				goto remove_phy;
+			}
+		} else {
+			/* PMIC does USB ID detection and notifies through
+			 * USB_OTG property of USB powersupply.
+			 */
+			dev_dbg(&pdev->dev, "PMIC does ID detection\n");
+		}
+	}
+
+	platform_set_drvdata(pdev, motg);
+	device_init_wakeup(&pdev->dev, 1);
+
+	ret = msm_otg_debugfs_init(motg);
+	if (ret)
+		dev_dbg(&pdev->dev, "mode debugfs file is not available\n");
+
+	if (motg->pdata->otg_control == OTG_PMIC_CONTROL &&
+			(!(motg->pdata->mode == USB_OTG) ||
+			 motg->pdata->pmic_id_irq || motg->ext_id_irq ||
+								!motg->phy_irq))
+		motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION;
+
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq ||
+				motg->pdata->enable_phy_id_pullup)
+		motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM;
+
+	if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int)
+		motg->caps |= ALLOW_HOST_PHY_RETENTION;
+
+	device_create_file(&pdev->dev, &dev_attr_dpdm_pulldown_enable);
+
+	if (motg->pdata->enable_lpm_on_dev_suspend)
+		motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
+
+	if (motg->pdata->disable_retention_with_vdd_min)
+		motg->caps |= ALLOW_VDD_MIN_WITH_RETENTION_DISABLED;
+
+	/*
+	 * PHY DVDD is supplied by a always on PMIC LDO (unlike
+	 * vddcx/vddmx). PHY can keep D+ pull-up and D+/D-
+	 * pull-down during suspend without any additional
+	 * hardware re-work.
+	 */
+	if (motg->pdata->phy_type == SNPS_FEMTO_PHY)
+		motg->caps |= ALLOW_BUS_SUSPEND_WITHOUT_REWORK;
+
+	pm_stay_awake(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	if (motg->pdata->delay_lpm_on_disconnect) {
+		pm_runtime_set_autosuspend_delay(&pdev->dev,
+			lpm_disconnect_thresh);
+		pm_runtime_use_autosuspend(&pdev->dev);
+	}
+
+	ret = msm_otg_setup_ext_chg_cdev(motg);
+	if (ret)
+		dev_dbg(&pdev->dev, "fail to setup cdev\n");
+
+	if (pdev->dev.of_node) {
+		ret = msm_otg_setup_devices(pdev, pdata->mode, true);
+		if (ret) {
+			dev_err(&pdev->dev, "devices setup failed\n");
+			goto remove_cdev;
+		}
+	}
+
+	psy = power_supply_get_by_name("usb");
+	if (!psy) {
+		dev_dbg(&pdev->dev, "Could not get usb power_supply\n");
+		ret = -EPROBE_DEFER;
+		goto otg_remove_devices;
+	}
+
+
+	ret = msm_otg_extcon_register(motg);
+	if (ret)
+		goto put_psy;
+
+	if (motg->extcon_vbus) {
+		ret = extcon_get_cable_state_(motg->extcon_vbus, EXTCON_USB);
+		if (ret)
+			set_bit(B_SESS_VLD, &motg->inputs);
+		else
+			clear_bit(B_SESS_VLD, &motg->inputs);
+	}
+
+	if (motg->extcon_id) {
+		ret = extcon_get_cable_state_(motg->extcon_id, EXTCON_USB_HOST);
+		if (ret)
+			clear_bit(ID, &motg->inputs);
+		else
+			set_bit(ID, &motg->inputs);
+	}
+
+	if (gpio_is_valid(motg->pdata->hub_reset_gpio)) {
+		ret = devm_gpio_request(&pdev->dev,
+				motg->pdata->hub_reset_gpio,
+				"HUB_RESET");
+		if (ret < 0) {
+			dev_err(&pdev->dev, "gpio req failed for hub_reset\n");
+		} else {
+			gpio_direction_output(
+				motg->pdata->hub_reset_gpio, 0);
+			/* 5 microsecs reset signaling to usb hub */
+			usleep_range(5, 10);
+			gpio_direction_output(
+				motg->pdata->hub_reset_gpio, 1);
+		}
+	}
+
+	if (gpio_is_valid(motg->pdata->usbeth_reset_gpio)) {
+		ret = devm_gpio_request(&pdev->dev,
+				motg->pdata->usbeth_reset_gpio,
+				"ETH_RESET");
+		if (ret < 0) {
+			dev_err(&pdev->dev, "gpio req failed for usbeth_reset\n");
+		} else {
+			gpio_direction_output(
+				motg->pdata->usbeth_reset_gpio, 0);
+			/* 100 microsecs reset signaling to usb-to-eth */
+			usleep_range(100, 110);
+			gpio_direction_output(
+				motg->pdata->usbeth_reset_gpio, 1);
+		}
+	}
+
+	motg->pm_notify.notifier_call = msm_otg_pm_notify;
+	register_pm_notifier(&motg->pm_notify);
+	msm_otg_dbg_log_event(phy, "OTG PROBE", motg->caps, motg->lpm_flags);
+
+	return 0;
+
+put_psy:
+	if (psy)
+		power_supply_put(psy);
+otg_remove_devices:
+	if (pdev->dev.of_node)
+		msm_otg_setup_devices(pdev, motg->pdata->mode, false);
+remove_cdev:
+	if (!motg->ext_chg_device) {
+		device_destroy(motg->ext_chg_class, motg->ext_chg_dev);
+		cdev_del(&motg->ext_chg_cdev);
+		class_destroy(motg->ext_chg_class);
+		unregister_chrdev_region(motg->ext_chg_dev, 1);
+	}
+remove_phy:
+	usb_remove_phy(&motg->phy);
+free_async_irq:
+	free_irq(motg->async_irq, motg);
+free_phy_irq:
+	if (motg->phy_irq)
+		free_irq(motg->phy_irq, motg);
+free_irq:
+	free_irq(motg->irq, motg);
+destroy_wq:
+	destroy_workqueue(motg->otg_wq);
+disable_core_clk:
+	clk_disable_unprepare(motg->core_clk);
+	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
+free_ldo_init:
+	msm_hsusb_ldo_init(motg, 0);
+free_hsusb_vdd:
+	regulator_disable(hsusb_vdd);
+free_config_vddcx:
+	regulator_set_voltage(hsusb_vdd,
+		vdd_val[VDD_NONE],
+		vdd_val[VDD_MAX]);
+devote_xo_handle:
+	clk_disable_unprepare(motg->pclk);
+	if (motg->xo_clk)
+		clk_disable_unprepare(motg->xo_clk);
+free_xo_handle:
+	if (motg->xo_clk) {
+		clk_put(motg->xo_clk);
+		motg->xo_clk = NULL;
+	}
+free_regs:
+	iounmap(motg->regs);
+devote_bus_bw:
+	if (motg->bus_perf_client) {
+		msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+		msm_bus_scale_unregister_client(motg->bus_perf_client);
+	}
+disable_phy_csr_clk:
+	if (motg->phy_csr_clk)
+		clk_disable_unprepare(motg->phy_csr_clk);
+disable_sleep_clk:
+	if (motg->sleep_clk)
+		clk_disable_unprepare(motg->sleep_clk);
+put_xo_clk:
+	if (motg->xo_clk)
+		clk_put(motg->xo_clk);
+put_pclk:
+	if (motg->pclk)
+		clk_put(motg->pclk);
+put_core_clk:
+	if (motg->core_clk)
+		clk_put(motg->core_clk);
+free_motg:
+	kfree(motg);
+	return ret;
+}
+
+static int msm_otg_remove(struct platform_device *pdev)
+{
+	struct msm_otg *motg = platform_get_drvdata(pdev);
+	struct usb_phy *phy = &motg->phy;
+	int cnt = 0;
+
+	if (phy->otg->host || phy->otg->gadget)
+		return -EBUSY;
+
+	unregister_pm_notifier(&motg->pm_notify);
+
+	extcon_unregister_notifier(motg->extcon_id, EXTCON_USB_HOST,
+							&motg->id_nb);
+	extcon_unregister_notifier(motg->extcon_vbus, EXTCON_USB,
+							&motg->vbus_nb);
+
+	if (!motg->ext_chg_device) {
+		device_destroy(motg->ext_chg_class, motg->ext_chg_dev);
+		cdev_del(&motg->ext_chg_cdev);
+		class_destroy(motg->ext_chg_class);
+		unregister_chrdev_region(motg->ext_chg_dev, 1);
+	}
+
+	if (pdev->dev.of_node)
+		msm_otg_setup_devices(pdev, motg->pdata->mode, false);
+	if (psy)
+		power_supply_put(psy);
+	msm_otg_debugfs_cleanup();
+	cancel_delayed_work_sync(&motg->chg_work);
+	cancel_delayed_work_sync(&motg->id_status_work);
+	cancel_delayed_work_sync(&motg->perf_vote_work);
+	msm_otg_perf_vote_update(motg, false);
+	cancel_work_sync(&motg->sm_work);
+	destroy_workqueue(motg->otg_wq);
+
+	pm_runtime_resume(&pdev->dev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	pm_runtime_disable(&pdev->dev);
+
+	if (motg->phy_irq)
+		free_irq(motg->phy_irq, motg);
+	if (motg->pdata->pmic_id_irq)
+		free_irq(motg->pdata->pmic_id_irq, motg);
+	usb_remove_phy(phy);
+	free_irq(motg->irq, motg);
+
+	if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int)
+		device_remove_file(&pdev->dev,
+				&dev_attr_dpdm_pulldown_enable);
+	if (motg->pdata->otg_control == OTG_PHY_CONTROL &&
+		motg->pdata->mpm_otgsessvld_int)
+		msm_mpm_enable_pin(motg->pdata->mpm_otgsessvld_int, 0);
+
+	if (motg->pdata->mpm_dpshv_int)
+		msm_mpm_enable_pin(motg->pdata->mpm_dpshv_int, 0);
+	if (motg->pdata->mpm_dmshv_int)
+		msm_mpm_enable_pin(motg->pdata->mpm_dmshv_int, 0);
+
+	/*
+	 * Put PHY in low power mode.
+	 */
+	ulpi_read(phy, 0x14);
+	ulpi_write(phy, 0x08, 0x09);
+
+	writel_relaxed(readl_relaxed(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
+	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+		if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
+			break;
+		udelay(1);
+		cnt++;
+	}
+	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
+		dev_err(phy->dev, "Unable to suspend PHY\n");
+
+	clk_disable_unprepare(motg->pclk);
+	clk_disable_unprepare(motg->core_clk);
+	if (motg->phy_csr_clk)
+		clk_disable_unprepare(motg->phy_csr_clk);
+	if (motg->xo_clk) {
+		clk_disable_unprepare(motg->xo_clk);
+		clk_put(motg->xo_clk);
+	}
+
+	if (!IS_ERR(motg->sleep_clk))
+		clk_disable_unprepare(motg->sleep_clk);
+
+	msm_hsusb_ldo_enable(motg, USB_PHY_REG_OFF);
+	msm_hsusb_ldo_init(motg, 0);
+	regulator_disable(hsusb_vdd);
+	regulator_set_voltage(hsusb_vdd,
+		vdd_val[VDD_NONE],
+		vdd_val[VDD_MAX]);
+
+	iounmap(motg->regs);
+	pm_runtime_set_suspended(&pdev->dev);
+
+	clk_put(motg->pclk);
+	clk_put(motg->core_clk);
+
+	if (motg->bus_perf_client) {
+		msm_otg_bus_vote(motg, USB_NO_PERF_VOTE);
+		msm_bus_scale_unregister_client(motg->bus_perf_client);
+	}
+
+	return 0;
+}
+
+static void msm_otg_shutdown(struct platform_device *pdev)
+{
+	struct msm_otg *motg = platform_get_drvdata(pdev);
+
+	dev_dbg(&pdev->dev, "OTG shutdown\n");
+	msm_hsusb_vbus_power(motg, 0);
+}
+
+#ifdef CONFIG_PM
+static int msm_otg_runtime_idle(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+	struct usb_phy *phy = &motg->phy;
+
+	dev_dbg(dev, "OTG runtime idle\n");
+	msm_otg_dbg_log_event(phy, "RUNTIME IDLE",
+			phy->otg->state, motg->ext_chg_active);
+
+	if (phy->otg->state == OTG_STATE_UNDEFINED)
+		return -EAGAIN;
+
+	if (motg->ext_chg_active == DEFAULT) {
+		dev_dbg(dev, "Deferring LPM\n");
+		/*
+		 * Charger detection may happen in user space.
+		 * Delay entering LPM by 3 sec.  Otherwise we
+		 * have to exit LPM when user space begins
+		 * charger detection.
+		 *
+		 * This timer will be canceled when user space
+		 * votes against LPM by incrementing PM usage
+		 * counter.  We enter low power mode when
+		 * PM usage counter is decremented.
+		 */
+		pm_schedule_suspend(dev, 3000);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int msm_otg_runtime_suspend(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG runtime suspend\n");
+	msm_otg_dbg_log_event(&motg->phy, "RUNTIME SUSPEND",
+			get_pm_runtime_counter(dev), 0);
+	return msm_otg_suspend(motg);
+}
+
+static int msm_otg_runtime_resume(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG runtime resume\n");
+	msm_otg_dbg_log_event(&motg->phy, "RUNTIME RESUME",
+			get_pm_runtime_counter(dev), 0);
+
+	return msm_otg_resume(motg);
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int msm_otg_pm_suspend(struct device *dev)
+{
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG PM suspend\n");
+	msm_otg_dbg_log_event(&motg->phy, "PM SUSPEND START",
+			get_pm_runtime_counter(dev),
+			atomic_read(&motg->pm_suspended));
+
+	/* flush any pending sm_work first */
+	flush_work(&motg->sm_work);
+	if (!atomic_read(&motg->in_lpm)) {
+		dev_err(dev, "Abort PM suspend!! (USB is outside LPM)\n");
+		return -EBUSY;
+	}
+	atomic_set(&motg->pm_suspended, 1);
+
+	return 0;
+}
+
+static int msm_otg_pm_resume(struct device *dev)
+{
+	int ret = 0;
+	struct msm_otg *motg = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "OTG PM resume\n");
+	msm_otg_dbg_log_event(&motg->phy, "PM RESUME START",
+			get_pm_runtime_counter(dev), pm_runtime_suspended(dev));
+
+	if (motg->resume_pending || motg->phy_irq_pending) {
+		msm_otg_dbg_log_event(&motg->phy, "PM RESUME BY USB",
+				motg->async_int, motg->resume_pending);
+		/* sm work if pending will start in pm notify to exit LPM */
+	}
+
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops msm_otg_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
+	SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
+				msm_otg_runtime_idle)
+};
+#endif
+
+static const struct of_device_id msm_otg_dt_match[] = {
+	{	.compatible = "qcom,hsusb-otg",
+	},
+	{}
+};
+
+static struct platform_driver msm_otg_driver = {
+	.probe = msm_otg_probe,
+	.remove = msm_otg_remove,
+	.shutdown = msm_otg_shutdown,
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &msm_otg_dev_pm_ops,
+#endif
+		.of_match_table = msm_otg_dt_match,
+	},
+};
+
+module_platform_driver(msm_otg_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM USB transceiver driver");
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 56ecb8b..584ae8c 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -63,6 +63,7 @@
 		- Google USB serial devices
 		- HP4x calculators
 		- a number of Motorola phones
+		- Motorola Tetra devices
 		- Novatel Wireless GPS receivers
 		- Siemens USB/MPI adapter.
 		- ViVOtech ViVOpay USB device.
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 464db17..de61271 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2215,7 +2215,6 @@
 		/* something went wrong */
 		dev_err(dev, "%s - usb_submit_urb(write command) failed, status = %d\n",
 			__func__, status);
-		usb_kill_urb(urb);
 		usb_free_urb(urb);
 		atomic_dec(&CmdUrbs);
 		return status;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index a818c43..1799aa0 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -383,6 +383,9 @@
 #define FOUR_G_SYSTEMS_PRODUCT_W14		0x9603
 #define FOUR_G_SYSTEMS_PRODUCT_W100		0x9b01
 
+/* Fujisoft products */
+#define FUJISOFT_PRODUCT_FS040U			0x9b02
+
 /* iBall 3.5G connect wireless modem */
 #define IBALL_3_5G_CONNECT			0x9605
 
@@ -1897,6 +1900,8 @@
 	{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
 	  .driver_info = (kernel_ulong_t)&four_g_w100_blacklist
 	},
+	{USB_DEVICE(LONGCHEER_VENDOR_ID, FUJISOFT_PRODUCT_FS040U),
+	 .driver_info = (kernel_ulong_t)&net_intf3_blacklist},
 	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
 	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, 0x9801, 0xff),
 	  .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index a51b283..3da25ad 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -39,6 +39,7 @@
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_CHILITAG) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 3b5a15d..1232890 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -17,6 +17,7 @@
 #define PL2303_PRODUCT_ID_DCU11		0x1234
 #define PL2303_PRODUCT_ID_PHAROS	0xaaa0
 #define PL2303_PRODUCT_ID_RSAQ3		0xaaa2
+#define PL2303_PRODUCT_ID_CHILITAG	0xaaa8
 #define PL2303_PRODUCT_ID_ALDIGA	0x0611
 #define PL2303_PRODUCT_ID_MMX		0x0612
 #define PL2303_PRODUCT_ID_GPRS		0x0609
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
index e98b6e5..6aa7ff2 100644
--- a/drivers/usb/serial/usb-serial-simple.c
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -80,6 +80,11 @@
 	{ USB_DEVICE(0x22b8, 0x2c64) }	/* Motorola V950 phone */
 DEVICE(moto_modem, MOTO_IDS);
 
+/* Motorola Tetra driver */
+#define MOTOROLA_TETRA_IDS()			\
+	{ USB_DEVICE(0x0cad, 0x9011) }	/* Motorola Solutions TETRA PEI */
+DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS);
+
 /* Novatel Wireless GPS driver */
 #define NOVATEL_IDS()			\
 	{ USB_DEVICE(0x09d7, 0x0100) }	/* NovAtel FlexPack GPS */
@@ -110,6 +115,7 @@
 	&google_device,
 	&vivopay_device,
 	&moto_modem_device,
+	&motorola_tetra_device,
 	&novatel_gps_device,
 	&hp4x_device,
 	&suunto_device,
@@ -125,6 +131,7 @@
 	GOOGLE_IDS(),
 	VIVOPAY_IDS(),
 	MOTO_IDS(),
+	MOTOROLA_TETRA_IDS(),
 	NOVATEL_IDS(),
 	HP4X_IDS(),
 	SUUNTO_IDS(),
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 9876af4..6891e90 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -1076,20 +1076,19 @@
 		return 0;
 
 	err = uas_configure_endpoints(devinfo);
-	if (err) {
+	if (err && err != ENODEV)
 		shost_printk(KERN_ERR, shost,
 			     "%s: alloc streams error %d after reset",
 			     __func__, err);
-		return 1;
-	}
 
+	/* we must unblock the host in every case lest we deadlock */
 	spin_lock_irqsave(shost->host_lock, flags);
 	scsi_report_bus_reset(shost, 0);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	scsi_unblock_requests(shost);
 
-	return 0;
+	return err ? 1 : 0;
 }
 
 static int uas_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
index 9f49037..f0b955f 100644
--- a/drivers/usb/usbip/usbip_common.h
+++ b/drivers/usb/usbip/usbip_common.h
@@ -271,6 +271,7 @@
 	/* lock for status */
 	spinlock_t lock;
 
+	int sockfd;
 	struct socket *tcp_socket;
 
 	struct task_struct *tcp_rx;
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 7f161b0..dbe615b 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -300,7 +300,7 @@
 		case USB_PORT_FEAT_POWER:
 			usbip_dbg_vhci_rh(
 				" ClearPortFeature: USB_PORT_FEAT_POWER\n");
-			dum->port_status[rhport] = 0;
+			dum->port_status[rhport] &= ~USB_PORT_STAT_POWER;
 			dum->resuming = 0;
 			break;
 		case USB_PORT_FEAT_C_RESET:
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index c404017..c287ccc 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -49,13 +49,17 @@
 
 	/*
 	 * output example:
-	 * port sta spd dev      socket           local_busid
-	 * 0000 004 000 00000000         c5a7bb80 1-2.3
-	 * 0001 004 000 00000000         d8cee980 2-3.4
+	 * port sta spd dev      sockfd local_busid
+	 * 0000 004 000 00000000 000003 1-2.3
+	 * 0001 004 000 00000000 000004 2-3.4
 	 *
-	 * IP address can be retrieved from a socket pointer address by looking
-	 * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
-	 * port number and its peer IP address.
+	 * Output includes socket fd instead of socket pointer address to
+	 * avoid leaking kernel memory address in:
+	 *	/sys/devices/platform/vhci_hcd.0/status and in debug output.
+	 * The socket pointer address is not used at the moment and it was
+	 * made visible as a convenient way to find IP address from socket
+	 * pointer address by looking up /proc/net/{tcp,tcp6}. As this opens
+	 * a security hole, the change is made to use sockfd instead.
 	 */
 	for (i = 0; i < VHCI_HC_PORTS; i++) {
 		struct vhci_device *vdev = &vhci->vdev[i];
@@ -68,13 +72,13 @@
 		if (vdev->ud.status == VDEV_ST_USED) {
 			out += sprintf(out, "%03u %08x ",
 					    vdev->speed, vdev->devid);
-			out += sprintf(out, "%16p %s",
-					    vdev->ud.tcp_socket,
+			out += sprintf(out, "%06u %s",
+					    vdev->ud.sockfd,
 					    dev_name(&vdev->udev->dev));
 
 		} else {
 			out += sprintf(out, "000 00000000 ");
-			out += sprintf(out, "0000000000000000 0-0");
+			out += sprintf(out, "000000 0-0");
 		}
 
 		out += sprintf(out, "\n");
@@ -125,7 +129,7 @@
 	int pdev_nr;
 
 	out += sprintf(out,
-		       "port sta spd dev      socket           local_busid\n");
+		       "port sta spd dev      sockfd local_busid\n");
 
 	pdev_nr = status_name_to_id(attr->attr.name);
 	if (pdev_nr < 0)
@@ -324,6 +328,7 @@
 
 	vdev->devid         = devid;
 	vdev->speed         = speed;
+	vdev->ud.sockfd     = sockfd;
 	vdev->ud.tcp_socket = socket;
 	vdev->ud.status     = VDEV_ST_NOTASSIGNED;
 
@@ -361,6 +366,7 @@
 	status->attr.attr.name = status->name;
 	status->attr.attr.mode = S_IRUGO;
 	status->attr.show = status_show;
+	sysfs_attr_init(&status->attr.attr);
 }
 
 static int init_status_attrs(void)
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 5d3b0db..eb44e99 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2328,6 +2328,20 @@
 	  Select this option if display contents should be inherited as set by
 	  the bootloader.
 
+config FB_MSM
+	tristate "MSM Framebuffer support"
+	depends on FB && ARCH_QCOM
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select SYNC
+	select SW_SYNC
+	---help---
+	  The MSM driver implements a frame buffer interface to
+	  provide access to the display hardware and provide
+	  a way for users to display graphics
+	  on connected display panels.
+
 config FB_MX3
 	tristate "MX3 Framebuffer support"
 	depends on FB && MX3_IPU
@@ -2448,6 +2462,7 @@
 source "drivers/video/fbdev/omap/Kconfig"
 source "drivers/video/fbdev/omap2/Kconfig"
 source "drivers/video/fbdev/mmp/Kconfig"
+source "drivers/video/fbdev/msm/Kconfig"
 
 config FB_SH_MOBILE_MERAM
 	tristate "SuperH Mobile MERAM read ahead support"
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index ee8c814..c16b198 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -130,6 +130,11 @@
 obj-$(CONFIG_FB_OPENCORES)	  += ocfb.o
 obj-$(CONFIG_FB_SM712)		  += sm712fb.o
 
+ifeq ($(CONFIG_FB_MSM),y)
+obj-y                             += msm/
+else
+obj-$(CONFIG_MSM_DBA)             += msm/msm_dba/
+endif
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index f8a3839..2ef33d4 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1085,7 +1085,7 @@
 EXPORT_SYMBOL(fb_blank);
 
 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
-			unsigned long arg)
+			unsigned long arg, struct file *file)
 {
 	struct fb_ops *fb;
 	struct fb_var_screeninfo var;
@@ -1222,7 +1222,9 @@
 		if (!lock_fb_info(info))
 			return -ENODEV;
 		fb = info->fbops;
-		if (fb->fb_ioctl)
+		if (fb->fb_ioctl_v2)
+			ret = fb->fb_ioctl_v2(info, cmd, arg, file);
+		else if (fb->fb_ioctl)
 			ret = fb->fb_ioctl(info, cmd, arg);
 		else
 			ret = -ENOTTY;
@@ -1237,7 +1239,7 @@
 
 	if (!info)
 		return -ENODEV;
-	return do_fb_ioctl(info, cmd, arg);
+	return do_fb_ioctl(info, cmd, arg, file);
 }
 
 #ifdef CONFIG_COMPAT
@@ -1268,7 +1270,7 @@
 };
 
 static int fb_getput_cmap(struct fb_info *info, unsigned int cmd,
-			  unsigned long arg)
+			  unsigned long arg, struct file *file)
 {
 	struct fb_cmap_user __user *cmap;
 	struct fb_cmap32 __user *cmap32;
@@ -1291,7 +1293,7 @@
 	    put_user(compat_ptr(data), &cmap->transp))
 		return -EFAULT;
 
-	err = do_fb_ioctl(info, cmd, (unsigned long) cmap);
+	err = do_fb_ioctl(info, cmd, (unsigned long) cmap, file);
 
 	if (!err) {
 		if (copy_in_user(&cmap32->start,
@@ -1336,7 +1338,7 @@
 }
 
 static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd,
-			      unsigned long arg)
+			      unsigned long arg, struct file *file)
 {
 	mm_segment_t old_fs;
 	struct fb_fix_screeninfo fix;
@@ -1347,7 +1349,7 @@
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	err = do_fb_ioctl(info, cmd, (unsigned long) &fix);
+	err = do_fb_ioctl(info, cmd, (unsigned long) &fix, file);
 	set_fs(old_fs);
 
 	if (!err)
@@ -1374,20 +1376,22 @@
 	case FBIOPUT_CON2FBMAP:
 		arg = (unsigned long) compat_ptr(arg);
 	case FBIOBLANK:
-		ret = do_fb_ioctl(info, cmd, arg);
+		ret = do_fb_ioctl(info, cmd, arg, file);
 		break;
 
 	case FBIOGET_FSCREENINFO:
-		ret = fb_get_fscreeninfo(info, cmd, arg);
+		ret = fb_get_fscreeninfo(info, cmd, arg, file);
 		break;
 
 	case FBIOGETCMAP:
 	case FBIOPUTCMAP:
-		ret = fb_getput_cmap(info, cmd, arg);
+		ret = fb_getput_cmap(info, cmd, arg, file);
 		break;
 
 	default:
-		if (fb->fb_compat_ioctl)
+		if (fb->fb_compat_ioctl_v2)
+			ret = fb->fb_compat_ioctl_v2(info, cmd, arg, file);
+		else if (fb->fb_compat_ioctl)
 			ret = fb->fb_compat_ioctl(info, cmd, arg);
 		break;
 	}
diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile
index ed3ff87..e09dcdb 100644
--- a/drivers/video/fbdev/msm/Makefile
+++ b/drivers/video/fbdev/msm/Makefile
@@ -1,6 +1,7 @@
 ccflags-y += -I$(src)
 
 obj-$(CONFIG_FB_MSM_MDSS_MHL3) += mhl3/
+obj-$(CONFIG_MSM_DBA) += msm_dba/
 
 mdss-mdp3-objs = mdp3.o mdp3_layer.o mdp3_dma.o mdp3_ctrl.o dsi_status_v2.o
 mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
@@ -9,7 +10,7 @@
 ccflags-y += -DTARGET_HW_MDSS_MDP3
 endif
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o dsi_status_6g.o
-mdss-mdp-objs += mdss_mdp_pp.o mdss_mdp_pp_debug.o mdss_mdp_pp_cache_config.o
+mdss-mdp-objs += mdss_mdp_pp.o mdss_mdp_pp_debug.o mdss_mdp_pp_cache_config.o mdss_sync.o
 mdss-mdp-objs += mdss_mdp_intf_video.o
 mdss-mdp-objs += mdss_mdp_intf_cmd.o
 mdss-mdp-objs += mdss_mdp_intf_writeback.o
@@ -20,6 +21,7 @@
 mdss-mdp-objs += mdss_mdp_cdm.o
 mdss-mdp-objs += mdss_smmu.o
 mdss-mdp-objs += mdss_mdp_wfd.o
+mdss-mdp-objs += mdss_io_util.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_mdp_debug.o
 
diff --git a/drivers/video/fbdev/msm/dsi_host_v2.c b/drivers/video/fbdev/msm/dsi_host_v2.c
index 2782702..33775ec 100644
--- a/drivers/video/fbdev/msm/dsi_host_v2.c
+++ b/drivers/video/fbdev/msm/dsi_host_v2.c
@@ -1114,7 +1114,7 @@
 
 	if (!pdata->panel_info.dynamic_switch_pending) {
 		for (i = 0; !ret && (i < DSI_MAX_PM); i++) {
-			ret = msm_dss_enable_vreg(
+			ret = msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 1);
 			if (ret) {
@@ -1215,7 +1215,7 @@
 error_vreg:
 	if (ret) {
 		for (; i >= 0; i--)
-			msm_dss_enable_vreg(
+			msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 0);
 	}
@@ -1250,7 +1250,7 @@
 
 	if (!pdata->panel_info.dynamic_switch_pending) {
 		for (i = DSI_MAX_PM - 1; i >= 0; i--) {
-			ret = msm_dss_enable_vreg(
+			ret = msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 0);
 			if (ret)
@@ -1287,7 +1287,7 @@
 	pinfo = &pdata->panel_info;
 	mutex_lock(&ctrl_pdata->mutex);
 	for (i = 0; !ret && (i < DSI_MAX_PM); i++) {
-		ret = msm_dss_enable_vreg(
+		ret = msm_mdss_enable_vreg(
 			ctrl_pdata->power_data[i].vreg_config,
 			ctrl_pdata->power_data[i].num_vreg, 1);
 		if (ret) {
@@ -1314,7 +1314,7 @@
 error_vreg:
 	if (ret) {
 		for (; i >= 0; i--)
-			msm_dss_enable_vreg(
+			msm_mdss_enable_vreg(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, 0);
 	}
diff --git a/drivers/video/fbdev/msm/dsi_io_v2.c b/drivers/video/fbdev/msm/dsi_io_v2.c
index dd2e308..28441b6 100644
--- a/drivers/video/fbdev/msm/dsi_io_v2.c
+++ b/drivers/video/fbdev/msm/dsi_io_v2.c
@@ -50,7 +50,7 @@
 	}
 }
 
-int msm_dsi_io_init(struct platform_device *pdev, struct dss_module_power *mp)
+int msm_dsi_io_init(struct platform_device *pdev, struct mdss_module_power *mp)
 {
 	int rc;
 
@@ -67,7 +67,7 @@
 		return rc;
 	}
 
-	rc = msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+	rc = msm_mdss_config_vreg(&pdev->dev, mp->vreg_config,
 						mp->num_vreg, 1);
 	if (rc) {
 		pr_err("fail to initialize DSI regulator\n");
@@ -78,11 +78,11 @@
 }
 
 void msm_dsi_io_deinit(struct platform_device *pdev,
-				 struct dss_module_power *mp)
+				 struct mdss_module_power *mp)
 {
 	if (dsi_io_private) {
 		msm_dsi_clk_deinit();
-		msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+		msm_mdss_config_vreg(&pdev->dev, mp->vreg_config,
 					mp->num_vreg, 0);
 		kfree(dsi_io_private);
 		dsi_io_private = NULL;
diff --git a/drivers/video/fbdev/msm/dsi_io_v2.h b/drivers/video/fbdev/msm/dsi_io_v2.h
index dd9adf9..d0227ec 100644
--- a/drivers/video/fbdev/msm/dsi_io_v2.h
+++ b/drivers/video/fbdev/msm/dsi_io_v2.h
@@ -18,10 +18,10 @@
 void msm_dsi_ahb_ctrl(int enable);
 
 int msm_dsi_io_init(struct platform_device *dev,
-				struct dss_module_power *mp);
+				struct mdss_module_power *mp);
 
 void msm_dsi_io_deinit(struct platform_device *dev,
-				struct dss_module_power *mp);
+				struct mdss_module_power *mp);
 
 int msm_dsi_clk_init(struct platform_device *dev);
 
diff --git a/drivers/video/fbdev/msm/dsi_v2.c b/drivers/video/fbdev/msm/dsi_v2.c
index 92d512a..74c0726 100644
--- a/drivers/video/fbdev/msm/dsi_v2.c
+++ b/drivers/video/fbdev/msm/dsi_v2.c
@@ -237,7 +237,7 @@
 }
 
 static void mdss_dsi_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		pr_err("%s: invalid input\n", __func__);
@@ -252,7 +252,7 @@
 }
 
 static int mdss_dsi_get_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp, enum dsi_pm_type module)
+	struct mdss_module_power *mp, enum dsi_pm_type module)
 {
 	int i = 0, rc = 0;
 	u32 tmp = 0;
@@ -287,7 +287,7 @@
 		pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
 	}
 
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 		mp->num_vreg, GFP_KERNEL);
 	if (!mp->vreg_config) {
 		rc = -ENOMEM;
diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c
index 308af51..5cf439c 100644
--- a/drivers/video/fbdev/msm/mdp3.c
+++ b/drivers/video/fbdev/msm/mdp3.c
@@ -45,7 +45,6 @@
 #include <linux/msm-bus.h>
 #include <linux/msm-bus-board.h>
 #include <linux/qcom_iommu.h>
-#include <linux/msm_iommu_domains.h>
 
 #include <linux/msm_dma_iommu_mapping.h>
 
diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h
index 3f0d979..6fb39a7 100644
--- a/drivers/video/fbdev/msm/mdp3.h
+++ b/drivers/video/fbdev/msm/mdp3.h
@@ -19,8 +19,6 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <linux/msm_iommu_domains.h>
-
 #include "mdss_dsi_clk.h"
 #include "mdp3_dma.h"
 #include "mdss_fb.h"
@@ -111,7 +109,6 @@
 struct mdp3_iommu_domain_map {
 	u32 domain_type;
 	char *client_name;
-	struct msm_iova_partition partitions[1];
 	int npartitions;
 	int domain_idx;
 	struct iommu_domain *domain;
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c
index 889c302..17dadf4 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.c
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.c
@@ -271,7 +271,7 @@
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
 
 	atomic_inc(&session->dma_done_cnt);
-	queue_kthread_work(&session->worker, &session->dma_done_work);
+	kthread_queue_work(&session->worker, &session->dma_done_work);
 	complete_all(&session->dma_completion);
 }
 
diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c
index b7c8d43..089d32d 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.c
+++ b/drivers/video/fbdev/msm/mdp3_dma.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved.
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
  * only version 2 as published by the Free Software Foundation.
diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h
index 6c8e7fe..24caedb9 100644
--- a/drivers/video/fbdev/msm/mdp3_dma.h
+++ b/drivers/video/fbdev/msm/mdp3_dma.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved.
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
  * only version 2 as published by the Free Software Foundation.
diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c
index 7964cf0..3b72b2d 100644
--- a/drivers/video/fbdev/msm/mdp3_ppp.c
+++ b/drivers/video/fbdev/msm/mdp3_ppp.c
@@ -1661,7 +1661,7 @@
 
 	mdp3_ppp_req_push(req_q, req);
 	mutex_unlock(&ppp_stat->req_mutex);
-	queue_kthread_work(&ppp_stat->kworker, &ppp_stat->blit_work);
+	kthread_queue_work(&ppp_stat->kworker, &ppp_stat->blit_work);
 	if (!async) {
 		/* wait for release fence */
 		rc = sync_fence_wait(fence,
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 5d9e612..17bad06 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -209,7 +209,7 @@
 struct mdss_smmu_client {
 	struct device *dev;
 	struct dma_iommu_mapping *mmu_mapping;
-	struct dss_module_power mp;
+	struct mdss_module_power mp;
 	struct reg_bus_client *reg_bus_clt;
 	bool domain_attached;
 	bool handoff_pending;
@@ -283,9 +283,9 @@
 	struct mdss_panel_data *pdata;
 
 	struct platform_device *pdev;
-	struct dss_io_data mdss_io;
-	struct dss_io_data vbif_io;
-	struct dss_io_data vbif_nrt_io;
+	struct mdss_io_data mdss_io;
+	struct mdss_io_data vbif_io;
+	struct mdss_io_data vbif_nrt_io;
 	char __iomem *mdp_base;
 
 	struct mdss_smmu_client mdss_smmu[MDSS_IOMMU_MAX_DOMAIN];
@@ -590,14 +590,14 @@
 }
 
 #define MDSS_VBIF_WRITE(mdata, offset, value, nrt_vbif) \
-		(nrt_vbif ? dss_reg_w(&mdata->vbif_nrt_io, offset, value, 0) :\
-		dss_reg_w(&mdata->vbif_io, offset, value, 0))
+		(nrt_vbif ? mdss_reg_w(&mdata->vbif_nrt_io, offset, value, 0) :\
+		mdss_reg_w(&mdata->vbif_io, offset, value, 0))
 #define MDSS_VBIF_READ(mdata, offset, nrt_vbif) \
-		(nrt_vbif ? dss_reg_r(&mdata->vbif_nrt_io, offset, 0) :\
-		dss_reg_r(&mdata->vbif_io, offset, 0))
+		(nrt_vbif ? mdss_reg_r(&mdata->vbif_nrt_io, offset, 0) :\
+		mdss_reg_r(&mdata->vbif_io, offset, 0))
 #define MDSS_REG_WRITE(mdata, offset, value) \
-		dss_reg_w(&mdata->mdss_io, offset, value, 0)
+		mdss_reg_w(&mdata->mdss_io, offset, value, 0)
 #define MDSS_REG_READ(mdata, offset) \
-		dss_reg_r(&mdata->mdss_io, offset, 0)
+		mdss_reg_r(&mdata->mdss_io, offset, 0)
 
 #endif /* MDSS_H */
diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c
index 06da395..9a9f5e4 100644
--- a/drivers/video/fbdev/msm/mdss_compat_utils.c
+++ b/drivers/video/fbdev/msm/mdss_compat_utils.c
@@ -4307,7 +4307,7 @@
 		break;
 	}
 
-	if (ret == -ENOTSUP)
+	if (ret == -ENOTSUPP)
 		pr_err("%s: unsupported ioctl\n", __func__);
 	else if (ret)
 		pr_debug("%s: ioctl err cmd=%u ret=%d\n", __func__, cmd, ret);
diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.h b/drivers/video/fbdev/msm/mdss_compat_utils.h
index 9dcf6d4..ebae393 100644
--- a/drivers/video/fbdev/msm/mdss_compat_utils.h
+++ b/drivers/video/fbdev/msm/mdss_compat_utils.h
@@ -18,11 +18,13 @@
 /*
  * To allow proper structure padding for 64bit/32bit target
  */
+#ifndef MDP_LAYER_COMMIT_V1_PAD
 #ifdef __LP64
 #define MDP_LAYER_COMMIT_V1_PAD 2
 #else
 #define MDP_LAYER_COMMIT_V1_PAD 3
 #endif
+#endif
 
 struct mdp_buf_sync32 {
 	u32		flags;
diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c
index 9edf2a8..2758a5a 100644
--- a/drivers/video/fbdev/msm/mdss_dba_utils.c
+++ b/drivers/video/fbdev/msm/mdss_dba_utils.c
@@ -14,7 +14,7 @@
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
 #include <video/msm_dba.h>
-#include <linux/switch.h>
+#include <linux/extcon.h>
 
 #include "mdss_dba_utils.h"
 #include "mdss_hdmi_edid.h"
@@ -32,8 +32,8 @@
 	bool hpd_state;
 	bool audio_switch_registered;
 	bool display_switch_registered;
-	struct switch_dev sdev_display;
-	struct switch_dev sdev_audio;
+	struct extcon_dev sdev_display;
+	struct extcon_dev sdev_audio;
 	struct kobject *kobj;
 	struct mdss_panel_info *pinfo;
 	void *dba_data;
@@ -103,7 +103,7 @@
 
 	state = udata->sdev_display.state;
 
-	switch_set_state(&udata->sdev_display, val);
+	extcon_set_state_sync(&udata->sdev_display, 0, val);
 
 	pr_debug("cable state %s %d\n",
 		udata->sdev_display.state == state ?
@@ -128,7 +128,7 @@
 
 	state = udata->sdev_audio.state;
 
-	switch_set_state(&udata->sdev_audio, val);
+	extcon_set_state_sync(&udata->sdev_audio, 0, val);
 
 	pr_debug("audio state %s %d\n",
 		udata->sdev_audio.state == state ?
@@ -485,7 +485,7 @@
 
 	/* create switch device to update display modules */
 	udata->sdev_display.name = "hdmi";
-	rc = switch_dev_register(&udata->sdev_display);
+	rc = extcon_dev_register(&udata->sdev_display);
 	if (rc) {
 		pr_err("display switch registration failed\n");
 		goto end;
@@ -495,7 +495,7 @@
 
 	/* create switch device to update audio modules */
 	udata->sdev_audio.name = "hdmi_audio";
-	ret = switch_dev_register(&udata->sdev_audio);
+	ret = extcon_dev_register(&udata->sdev_audio);
 	if (ret) {
 		pr_err("audio switch registration failed\n");
 		goto end;
@@ -895,10 +895,10 @@
 	}
 
 	if (udata->audio_switch_registered)
-		switch_dev_unregister(&udata->sdev_audio);
+		extcon_dev_unregister(&udata->sdev_audio);
 
 	if (udata->display_switch_registered)
-		switch_dev_unregister(&udata->sdev_display);
+		extcon_dev_unregister(&udata->sdev_display);
 
 	if (udata->kobj)
 		mdss_dba_utils_sysfs_remove(udata->kobj);
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index 19335772..f38d40c 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -886,7 +886,7 @@
 
 	buf[count] = 0;	/* end of string */
 
-	if (kstrtoint(buf, "%d", &perf_mode) != 1)
+	if (kstrtoint(buf, 10, &perf_mode) != 1)
 		return -EFAULT;
 
 	if (perf_mode) {
@@ -1023,7 +1023,7 @@
 
 	buf[count] = 0;	/* end of string */
 
-	if (kstrtoint(buf, "%d", &disable_panic) != 1)
+	if (kstrtoint(buf, 10, &disable_panic) != 1)
 		return -EFAULT;
 
 	if (disable_panic) {
@@ -1169,10 +1169,10 @@
 		(struct mdss_data_type *)mdata, &mdss_perf_panic_enable);
 
 	debugfs_create_bool("enable_bw_release", 0644, mdd->perf,
-		(u32 *)&mdata->enable_bw_release);
+		(bool *)&mdata->enable_bw_release);
 
 	debugfs_create_bool("enable_rotator_bw_release", 0644, mdd->perf,
-		(u32 *)&mdata->enable_rotator_bw_release);
+		(bool *)&mdata->enable_rotator_bw_release);
 
 	debugfs_create_file("ab_factor", 0644, mdd->perf,
 		&mdata->ab_factor, &mdss_factor_fops);
@@ -1685,7 +1685,7 @@
 		resp->crc_op_mode = map->crc_op_mode;
 		break;
 	default:
-		ret = -ENOTSUP;
+		ret = -ENOTSUPP;
 		break;
 	}
 
diff --git a/drivers/video/fbdev/msm/mdss_debug.h b/drivers/video/fbdev/msm/mdss_debug.h
index 01d300e..0d482c0 100644
--- a/drivers/video/fbdev/msm/mdss_debug.h
+++ b/drivers/video/fbdev/msm/mdss_debug.h
@@ -78,8 +78,8 @@
 #define MDSS_XLOG_IOMMU(...) mdss_xlog(__func__, __LINE__, MDSS_XLOG_IOMMU, \
 		##__VA_ARGS__, DATA_LIMITER)
 
-#define ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
-#define ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
+#define ATRACE_END(name) trace_mdss_mark_write(current->tgid, name, 0)
+#define ATRACE_BEGIN(name) trace_mdss_mark_write(current->tgid, name, 1)
 #define ATRACE_FUNC() ATRACE_BEGIN(__func__)
 
 #define ATRACE_INT(name, value) \
@@ -225,7 +225,7 @@
 int mdss_dump_misr_data(char **buf, u32 size);
 
 static inline int mdss_debug_register_io(const char *name,
-		struct dss_io_data *io_data, struct mdss_debug_base **dbg_blk)
+		struct mdss_io_data *io_data, struct mdss_debug_base **dbg_blk)
 {
 	return mdss_debug_register_base(name, io_data->base, io_data->len,
 		dbg_blk);
diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c
index e493dcd..49684f4 100644
--- a/drivers/video/fbdev/msm/mdss_debug_xlog.c
+++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c
@@ -734,7 +734,7 @@
 	debugfs_create_u32("enable", 0644, mdss_dbg_xlog.xlog,
 			    &mdss_dbg_xlog.xlog_enable);
 	debugfs_create_bool("panic", 0644, mdss_dbg_xlog.xlog,
-			    &mdss_dbg_xlog.panic_on_err);
+			    (bool *)&mdss_dbg_xlog.panic_on_err);
 	debugfs_create_u32("reg_dump", 0644, mdss_dbg_xlog.xlog,
 			    &mdss_dbg_xlog.enable_reg_dump);
 	debugfs_create_u32("dbgbus_dump", 0644, mdss_dbg_xlog.xlog,
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index bc6d568..d70c1e8 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -26,6 +26,7 @@
 #include <linux/uaccess.h>
 #include <linux/msm-bus.h>
 #include <linux/pm_qos.h>
+#include <linux/mdss_io_util.h>
 
 #include "mdss.h"
 #include "mdss_panel.h"
@@ -253,14 +254,14 @@
 	}
 
 	for (i = DSI_CORE_PM; !rc && (i < DSI_MAX_PM); i++) {
-		rc = msm_dss_config_vreg(&pdev->dev,
+		rc = msm_mdss_config_vreg(&pdev->dev,
 			sdata->power_data[i].vreg_config,
 			sdata->power_data[i].num_vreg, 1);
 		if (rc) {
 			pr_err("%s: failed to init vregs for %s\n",
 				__func__, __mdss_dsi_pm_name(i));
 			for (j = i-1; j >= DSI_CORE_PM; j--) {
-				msm_dss_config_vreg(&pdev->dev,
+				msm_mdss_config_vreg(&pdev->dev,
 				sdata->power_data[j].vreg_config,
 				sdata->power_data[j].num_vreg, 0);
 			}
@@ -293,7 +294,7 @@
 	if (mdss_dsi_pinctrl_set_state(ctrl_pdata, false))
 		pr_debug("reset disable: pinctrl not enabled\n");
 
-	ret = msm_dss_enable_vreg(
+	ret = msm_mdss_enable_vreg(
 		ctrl_pdata->panel_power_data.vreg_config,
 		ctrl_pdata->panel_power_data.num_vreg, 0);
 	if (ret)
@@ -317,7 +318,7 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
-	ret = msm_dss_enable_vreg(
+	ret = msm_mdss_enable_vreg(
 		ctrl_pdata->panel_power_data.vreg_config,
 		ctrl_pdata->panel_power_data.num_vreg, 1);
 	if (ret) {
@@ -378,11 +379,11 @@
 		if (i == DSI_CORE_PM)
 			continue;
 		if (i == DSI_PANEL_PM)
-			ret = msm_dss_config_vreg_opt_mode(
+			ret = msm_mdss_config_vreg_opt_mode(
 				ctrl_pdata->panel_power_data.vreg_config,
 				ctrl_pdata->panel_power_data.num_vreg, mode);
 		else
-			ret = msm_dss_config_vreg_opt_mode(
+			ret = msm_mdss_config_vreg_opt_mode(
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, mode);
 		if (ret) {
@@ -395,7 +396,7 @@
 	if (ret) {
 		mode = enable ? DSS_REG_MODE_ENABLE : DSS_REG_MODE_ULP;
 		for (; i >= 0; i--)
-			msm_dss_config_vreg_opt_mode(
+			msm_mdss_config_vreg_opt_mode(
 				ctrl_pdata->power_data[i].vreg_config,
 				ctrl_pdata->power_data[i].num_vreg, mode);
 	}
@@ -405,7 +406,7 @@
 int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata,
 	int power_state)
 {
-	int ret;
+	int ret = 0;
 	struct mdss_panel_info *pinfo;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
@@ -478,7 +479,7 @@
 }
 
 static void mdss_dsi_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		pr_err("%s: invalid input\n", __func__);
@@ -493,7 +494,7 @@
 }
 
 static int mdss_dsi_get_dt_vreg_data(struct device *dev,
-	struct device_node *of_node, struct dss_module_power *mp,
+	struct device_node *of_node, struct mdss_module_power *mp,
 	enum dsi_pm_type module)
 {
 	int i = 0, rc = 0;
@@ -535,7 +536,7 @@
 		pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
 	}
 
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 		mp->num_vreg, GFP_KERNEL);
 	if (!mp->vreg_config) {
 		rc = -ENOMEM;
@@ -1033,9 +1034,9 @@
 			   &dfs->override_flag);
 
 	debugfs_create_bool("cmd_sync_wait_broadcast", 0644, dfs->root,
-			    (u32 *)&dfs_ctrl->cmd_sync_wait_broadcast);
+		&dfs_ctrl->cmd_sync_wait_broadcast);
 	debugfs_create_bool("cmd_sync_wait_trigger", 0644, dfs->root,
-			    (u32 *)&dfs_ctrl->cmd_sync_wait_trigger);
+		&dfs_ctrl->cmd_sync_wait_trigger);
 
 	debugfs_create_file("dsi_on_cmd_state", 0644, dfs->root,
 		&dfs_ctrl->on_cmds.link_state, &mdss_dsi_cmd_state_fop);
@@ -2028,7 +2029,7 @@
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL;
-	struct mdss_panel_info *pinfo, *spinfo;
+	struct mdss_panel_info *pinfo, *spinfo = NULL;
 	int rc = 0;
 
 	if (pdata == NULL) {
@@ -3452,7 +3453,7 @@
 		goto res_release;
 
 	for (i = (DSI_MAX_PM - 1); i >= DSI_CORE_PM; i--) {
-		if (msm_dss_config_vreg(&pdev->dev,
+		if (msm_mdss_config_vreg(&pdev->dev,
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, 1) < 0)
 			pr_err("%s: failed to de-init vregs for %s\n",
@@ -3748,12 +3749,6 @@
 		return -EPROBE_DEFER;
 	}
 
-	if (util->display_disabled) {
-		pr_info("%s: Display is disabled, not progressing with dsi probe\n",
-			__func__);
-		return -ENOTSUPP;
-	}
-
 	if (!pdev || !pdev->dev.of_node) {
 		pr_err("%s: DSI driver only supports device tree probe\n",
 			__func__);
@@ -3824,7 +3819,7 @@
 
 	mdss_dsi_pm_qos_remove_request(ctrl_pdata->shared_data);
 
-	if (msm_dss_config_vreg(&pdev->dev,
+	if (msm_mdss_config_vreg(&pdev->dev,
 			ctrl_pdata->panel_power_data.vreg_config,
 			ctrl_pdata->panel_power_data.num_vreg, 1) < 0)
 		pr_err("%s: failed to de-init vregs for %s\n",
@@ -3832,9 +3827,9 @@
 	mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->panel_power_data);
 
 	mfd = platform_get_drvdata(pdev);
-	msm_dss_iounmap(&ctrl_pdata->mmss_misc_io);
-	msm_dss_iounmap(&ctrl_pdata->phy_io);
-	msm_dss_iounmap(&ctrl_pdata->ctrl_io);
+	msm_mdss_iounmap(&ctrl_pdata->mmss_misc_io);
+	msm_mdss_iounmap(&ctrl_pdata->phy_io);
+	msm_mdss_iounmap(&ctrl_pdata->ctrl_io);
 	mdss_dsi_debugfs_cleanup(ctrl_pdata);
 
 	if (ctrl_pdata->workq)
@@ -3877,7 +3872,7 @@
 		return -EPERM;
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->ctrl_io, "dsi_ctrl");
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->ctrl_io, "dsi_ctrl");
 	if (rc) {
 		pr_err("%s:%d unable to remap dsi ctrl resources\n",
 			       __func__, __LINE__);
@@ -3887,14 +3882,14 @@
 	ctrl->ctrl_base = ctrl->ctrl_io.base;
 	ctrl->reg_size = ctrl->ctrl_io.len;
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->phy_io, "dsi_phy");
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->phy_io, "dsi_phy");
 	if (rc) {
 		pr_err("%s:%d unable to remap dsi phy resources\n",
 			       __func__, __LINE__);
 		return rc;
 	}
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->phy_regulator_io,
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->phy_regulator_io,
 			"dsi_phy_regulator");
 	if (rc)
 		pr_debug("%s:%d unable to remap dsi phy regulator resources\n",
@@ -3908,7 +3903,7 @@
 		__func__, ctrl->ctrl_base, ctrl->reg_size, ctrl->phy_io.base,
 		ctrl->phy_io.len);
 
-	rc = msm_dss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
+	rc = msm_mdss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
 		"mmss_misc_phys");
 	if (rc) {
 		pr_debug("%s:%d mmss_misc IO remap failed\n",
@@ -3924,7 +3919,7 @@
 	int ret;
 
 	ret = devm_request_irq(dev, irq_no, mdss_dsi_isr,
-				IRQF_DISABLED, "DSI", ctrl);
+				0, "DSI", ctrl);
 	if (ret) {
 		pr_err("msm_dsi_irq_init request_irq() failed!\n");
 		return ret;
@@ -4181,7 +4176,7 @@
 		return rc;
 	}
 
-	rc = msm_dss_config_vreg(&ctrl_pdev->dev,
+	rc = msm_mdss_config_vreg(&ctrl_pdev->dev,
 		ctrl_pdata->panel_power_data.vreg_config,
 		ctrl_pdata->panel_power_data.num_vreg, 1);
 	if (rc) {
@@ -4263,7 +4258,7 @@
 	sdata = ctrl_pdata->shared_data;
 
 	if (pinfo->ulps_suspend_enabled) {
-		rc = msm_dss_enable_vreg(
+		rc = msm_mdss_enable_vreg(
 			sdata->power_data[DSI_PHY_PM].vreg_config,
 			sdata->power_data[DSI_PHY_PM].num_vreg, 1);
 		if (rc) {
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index ea38c0d..60bc455 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -272,7 +272,7 @@
 	struct clk *pixel1_parent;
 
 	/* DSI core regulators */
-	struct dss_module_power power_data[DSI_MAX_PM];
+	struct mdss_module_power power_data[DSI_MAX_PM];
 
 	/* Shared mutex for DSI PHY regulator */
 	struct mutex phy_reg_lock;
@@ -407,10 +407,10 @@
 	void (*switch_mode)(struct mdss_panel_data *pdata, int mode);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
-	struct dss_io_data ctrl_io;
-	struct dss_io_data mmss_misc_io;
-	struct dss_io_data phy_io;
-	struct dss_io_data phy_regulator_io;
+	struct mdss_io_data ctrl_io;
+	struct mdss_io_data mmss_misc_io;
+	struct mdss_io_data phy_io;
+	struct mdss_io_data phy_regulator_io;
 	int reg_size;
 	u32 flags;
 	struct clk *byte_clk;
@@ -459,8 +459,8 @@
 	u32 pclk_rate_bkp;
 	u32 byte_clk_rate_bkp;
 	bool refresh_clk_rate; /* flag to recalculate clk_rate */
-	struct dss_module_power panel_power_data;
-	struct dss_module_power power_data[DSI_MAX_PM]; /* for 8x10 */
+	struct mdss_module_power panel_power_data;
+	struct mdss_module_power power_data[DSI_MAX_PM]; /* for 8x10 */
 	u32 dsi_irq_mask;
 	struct mdss_hw *dsi_hw;
 	struct mdss_intf_recovery *recovery;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 14ac3e1..988c7a9 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -1656,7 +1656,7 @@
 				len = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
 			else
 				len = mdss_dsi_cmd_dma_tx(ctrl, tp);
-			if (IS_ERR_VALUE(len)) {
+			if (IS_ERR_VALUE((unsigned long)len)) {
 				mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
 				pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n",
 					__func__,  cm->payload[0]);
@@ -1886,7 +1886,7 @@
 			ret = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
 		else
 			ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
 			pr_err("%s: failed to tx max_pkt_size\n",
 				__func__);
@@ -1924,7 +1924,7 @@
 			ret = mdss_dsi_cmd_dma_tpg_tx(ctrl, tp);
 		else
 			ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
 			pr_err("%s: failed to tx cmd = 0x%x\n",
 				__func__,  cmds->payload[0]);
@@ -2043,7 +2043,7 @@
 	if (ctrl->mdss_util->iommu_attached()) {
 		ret = mdss_smmu_dsi_map_buffer(tp->dmap, domain, ctrl->dma_size,
 			&(ctrl->dma_addr), tp->start, DMA_TO_DEVICE);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("unable to map dma memory to iommu(%d)\n", ret);
 			ctrl->mdss_util->iommu_unlock();
 			return -ENOMEM;
@@ -2116,7 +2116,7 @@
 		}
 	}
 
-	if (!IS_ERR_VALUE(ret))
+	if (!IS_ERR_VALUE((unsigned long)ret))
 		ret = tp->len;
 
 	if (mctrl && mctrl->dma_addr) {
@@ -2678,7 +2678,7 @@
 
 		if (ctrl->mdss_util->iommu_ctrl) {
 			rc = ctrl->mdss_util->iommu_ctrl(1);
-			if (IS_ERR_VALUE(rc)) {
+			if (IS_ERR_VALUE((unsigned long)rc)) {
 				pr_err("IOMMU attach failed\n");
 				mutex_unlock(&ctrl->cmd_mutex);
 				return rc;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index d84cf5e..1cbaa44 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -79,10 +79,10 @@
 
 	if (level == 0) {
 		if (ctrl->pwm_enabled) {
-			ret = pwm_config_us(ctrl->pwm_bl, level,
-					ctrl->pwm_period);
+			ret = pwm_config(ctrl->pwm_bl, 0,
+					ctrl->pwm_period * NSEC_PER_USEC);
 			if (ret)
-				pr_err("%s: pwm_config_us() failed err=%d.\n",
+				pr_err("%s: pwm_config() failed err=%d.\n",
 						__func__, ret);
 			pwm_disable(ctrl->pwm_bl);
 		}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c
index 7b6be11..992d687 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_status.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_status.c
@@ -227,17 +227,6 @@
 int __init mdss_dsi_status_init(void)
 {
 	int rc = 0;
-	struct mdss_util_intf *util = mdss_get_util_intf();
-
-	if (!util) {
-		pr_err("%s: Failed to get utility functions\n", __func__);
-		return -ENODEV;
-	}
-
-	if (util->display_disabled) {
-		pr_info("Display is disabled, not progressing with dsi_init\n");
-		return -ENOTSUPP;
-	}
 
 	pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
 	if (!pstatus_data)
diff --git a/drivers/video/fbdev/msm/mdss_edp.c b/drivers/video/fbdev/msm/mdss_edp.c
index 55d4ab3..79eae8b 100644
--- a/drivers/video/fbdev/msm/mdss_edp.c
+++ b/drivers/video/fbdev/msm/mdss_edp.c
@@ -27,12 +27,9 @@
 #include <linux/clk.h>
 #include <linux/spinlock_types.h>
 #include <linux/kthread.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
 
 #include "mdss.h"
 #include "mdss_edp.h"
-#include "mdss_debug.h"
 
 #define RGB_COMPONENTS		3
 #define VDDA_MIN_UV			1800000	/* uV units */
diff --git a/drivers/video/fbdev/msm/mdss_edp_aux.c b/drivers/video/fbdev/msm/mdss_edp_aux.c
index dc12f3b..268daaa 100644
--- a/drivers/video/fbdev/msm/mdss_edp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_edp_aux.c
@@ -28,10 +28,6 @@
 #include <linux/of_gpio.h>
 #include <linux/clk/msm-clk.h>
 
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/dma.h>
-
 #include "mdss_panel.h"
 #include "mdss_edp.h"
 
@@ -611,7 +607,6 @@
 
 /*
  * EDID structure can be found in VESA standard here:
- * http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf
  *
  * following table contains default edid
  * static char edid_raw_data[128] = {
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 64f462f..65b689f 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -43,8 +43,6 @@
 #include <linux/uaccess.h>
 #include <linux/version.h>
 #include <linux/vmalloc.h>
-#include <linux/sync.h>
-#include <linux/sw_sync.h>
 #include <linux/file.h>
 #include <linux/kthread.h>
 #include <linux/dma-buf.h>
@@ -55,6 +53,7 @@
 #include "mdss_smmu.h"
 #include "mdss_mdp.h"
 #include "mdp3_ctrl.h"
+#include "mdss_sync.h"
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MDSS_FB_NUM 3
@@ -945,9 +944,6 @@
 {
 	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
 
-	if (!mfd)
-		return;
-
 	mfd->shutdown_pending = true;
 
 	/* wake up threads waiting on idle or kickoff queues */
@@ -1314,12 +1310,20 @@
 
 	mfd->mdp_sync_pt_data.fence_name = "mdp-fence";
 	if (mfd->mdp_sync_pt_data.timeline == NULL) {
-		char timeline_name[16];
+		char timeline_name[32];
 
 		snprintf(timeline_name, sizeof(timeline_name),
 			"mdss_fb_%d", mfd->index);
 		 mfd->mdp_sync_pt_data.timeline =
-				sw_sync_timeline_create(timeline_name);
+				mdss_create_timeline(timeline_name);
+		if (mfd->mdp_sync_pt_data.timeline == NULL) {
+			pr_err("cannot create release fence time line\n");
+			return -ENOMEM;
+		}
+		snprintf(timeline_name, sizeof(timeline_name),
+			"mdss_fb_%d_retire", mfd->index);
+		 mfd->mdp_sync_pt_data.timeline_retire =
+				mdss_create_timeline(timeline_name);
 		if (mfd->mdp_sync_pt_data.timeline == NULL) {
 			pr_err("cannot create release fence time line\n");
 			return -ENOMEM;
@@ -1864,7 +1868,7 @@
 	/* Start Display thread */
 	if (mfd->disp_thread == NULL) {
 		ret = mdss_fb_start_disp_thread(mfd);
-		if (IS_ERR_VALUE(ret))
+		if (IS_ERR_VALUE((unsigned long)ret))
 			return ret;
 	}
 
@@ -2290,7 +2294,7 @@
 			pr_debug("vm_start=%x vm_end=%x vm_page_prot=%ld\n",
 					(unsigned int)vma->vm_start,
 					(unsigned int)vma->vm_end,
-					(unsigned long int)vma->vm_page_prot);
+				(unsigned long int)vma->vm_page_prot.pgprot);
 
 			io_remap_pfn_range(vma, addr, page_to_pfn(page), len,
 					vma->vm_page_prot);
@@ -2874,7 +2878,7 @@
 }
 
 static void __mdss_fb_copy_fence(struct msm_sync_pt_data *sync_pt_data,
-	struct sync_fence **fences, u32 *fence_cnt)
+	struct mdss_fence **fences, u32 *fence_cnt)
 {
 	pr_debug("%s: wait for fences\n", sync_pt_data->fence_name);
 
@@ -2887,12 +2891,12 @@
 	sync_pt_data->acq_fen_cnt = 0;
 	if (*fence_cnt)
 		memcpy(fences, sync_pt_data->acq_fen,
-				*fence_cnt * sizeof(struct sync_fence *));
+				*fence_cnt * sizeof(struct mdss_fence *));
 	mutex_unlock(&sync_pt_data->sync_mutex);
 }
 
 static int __mdss_fb_wait_for_fence_sub(struct msm_sync_pt_data *sync_pt_data,
-	struct sync_fence **fences, int fence_cnt)
+	struct mdss_fence **fences, int fence_cnt)
 {
 	int i, ret = 0;
 	unsigned long max_wait = msecs_to_jiffies(WAIT_MAX_FENCE_TIMEOUT);
@@ -2916,7 +2920,7 @@
 			wait_ms = min_t(long, WAIT_FENCE_FIRST_TIMEOUT,
 					wait_ms);
 
-		ret = sync_fence_wait(fences[i], wait_ms);
+		ret = mdss_wait_sync_fence(fences[i], wait_ms);
 
 		if (ret == -ETIME) {
 			wait_jf = timeout - jiffies;
@@ -2928,31 +2932,31 @@
 						wait_ms);
 
 			pr_warn("%s: sync_fence_wait timed out! ",
-					fences[i]->name);
+					mdss_get_sync_fence_name(fences[i]));
 			pr_cont("Waiting %ld.%ld more seconds\n",
 				(wait_ms/MSEC_PER_SEC), (wait_ms%MSEC_PER_SEC));
 			MDSS_XLOG(sync_pt_data->timeline_value);
 			MDSS_XLOG_TOUT_HANDLER("mdp");
-			ret = sync_fence_wait(fences[i], wait_ms);
+			ret = mdss_wait_sync_fence(fences[i], wait_ms);
 
 			if (ret == -ETIME)
 				break;
 		}
-		sync_fence_put(fences[i]);
+		mdss_put_sync_fence(fences[i]);
 	}
 
 	if (ret < 0) {
 		pr_err("%s: sync_fence_wait failed! ret = %x\n",
 				sync_pt_data->fence_name, ret);
 		for (; i < fence_cnt; i++)
-			sync_fence_put(fences[i]);
+			mdss_put_sync_fence(fences[i]);
 	}
 	return ret;
 }
 
 int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data)
 {
-	struct sync_fence *fences[MDP_MAX_FENCE_FD];
+	struct mdss_fence *fences[MDP_MAX_FENCE_FD];
 	int fence_cnt = 0;
 
 	__mdss_fb_copy_fence(sync_pt_data, fences, &fence_cnt);
@@ -2977,7 +2981,8 @@
 	mutex_lock(&sync_pt_data->sync_mutex);
 	if (atomic_add_unless(&sync_pt_data->commit_cnt, -1, 0) &&
 			sync_pt_data->timeline) {
-		sw_sync_timeline_inc(sync_pt_data->timeline, 1);
+		mdss_inc_timeline(sync_pt_data->timeline, 1);
+		mdss_inc_timeline(sync_pt_data->timeline_retire, 1);
 		MDSS_XLOG(sync_pt_data->timeline_value);
 		sync_pt_data->timeline_value++;
 
@@ -3009,7 +3014,7 @@
 	if (sync_pt_data->timeline) {
 		val = sync_pt_data->threshold +
 			atomic_read(&sync_pt_data->commit_cnt);
-		sw_sync_timeline_inc(sync_pt_data->timeline, val);
+		mdss_inc_timeline(sync_pt_data->timeline, val);
 		sync_pt_data->timeline_value += val;
 		atomic_set(&sync_pt_data->commit_cnt, 0);
 	}
@@ -3182,7 +3187,7 @@
 	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
 		return -EINVAL;
 
-	ret = mdss_fb_pan_idle(mfd);
+	ret = mdss_fb_wait_for_kickoff(mfd);
 	if (ret) {
 		pr_err("wait_for_kick failed. rc=%d\n", ret);
 		return ret;
@@ -3513,7 +3518,7 @@
 
 	if (var->grayscale > 1) {
 		format = mdss_grayscale_to_mdp_format(var->grayscale);
-		if (!IS_ERR_VALUE(format))
+		if (!IS_ERR_VALUE((unsigned long)format))
 			pinfo->out_format = format;
 		else
 			pr_warn("Failed to map grayscale value (%d) to an MDP format\n",
@@ -3593,7 +3598,7 @@
 {
 	struct msm_sync_pt_data *sync_pt_data = &mfd->mdp_sync_pt_data;
 	struct msm_fb_backup_type *fb_backup = &mfd->msm_fb_backup;
-	int ret = -ENOTSUP;
+	int ret = -ENOTSUPP;
 	u32 new_dsi_mode, dynamic_dsi_switch = 0;
 
 	if (!sync_pt_data->async_wait_fences)
@@ -3648,7 +3653,7 @@
 	if (!ret)
 		mdss_fb_update_backlight(mfd);
 
-	if (IS_ERR_VALUE(ret) || !sync_pt_data->flushed) {
+	if (IS_ERR_VALUE((unsigned long)ret) || !sync_pt_data->flushed) {
 		mdss_fb_release_kickoff(mfd);
 		mdss_fb_signal_timeline(sync_pt_data);
 		if ((mfd->panel.type == MIPI_CMD_PANEL) &&
@@ -3823,7 +3828,7 @@
 		mdss_fb_var_to_panelinfo(var, panel_info);
 		rc = mdss_fb_send_panel_event(mfd, MDSS_EVENT_CHECK_PARAMS,
 			panel_info);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			kfree(panel_info);
 			return rc;
 		}
@@ -3984,7 +3989,7 @@
 				mfd->fbi->var.yres) * mfd->fb_page;
 
 	old_format = mdss_grayscale_to_mdp_format(var->grayscale);
-	if (!IS_ERR_VALUE(old_format)) {
+	if (!IS_ERR_VALUE((unsigned long)old_format)) {
 		if (old_format != mfd->panel_info->out_format)
 			mfd->panel_reconfig = true;
 	}
@@ -4186,24 +4191,16 @@
  * Function returns a fence on the timeline given with the name provided.
  * The fence created will be signaled when the timeline is advanced.
  */
-struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
+struct mdss_fence *mdss_fb_sync_get_fence(struct mdss_timeline *timeline,
 		const char *fence_name, int val)
 {
-	struct sync_pt *sync_pt;
-	struct sync_fence *fence;
+	struct mdss_fence *fence;
 
-	pr_debug("%s: buf sync fence timeline=%d\n", fence_name, val);
 
-	sync_pt = sw_sync_pt_create(timeline, val);
-	if (sync_pt == NULL) {
-		pr_err("%s: cannot create sync point\n", fence_name);
-		return NULL;
-	}
-
-	/* create fence */
-	fence = sync_fence_create(fence_name, sync_pt);
+	fence = mdss_get_sync_fence(timeline, fence_name, NULL, val);
+	pr_debug("%s: buf sync fence timeline=%d\n",
+		 mdss_get_sync_fence_name(fence), val);
 	if (fence == NULL) {
-		sync_pt_free(sync_pt);
 		pr_err("%s: cannot create fence\n", fence_name);
 		return NULL;
 	}
@@ -4216,7 +4213,7 @@
 {
 	int i, ret = 0;
 	int acq_fen_fd[MDP_MAX_FENCE_FD];
-	struct sync_fence *fence, *rel_fence, *retire_fence;
+	struct mdss_fence *fence, *rel_fence, *retire_fence;
 	int rel_fen_fd;
 	int retire_fen_fd;
 	int val;
@@ -4240,7 +4237,7 @@
 
 	mutex_lock(&sync_pt_data->sync_mutex);
 	for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) {
-		fence = sync_fence_fdget(acq_fen_fd[i]);
+		fence = mdss_get_fd_sync_fence(acq_fen_fd[i]);
 		if (fence == NULL) {
 			pr_err("%s: null fence! i=%d fd=%d\n",
 					sync_pt_data->fence_name, i,
@@ -4254,7 +4251,7 @@
 	if (ret)
 		goto buf_sync_err_1;
 
-	val = sync_pt_data->timeline_value + sync_pt_data->threshold +
+	val = sync_pt_data->threshold +
 			atomic_read(&sync_pt_data->commit_cnt);
 
 	MDSS_XLOG(sync_pt_data->timeline_value, val,
@@ -4273,7 +4270,7 @@
 	}
 
 	/* create fd */
-	rel_fen_fd = get_unused_fd_flags(0);
+	rel_fen_fd = mdss_get_sync_fence_fd(rel_fence);
 	if (rel_fen_fd < 0) {
 		pr_err("%s: get_unused_fd_flags failed error:0x%x\n",
 				sync_pt_data->fence_name, rel_fen_fd);
@@ -4307,13 +4304,13 @@
 		ret = retire_fence ? PTR_ERR(rel_fence) : -ENOMEM;
 		goto buf_sync_err_3;
 	}
-	retire_fen_fd = get_unused_fd_flags(0);
+	retire_fen_fd = mdss_get_sync_fence_fd(retire_fence);
 
 	if (retire_fen_fd < 0) {
 		pr_err("%s: get_unused_fd_flags failed for retire fence error:0x%x\n",
 				sync_pt_data->fence_name, retire_fen_fd);
 		ret = retire_fen_fd;
-		sync_fence_put(retire_fence);
+		mdss_put_sync_fence(retire_fence);
 		goto buf_sync_err_3;
 	}
 
@@ -4323,14 +4320,12 @@
 		pr_err("%s: copy_to_user failed for retire fence\n",
 				sync_pt_data->fence_name);
 		put_unused_fd(retire_fen_fd);
-		sync_fence_put(retire_fence);
+		mdss_put_sync_fence(retire_fence);
 		goto buf_sync_err_3;
 	}
 
-	sync_fence_install(retire_fence, retire_fen_fd);
-
 skip_retire_fence:
-	sync_fence_install(rel_fence, rel_fen_fd);
+	mdss_get_sync_fence_fd(rel_fence);
 	mutex_unlock(&sync_pt_data->sync_mutex);
 
 	if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
@@ -4340,10 +4335,10 @@
 buf_sync_err_3:
 	put_unused_fd(rel_fen_fd);
 buf_sync_err_2:
-	sync_fence_put(rel_fence);
+	mdss_put_sync_fence(rel_fence);
 buf_sync_err_1:
 	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
-		sync_fence_put(sync_pt_data->acq_fen[i]);
+		mdss_put_sync_fence(sync_pt_data->acq_fen[i]);
 	sync_pt_data->acq_fen_cnt = 0;
 	mutex_unlock(&sync_pt_data->sync_mutex);
 	return ret;
@@ -4796,7 +4791,7 @@
 {
 	struct msm_fb_data_type *mfd;
 	void __user *argp = (void __user *)arg;
-	int ret = -ENOTSUP;
+	int ret = -ENOTSUPP;
 	struct mdp_buf_sync buf_sync;
 	unsigned int dsi_mode = 0;
 	struct mdss_panel_data *pdata = NULL;
@@ -4884,7 +4879,7 @@
 		break;
 	}
 
-	if (ret == -ENOTSUP)
+	if (ret == -ENOTSUPP)
 		pr_err("unsupported ioctl (%x)\n", cmd);
 
 exit:
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index f8ef48a..19e6299 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -171,11 +171,12 @@
 struct msm_sync_pt_data {
 	char *fence_name;
 	u32 acq_fen_cnt;
-	struct sync_fence *acq_fen[MDP_MAX_FENCE_FD];
+	struct mdss_fence *acq_fen[MDP_MAX_FENCE_FD];
 	u32 temp_fen_cnt;
-	struct sync_fence *temp_fen[MDP_MAX_FENCE_FD];
+	struct mdss_fence *temp_fen[MDP_MAX_FENCE_FD];
 
-	struct sw_sync_timeline *timeline;
+	struct mdss_timeline *timeline;
+	struct mdss_timeline *timeline_retire;
 	int timeline_value;
 	u32 threshold;
 	u32 retire_threshold;
@@ -186,7 +187,7 @@
 	struct mutex sync_mutex;
 	struct notifier_block notifier;
 
-	struct sync_fence *(*get_retire_fence)
+	struct mdss_fence *(*get_retire_fence)
 		(struct msm_sync_pt_data *sync_pt_data);
 };
 
@@ -452,7 +453,7 @@
 void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
 int mdss_fb_wait_for_fence(struct msm_sync_pt_data *sync_pt_data);
 void mdss_fb_signal_timeline(struct msm_sync_pt_data *sync_pt_data);
-struct sync_fence *mdss_fb_sync_get_fence(struct sw_sync_timeline *timeline,
+struct mdss_fence *mdss_fb_sync_get_fence(struct mdss_timeline *timeline,
 				const char *fence_name, int val);
 int mdss_fb_register_mdp_instance(struct msm_mdp_interface *mdp);
 int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_audio.c b/drivers/video/fbdev/msm/mdss_hdmi_audio.c
index e4dc530..446e8b4 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_audio.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_audio.c
@@ -19,7 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/iopoll.h>
 #include <linux/types.h>
-#include <linux/switch.h>
+#include <linux/extcon.h>
 #include <linux/gcd.h>
 
 #include "mdss_hdmi_audio.h"
@@ -63,9 +63,9 @@
 };
 
 struct hdmi_audio {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct msm_hdmi_audio_setup_params params;
-	struct switch_dev sdev;
+	struct extcon_dev sdev;
 	u32 pclk;
 	bool ack_enabled;
 	bool audio_ack_enabled;
@@ -143,7 +143,7 @@
 
 static void hdmi_audio_acr_enable(struct hdmi_audio *audio)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_audio_acr acr;
 	struct msm_hdmi_audio_setup_params *params;
 	u32 pclk, layout, multiplier = 1, sample_rate;
@@ -260,7 +260,7 @@
 
 static void hdmi_audio_infoframe_setup(struct hdmi_audio *audio, bool enabled)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	u32 channels, channel_allocation, level_shift, down_mix, layout;
 	u32 hdmi_debug_reg = 0, audio_info_0_reg = 0, audio_info_1_reg = 0;
 	u32 audio_info_ctrl_reg, aud_pck_ctrl_2_reg;
@@ -393,7 +393,7 @@
 		return;
 	}
 
-	switch_set_state(&audio->sdev, val);
+	extcon_set_state_sync(&audio->sdev, 0, val);
 	switched = audio->sdev.state != state;
 
 	if (audio->ack_enabled && switched)
@@ -490,7 +490,7 @@
 		goto end;
 
 	audio->sdev.name = "hdmi_audio";
-	rc = switch_dev_register(&audio->sdev);
+	rc = extcon_dev_register(&audio->sdev);
 	if (rc) {
 		pr_err("audio switch registration failed\n");
 		kzfree(audio);
@@ -520,7 +520,7 @@
 	struct hdmi_audio *audio = ctx;
 
 	if (audio) {
-		switch_dev_unregister(&audio->sdev);
+		extcon_dev_unregister(&audio->sdev);
 		kfree(ctx);
 	}
 }
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_audio.h b/drivers/video/fbdev/msm/mdss_hdmi_audio.h
index 7b33cb8..2449123 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_audio.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_audio.h
@@ -62,7 +62,7 @@
  * Defines the data needed to be provided while initializing audio module
  */
 struct hdmi_audio_init_data {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_audio_ops *ops;
 };
 
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_cec.c b/drivers/video/fbdev/msm/mdss_hdmi_cec.c
index f1be313..f15272e 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_cec.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_cec.c
@@ -52,7 +52,7 @@
 	u32 frame_retransmit = RETRANSMIT_MAX_NUM;
 	bool frame_type;
 	unsigned long flags;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)data;
 
 	if (!cec_ctrl || !cec_ctrl->init_data.io || !msg) {
@@ -169,7 +169,7 @@
 	int i;
 	u32 data;
 	struct hdmi_cec_ctrl *cec_ctrl = NULL;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct cec_msg msg;
 	struct cec_cbs *cbs;
 
@@ -262,7 +262,7 @@
 	int rc = 0;
 	u32 cec_intr, cec_status;
 	unsigned long flags;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
 
 	if (!cec_ctrl || !cec_ctrl->init_data.io) {
@@ -368,7 +368,7 @@
 {
 	int ret = 0;
 	u32 hdmi_hw_version, reg_val;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_cec_ctrl *cec_ctrl = (struct hdmi_cec_ctrl *)input;
 	struct mdss_panel_info *pinfo;
 
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_cec.h b/drivers/video/fbdev/msm/mdss_hdmi_cec.h
index 57a7664..de4bb35 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_cec.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_cec.h
@@ -30,7 +30,7 @@
  */
 struct hdmi_cec_init_data {
 	struct workqueue_struct *workq;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct mdss_panel_info *pinfo;
 	struct cec_cbs *cbs;
 	struct cec_ops *ops;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index d6e37a1..ab8491d 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -738,7 +738,7 @@
 	}
 
 	rc = sscanf(buf,
-		"%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+		"%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %u",
 		(unsigned long *) &timing.active_h,
 		(unsigned long *) &timing.front_porch_h,
 		(unsigned long *) &timing.pulse_width_h,
@@ -753,7 +753,7 @@
 		(unsigned long *) &timing.refresh_rate,
 		(unsigned long *) &timing.interlaced,
 		(unsigned long *) &timing.supported,
-		(unsigned long *) &timing.ar);
+		(unsigned int *) &timing.ar);
 
 	if (rc != 15) {
 		DEV_ERR("%s: error reading buf\n", __func__);
@@ -762,7 +762,7 @@
 
 	rc = hdmi_set_resv_timing_info(&timing);
 
-	if (!IS_ERR_VALUE(rc)) {
+	if (!IS_ERR_VALUE((unsigned long)rc)) {
 		DEV_DBG("%s: added new res %d\n", __func__, rc);
 	} else {
 		DEV_ERR("%s: error adding new res %d\n", __func__, rc);
@@ -1499,7 +1499,7 @@
 		rc = -EINVAL;
 	}
 
-	if (!IS_ERR_VALUE(rc)) {
+	if (!IS_ERR_VALUE((unsigned long)rc)) {
 		*disp_mode = rc;
 		DEV_DBG("%s: DTD mode found: %d\n", __func__, *disp_mode);
 	} else {
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
index bbdf485..41c6844 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c
@@ -87,7 +87,7 @@
 	int hdcp_ddc_status;
 	int failure;
 	int nack0;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -166,7 +166,7 @@
 
 static void hdmi_hdcp_hw_ddc_clean(struct hdmi_hdcp_ctrl *hdcp_ctrl)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	u32 hdcp_ddc_status, ddc_hw_status;
 	u32 ddc_xfer_done, ddc_xfer_req;
 	u32 ddc_hw_req, ddc_hw_not_idle;
@@ -254,8 +254,8 @@
 	u32 ksv_lsb_addr, ksv_msb_addr;
 	u32 aksv_lsb, aksv_msb;
 	u8 aksv[5];
-	struct dss_io_data *io;
-	struct dss_io_data *qfprom_io;
+	struct mdss_io_data *io;
+	struct mdss_io_data *qfprom_io;
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = input;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
@@ -352,8 +352,8 @@
 	u32 link0_an_0, link0_an_1;
 	u32 timeout_count;
 	bool is_match;
-	struct dss_io_data *io;
-	struct dss_io_data *hdcp_io;
+	struct mdss_io_data *io;
+	struct mdss_io_data *hdcp_io;
 	u8 aksv[5], *bksv = NULL;
 	u8 an[8];
 	u8 bcaps = 0;
@@ -676,30 +676,34 @@
 	return rc;
 } /* hdmi_hdcp_authentication_part1 */
 
-static  int read_write_v_h(dss_io_data *io, int off. char *name, u32 reg,
-				    bool wr)
+static int read_write_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl,
+			  struct hdmi_tx_ddc_data ddc_data,
+			  struct mdss_io_data *io, int off, char *name,
+			  u32 reg, bool wr)
 {
-	char what[20];
 	int rc = 0;
 
 	do {
 		ddc_data.offset = off;
-		memset(what, 0, sizeof(what));
-		snprintf(what, 20, name);
+		memset(ddc_data.what, 0, 20);
+		snprintf(ddc_data.what, 20, name);
 		hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
 		rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
 		if (rc) {
 			DEV_ERR("%s: %s: Read %s failed\n", __func__,
-				HDCP_STATE_NAME, what);
+				HDCP_STATE_NAME, ddc_data.what);
 			return rc;
 		}
 		DEV_DBG("%s: %s: %s: buf[0]=%x, [1]=%x,[2]=%x, [3]=%x\n",
-			__func__, HDCP_STATE_NAME, what, buf[0], buf[1],
-			buf[2], buf[3]);
+			__func__, HDCP_STATE_NAME, ddc_data.what,
+			ddc_data.data_buf[0], ddc_data.data_buf[1],
+			ddc_data.data_buf[2], ddc_data.data_buf[3]);
 		if (wr) {
 			DSS_REG_W((io), (reg),
-					(buf[3] << 24 | buf[2] << 16 |
-					buf[1] << 8 | buf[0]));
+					(ddc_data.data_buf[3] << 24 |
+					 ddc_data.data_buf[2] << 16 |
+					 ddc_data.data_buf[1] << 8 |
+					 ddc_data.data_buf[0]));
 		}
 	} while (0);
 	return rc;
@@ -711,7 +715,7 @@
 	int rc = 0;
 	u8 buf[4];
 	struct hdmi_tx_ddc_data ddc_data;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
 	u32 phy_addr;
@@ -728,14 +732,6 @@
 	u32 ret  = 0;
 	u32 resp = 0;
 
-	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
-		DEV_ERR("%s: invalid input\n", __func__);
-		return -EINVAL;
-	}
-
-	phy_addr = hdcp_ctrl->init_data.phy_addr;
-
-	io = hdcp_ctrl->init_data.core_io;
 	memset(&ddc_data, 0, sizeof(ddc_data));
 	ddc_data.dev_addr = 0x74;
 	ddc_data.data_buf = buf;
@@ -744,13 +740,23 @@
 	ddc_data.retry = 5;
 	ddc_data.what = what;
 
+	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+		DEV_ERR("%s: invalid input\n", __func__);
+		return -EINVAL;
+	}
+
+	phy_addr = hdcp_ctrl->init_data.phy_addr;
+
+	io = hdcp_ctrl->init_data.core_io;
+
 	if (hdcp_ctrl->tz_hdcp) {
 		memset(scm_buf, 0x00, sizeof(scm_buf));
 
 		for (iter = 0; iter < size && iter < SCM_HDCP_MAX_REG; iter++) {
 			struct hdmi_hdcp_reg_data *rd = reg_data + iter;
 
-			if (read_write_v_h(io, rd->off, rd->name, 0, false))
+			if (read_write_v_h(hdcp_ctrl, ddc_data, io, rd->off,
+					   rd->name, 0, false))
 				goto error;
 
 			rd->reg_val = buf[3] << 24 | buf[2] << 16 |
@@ -768,56 +774,56 @@
 			goto error;
 		}
 	} else if (hdcp_ctrl->hdmi_tx_ver_4) {
-		struct dss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io;
+		struct mdss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io;
 
 		/* Read V'.HO 4 Byte at offset 0x20 */
-		if (read_write_v_h(hdcp_io, 0x20, "V' H0",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x20, "V' H0",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, true))
 			goto error;
 
 		/* Read V'.H1 4 Byte at offset 0x24 */
-		if (read_write_v_h(hdcp_io, 0x24, "V' H1",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x24, "V' H1",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, true))
 			goto error;
 
 		/* Read V'.H2 4 Byte at offset 0x28 */
-		if (read_write_v_h(hdcp_io, 0x28, "V' H2",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x28, "V' H2",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, true))
 			goto error;
 
 		/* Read V'.H3 4 Byte at offset 0x2C */
-		if (read_write_v_h(hdcp_io, 0x2C, "V' H3",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x2C, "V' H3",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, true))
 			goto error;
 
 		/* Read V'.H4 4 Byte at offset 0x30 */
-		if (read_write_v_h(hdcp_io, 0x30, "V' H4",
+		if (read_write_v_h(hdcp_ctrl, ddc_data, hdcp_io, 0x30, "V' H4",
 				HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, true))
 			goto error;
 	} else {
 		/* Read V'.HO 4 Byte at offset 0x20 */
-		if (read_write_v_h(io, 0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x20, "V' H0",
+				   HDMI_HDCP_RCVPORT_DATA7, true))
 			goto error;
 
 		/* Read V'.H1 4 Byte at offset 0x24 */
-		if (read_write_v_h(io, 0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x24, "V' H1",
+				   HDMI_HDCP_RCVPORT_DATA8, true))
 			goto error;
 
 		/* Read V'.H2 4 Byte at offset 0x28 */
-		if (read_write_v_h(io, 0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x28, "V' H2",
+				   HDMI_HDCP_RCVPORT_DATA9, true))
 			goto error;
 
 		/* Read V'.H3 4 Byte at offset 0x2C */
-		if (read_write_v_h(io, 0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x2C, "V' H3",
+				   HDMI_HDCP_RCVPORT_DATA10, true))
 			goto error;
 
 		/* Read V'.H4 4 Byte at offset 0x30 */
-		if (read_write_v_h(io, 0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11,
-				true))
+		if (read_write_v_h(hdcp_ctrl, ddc_data, io, 0x30, "V' H4",
+				   HDMI_HDCP_RCVPORT_DATA11, true))
 			goto error;
 	}
 
@@ -837,7 +843,7 @@
 	u16 bstatus, max_devs_exceeded = 0, max_cascade_exceeded = 0;
 	u32 link0_status;
 	u32 ksv_bytes;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
 	u32 phy_addr;
@@ -1241,7 +1247,7 @@
 	struct delayed_work *dw = to_delayed_work(work);
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(dw,
 		struct hdmi_hdcp_ctrl, hdcp_auth_work);
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	if (!hdcp_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -1347,7 +1353,7 @@
 int hdmi_hdcp_reauthenticate(void *input)
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	u32 hdmi_hw_version;
 	u32 ret = 0;
 
@@ -1394,7 +1400,7 @@
 void hdmi_hdcp_off(void *input)
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	int rc = 0;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
@@ -1447,7 +1453,7 @@
 {
 	struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
 	int rc = 0;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	u32 hdcp_int_val;
 
 	if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
index 2098943..2276009 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h
@@ -28,9 +28,9 @@
 };
 
 struct hdmi_hdcp_init_data {
-	struct dss_io_data *core_io;
-	struct dss_io_data *qfprom_io;
-	struct dss_io_data *hdcp_io;
+	struct mdss_io_data *core_io;
+	struct mdss_io_data *qfprom_io;
+	struct mdss_io_data *hdcp_io;
 	struct mutex *mutex;
 	struct kobject *sysfs_kobj;
 	struct workqueue_struct *workq;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
index fc0c878..8dce151 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
@@ -64,7 +64,7 @@
 	void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */
 	struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */
 
-	enum hdmi_hdcp_wakeup_cmd wakeup_cmd;
+	enum hdcp_wakeup_cmd wakeup_cmd;
 	enum hdmi_auth_status auth_status;
 	char *send_msg_buf;
 	uint32_t send_msg_len;
@@ -89,7 +89,7 @@
 
 static inline bool hdmi_hdcp2p2_is_valid_state(struct hdmi_hdcp2p2_ctrl *ctrl)
 {
-	if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE)
+	if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_AUTHENTICATE)
 		return true;
 
 	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
@@ -99,7 +99,7 @@
 }
 
 static int hdmi_hdcp2p2_copy_buf(struct hdmi_hdcp2p2_ctrl *ctrl,
-	struct hdmi_hdcp_wakeup_data *data)
+	struct hdcp_wakeup_data *data)
 {
 	mutex_lock(&ctrl->msg_lock);
 
@@ -126,7 +126,7 @@
 	return 0;
 }
 
-static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
+static int hdmi_hdcp2p2_wakeup(struct hdcp_wakeup_data *data)
 {
 	struct hdmi_hdcp2p2_ctrl *ctrl;
 
@@ -144,7 +144,7 @@
 	mutex_lock(&ctrl->wakeup_mutex);
 
 	pr_debug("cmd: %s, timeout %dms, tethered %d\n",
-		hdmi_hdcp_cmd_to_str(data->cmd),
+		hdcp_cmd_to_str(data->cmd),
 		data->timeout, ctrl->tethered);
 
 	ctrl->wakeup_cmd = data->cmd;
@@ -162,30 +162,30 @@
 	if (hdmi_hdcp2p2_copy_buf(ctrl, data))
 		goto exit;
 
-	if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS)
+	if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_SUCCESS)
 		ctrl->auth_status = HDMI_HDCP_AUTH_STATUS_SUCCESS;
-	else if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_STATUS_FAILED)
+	else if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_FAILED)
 		ctrl->auth_status = HDMI_HDCP_AUTH_STATUS_FAILURE;
 
 	if (ctrl->tethered)
 		goto exit;
 
 	switch (ctrl->wakeup_cmd) {
-	case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
-		queue_kthread_work(&ctrl->worker, &ctrl->send_msg);
+	case HDCP_WKUP_CMD_SEND_MESSAGE:
+		kthread_queue_work(&ctrl->worker, &ctrl->send_msg);
 		break;
-	case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
-		queue_kthread_work(&ctrl->worker, &ctrl->recv_msg);
+	case HDCP_WKUP_CMD_RECV_MESSAGE:
+		kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
 		break;
-	case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
-	case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
-		queue_kthread_work(&ctrl->worker, &ctrl->status);
+	case HDCP_WKUP_CMD_STATUS_SUCCESS:
+	case HDCP_WKUP_CMD_STATUS_FAILED:
+		kthread_queue_work(&ctrl->worker, &ctrl->status);
 		break;
-	case HDMI_HDCP_WKUP_CMD_LINK_POLL:
-		queue_kthread_work(&ctrl->worker, &ctrl->poll);
+	case HDCP_WKUP_CMD_LINK_POLL:
+		kthread_queue_work(&ctrl->worker, &ctrl->poll);
 		break;
-	case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
-		queue_kthread_work(&ctrl->worker, &ctrl->auth);
+	case HDCP_WKUP_CMD_AUTHENTICATE:
+		kthread_queue_work(&ctrl->worker, &ctrl->auth);
 		break;
 	default:
 		pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd);
@@ -220,19 +220,19 @@
 
 	while (1) {
 		switch (ctrl->wakeup_cmd) {
-		case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
-			ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
+		case HDCP_WKUP_CMD_SEND_MESSAGE:
+			ctrl->wakeup_cmd = HDCP_WKUP_CMD_INVALID;
 			hdmi_hdcp2p2_send_msg(ctrl);
 			break;
-		case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
-			ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
+		case HDCP_WKUP_CMD_RECV_MESSAGE:
+			ctrl->wakeup_cmd = HDCP_WKUP_CMD_INVALID;
 			hdmi_hdcp2p2_recv_msg(ctrl);
 			break;
-		case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
-		case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
+		case HDCP_WKUP_CMD_STATUS_SUCCESS:
+		case HDCP_WKUP_CMD_STATUS_FAILED:
 			hdmi_hdcp2p2_auth_status(ctrl);
 			goto exit;
-		case HDMI_HDCP_WKUP_CMD_LINK_POLL:
+		case HDCP_WKUP_CMD_LINK_POLL:
 			hdmi_hdcp2p2_link_check(ctrl);
 			goto exit;
 		default:
@@ -240,7 +240,7 @@
 		}
 	}
 exit:
-	ctrl->wakeup_cmd = HDMI_HDCP_WKUP_CMD_INVALID;
+	ctrl->wakeup_cmd = HDCP_WKUP_CMD_INVALID;
 }
 
 int hdmi_hdcp2p2_authenticate_tethered(struct hdmi_hdcp2p2_ctrl *ctrl)
@@ -278,7 +278,7 @@
 static void hdmi_hdcp2p2_off(void *input)
 {
 	struct hdmi_hdcp2p2_ctrl *ctrl = (struct hdmi_hdcp2p2_ctrl *)input;
-	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};
+	struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
 
 	if (!ctrl) {
 		pr_err("invalid input\n");
@@ -287,7 +287,7 @@
 
 	hdmi_hdcp2p2_reset(ctrl);
 
-	flush_kthread_worker(&ctrl->worker);
+	kthread_flush_worker(&ctrl->worker);
 
 	hdmi_hdcp2p2_ddc_disable(ctrl->init_data.ddc_ctrl);
 
@@ -302,7 +302,7 @@
 static int hdmi_hdcp2p2_authenticate(void *input)
 {
 	struct hdmi_hdcp2p2_ctrl *ctrl = input;
-	struct hdmi_hdcp_wakeup_data cdata = {HDMI_HDCP_WKUP_CMD_AUTHENTICATE};
+	struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE};
 	u32 regval;
 	int rc = 0;
 
@@ -312,7 +312,7 @@
 
 	DSS_REG_W(ctrl->init_data.core_io, HDMI_HDCP_INT_CTRL2, regval);
 
-	flush_kthread_worker(&ctrl->worker);
+	kthread_flush_worker(&ctrl->worker);
 
 	ctrl->sink_status = SINK_CONNECTED;
 	atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);
@@ -385,8 +385,8 @@
 
 	ctrl->tethered = !!tethered;
 
-	if (ctrl->lib && ctrl->lib->update_exec_type && ctrl->lib_ctx)
-		ctrl->lib->update_exec_type(ctrl->lib_ctx, ctrl->tethered);
+	//if (ctrl->lib && ctrl->lib->update_exec_type && ctrl->lib_ctx)
+	//	ctrl->lib->update_exec_type(ctrl->lib_ctx, ctrl->tethered);
 exit:
 	mutex_unlock(&ctrl->mutex);
 
@@ -661,7 +661,7 @@
 	}
 
 	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
-		queue_kthread_work(&ctrl->worker, &ctrl->link);
+		kthread_queue_work(&ctrl->worker, &ctrl->link);
 }
 
 static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl)
@@ -1042,7 +1042,7 @@
 	register_data.client_ops = &client_ops;
 	register_data.txmtr_ops = &txmtr_ops;
 	register_data.client_ctx = ctrl;
-	register_data.tethered = ctrl->tethered;
+	//register_data.tethered = ctrl->tethered;
 
 	rc = hdcp_library_register(&register_data);
 	if (rc) {
@@ -1050,14 +1050,14 @@
 		goto error;
 	}
 
-	init_kthread_worker(&ctrl->worker);
+	kthread_init_worker(&ctrl->worker);
 
-	init_kthread_work(&ctrl->auth,     hdmi_hdcp2p2_auth_work);
-	init_kthread_work(&ctrl->send_msg, hdmi_hdcp2p2_send_msg_work);
-	init_kthread_work(&ctrl->recv_msg, hdmi_hdcp2p2_recv_msg_work);
-	init_kthread_work(&ctrl->status,   hdmi_hdcp2p2_auth_status_work);
-	init_kthread_work(&ctrl->link,     hdmi_hdcp2p2_link_work);
-	init_kthread_work(&ctrl->poll,     hdmi_hdcp2p2_poll_work);
+	kthread_init_work(&ctrl->auth,     hdmi_hdcp2p2_auth_work);
+	kthread_init_work(&ctrl->send_msg, hdmi_hdcp2p2_send_msg_work);
+	kthread_init_work(&ctrl->recv_msg, hdmi_hdcp2p2_recv_msg_work);
+	kthread_init_work(&ctrl->status,   hdmi_hdcp2p2_auth_status_work);
+	kthread_init_work(&ctrl->link,     hdmi_hdcp2p2_link_work);
+	kthread_init_work(&ctrl->poll,     hdmi_hdcp2p2_poll_work);
 
 	ctrl->thread = kthread_run(kthread_worker_fn,
 		&ctrl->worker, "hdmi_hdcp2p2");
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
index 9e082b3a..3823d3b 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
@@ -108,7 +108,7 @@
 };
 
 struct hdmi_panel {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_util_ds_data *ds_data;
 	struct hdmi_panel_data *data;
 	struct hdmi_video_config vid_cfg;
@@ -275,7 +275,7 @@
 	u32 total_h, start_h, end_h;
 	u32 total_v, start_v, end_v;
 	u32 div = 0;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 	struct msm_hdmi_mode_timing_info *timing;
 
 	timing = panel->vid_cfg.timing;
@@ -342,7 +342,7 @@
 	u8  avi_iframe[AVI_MAX_DATA_BYTES] = {0};
 	u8 checksum;
 	u32 sum, reg_val;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 	struct hdmi_avi_infoframe_config *avi;
 	struct msm_hdmi_mode_timing_info *timing;
 
@@ -477,7 +477,7 @@
 	u32 sum, reg_val;
 	u32 hdmi_vic, hdmi_video_format, s3d_struct = 0;
 	struct hdmi_panel *panel = input;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 
 	/* HDMI Spec 1.4a Table 8-10 */
 	vs_iframe[0] = 0x81; /* type */
@@ -564,7 +564,7 @@
 	u32 packet_control = 0;
 	u8 *vendor_name = NULL;
 	u8 *product_description = NULL;
-	struct dss_io_data *io = panel->io;
+	struct mdss_io_data *io = panel->io;
 
 	vendor_name = panel->spd_vendor_name;
 	product_description = panel->spd_product_description;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.h b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
index 4685b4e..50e168a 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
@@ -73,7 +73,7 @@
  * @version:  hardware version of the hdmi tx
  */
 struct hdmi_panel_init_data {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct hdmi_util_ds_data *ds_data;
 	struct hdmi_panel_data *panel_data;
 	struct hdmi_tx_ddc_ctrl *ddc;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 12aba84..4f2bb09 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -117,23 +117,23 @@
 	.irq_handler = hdmi_tx_isr,
 };
 
-static struct dss_gpio hpd_gpio_config[] = {
+static struct mdss_gpio hpd_gpio_config[] = {
 	{0, 1, COMPATIBLE_NAME "-hpd"},
 	{0, 1, COMPATIBLE_NAME "-mux-en"},
 	{0, 0, COMPATIBLE_NAME "-mux-sel"},
 	{0, 1, COMPATIBLE_NAME "-mux-lpm"}
 };
 
-static struct dss_gpio ddc_gpio_config[] = {
+static struct mdss_gpio ddc_gpio_config[] = {
 	{0, 1, COMPATIBLE_NAME "-ddc-mux-sel"},
 	{0, 1, COMPATIBLE_NAME "-ddc-clk"},
 	{0, 1, COMPATIBLE_NAME "-ddc-data"}
 };
 
-static struct dss_gpio core_gpio_config[] = {
+static struct mdss_gpio core_gpio_config[] = {
 };
 
-static struct dss_gpio cec_gpio_config[] = {
+static struct mdss_gpio cec_gpio_config[] = {
 	{0, 1, COMPATIBLE_NAME "-cec"}
 };
 
@@ -152,7 +152,7 @@
 {
 	int rc;
 	int reg_val;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 
 	rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, true);
 	if (rc) {
@@ -369,7 +369,7 @@
 	}
 	state = hdmi_ctrl->sdev.state;
 
-	switch_set_state(&hdmi_ctrl->sdev, val);
+	extcon_set_state_sync(&hdmi_ctrl->sdev, EXTCON_DISP_HDMI, state);
 
 	DEV_INFO("%s: cable state %s %d\n", __func__,
 		hdmi_ctrl->sdev.state == state ?
@@ -392,7 +392,7 @@
 {
 	u64 status = 0;
 	u32 wait_for_vote = 50;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -483,7 +483,7 @@
 
 static int hdmi_tx_config_5v(struct hdmi_tx_ctrl *hdmi_ctrl, bool enable)
 {
-	struct dss_module_power *pd = NULL;
+	struct mdss_module_power *pd = NULL;
 	int ret = 0;
 
 	if (!hdmi_ctrl) {
@@ -644,7 +644,7 @@
 
 static int hdmi_tx_update_pixel_clk(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 	struct mdss_panel_info *pinfo;
 	int rc = 0;
 
@@ -675,7 +675,7 @@
 
 	DEV_DBG("%s: rate %ld\n", __func__, power_data->clk_config->rate);
 
-	msm_dss_clk_set_rate(power_data->clk_config, power_data->num_clk);
+	msm_mdss_clk_set_rate(power_data->clk_config, power_data->num_clk);
 end:
 	return rc;
 }
@@ -736,7 +736,7 @@
 {
 	int sim_mode, rc;
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
 
@@ -1222,7 +1222,7 @@
 {
 	int read, ret;
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct dss_module_power *pd = NULL;
+	struct mdss_module_power *pd = NULL;
 
 	hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
 	if (!hdmi_ctrl) {
@@ -1333,7 +1333,7 @@
 
 static int hdmi_tx_config_avmute(struct hdmi_tx_ctrl *hdmi_ctrl, bool set)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	u32 av_mute_status;
 	bool av_pkt_en = false;
 
@@ -1374,7 +1374,7 @@
 
 static bool hdmi_tx_is_encryption_set(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	bool enc_en = true;
 	u32 reg_val;
 
@@ -1960,7 +1960,7 @@
 
 static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+	struct mdss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
 
 	return DSS_REG_R_ND(io, HDMI_CTRL) & BIT(0);
 } /* hdmi_tx_is_controller_on */
@@ -2096,7 +2096,7 @@
 static void hdmi_tx_hpd_int_work(struct work_struct *work)
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	int rc = -EINVAL;
 	int retry = MAX_EDID_READ_RETRY;
 
@@ -2149,7 +2149,7 @@
 static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	u32 hdmi_disabled, hdcp_disabled, reg_val;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	int ret = 0;
 
 	if (!hdmi_ctrl) {
@@ -2208,7 +2208,7 @@
 
 static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	/* Defaults: Disable block, HDMI mode */
 	u32 reg_val = BIT(1);
 
@@ -2260,7 +2260,7 @@
 {
 	struct pinctrl_state *pin_state = NULL;
 	int rc = -EFAULT;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 	u64 cur_pin_states;
 
 	if (!hdmi_ctrl) {
@@ -2357,7 +2357,7 @@
 	enum hdmi_tx_power_module_type module, int config)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 	char name[MAX_CLIENT_NAME_LEN];
 
 	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
@@ -2374,7 +2374,7 @@
 	}
 
 	if (config) {
-		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+		rc = msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to config %s vreg. Err=%d\n",
@@ -2387,13 +2387,13 @@
 			mdss_reg_bus_vote_client_create(name);
 		if (IS_ERR(hdmi_ctrl->pdata.reg_bus_clt[module])) {
 			pr_err("reg bus client create failed\n");
-			msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+			msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 0);
 			rc = PTR_ERR(hdmi_ctrl->pdata.reg_bus_clt[module]);
 			goto exit;
 		}
 
-		rc = msm_dss_get_clk(&hdmi_ctrl->pdev->dev,
+		rc = msm_mdss_get_clk(&hdmi_ctrl->pdev->dev,
 			power_data->clk_config, power_data->num_clk);
 		if (rc) {
 			DEV_ERR("%s: Failed to get %s clk. Err=%d\n",
@@ -2402,16 +2402,16 @@
 			mdss_reg_bus_vote_client_destroy(
 				hdmi_ctrl->pdata.reg_bus_clt[module]);
 			hdmi_ctrl->pdata.reg_bus_clt[module] = NULL;
-			msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+			msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 0);
 		}
 	} else {
-		msm_dss_put_clk(power_data->clk_config, power_data->num_clk);
+		msm_mdss_put_clk(power_data->clk_config, power_data->num_clk);
 		mdss_reg_bus_vote_client_destroy(
 			hdmi_ctrl->pdata.reg_bus_clt[module]);
 		hdmi_ctrl->pdata.reg_bus_clt[module] = NULL;
 
-		rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+		rc = msm_mdss_config_vreg(&hdmi_ctrl->pdev->dev,
 			power_data->vreg_config, power_data->num_vreg, 0);
 		if (rc)
 			DEV_ERR("%s: Fail to deconfig %s vreg. Err=%d\n",
@@ -2427,7 +2427,7 @@
 {
 	int i;
 	int rc = 0;
-	struct dss_module_power *pd = NULL;
+	struct mdss_module_power *pd = NULL;
 
 	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
 		DEV_ERR("%s: Error: invalid input\n", __func__);
@@ -2473,7 +2473,7 @@
 	enum hdmi_tx_power_module_type module, int enable)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 
 	if (!hdmi_ctrl || module >= HDMI_TX_MAX_PM) {
 		DEV_ERR("%s: Error: invalid input\n", __func__);
@@ -2495,7 +2495,7 @@
 	}
 
 	if (enable && !hdmi_ctrl->power_data_enable[module]) {
-		rc = msm_dss_enable_vreg(power_data->vreg_config,
+		rc = msm_mdss_enable_vreg(power_data->vreg_config,
 			power_data->num_vreg, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable %s vreg. Error=%d\n",
@@ -2510,7 +2510,7 @@
 			goto error;
 		}
 
-		rc = msm_dss_enable_gpio(power_data->gpio_config,
+		rc = msm_mdss_enable_gpio(power_data->gpio_config,
 			power_data->num_gpio, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable %s gpio. Error=%d\n",
@@ -2520,7 +2520,7 @@
 		mdss_update_reg_bus_vote(hdmi_ctrl->pdata.reg_bus_clt[module],
 			VOTE_INDEX_LOW);
 
-		rc = msm_dss_clk_set_rate(power_data->clk_config,
+		rc = msm_mdss_clk_set_rate(power_data->clk_config,
 			power_data->num_clk);
 		if (rc) {
 			DEV_ERR("%s: failed to set clks rate for %s. err=%d\n",
@@ -2528,7 +2528,7 @@
 			goto disable_gpio;
 		}
 
-		rc = msm_dss_enable_clk(power_data->clk_config,
+		rc = msm_mdss_enable_clk(power_data->clk_config,
 			power_data->num_clk, 1);
 		if (rc) {
 			DEV_ERR("%s: Failed to enable clks for %s. Error=%d\n",
@@ -2539,14 +2539,14 @@
 	} else if (!enable && hdmi_ctrl->power_data_enable[module] &&
 		(!hdmi_tx_is_cec_wakeup_en(hdmi_ctrl) ||
 		((module != HDMI_TX_HPD_PM) && (module != HDMI_TX_CEC_PM)))) {
-		msm_dss_enable_clk(power_data->clk_config,
+		msm_mdss_enable_clk(power_data->clk_config,
 			power_data->num_clk, 0);
 		mdss_update_reg_bus_vote(hdmi_ctrl->pdata.reg_bus_clt[module],
 			VOTE_INDEX_DISABLE);
-		msm_dss_enable_gpio(power_data->gpio_config,
+		msm_mdss_enable_gpio(power_data->gpio_config,
 			power_data->num_gpio, 0);
 		hdmi_tx_pinctrl_set_state(hdmi_ctrl, module, 0);
-		msm_dss_enable_vreg(power_data->vreg_config,
+		msm_mdss_enable_vreg(power_data->vreg_config,
 			power_data->num_vreg, 0);
 		hdmi_ctrl->power_data_enable[module] = false;
 	}
@@ -2556,9 +2556,9 @@
 disable_gpio:
 	mdss_update_reg_bus_vote(hdmi_ctrl->pdata.reg_bus_clt[module],
 		VOTE_INDEX_DISABLE);
-	msm_dss_enable_gpio(power_data->gpio_config, power_data->num_gpio, 0);
+	msm_mdss_enable_gpio(power_data->gpio_config, power_data->num_gpio, 0);
 disable_vreg:
-	msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
+	msm_mdss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
 error:
 	return rc;
 } /* hdmi_tx_enable_power */
@@ -2607,7 +2607,7 @@
 	unsigned int phy_reset_polarity = 0x0;
 	unsigned int pll_reset_polarity = 0x0;
 	unsigned int val;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -2803,7 +2803,7 @@
 	return hpd;
 }
 
-int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+int msm_mdss_hdmi_register_audio_codec(struct platform_device *pdev,
 	struct msm_hdmi_audio_codec_ops *ops)
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
@@ -2819,7 +2819,7 @@
 
 	return 0;
 } /* hdmi_tx_audio_register */
-EXPORT_SYMBOL(msm_hdmi_register_audio_codec);
+EXPORT_SYMBOL(msm_mdss_hdmi_register_audio_codec);
 
 static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
@@ -2865,7 +2865,7 @@
 static void hdmi_tx_hpd_polarity_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
 	bool polarity)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	bool cable_sense;
 
 	if (!hdmi_ctrl) {
@@ -2913,7 +2913,7 @@
 
 static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	void *pdata =  NULL;
 
 	if (!hdmi_ctrl) {
@@ -3041,7 +3041,7 @@
 static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
 {
 	int rc = 0;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	unsigned long flags;
 
 	if (!hdmi_ctrl) {
@@ -3091,7 +3091,7 @@
 {
 	u32 reg_val;
 	int rc = 0;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!hdmi_ctrl) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -3114,7 +3114,7 @@
 			return rc;
 		}
 
-		dss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP);
+		mdss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP);
 
 		if (!hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) {
 			hdmi_tx_set_mode(hdmi_ctrl, false);
@@ -3213,7 +3213,7 @@
 
 static irqreturn_t hdmi_tx_isr(int irq, void *data)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
 	unsigned long flags;
 	u32 hpd_current_state;
@@ -3304,7 +3304,7 @@
 	hdmi_ctrl->hdcp_ops = NULL;
 	hdmi_ctrl->hdcp_data = NULL;
 
-	switch_dev_unregister(&hdmi_ctrl->sdev);
+	extcon_dev_unregister(&hdmi_ctrl->sdev);
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
 	mutex_destroy(&hdmi_ctrl->tx_lock);
@@ -3407,7 +3407,7 @@
 	}
 
 	hdmi_ctrl->sdev.name = "hdmi";
-	rc = switch_dev_register(&hdmi_ctrl->sdev);
+	rc = extcon_set_state_sync(&hdmi_ctrl->sdev, EXTCON_DISP_HDMI, false);
 	if (rc) {
 		DEV_ERR("%s: display switch registration failed\n", __func__);
 		goto end;
@@ -3581,7 +3581,7 @@
 	return 0;
 
 primary_err:
-	switch_dev_unregister(&hdmi_ctrl->sdev);
+	extcon_dev_unregister(&hdmi_ctrl->sdev);
 switch_err:
 	hdmi_tx_deinit_features(hdmi_ctrl, HDMI_TX_FEAT_MAX);
 init_err:
@@ -3854,7 +3854,7 @@
 	/* IO */
 	for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--) {
 		if (hdmi_ctrl->pdata.io[i].base)
-			msm_dss_iounmap(&hdmi_ctrl->pdata.io[i]);
+			msm_mdss_iounmap(&hdmi_ctrl->pdata.io[i]);
 	}
 } /* hdmi_tx_deinit_resource */
 
@@ -3874,7 +3874,7 @@
 
 	/* IO */
 	for (i = 0; i < HDMI_TX_MAX_IO; i++) {
-		rc = msm_dss_ioremap_byname(hdmi_ctrl->pdev, &pdata->io[i],
+		rc = msm_mdss_ioremap_byname(hdmi_ctrl->pdev, &pdata->io[i],
 			hdmi_tx_io_name(i));
 		if (rc) {
 			DEV_DBG("%s: '%s' remap failed or not available\n",
@@ -3903,7 +3903,7 @@
 } /* hdmi_tx_init_resource */
 
 static void hdmi_tx_put_dt_clk_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -3919,7 +3919,7 @@
 
 /* todo: once clk are moved to device tree then change this implementation */
 static int hdmi_tx_get_dt_clk_data(struct device *dev,
-	struct dss_module_power *mp, u32 module_type)
+	struct mdss_module_power *mp, u32 module_type)
 {
 	int rc = 0;
 
@@ -3933,7 +3933,7 @@
 	switch (module_type) {
 	case HDMI_TX_HPD_PM:
 		mp->num_clk = 4;
-		mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+		mp->clk_config = devm_kzalloc(dev, sizeof(struct mdss_clk) *
 			mp->num_clk, GFP_KERNEL);
 		if (!mp->clk_config) {
 			DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
@@ -3966,7 +3966,7 @@
 
 	case HDMI_TX_CORE_PM:
 		mp->num_clk = 1;
-		mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+		mp->clk_config = devm_kzalloc(dev, sizeof(struct mdss_clk) *
 			mp->num_clk, GFP_KERNEL);
 		if (!mp->clk_config) {
 			DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
@@ -4005,7 +4005,7 @@
 } /* hdmi_tx_get_dt_clk_data */
 
 static void hdmi_tx_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -4020,7 +4020,7 @@
 } /* hdmi_tx_put_dt_vreg_data */
 
 static int hdmi_tx_get_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp, u32 module_type)
+	struct mdss_module_power *mp, u32 module_type)
 {
 	int i, j, rc = 0;
 	int dt_vreg_total = 0, mod_vreg_total = 0;
@@ -4085,7 +4085,7 @@
 
 	if (mod_vreg_total > 0) {
 		mp->num_vreg = mod_vreg_total;
-		mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+		mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 			mod_vreg_total, GFP_KERNEL);
 		if (!mp->vreg_config) {
 			DEV_ERR("%s: can't alloc '%s' vreg mem\n", __func__,
@@ -4198,7 +4198,7 @@
 } /* hdmi_tx_get_dt_vreg_data */
 
 static void hdmi_tx_put_dt_gpio_data(struct device *dev,
-	struct dss_module_power *module_power)
+	struct mdss_module_power *module_power)
 {
 	if (!module_power) {
 		DEV_ERR("%s: invalid input\n", __func__);
@@ -4213,11 +4213,11 @@
 } /* hdmi_tx_put_dt_gpio_data */
 
 static int hdmi_tx_get_dt_gpio_data(struct device *dev,
-	struct dss_module_power *mp, u32 module_type)
+	struct mdss_module_power *mp, u32 module_type)
 {
 	int i, j;
 	int mp_gpio_cnt = 0, gpio_list_size = 0;
-	struct dss_gpio *gpio_list = NULL;
+	struct mdss_gpio *gpio_list = NULL;
 	struct device_node *of_node = NULL;
 
 	DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
@@ -4264,7 +4264,7 @@
 	DEV_DBG("%s: mp_gpio_cnt = %d\n", __func__, mp_gpio_cnt);
 	mp->num_gpio = mp_gpio_cnt;
 
-	mp->gpio_config = devm_kzalloc(dev, sizeof(struct dss_gpio) *
+	mp->gpio_config = devm_kzalloc(dev, sizeof(struct mdss_gpio) *
 		mp_gpio_cnt, GFP_KERNEL);
 	if (!mp->gpio_config) {
 		DEV_ERR("%s: can't alloc '%s' gpio mem\n", __func__,
@@ -4283,7 +4283,7 @@
 			continue;
 		}
 		memcpy(&mp->gpio_config[j], &gpio_list[i],
-			sizeof(struct dss_gpio));
+			sizeof(struct mdss_gpio));
 
 		mp->gpio_config[j].gpio = (unsigned int)gpio;
 
@@ -4531,17 +4531,17 @@
 
 	if (hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) {
 		for (i = 0; i < HDMI_TX_MAX_PM; i++) {
-			msm_dss_enable_vreg(
+			msm_mdss_enable_vreg(
 				hdmi_ctrl->pdata.power_data[i].vreg_config,
 				hdmi_ctrl->pdata.power_data[i].num_vreg, 1);
 
 			hdmi_tx_pinctrl_set_state(hdmi_ctrl, i, 1);
 
-			msm_dss_enable_gpio(
+			msm_mdss_enable_gpio(
 				hdmi_ctrl->pdata.power_data[i].gpio_config,
 				hdmi_ctrl->pdata.power_data[i].num_gpio, 1);
 
-			msm_dss_enable_clk(
+			msm_mdss_enable_clk(
 				hdmi_ctrl->pdata.power_data[i].clk_config,
 				hdmi_ctrl->pdata.power_data[i].num_clk, 1);
 
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
index e55aaea..6a13c75 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
@@ -13,7 +13,7 @@
 #ifndef __MDSS_HDMI_TX_H__
 #define __MDSS_HDMI_TX_H__
 
-#include <linux/switch.h>
+#include <linux/extcon.h>
 #include "mdss_hdmi_util.h"
 #include "mdss_hdmi_panel.h"
 #include "mdss_cec_core.h"
@@ -41,8 +41,8 @@
 	bool primary;
 	bool cont_splash_enabled;
 	bool cond_power_on;
-	struct dss_io_data io[HDMI_TX_MAX_IO];
-	struct dss_module_power power_data[HDMI_TX_MAX_PM];
+	struct mdss_io_data io[HDMI_TX_MAX_IO];
+	struct mdss_module_power power_data[HDMI_TX_MAX_PM];
 	struct reg_bus_client *reg_bus_clt[HDMI_TX_MAX_PM];
 	/* bitfield representing each module's pin state */
 	u64 pin_states;
@@ -72,7 +72,7 @@
 	struct mutex tx_lock;
 	struct list_head cable_notify_handlers;
 	struct kobject *kobj;
-	struct switch_dev sdev;
+	struct extcon_dev sdev;
 	struct workqueue_struct *workq;
 	struct hdmi_util_ds_data ds_data;
 	struct completion hpd_int_done;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index 8942e71..b5bedfa 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -186,7 +186,7 @@
 {
 	u32 reg_val;
 	int rc;
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 
 	if (!ctrl || !ctrl->io) {
 		pr_err("invalid input\n");
@@ -655,7 +655,7 @@
 		enum trigger_mode mode, bool seg)
 {
 	struct hdmi_tx_ddc_data *ddc_data = &ddc_ctrl->ddc_data;
-	struct dss_io_data *io = ddc_ctrl->io;
+	struct mdss_io_data *io = ddc_ctrl->io;
 	u32 const seg_addr = 0x60, seg_num = 0x01;
 	u32 ddc_ctrl_reg_val;
 
@@ -738,7 +738,7 @@
 	u32 reg_val, ndx, time_out_count, wait_time;
 	struct hdmi_tx_ddc_data *ddc_data;
 	int status;
-	int busy_wait_us;
+	int busy_wait_us = 0;
 
 	if (!ddc_ctrl || !ddc_ctrl->io) {
 		pr_err("invalid input\n");
@@ -886,7 +886,7 @@
 
 static int hdmi_ddc_hdcp2p2_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
 {
-	struct dss_io_data *io = NULL;
+	struct mdss_io_data *io = NULL;
 	struct hdmi_tx_hdcp2p2_ddc_data *data;
 	u32 intr0, intr2, intr5;
 	u32 msg_size;
@@ -1022,7 +1022,7 @@
 
 static int hdmi_ddc_scrambling_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
 {
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	bool scrambler_timer_off = false;
 	u32 intr2, intr5;
 
@@ -1216,7 +1216,7 @@
 	u32 time_out_count;
 	struct hdmi_tx_ddc_data *ddc_data;
 	u32 wait_time;
-	int busy_wait_us;
+	int busy_wait_us = 0;
 
 	if (!ddc_ctrl || !ddc_ctrl->io) {
 		pr_err("invalid input\n");
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h
index d26be99..ecab9d5 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h
@@ -447,7 +447,7 @@
 	atomic_t write_busy_wait_done;
 	atomic_t read_busy_wait_done;
 	atomic_t rxstatus_busy_wait_done;
-	struct dss_io_data *io;
+	struct mdss_io_data *io;
 	struct completion ddc_sw_done;
 	struct hdmi_tx_ddc_data ddc_data;
 	struct hdmi_tx_hdcp2p2_ddc_data hdcp2p2_ddc_data;
diff --git a/drivers/video/fbdev/msm/mdss_io_util.c b/drivers/video/fbdev/msm/mdss_io_util.c
index bd96c605..3117793 100644
--- a/drivers/video/fbdev/msm/mdss_io_util.c
+++ b/drivers/video/fbdev/msm/mdss_io_util.c
@@ -17,7 +17,7 @@
 #include <linux/mdss_io_util.h>
 
 #define MAX_I2C_CMDS  16
-void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
+void mdss_reg_w(struct mdss_io_data *io, u32 offset, u32 value, u32 debug)
 {
 	u32 in_val;
 
@@ -41,10 +41,10 @@
 
 			value, in_val);
 	}
-} /* dss_reg_w */
-EXPORT_SYMBOL(dss_reg_w);
+} /* mdss_reg_w */
+EXPORT_SYMBOL(mdss_reg_w);
 
-u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug)
+u32 mdss_reg_r(struct mdss_io_data *io, u32 offset, u32 debug)
 {
 	u32 value;
 
@@ -66,19 +66,19 @@
 			(u32)(unsigned long)(io->base + offset), value);
 
 	return value;
-} /* dss_reg_r */
-EXPORT_SYMBOL(dss_reg_r);
+} /* mdss_reg_r */
+EXPORT_SYMBOL(mdss_reg_r);
 
-void dss_reg_dump(void __iomem *base, u32 length, const char *prefix,
+void mdss_reg_dump(void __iomem *base, u32 length, const char *prefix,
 	u32 debug)
 {
 	if (debug)
 		print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
 			(void *)base, length, false);
-} /* dss_reg_dump */
-EXPORT_SYMBOL(dss_reg_dump);
+} /* mdss_reg_dump */
+EXPORT_SYMBOL(mdss_reg_dump);
 
-static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
+static struct resource *msm_mdss_get_res_byname(struct platform_device *pdev,
 	unsigned int type, const char *name)
 {
 	struct resource *res = NULL;
@@ -88,11 +88,11 @@
 		DEV_ERR("%s: '%s' resource not found\n", __func__, name);
 
 	return res;
-} /* msm_dss_get_res_byname */
-EXPORT_SYMBOL(msm_dss_get_res_byname);
+} /* msm_mdss_get_res_byname */
+EXPORT_SYMBOL(msm_mdss_get_res_byname);
 
-int msm_dss_ioremap_byname(struct platform_device *pdev,
-	struct dss_io_data *io_data, const char *name)
+int msm_mdss_ioremap_byname(struct platform_device *pdev,
+	struct mdss_io_data *io_data, const char *name)
 {
 	struct resource *res = NULL;
 
@@ -102,9 +102,9 @@
 		return -EINVAL;
 	}
 
-	res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
+	res = msm_mdss_get_res_byname(pdev, IORESOURCE_MEM, name);
 	if (!res) {
-		DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n",
+		DEV_ERR("%pS->%s: '%s' msm_mdss_get_res_byname failed\n",
 			__builtin_return_address(0), __func__, name);
 		return -ENODEV;
 	}
@@ -118,10 +118,10 @@
 	}
 
 	return 0;
-} /* msm_dss_ioremap_byname */
-EXPORT_SYMBOL(msm_dss_ioremap_byname);
+} /* msm_mdss_ioremap_byname */
+EXPORT_SYMBOL(msm_mdss_ioremap_byname);
 
-void msm_dss_iounmap(struct dss_io_data *io_data)
+void msm_mdss_iounmap(struct mdss_io_data *io_data)
 {
 	if (!io_data) {
 		DEV_ERR("%pS->%s: invalid input\n",
@@ -134,15 +134,15 @@
 		io_data->base = NULL;
 	}
 	io_data->len = 0;
-} /* msm_dss_iounmap */
-EXPORT_SYMBOL(msm_dss_iounmap);
+} /* msm_mdss_iounmap */
+EXPORT_SYMBOL(msm_mdss_iounmap);
 
-int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+int msm_mdss_config_vreg(struct device *dev, struct mdss_vreg *in_vreg,
 	int num_vreg, int config)
 {
 	int i = 0, rc = 0;
-	struct dss_vreg *curr_vreg = NULL;
-	enum dss_vreg_type type;
+	struct mdss_vreg *curr_vreg = NULL;
+	enum mdss_vreg_type type;
 
 	if (!in_vreg || !num_vreg)
 		return rc;
@@ -196,7 +196,7 @@
 
 vreg_unconfig:
 if (type == DSS_REG_LDO)
-	regulator_set_optimum_mode(curr_vreg->vreg, 0);
+	regulator_set_load(curr_vreg->vreg, 0);
 
 vreg_set_voltage_fail:
 	regulator_put(curr_vreg->vreg);
@@ -210,11 +210,11 @@
 		goto vreg_unconfig;
 	}
 	return rc;
-} /* msm_dss_config_vreg */
-EXPORT_SYMBOL(msm_dss_config_vreg);
+} /* msm_mdss_config_vreg */
+EXPORT_SYMBOL(msm_mdss_config_vreg);
 
-int msm_dss_config_vreg_opt_mode(struct dss_vreg *in_vreg, int num_vreg,
-				 enum dss_vreg_mode mode)
+int msm_mdss_config_vreg_opt_mode(struct mdss_vreg *in_vreg, int num_vreg,
+				 enum mdss_vreg_mode mode)
 {
 	int i = 0, rc = 0;
 
@@ -237,7 +237,7 @@
 		DEV_DBG("%s: Setting optimum mode %d for %s (load=%d)\n",
 			__func__, mode, in_vreg[i].vreg_name,
 			in_vreg[i].load[mode]);
-		rc = regulator_set_optimum_mode(in_vreg[i].vreg,
+		rc = regulator_set_load(in_vreg[i].vreg,
 					in_vreg[i].load[mode]);
 		if (rc < 0) {
 			DEV_ERR("%pS->%s: %s set opt mode failed. rc=%d\n",
@@ -246,7 +246,7 @@
 			goto error;
 		} else {
 			/*
-			 * regulator_set_optimum_mode can return non-zero
+			 * regulator_set_load can return non-zero
 			 * value for success. However, this API is expected
 			 * to return 0 for success.
 			 */
@@ -257,9 +257,9 @@
 error:
 	return rc;
 }
-EXPORT_SYMBOL(msm_dss_config_vreg_opt_mode);
+EXPORT_SYMBOL(msm_mdss_config_vreg_opt_mode);
 
-int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable)
+int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable)
 {
 	int i = 0, rc = 0;
 	bool need_sleep;
@@ -277,7 +277,7 @@
 			if (in_vreg[i].pre_on_sleep && need_sleep)
 				usleep_range(in_vreg[i].pre_on_sleep * 1000,
 					in_vreg[i].pre_on_sleep * 1000);
-			rc = regulator_set_optimum_mode(in_vreg[i].vreg,
+			rc = regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].load[DSS_REG_MODE_ENABLE]);
 			if (rc < 0) {
 				DEV_ERR("%pS->%s: %s set opt m fail\n",
@@ -301,7 +301,7 @@
 			if (in_vreg[i].pre_off_sleep)
 				usleep_range(in_vreg[i].pre_off_sleep * 1000,
 					in_vreg[i].pre_off_sleep * 1000);
-			regulator_set_optimum_mode(in_vreg[i].vreg,
+			regulator_set_load(in_vreg[i].vreg,
 				in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 
 			if (regulator_is_enabled(in_vreg[i].vreg))
@@ -315,7 +315,7 @@
 	return rc;
 
 disable_vreg:
-	regulator_set_optimum_mode(in_vreg[i].vreg,
+	regulator_set_load(in_vreg[i].vreg,
 					in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 
 vreg_set_opt_mode_fail:
@@ -323,7 +323,7 @@
 		if (in_vreg[i].pre_off_sleep)
 			usleep_range(in_vreg[i].pre_off_sleep * 1000,
 				in_vreg[i].pre_off_sleep * 1000);
-		regulator_set_optimum_mode(in_vreg[i].vreg,
+		regulator_set_load(in_vreg[i].vreg,
 			in_vreg[i].load[DSS_REG_MODE_DISABLE]);
 		regulator_disable(in_vreg[i].vreg);
 		if (in_vreg[i].post_off_sleep)
@@ -332,10 +332,10 @@
 	}
 
 	return rc;
-} /* msm_dss_enable_vreg */
-EXPORT_SYMBOL(msm_dss_enable_vreg);
+} /* msm_mdss_enable_vreg */
+EXPORT_SYMBOL(msm_mdss_enable_vreg);
 
-int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable)
+int msm_mdss_enable_gpio(struct mdss_gpio *in_gpio, int num_gpio, int enable)
 {
 	int i = 0, rc = 0;
 
@@ -372,10 +372,10 @@
 			gpio_free(in_gpio[i].gpio);
 
 	return rc;
-} /* msm_dss_enable_gpio */
-EXPORT_SYMBOL(msm_dss_enable_gpio);
+} /* msm_mdss_enable_gpio */
+EXPORT_SYMBOL(msm_mdss_enable_gpio);
 
-void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
+void msm_mdss_put_clk(struct mdss_clk *clk_arry, int num_clk)
 {
 	int i;
 
@@ -384,10 +384,10 @@
 			clk_put(clk_arry[i].clk);
 		clk_arry[i].clk = NULL;
 	}
-} /* msm_dss_put_clk */
-EXPORT_SYMBOL(msm_dss_put_clk);
+} /* msm_mdss_put_clk */
+EXPORT_SYMBOL(msm_mdss_put_clk);
 
-int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
+int msm_mdss_get_clk(struct device *dev, struct mdss_clk *clk_arry, int num_clk)
 {
 	int i, rc = 0;
 
@@ -405,13 +405,13 @@
 	return rc;
 
 error:
-	msm_dss_put_clk(clk_arry, num_clk);
+	msm_mdss_put_clk(clk_arry, num_clk);
 
 	return rc;
-} /* msm_dss_get_clk */
-EXPORT_SYMBOL(msm_dss_get_clk);
+} /* msm_mdss_get_clk */
+EXPORT_SYMBOL(msm_mdss_get_clk);
 
-int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
+int msm_mdss_clk_set_rate(struct mdss_clk *clk_arry, int num_clk)
 {
 	int i, rc = 0;
 
@@ -442,10 +442,10 @@
 	}
 
 	return rc;
-} /* msm_dss_clk_set_rate */
-EXPORT_SYMBOL(msm_dss_clk_set_rate);
+} /* msm_mdss_clk_set_rate */
+EXPORT_SYMBOL(msm_mdss_clk_set_rate);
 
-int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
+int msm_mdss_enable_clk(struct mdss_clk *clk_arry, int num_clk, int enable)
 {
 	int i, rc = 0;
 
@@ -469,7 +469,7 @@
 			}
 
 			if (rc) {
-				msm_dss_enable_clk(&clk_arry[i],
+				msm_mdss_enable_clk(&clk_arry[i],
 					i, false);
 				break;
 			}
@@ -490,8 +490,8 @@
 	}
 
 	return rc;
-} /* msm_dss_enable_clk */
-EXPORT_SYMBOL(msm_dss_enable_clk);
+} /* msm_mdss_enable_clk */
+EXPORT_SYMBOL(msm_mdss_enable_clk);
 
 
 int mdss_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 73324489..a9a5d8f 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -114,7 +114,7 @@
 	.irq_handler = NULL,
 };
 
-#ifdef CONFIG_MSM_BUS_SCALING
+#ifdef CONFIG_QCOM_BUS_SCALING
 #define MDP_REG_BUS_VECTOR_ENTRY(ab_val, ib_val)	\
 	{						\
 		.src = MSM_BUS_MASTER_AMPSS_M0,		\
@@ -354,7 +354,6 @@
 	/* check here if virq is a valid interrupt line */
 	irq_set_chip_and_handler(virq, &mdss_irq_chip, handle_level_irq);
 	irq_set_chip_data(virq, mdata);
-	set_irq_flags(virq, IRQF_VALID);
 	return 0;
 }
 
@@ -418,7 +417,7 @@
 	return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_MSM_BUS_SCALING
+#ifdef CONFIG_QCOM_BUS_SCALING
 static int mdss_mdp_bus_scale_register(struct mdss_data_type *mdata)
 {
 	struct msm_bus_scale_pdata *reg_bus_pdata;
@@ -812,7 +811,7 @@
 
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
 {
-	int irq_idx, idx;
+	int irq_idx;
 	unsigned long irq_flags;
 	int ret = 0;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -831,7 +830,7 @@
 	spin_lock_irqsave(&mdp_lock, irq_flags);
 	if (mdata->mdp_irq_mask[irq.reg_idx] & irq.irq_mask) {
 		pr_warn("MDSS MDP IRQ-0x%x is already set, mask=%x\n",
-				irq.irq_mask, mdata->mdp_irq_mask[idx]);
+			irq.irq_mask, mdata->mdp_irq_mask[irq.reg_idx]);
 		ret = -EBUSY;
 	} else {
 		pr_debug("MDP IRQ mask old=%x new=%x\n",
@@ -1182,7 +1181,8 @@
 		if (IS_ERR_VALUE(clk_rate)) {
 			pr_err("unable to round rate err=%ld\n", clk_rate);
 		} else if (clk_rate != clk_get_rate(clk)) {
-			if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate)))
+			if (IS_ERR_VALUE((unsigned long)
+					 clk_set_rate(clk, clk_rate)))
 				pr_err("clk_set_rate failed\n");
 			else
 				pr_debug("mdp clk rate=%lu\n", clk_rate);
@@ -1374,7 +1374,7 @@
 	}
 	mutex_unlock(&mdp_iommu_ref_cnt_lock);
 
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		return rc;
 	else
 		return mdata->iommu_ref_cnt;
@@ -1431,7 +1431,7 @@
 
 	pr_debug("called from %pS\n", __builtin_return_address(0));
 	rc = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(rc)) {
+	if (IS_ERR_VALUE((unsigned long)rc)) {
 		pr_err("mdss iommu attach failed rc=%d\n", rc);
 		goto end;
 	}
@@ -1546,7 +1546,7 @@
 				VOTE_INDEX_LOW);
 
 			rc = mdss_iommu_ctrl(1);
-			if (IS_ERR_VALUE(rc))
+			if (IS_ERR_VALUE((unsigned long)rc))
 				pr_err("IOMMU attach failed\n");
 
 			/* Active+Sleep */
@@ -1665,7 +1665,7 @@
 	pr_debug("max mdp clk rate=%d\n", mdata->max_mdp_clk_rate);
 
 	ret = devm_request_irq(&mdata->pdev->dev, mdss_mdp_hw.irq_info->irq,
-				mdss_irq_handler, IRQF_DISABLED, "MDSS", mdata);
+				mdss_irq_handler, 0, "MDSS", mdata);
 	if (ret) {
 		pr_err("mdp request_irq() failed!\n");
 		return ret;
@@ -2630,13 +2630,7 @@
 	mdss_res->mdss_util->panel_intf_type = mdss_panel_intf_type;
 	mdss_res->mdss_util->panel_intf_status = mdss_panel_get_intf_status;
 
-	if (mdss_res->mdss_util->param_check(mdss_mdp_panel)) {
-		mdss_res->mdss_util->display_disabled = true;
-		mdss_res->mdss_util->mdp_probe_done = true;
-		return 0;
-	}
-
-	rc = msm_dss_ioremap_byname(pdev, &mdata->mdss_io, "mdp_phys");
+	rc = msm_mdss_ioremap_byname(pdev, &mdata->mdss_io, "mdp_phys");
 	if (rc) {
 		pr_err("unable to map MDP base\n");
 		goto probe_done;
@@ -2645,7 +2639,7 @@
 		(int) (unsigned long) mdata->mdss_io.base,
 		mdata->mdss_io.len);
 
-	rc = msm_dss_ioremap_byname(pdev, &mdata->vbif_io, "vbif_phys");
+	rc = msm_mdss_ioremap_byname(pdev, &mdata->vbif_io, "vbif_phys");
 	if (rc) {
 		pr_err("unable to map MDSS VBIF base\n");
 		goto probe_done;
@@ -2654,7 +2648,8 @@
 		(int) (unsigned long) mdata->vbif_io.base,
 		mdata->vbif_io.len);
 
-	rc = msm_dss_ioremap_byname(pdev, &mdata->vbif_nrt_io, "vbif_nrt_phys");
+	rc = msm_mdss_ioremap_byname(pdev, &mdata->vbif_nrt_io,
+				     "vbif_nrt_phys");
 	if (rc)
 		pr_debug("unable to map MDSS VBIF non-realtime base\n");
 	else
@@ -2834,7 +2829,7 @@
 		num_of_display_on, intf_sel);
 
 probe_done:
-	if (IS_ERR_VALUE(rc)) {
+	if (IS_ERR_VALUE((unsigned long)rc)) {
 		if (!num_of_display_on)
 			mdss_mdp_footswitch_ctrl_splash(false);
 
@@ -2850,8 +2845,8 @@
 	return rc;
 }
 
-static void mdss_mdp_parse_dt_regs_array(const u32 *arr, struct dss_io_data *io,
-	struct mdss_hw_settings *hws, int count)
+static void mdss_mdp_parse_dt_regs_array(const u32 *arr,
+	struct mdss_io_data *io, struct mdss_hw_settings *hws, int count)
 {
 	u32 len, reg;
 	int i;
@@ -3261,28 +3256,28 @@
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_VIG, "vig",
 			&mdata->vig_pipes, mdata->nvig_pipes, 0);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->nvig_pipes = rc;
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_RGB, "rgb",
 			&mdata->rgb_pipes, mdata->nrgb_pipes,
 			mdata->nvig_pipes);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->nrgb_pipes = rc;
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_DMA, "dma",
 			&mdata->dma_pipes, mdata->ndma_pipes,
 			mdata->nvig_pipes + mdata->nrgb_pipes);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->ndma_pipes = rc;
 
 	rc = mdss_mdp_parse_dt_pipe_helper(pdev, MDSS_MDP_PIPE_TYPE_CURSOR,
 			"cursor", &mdata->cursor_pipes, mdata->ncursor_pipes,
 			0);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		goto parse_fail;
 	mdata->ncursor_pipes = rc;
 
@@ -4282,7 +4277,7 @@
 	return 0;
 }
 
-#ifdef CONFIG_MSM_BUS_SCALING
+#ifdef CONFIG_QCOM_BUS_SCALING
 static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev)
 {
 	int rc, paths;
@@ -4358,6 +4353,7 @@
 	return rc;
 }
 #else
+__maybe_unused
 static int mdss_mdp_parse_dt_bus_scale(struct platform_device *pdev)
 {
 	return 0;
@@ -4975,7 +4971,7 @@
 #define mdss_mdp_resume NULL
 #endif
 
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
 static int mdss_mdp_runtime_resume(struct device *dev)
 {
 	struct mdss_data_type *mdata = dev_get_drvdata(dev);
@@ -5033,9 +5029,11 @@
 
 static const struct dev_pm_ops mdss_mdp_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(mdss_mdp_pm_suspend, mdss_mdp_pm_resume)
+#ifdef CONFIG_PM
 	SET_RUNTIME_PM_OPS(mdss_mdp_runtime_suspend,
 			mdss_mdp_runtime_resume,
 			mdss_mdp_runtime_idle)
+#endif
 };
 
 static int mdss_mdp_remove(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index eb85ceb..4307119 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -648,7 +648,6 @@
 
 	/* vsync handler for FRC */
 	struct mdss_mdp_vsync_handler frc_vsync_handler;
-	bool commit_in_progress;
 };
 
 struct mdss_mdp_mixer {
@@ -1010,7 +1009,7 @@
 	u32 splash_mem_size;
 	u32 sd_enabled;
 
-	struct sw_sync_timeline *vsync_timeline;
+	struct mdss_timeline *vsync_timeline;
 	struct mdss_mdp_vsync_handler vsync_retire_handler;
 	int retire_cnt;
 	bool kickoff_released;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 6e4a6b3..4f17310 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -942,6 +942,7 @@
 	if (!ctl || !ctl->mdata)
 		return 0;
 
+	mdata = ctl->mdata;
 	mixer = pipe->mixer_left;
 	if (!mixer)
 		return -EINVAL;
@@ -2670,7 +2671,7 @@
 	ktime_t current_time = ktime_get();
 
 	if (!ctl->ops.read_line_cnt_fnc)
-		return -ENOTSUP;
+		return -ENOTSUPP;
 
 	pinfo = &ctl->panel_data->panel_info;
 	if (!pinfo)
@@ -5524,9 +5525,7 @@
 		} else {
 			sctl_flush_bits = sctl->flush_bits;
 		}
-		sctl->commit_in_progress = true;
 	}
-	ctl->commit_in_progress = true;
 	ctl_flush_bits = ctl->flush_bits;
 
 	ATRACE_END("postproc_programming");
@@ -5666,15 +5665,11 @@
 
 	ATRACE_BEGIN("flush_kickoff");
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits);
-	if (sctl) {
-		if (sctl_flush_bits) {
-			mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
-				sctl_flush_bits);
-			sctl->flush_bits = 0;
-		}
-		sctl->commit_in_progress = false;
+	if (sctl && sctl_flush_bits) {
+		mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
+				   sctl_flush_bits);
+		sctl->flush_bits = 0;
 	}
-	ctl->commit_in_progress = false;
 
 	MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits,
 		split_lm_valid);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c
index b641ccb..d24ff53 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_debug.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c
@@ -1495,11 +1495,11 @@
 	debugfs_create_file("safe_stat", 0644, mdd->root, mdata,
 			&mdss_debugfs_safe_stats_fops);
 	debugfs_create_bool("serialize_wait4pp", 0644, mdd->root,
-		(u32 *)&mdata->serialize_wait4pp);
+		(bool *)&mdata->serialize_wait4pp);
 	debugfs_create_bool("wait4autorefresh", 0644, mdd->root,
-		(u32 *)&mdata->wait4autorefresh);
+		(bool *)&mdata->wait4autorefresh);
 	debugfs_create_bool("enable_gate", 0644, mdd->root,
-		(u32 *)&mdata->enable_gate);
+		(bool *)&mdata->enable_gate);
 
 	debugfs_create_u32("color0", 0644, mdd->bordercolor,
 		(u32 *)&mdata->bcolor0);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 84218e3..7a0542a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -1206,7 +1206,6 @@
 			       atomic_read(&ctx->koff_cnt));
 		if (sync_ppdone) {
 			atomic_inc(&ctx->pp_done_cnt);
-			if (!ctl->commit_in_progress)
 				schedule_work(&ctx->pp_done_work);
 
 			mdss_mdp_resource_control(ctl,
@@ -3080,7 +3079,7 @@
 
 	pr_debug("%s: turn off interface clocks\n", __func__);
 	ret = mdss_mdp_cmd_stop_sub(ctl, panel_power_state);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("%s: unable to stop interface: %d\n",
 				__func__, ret);
 		goto end;
@@ -3088,7 +3087,7 @@
 
 	if (sctl) {
 		mdss_mdp_cmd_stop_sub(sctl, panel_power_state);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("%s: unable to stop slave intf: %d\n",
 					__func__, ret);
 			goto end;
@@ -3127,7 +3126,7 @@
 	ctl->ops.reconfigure = NULL;
 
 end:
-	if (!IS_ERR_VALUE(ret)) {
+	if (!IS_ERR_VALUE((unsigned long)ret)) {
 		struct mdss_mdp_cmd_ctx *sctx = NULL;
 
 		ctx->panel_power_state = panel_power_state;
@@ -3505,7 +3504,7 @@
 	/* Command mode is supported only starting at INTF1 */
 	session = ctl->intf_num - MDSS_MDP_INTF1;
 	ret = mdss_mdp_cmd_intfs_setup(ctl, session);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("unable to set cmd interface: %d\n", ret);
 		return ret;
 	}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 453fe28..7b69aa3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -926,7 +926,7 @@
 
 	intfs_num = ctl->intf_num - MDSS_MDP_INTF0;
 	ret = mdss_mdp_video_intfs_stop(ctl, ctl->panel_data, intfs_num);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("unable to stop video interface: %d\n", ret);
 		return ret;
 	}
@@ -1512,7 +1512,7 @@
 		}
 
 		rc = mdss_iommu_ctrl(1);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("IOMMU attach failed\n");
 			return rc;
 		}
@@ -2166,7 +2166,7 @@
 
 	intfs_num = ctl->intf_num - MDSS_MDP_INTF0;
 	ret = mdss_mdp_video_intfs_setup(ctl, ctl->panel_data, intfs_num);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("unable to set video interface: %d\n", ret);
 		return ret;
 	}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
index b155870..46f25dd 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
@@ -794,7 +794,7 @@
 	mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
 
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("IOMMU attach failed\n");
 		return ret;
 	}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 49a7bf4..b1c8041 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -21,8 +21,6 @@
 #include <linux/delay.h>
 #include <linux/msm_mdp.h>
 #include <linux/memblock.h>
-#include <linux/sync.h>
-#include <linux/sw_sync.h>
 #include <linux/file.h>
 
 #include <soc/qcom/event_timer.h>
@@ -31,6 +29,7 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 #include "mdss_mdp_wfd.h"
+#include "mdss_sync.h"
 
 #define CHECK_LAYER_BOUNDS(offset, size, max_size) \
 	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
@@ -704,13 +703,13 @@
 	return ret;
 }
 
-static struct sync_fence *__create_fence(struct msm_fb_data_type *mfd,
+static struct mdss_fence *__create_fence(struct msm_fb_data_type *mfd,
 	struct msm_sync_pt_data *sync_pt_data, u32 fence_type,
 	int *fence_fd, int value)
 {
 	struct mdss_overlay_private *mdp5_data;
 	struct mdss_mdp_ctl *ctl;
-	struct sync_fence *sync_fence = NULL;
+	struct mdss_fence *sync_fence = NULL;
 	char fence_name[32];
 
 	mdp5_data = mfd_to_mdp5_data(mfd);
@@ -736,16 +735,23 @@
 	if ((fence_type == MDSS_MDP_RETIRE_FENCE) &&
 		(mfd->panel.type == MIPI_CMD_PANEL)) {
 		if (mdp5_data->vsync_timeline) {
-			value = mdp5_data->vsync_timeline->value + 1 +
-				mdp5_data->retire_cnt++;
+			value = 1 + mdp5_data->retire_cnt++;
 			sync_fence = mdss_fb_sync_get_fence(
-				mdp5_data->vsync_timeline, fence_name, value);
+				mdp5_data->vsync_timeline, fence_name,
+				value);
 		} else {
 			return ERR_PTR(-EPERM);
 		}
 	} else {
-		sync_fence = mdss_fb_sync_get_fence(sync_pt_data->timeline,
-			fence_name, value);
+		if (fence_type == MDSS_MDP_RETIRE_FENCE)
+			sync_fence = mdss_fb_sync_get_fence(
+						sync_pt_data->timeline_retire,
+						fence_name, value);
+		else
+			sync_fence = mdss_fb_sync_get_fence(
+						sync_pt_data->timeline,
+						fence_name, value);
+
 	}
 
 	if (IS_ERR_OR_NULL(sync_fence)) {
@@ -754,14 +760,15 @@
 	}
 
 	/* get fence fd */
-	*fence_fd = get_unused_fd_flags(0);
+	*fence_fd = mdss_get_sync_fence_fd(sync_fence);
 	if (*fence_fd < 0) {
 		pr_err("%s: get_unused_fd_flags failed error:0x%x\n",
 			fence_name, *fence_fd);
-		sync_fence_put(sync_fence);
+		mdss_put_sync_fence(sync_fence);
 		sync_fence = NULL;
 		goto end;
 	}
+	pr_debug("%s:val=%d\n", mdss_get_sync_fence_name(sync_fence), value);
 
 end:
 	return sync_fence;
@@ -777,7 +784,7 @@
 static int __handle_buffer_fences(struct msm_fb_data_type *mfd,
 	struct mdp_layer_commit_v1 *commit, struct mdp_input_layer *layer_list)
 {
-	struct sync_fence *fence, *release_fence, *retire_fence;
+	struct mdss_fence *fence, *release_fence, *retire_fence;
 	struct msm_sync_pt_data *sync_pt_data = NULL;
 	struct mdp_input_layer *layer;
 	int value;
@@ -803,7 +810,7 @@
 		if (layer->buffer.fence < 0)
 			continue;
 
-		fence = sync_fence_fdget(layer->buffer.fence);
+		fence = mdss_get_fd_sync_fence(layer->buffer.fence);
 		if (!fence) {
 			pr_err("%s: sync fence get failed! fd=%d\n",
 				sync_pt_data->fence_name, layer->buffer.fence);
@@ -816,7 +823,7 @@
 	if (ret)
 		goto sync_fence_err;
 
-	value = sync_pt_data->timeline_value + sync_pt_data->threshold +
+	value = sync_pt_data->threshold +
 			atomic_read(&sync_pt_data->commit_cnt);
 
 	release_fence = __create_fence(mfd, sync_pt_data,
@@ -835,21 +842,18 @@
 		goto retire_fence_err;
 	}
 
-	sync_fence_install(release_fence, commit->release_fence);
-	sync_fence_install(retire_fence, commit->retire_fence);
-
 	mutex_unlock(&sync_pt_data->sync_mutex);
 	return ret;
 
 retire_fence_err:
 	put_unused_fd(commit->release_fence);
-	sync_fence_put(release_fence);
+	mdss_put_sync_fence(release_fence);
 release_fence_err:
 	commit->retire_fence = -1;
 	commit->release_fence = -1;
 sync_fence_err:
 	for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
-		sync_fence_put(sync_pt_data->acq_fen[i]);
+		mdss_put_sync_fence(sync_pt_data->acq_fen[i]);
 	sync_pt_data->acq_fen_cnt = 0;
 
 	mutex_unlock(&sync_pt_data->sync_mutex);
@@ -1522,7 +1526,7 @@
 	int cnt = 1;
 
 	mode = __multirect_layer_flags_to_mode(layer_list[ndx].flags);
-	if (IS_ERR_VALUE(mode))
+	if (IS_ERR_VALUE((unsigned long)mode))
 		return mode;
 
 	pr_debug("layer #%d pipe_ndx=%d multirect mode=%d\n",
@@ -1557,7 +1561,7 @@
 
 			mode = __multirect_layer_flags_to_mode(
 					layer_list[i].flags);
-			if (IS_ERR_VALUE(mode))
+			if (IS_ERR_VALUE((unsigned long)mode))
 				return mode;
 
 			if (mode != vinfo[0]->multirect.mode) {
@@ -1598,7 +1602,7 @@
 
 	cnt = __update_multirect_info(mfd, validate_info_list,
 			layer_list, ndx, layer_cnt);
-	if (IS_ERR_VALUE(cnt))
+	if (IS_ERR_VALUE((unsigned long)cnt))
 		return cnt;
 
 	if (cnt <= 1) {
@@ -1619,7 +1623,7 @@
 	}
 
 	rc = __multirect_validate_mode(mfd, layers, cnt);
-	if (IS_ERR_VALUE(rc))
+	if (IS_ERR_VALUE((unsigned long)rc))
 		return rc;
 
 	return 0;
@@ -1647,7 +1651,7 @@
 	u32 mixer_mux, dst_x;
 	int layer_count = commit->input_layer_cnt;
 
-	struct mdss_mdp_pipe *pipe, *tmp, *left_blend_pipe;
+	struct mdss_mdp_pipe *pipe = NULL, *tmp, *left_blend_pipe;
 	struct mdss_mdp_pipe *right_plist[MAX_PIPES_PER_LM] = {0};
 	struct mdss_mdp_pipe *left_plist[MAX_PIPES_PER_LM] = {0};
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -1867,7 +1871,7 @@
 			rec_destroy_ndx[rect_num] |= pipe->ndx;
 
 		ret = mdss_mdp_pipe_map(pipe);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("Unable to map used pipe%d ndx=%x\n",
 				pipe->num, pipe->ndx);
 			layer->error_code = ret;
@@ -1937,7 +1941,7 @@
 			rec_destroy_ndx[0], rec_destroy_ndx[1], ret);
 	mutex_lock(&mdp5_data->list_lock);
 	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_used, list) {
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			if (((pipe->ndx & rec_release_ndx[0]) &&
 						(pipe->multirect.num == 0)) ||
 					((pipe->ndx & rec_release_ndx[1]) &&
@@ -2062,7 +2066,7 @@
 		if (!validate_info_list[i].layer) {
 			ret = __update_multirect_info(mfd, validate_info_list,
 						   layer_list, i, layer_count);
-			if (IS_ERR_VALUE(ret)) {
+			if (IS_ERR_VALUE((unsigned long)ret)) {
 				pr_err("error updating multirect config. ret=%d i=%d\n",
 					ret, i);
 				goto end;
@@ -2180,7 +2184,7 @@
 	struct mdss_mdp_wfd *wfd = NULL;
 	struct mdp_output_layer *output_layer = NULL;
 	struct mdss_mdp_wfd_data *data = NULL;
-	struct sync_fence *fence = NULL;
+	struct mdss_fence *fence = NULL;
 	struct msm_sync_pt_data *sync_pt_data = NULL;
 
 	if (!mfd || !commit)
@@ -2208,7 +2212,8 @@
 			return PTR_ERR(data);
 
 		if (output_layer->buffer.fence >= 0) {
-			fence = sync_fence_fdget(output_layer->buffer.fence);
+			fence = mdss_get_fd_sync_fence(
+						output_layer->buffer.fence);
 			if (!fence) {
 				pr_err("fail to get output buffer fence\n");
 				rc = -EINVAL;
@@ -2249,7 +2254,7 @@
 
 input_layer_err:
 	if (fence)
-		sync_fence_put(fence);
+		mdss_put_sync_fence(fence);
 fence_get_err:
 	if (data)
 		mdss_mdp_wfd_remove_data(wfd, data);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index f69f5b3..3144b6c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -25,8 +25,8 @@
 #include <linux/msm_mdp.h>
 #include <linux/memblock.h>
 #include <linux/sort.h>
-#include <linux/sw_sync.h>
 #include <linux/kmemleak.h>
+#include <linux/kthread.h>
 #include <asm/div64.h>
 
 #include <soc/qcom/event_timer.h>
@@ -38,6 +38,7 @@
 #include "mdss_smmu.h"
 #include "mdss_mdp_wfd.h"
 #include "mdss_dsi_clk.h"
+#include "mdss_sync.h"
 
 #define VSYNC_PERIOD 16
 #define BORDERFILL_NDX	0x0BF000BF
@@ -760,7 +761,7 @@
 		}
 
 		ret = mdss_mdp_pipe_map(pipe);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("Unable to map used pipe%d ndx=%x\n",
 					pipe->num, pipe->ndx);
 			return ret;
@@ -1387,7 +1388,7 @@
 	if (!mdp5_data->mdata->idle_pc_enabled ||
 		(mfd->panel_info->type != MIPI_CMD_PANEL)) {
 		rc = pm_runtime_get_sync(&mfd->pdev->dev);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("unable to resume with pm_runtime_get_sync rc=%d\n",
 				rc);
 			goto end;
@@ -1404,7 +1405,7 @@
 	 */
 	if (!mfd->panel_info->cont_splash_enabled) {
 		rc = mdss_iommu_ctrl(1);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("iommu attach failed rc=%d\n", rc);
 			goto end;
 		}
@@ -1591,10 +1592,10 @@
 		 * if we reach here without errors and buf == NULL
 		 * then solid fill will be set
 		 */
-		if (!IS_ERR_VALUE(ret))
+		if (!IS_ERR_VALUE((unsigned long)ret))
 			ret = mdss_mdp_pipe_queue_data(pipe, buf);
 
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_warn("Unable to queue data for pnum=%d rect=%d\n",
 					pipe->num, pipe->multirect.num);
 
@@ -2231,7 +2232,7 @@
 
 		if (frc_info->video_stat.last_delta) {
 			video_fps_changed =
-				abs64(delta_t - frc_info->video_stat.last_delta)
+				abs(delta_t - frc_info->video_stat.last_delta)
 				> (FRC_VIDEO_FPS_CHANGE_THRESHOLD_US *
 					FRC_VIDEO_FPS_DETECT_WINDOW);
 
@@ -2883,7 +2884,7 @@
 	}
 
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("iommu attach failed rc=%d\n", ret);
 		mutex_unlock(&mdp5_data->ov_lock);
 		if (ctl->shared_lock)
@@ -2906,7 +2907,7 @@
 	sd_transition_state = mdp5_data->sd_transition_state;
 	if (sd_transition_state != SD_TRANSITION_NONE) {
 		ret = __config_secure_display(mdp5_data);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("Secure session config failed\n");
 			goto commit_fail;
 		}
@@ -2963,7 +2964,7 @@
 	if (!mdp5_data->kickoff_released)
 		mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_CTX_DONE);
 
-	if (IS_ERR_VALUE(ret))
+	if (IS_ERR_VALUE((unsigned long)ret))
 		goto commit_fail;
 
 	mutex_unlock(&mdp5_data->ov_lock);
@@ -2985,7 +2986,7 @@
 	ret = mdss_mdp_ctl_update_fps(ctl);
 	ATRACE_END("fps_update");
 
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("failed to update fps!\n");
 		goto commit_fail;
 	}
@@ -3166,7 +3167,7 @@
 	}
 
 	ret = mdss_mdp_pipe_map(pipe);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("Unable to map used pipe%d ndx=%x\n",
 				pipe->num, pipe->ndx);
 		return ret;
@@ -3192,7 +3193,7 @@
 		ret = mdss_mdp_data_get_and_validate_size(src_data, &req->data,
 			1, flags, &mfd->pdev->dev, false, DMA_TO_DEVICE,
 			&buffer);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			mdss_mdp_overlay_buf_free(mfd, src_data);
 			pr_err("src_data pmem error\n");
 		}
@@ -3435,7 +3436,7 @@
 	}
 
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_err("IOMMU attach failed\n");
 		goto clk_disable;
 	}
@@ -5095,7 +5096,7 @@
 static int mdss_mdp_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd,
 				void __user *argp)
 {
-	int ret = -ENOTSUP;
+	int ret = -ENOTSUPP;
 	struct mdp_histogram_data hist;
 	struct mdp_histogram_start_req hist_req;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -5493,7 +5494,7 @@
 			left_blend_pipe, is_single_layer);
 		req->z_order -= MDSS_MDP_STAGE_0;
 
-		if (IS_ERR_VALUE(ret))
+		if (IS_ERR_VALUE((unsigned long)ret))
 			goto validate_exit;
 
 		pr_debug("pnum:%d id:0x%x flags:0x%x dst_x:%d l_blend_pnum%d\n",
@@ -5533,7 +5534,7 @@
 	else
 		ovlist->processed_overlays = i;
 
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		pr_debug("err=%d total_ovs:%d processed:%d left:%d right:%d\n",
 			ret, num_ovs, ovlist->processed_overlays, left_lm_ovs,
 			right_lm_ovs);
@@ -5586,7 +5587,7 @@
 	}
 
 	ret = __handle_overlay_prepare(mfd, &ovlist, overlays);
-	if (!IS_ERR_VALUE(ret)) {
+	if (!IS_ERR_VALUE((unsigned long)ret)) {
 		for (i = 0; i < ovlist.num_overlays; i++) {
 			if (copy_to_user(req_list[i], overlays + i,
 					sizeof(struct mdp_overlay))) {
@@ -5609,7 +5610,7 @@
 					  u32 cmd, void __user *argp)
 {
 	struct mdp_overlay *req = NULL;
-	int val, ret = -ENOTSUP;
+	int val, ret = -ENOTSUPP;
 	struct msmfb_metadata metadata;
 	struct mdp_pp_feature_version pp_feature_version;
 	struct msmfb_overlay_data data;
@@ -5653,7 +5654,7 @@
 		if (!ret) {
 			ret = mdss_mdp_overlay_get(mfd, req);
 
-			if (!IS_ERR_VALUE(ret))
+			if (!IS_ERR_VALUE((unsigned long)ret))
 				ret = copy_to_user(argp, req, sizeof(*req));
 		}
 
@@ -5669,7 +5670,7 @@
 		if (!ret) {
 			ret = mdss_mdp_overlay_set(mfd, req);
 
-			if (!IS_ERR_VALUE(ret))
+			if (!IS_ERR_VALUE((unsigned long)ret))
 				ret = copy_to_user(argp, req, sizeof(*req));
 		}
 		if (ret)
@@ -5949,7 +5950,7 @@
 	}
 
 panel_on:
-	if (IS_ERR_VALUE(rc)) {
+	if (IS_ERR_VALUE((unsigned long)rc)) {
 		pr_err("Failed to turn on fb%d\n", mfd->index);
 		mdss_mdp_overlay_off(mfd);
 		goto end;
@@ -6110,7 +6111,7 @@
 		 * retire_signal api checks for retire_cnt with sync_mutex lock.
 		 */
 
-		flush_kthread_work(&mdp5_data->vsync_work);
+		kthread_flush_work(&mdp5_data->vsync_work);
 	}
 
 ctl_stop:
@@ -6316,7 +6317,7 @@
 	}
 
 	mdp5_data = mfd_to_mdp5_data(mfd);
-	queue_kthread_work(&mdp5_data->worker, &mdp5_data->vsync_work);
+	kthread_queue_work(&mdp5_data->worker, &mdp5_data->vsync_work);
 }
 
 static void __vsync_retire_work_handler(struct kthread_work *work)
@@ -6339,11 +6340,11 @@
 
 	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
 	if (mdp5_data->retire_cnt > 0) {
-		sw_sync_timeline_inc(mdp5_data->vsync_timeline, val);
+		mdss_inc_timeline(mdp5_data->vsync_timeline, val);
 		mdp5_data->retire_cnt -= min(val, mdp5_data->retire_cnt);
 		pr_debug("Retire signaled! timeline val=%d remaining=%d\n",
-				mdp5_data->vsync_timeline->value,
-				mdp5_data->retire_cnt);
+			mdss_get_timeline_retire_ts(mdp5_data->vsync_timeline),
+			mdp5_data->retire_cnt);
 
 		if (mdp5_data->retire_cnt == 0) {
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
@@ -6355,7 +6356,7 @@
 	mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex);
 }
 
-static struct sync_fence *
+static struct mdss_fence *
 __vsync_retire_get_fence(struct msm_sync_pt_data *sync_pt_data)
 {
 	struct msm_fb_data_type *mfd;
@@ -6378,7 +6379,7 @@
 		return ERR_PTR(-EPERM);
 	}
 
-	value = mdp5_data->vsync_timeline->value + 1 + mdp5_data->retire_cnt;
+	value = 1 + mdp5_data->retire_cnt;
 	mdp5_data->retire_cnt++;
 
 	return mdss_fb_sync_get_fence(mdp5_data->vsync_timeline,
@@ -6419,14 +6420,14 @@
 	struct sched_param param = { .sched_priority = 5 };
 
 	snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index);
-	mdp5_data->vsync_timeline = sw_sync_timeline_create(name);
+	mdp5_data->vsync_timeline = mdss_create_timeline(name);
 	if (mdp5_data->vsync_timeline == NULL) {
 		pr_err("cannot vsync create time line");
 		return -ENOMEM;
 	}
 
-	init_kthread_worker(&mdp5_data->worker);
-	init_kthread_work(&mdp5_data->vsync_work, __vsync_retire_work_handler);
+	kthread_init_worker(&mdp5_data->worker);
+	kthread_init_work(&mdp5_data->vsync_work, __vsync_retire_work_handler);
 
 	mdp5_data->thread = kthread_run(kthread_worker_fn,
 					&mdp5_data->worker,
@@ -6717,7 +6718,7 @@
 	if (mfd->panel_info->mipi.dms_mode ||
 			mfd->panel_info->type == MIPI_CMD_PANEL) {
 		rc = __vsync_retire_setup(mfd);
-		if (IS_ERR_VALUE(rc)) {
+		if (IS_ERR_VALUE((unsigned long)rc)) {
 			pr_err("unable to create vsync timeline\n");
 			goto init_fail;
 		}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 6131ed1..74b698c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -1717,7 +1717,7 @@
 			lut_offset = mdata->scaler_off->dest_base +
 				mdata->scaler_off->dest_scaler_lut_off[id];
 			/*TODO : set pixel fmt to RGB101010 */
-			return -ENOTSUP;
+			return -ENOTSUPP;
 		} else {
 			return -EINVAL;
 		}
@@ -7209,6 +7209,13 @@
 		ret = -EINVAL;
 		goto exit_version;
 	}
+	/* PA dither is not supported by driver */
+	if (version->pp_feature == PA_DITHER) {
+		pr_warn("unsupported feature %d\n", version->pp_feature);
+		version->version_info = 0;
+		ret = 0;
+		goto exit_version;
+	}
 	if (version->pp_feature >= PP_FEATURE_MAX) {
 		pr_err("invalid feature passed %d\n", version->pp_feature);
 		ret = -EINVAL;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
index f17cf6f..44817c3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_splash_logo.c
@@ -1,5 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -89,7 +88,7 @@
 	}
 	sinfo->size = buf_size;
 
-	dma_buf_begin_cpu_access(sinfo->dma_buf, 0, size, DMA_BIDIRECTIONAL);
+	dma_buf_begin_cpu_access(sinfo->dma_buf, DMA_BIDIRECTIONAL);
 	sinfo->splash_buffer = dma_buf_kmap(sinfo->dma_buf, 0);
 	if (IS_ERR(sinfo->splash_buffer)) {
 		pr_err("ion kernel memory mapping failed\n");
@@ -133,8 +132,7 @@
 	if (!mdata || !mdata->iclient || !sinfo->dma_buf)
 		return;
 
-	dma_buf_end_cpu_access(sinfo->dma_buf, 0, sinfo->size,
-			       DMA_BIDIRECTIONAL);
+	dma_buf_end_cpu_access(sinfo->dma_buf, DMA_BIDIRECTIONAL);
 	dma_buf_kunmap(sinfo->dma_buf, 0, sinfo->splash_buffer);
 
 	mdss_smmu_unmap_dma_buf(sinfo->table, MDSS_IOMMU_DOMAIN_UNSECURE, 0,
@@ -177,7 +175,7 @@
 		pr_debug("iommu memory mapping failed rc=%d\n", rc);
 	} else {
 		ret = mdss_iommu_ctrl(1);
-		if (IS_ERR_VALUE(ret)) {
+		if (IS_ERR_VALUE((unsigned long)ret)) {
 			pr_err("mdss iommu attach failed\n");
 			mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE,
 					mdp5_data->splash_mem_addr,
@@ -288,7 +286,7 @@
 		 */
 		if (mdp5_data->handoff && ctl && ctl->is_video_mode) {
 			rc = mdss_mdp_display_commit(ctl, NULL, NULL);
-			if (!IS_ERR_VALUE(rc)) {
+			if (!IS_ERR_VALUE((unsigned long)rc)) {
 				mdss_mdp_display_wait4comp(ctl);
 			} else {
 				/*
diff --git a/drivers/video/fbdev/msm/mdss_mdp_trace.h b/drivers/video/fbdev/msm/mdss_mdp_trace.h
index c100e9c..f8a6baf 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_trace.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_trace.h
@@ -376,7 +376,7 @@
 			__entry->kickoff_cnt)
 );
 
-TRACE_EVENT(tracing_mark_write,
+TRACE_EVENT(mdss_mark_write,
 	TP_PROTO(int pid, const char *name, bool trace_begin),
 	TP_ARGS(pid, name, trace_begin),
 	TP_STRUCT__entry(
diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c
index 6c28fe9..44f53a7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_util.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_util.c
@@ -420,8 +420,8 @@
 
 	if (fmt->format == MDP_Y_CBCR_H2V2_UBWC ||
 		fmt->format == MDP_Y_CBCR_H2V2_TP10_UBWC) {
-		uint32_t y_stride_alignment, uv_stride_alignment;
-		uint32_t y_height_alignment, uv_height_alignment;
+		uint32_t y_stride_alignment = 0, uv_stride_alignment = 0;
+		uint32_t y_height_alignment = 0, uv_height_alignment = 0;
 		uint32_t y_tile_width = fmt_ubwc->micro.tile_width;
 		uint32_t y_tile_height = fmt_ubwc->micro.tile_height;
 		uint32_t uv_tile_width = y_tile_width / 2;
@@ -517,12 +517,11 @@
 	if (ps == NULL)
 		return -EINVAL;
 
-	memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
-
 	if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT))
 		return -ERANGE;
 
 	bpp = fmt->bpp;
+	memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
 
 	if (mdss_mdp_is_ubwc_format(fmt)) {
 		rc = mdss_mdp_get_ubwc_plane_size(fmt, w, h, ps);
@@ -1002,8 +1001,8 @@
 		}
 		data->srcp_f = f;
 
-		if (MAJOR(f.file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
-			fb_num = MINOR(f.file->f_dentry->d_inode->i_rdev);
+		if (MAJOR(f.file->f_path.dentry->d_inode->i_rdev) == FB_MAJOR) {
+			fb_num = MINOR(f.file->f_path.dentry->d_inode->i_rdev);
 			ret = mdss_fb_get_phys_info(start, len, fb_num);
 			if (ret)
 				pr_err("mdss_fb_get_phys_info() failed\n");
@@ -1051,7 +1050,7 @@
 			struct sg_table *sg_ptr = NULL;
 
 			do {
-				ihandle = ion_import_dma_buf(iclient,
+				ihandle = ion_import_dma_buf_fd(iclient,
 							     img->memory_id);
 				if (IS_ERR_OR_NULL(ihandle)) {
 					ret = -EINVAL;
@@ -1140,7 +1139,7 @@
 			ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf,
 					data->srcp_table, domain,
 					&data->addr, &data->len, dir);
-			if (IS_ERR_VALUE(ret)) {
+			if (IS_ERR_VALUE((unsigned long)ret)) {
 				pr_err("smmu map dma buf failed: (%d)\n", ret);
 				goto err_unmap;
 			}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_wfd.h b/drivers/video/fbdev/msm/mdss_mdp_wfd.h
index e603c48..b35feb7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_wfd.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_wfd.h
@@ -14,8 +14,6 @@
 #ifndef __MDSS_MDP_WFD_H__
 #define __MDSS_MDP_WFD_H__
 
-#include <linux/sync.h>
-#include <linux/sw_sync.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 #include <linux/msm_mdp_ext.h>
diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c
index 73676d0..2dc9a1f 100644
--- a/drivers/video/fbdev/msm/mdss_rotator.c
+++ b/drivers/video/fbdev/msm/mdss_rotator.c
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/sync.h>
 #include <linux/uaccess.h>
 #include <linux/of.h>
 #include <linux/clk.h>
@@ -28,6 +27,7 @@
 #include "mdss_rotator_internal.h"
 #include "mdss_mdp.h"
 #include "mdss_debug.h"
+#include "mdss_sync.h"
 
 /* waiting for hw time out, 3 vsync for 30fps*/
 #define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100
@@ -230,7 +230,7 @@
 			pr_err("unable to round rate err=%ld\n", clk_rate);
 		} else if (clk_rate != clk_get_rate(clk)) {
 			ret = clk_set_rate(clk, clk_rate);
-			if (IS_ERR_VALUE(ret)) {
+			if (IS_ERR_VALUE((unsigned long)ret)) {
 				pr_err("clk_set_rate failed, err:%d\n", ret);
 			} else {
 				pr_debug("rotator clk rate=%lu\n", clk_rate);
@@ -253,7 +253,7 @@
 	}
 
 	pr_debug("%s: rotator regulators", on ? "Enable" : "Disable");
-	ret = msm_dss_enable_vreg(mgr->module_power.vreg_config,
+	ret = msm_mdss_enable_vreg(mgr->module_power.vreg_config,
 		mgr->module_power.num_vreg, on);
 	if (ret) {
 		pr_warn("Rotator regulator failed to %s\n",
@@ -374,21 +374,11 @@
 	return false;
 }
 
-static void mdss_rotator_install_fence_fd(struct mdss_rot_entry_container *req)
-{
-	int i = 0;
-
-	for (i = 0; i < req->count; i++)
-		sync_fence_install(req->entries[i].output_fence,
-				req->entries[i].output_fence_fd);
-}
-
 static int mdss_rotator_create_fence(struct mdss_rot_entry *entry)
 {
 	int ret = 0, fd;
 	u32 val;
-	struct sync_pt *sync_pt;
-	struct sync_fence *fence;
+	struct mdss_fence *fence;
 	struct mdss_rot_timeline *rot_timeline;
 
 	if (!entry->queue)
@@ -397,24 +387,15 @@
 	rot_timeline = &entry->queue->timeline;
 
 	mutex_lock(&rot_timeline->lock);
-	val = rot_timeline->next_value + 1;
+	val = 1;
 
-	sync_pt = sw_sync_pt_create(rot_timeline->timeline, val);
-	if (sync_pt == NULL) {
+	fence = mdss_get_sync_fence(rot_timeline->timeline,
+					rot_timeline->fence_name, NULL, val);
+	if (fence == NULL) {
 		pr_err("cannot create sync point\n");
 		goto sync_pt_create_err;
 	}
-
-	/* create fence */
-	fence = sync_fence_create(rot_timeline->fence_name, sync_pt);
-	if (fence == NULL) {
-		pr_err("%s: cannot create fence\n", rot_timeline->fence_name);
-		sync_pt_free(sync_pt);
-		ret = -ENOMEM;
-		goto sync_pt_create_err;
-	}
-
-	fd = get_unused_fd_flags(0);
+	fd = mdss_get_sync_fence_fd(fence);
 	if (fd < 0) {
 		pr_err("get_unused_fd_flags failed error:0x%x\n", fd);
 		ret = fd;
@@ -426,12 +407,13 @@
 
 	entry->output_fence_fd = fd;
 	entry->output_fence = fence;
-	pr_debug("output sync point created at val=%u\n", val);
+	pr_debug("output sync point created at %s:val=%u\n",
+		mdss_get_sync_fence_name(fence), val);
 
 	return 0;
 
 get_fd_err:
-	sync_fence_put(fence);
+	mdss_put_sync_fence(fence);
 sync_pt_create_err:
 	mutex_unlock(&rot_timeline->lock);
 	return ret;
@@ -442,7 +424,7 @@
 	struct mdss_rot_timeline *rot_timeline;
 
 	if (entry->input_fence) {
-		sync_fence_put(entry->input_fence);
+		mdss_put_sync_fence(entry->input_fence);
 		entry->input_fence = NULL;
 	}
 
@@ -450,7 +432,7 @@
 
 	/* fence failed to copy to user space */
 	if (entry->output_fence) {
-		sync_fence_put(entry->output_fence);
+		mdss_put_sync_fence(entry->output_fence);
 		entry->output_fence = NULL;
 		put_unused_fd(entry->output_fence_fd);
 
@@ -475,7 +457,7 @@
 	}
 
 	mutex_lock(&rot_timeline->lock);
-	sw_sync_timeline_inc(rot_timeline->timeline, 1);
+	mdss_inc_timeline(rot_timeline->timeline, 1);
 	mutex_unlock(&rot_timeline->lock);
 
 	entry->output_signaled = true;
@@ -492,8 +474,8 @@
 		return 0;
 	}
 
-	ret = sync_fence_wait(entry->input_fence, ROT_FENCE_WAIT_TIMEOUT);
-	sync_fence_put(entry->input_fence);
+	ret = mdss_wait_sync_fence(entry->input_fence, ROT_FENCE_WAIT_TIMEOUT);
+	mdss_put_sync_fence(entry->input_fence);
 	entry->input_fence = NULL;
 	return ret;
 }
@@ -545,7 +527,7 @@
 
 	ATRACE_BEGIN(__func__);
 	ret = mdss_iommu_ctrl(1);
-	if (IS_ERR_VALUE(ret)) {
+	if (IS_ERR_VALUE((unsigned long)ret)) {
 		ATRACE_END(__func__);
 		return ret;
 	}
@@ -697,7 +679,7 @@
 	struct mdss_rot_hw_resource *hw;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	u32 pipe_ndx, offset = mdss_mdp_get_wb_ctl_support(mdata, true);
-	int ret;
+	int ret = 0;
 
 	hw = devm_kzalloc(&mgr->pdev->dev, sizeof(struct mdss_rot_hw_resource),
 		GFP_KERNEL);
@@ -867,7 +849,7 @@
 		snprintf(name, sizeof(name), "rot_timeline_%d", i);
 		pr_debug("timeline name=%s\n", name);
 		mgr->queues[i].timeline.timeline =
-			sw_sync_timeline_create(name);
+			mdss_create_timeline(name);
 		if (!mgr->queues[i].timeline.timeline) {
 			ret = -EPERM;
 			break;
@@ -896,11 +878,11 @@
 			destroy_workqueue(mgr->queues[i].rot_work_queue);
 
 		if (mgr->queues[i].timeline.timeline) {
-			struct sync_timeline *obj;
+			struct mdss_timeline *obj;
 
-			obj = (struct sync_timeline *)
+			obj = (struct mdss_timeline *)
 				mgr->queues[i].timeline.timeline;
-			sync_timeline_destroy(obj);
+			mdss_destroy_timeline(obj);
 		}
 	}
 	devm_kfree(&mgr->pdev->dev, mgr->queues);
@@ -1524,8 +1506,8 @@
 		}
 
 		if (item->input.fence >= 0) {
-			entry->input_fence =
-				sync_fence_fdget(item->input.fence);
+			entry->input_fence = mdss_get_fd_sync_fence(
+							    item->input.fence);
 			if (!entry->input_fence) {
 				pr_err("invalid input fence fd\n");
 				return -EINVAL;
@@ -2263,7 +2245,6 @@
 		goto handle_request_err1;
 	}
 
-	mdss_rotator_install_fence_fd(req);
 	mdss_rotator_queue_request(mgr, private, req);
 
 	mutex_unlock(&mgr->lock);
@@ -2423,7 +2404,6 @@
 		goto handle_request32_err1;
 	}
 
-	mdss_rotator_install_fence_fd(req);
 	mdss_rotator_queue_request(mgr, private, req);
 
 	mutex_unlock(&mgr->lock);
@@ -2677,14 +2657,14 @@
 }
 
 static void mdss_rotator_put_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp)
+	struct mdss_module_power *mp)
 {
 	if (!mp) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return;
 	}
 
-	msm_dss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 0);
+	msm_mdss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 0);
 	if (mp->vreg_config) {
 		devm_kfree(dev, mp->vreg_config);
 		mp->vreg_config = NULL;
@@ -2693,7 +2673,7 @@
 }
 
 static int mdss_rotator_get_dt_vreg_data(struct device *dev,
-	struct dss_module_power *mp)
+	struct mdss_module_power *mp)
 {
 	const char *st = NULL;
 	struct device_node *of_node = NULL;
@@ -2715,7 +2695,7 @@
 		return 0;
 	}
 	mp->num_vreg = dt_vreg_total;
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 		dt_vreg_total, GFP_KERNEL);
 	if (!mp->vreg_config) {
 		DEV_ERR("%s: can't alloc vreg mem\n", __func__);
@@ -2733,7 +2713,7 @@
 		}
 		snprintf(mp->vreg_config[i].vreg_name, 32, "%s", st);
 	}
-	msm_dss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 1);
+	msm_mdss_config_vreg(dev, mp->vreg_config, mp->num_vreg, 1);
 
 	for (i = 0; i < dt_vreg_total; i++) {
 		DEV_DBG("%s: %s min=%d, max=%d, enable=%d disable=%d\n",
diff --git a/drivers/video/fbdev/msm/mdss_rotator_internal.h b/drivers/video/fbdev/msm/mdss_rotator_internal.h
index 8dd400e..88f530a 100644
--- a/drivers/video/fbdev/msm/mdss_rotator_internal.h
+++ b/drivers/video/fbdev/msm/mdss_rotator_internal.h
@@ -15,10 +15,8 @@
 #define MDSS_MDP_ROTATOR_INTERNAL_H
 
 #include <linux/list.h>
-#include <linux/sync.h>
 #include <linux/file.h>
 #include <linux/mdss_rotator.h>
-#include <linux/sw_sync.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 #include <linux/cdev.h>
@@ -52,7 +50,7 @@
 
 struct mdss_rot_timeline {
 	struct mutex lock;
-	struct sw_sync_timeline *timeline;
+	struct mdss_timeline *timeline;
 	u32 next_value;
 	char fence_name[32];
 };
@@ -95,10 +93,10 @@
 	struct mdss_mdp_data src_buf;
 	struct mdss_mdp_data dst_buf;
 
-	struct sync_fence *input_fence;
+	struct mdss_fence *input_fence;
 
 	int output_fence_fd;
-	struct sync_fence *output_fence;
+	struct mdss_fence *output_fence;
 	bool output_signaled;
 
 	u32 dnsc_factor_w;
@@ -174,7 +172,7 @@
 	struct mdss_rot_bus_data_type reg_bus;
 
 	/* Module power is only used for regulator management */
-	struct dss_module_power module_power;
+	struct mdss_module_power module_power;
 	bool regulator_enable;
 
 	struct mutex clk_lock;
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 05353a0..7a44824 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -17,17 +17,15 @@
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
 #include <linux/iommu.h>
-#include <linux/qcom_iommu.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/clk/msm-clk.h>
-
+#include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-buf.h>
 #include <linux/of_platform.h>
 #include <linux/msm_dma_iommu_mapping.h>
 
-#include <linux/qcom_iommu.h>
 #include <asm/dma-iommu.h>
 #include "soc/qcom/secure_buffer.h"
 
@@ -38,6 +36,27 @@
 
 #define SZ_4G 0xF0000000
 
+#ifdef CONFIG_QCOM_IOMMU
+#include <linux/qcom_iommu.h>
+static inline struct bus_type *mdss_mmu_get_bus(struct device *dev)
+{
+	return msm_iommu_get_bus(dev);
+}
+static inline struct device *mdss_mmu_get_ctx(const char *name)
+{
+	return msm_iommu_get_ctx(name);
+}
+#else
+static inline struct bus_type *mdss_mmu_get_bus(struct device *dev)
+{
+	return &platform_bus_type;
+}
+static inline struct device *mdss_mmu_get_ctx(const char *name)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
 static DEFINE_MUTEX(mdp_iommu_lock);
 
 void mdss_iommu_lock(void)
@@ -51,7 +70,7 @@
 }
 
 static int mdss_smmu_util_parse_dt_clock(struct platform_device *pdev,
-		struct dss_module_power *mp)
+		struct mdss_module_power *mp)
 {
 	u32 i = 0, rc = 0;
 	const char *clock_name;
@@ -67,7 +86,7 @@
 
 	mp->num_clk = num_clk;
 	mp->clk_config = devm_kzalloc(&pdev->dev,
-			sizeof(struct dss_clk) * mp->num_clk, GFP_KERNEL);
+			sizeof(struct mdss_clk) * mp->num_clk, GFP_KERNEL);
 	if (!mp->clk_config) {
 		rc = -ENOMEM;
 		mp->num_clk = 0;
@@ -95,7 +114,7 @@
 }
 
 static int mdss_smmu_clk_register(struct platform_device *pdev,
-		struct dss_module_power *mp)
+		struct mdss_module_power *mp)
 {
 	int i, ret;
 	struct clk *clk;
@@ -123,7 +142,7 @@
 	bool enable)
 {
 	int rc = 0;
-	struct dss_module_power *mp;
+	struct mdss_module_power *mp;
 
 	if (!mdss_smmu)
 		return -EINVAL;
@@ -134,27 +153,27 @@
 		return 0;
 
 	if (enable) {
-		rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, true);
+		rc = msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, true);
 		if (rc) {
 			pr_err("vreg enable failed - rc:%d\n", rc);
 			goto end;
 		}
 		mdss_update_reg_bus_vote(mdss_smmu->reg_bus_clt,
 			VOTE_INDEX_LOW);
-		rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true);
+		rc = msm_mdss_enable_clk(mp->clk_config, mp->num_clk, true);
 		if (rc) {
 			pr_err("clock enable failed - rc:%d\n", rc);
 			mdss_update_reg_bus_vote(mdss_smmu->reg_bus_clt,
 				VOTE_INDEX_DISABLE);
-			msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
+			msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg,
 				false);
 			goto end;
 		}
 	} else {
-		msm_dss_enable_clk(mp->clk_config, mp->num_clk, false);
+		msm_mdss_enable_clk(mp->clk_config, mp->num_clk, false);
 		mdss_update_reg_bus_vote(mdss_smmu->reg_bus_clt,
 			VOTE_INDEX_DISABLE);
-		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false);
+		msm_mdss_enable_vreg(mp->vreg_config, mp->num_vreg, false);
 	}
 end:
 	return rc;
@@ -655,7 +674,10 @@
 
 	parent = dev->of_node;
 	for_each_child_of_node(parent, child) {
-		if (is_mdss_smmu_compatible_device(child->name))
+		char name[MDSS_SMMU_COMPAT_STR_LEN] = {};
+
+		strlcpy(name, child->name, sizeof(name));
+		if (is_mdss_smmu_compatible_device(name))
 			of_platform_device_create(child, NULL, dev);
 	}
 }
@@ -704,8 +726,7 @@
 	int rc = 0;
 	struct mdss_smmu_domain smmu_domain;
 	const struct of_device_id *match;
-	struct dss_module_power *mp;
-	int disable_htw = 1;
+	struct mdss_module_power *mp;
 	char name[MAX_CLIENT_NAME_LEN];
 	const __be32 *address = NULL, *size = NULL;
 
@@ -733,7 +754,7 @@
 		 * For old iommu driver we query the context bank device
 		 * rather than getting it from dt.
 		 */
-		dev = msm_iommu_get_ctx(smmu_domain.ctx_name);
+		dev = mdss_mmu_get_ctx(smmu_domain.ctx_name);
 		if (!dev) {
 			pr_err("Invalid SMMU ctx for domain:%d\n",
 				smmu_domain.domain);
@@ -743,13 +764,13 @@
 
 	mdss_smmu = &mdata->mdss_smmu[smmu_domain.domain];
 	mp = &mdss_smmu->mp;
-	memset(mp, 0, sizeof(struct dss_module_power));
+	memset(mp, 0, sizeof(struct mdss_module_power));
 
 	if (of_find_property(pdev->dev.of_node,
 		"gdsc-mmagic-mdss-supply", NULL)) {
 
 		mp->vreg_config = devm_kzalloc(&pdev->dev,
-			sizeof(struct dss_vreg), GFP_KERNEL);
+			sizeof(struct mdss_vreg), GFP_KERNEL);
 		if (!mp->vreg_config)
 			return -ENOMEM;
 
@@ -758,7 +779,7 @@
 		mp->num_vreg = 1;
 	}
 
-	rc = msm_dss_config_vreg(&pdev->dev, mp->vreg_config,
+	rc = msm_mdss_config_vreg(&pdev->dev, mp->vreg_config,
 		mp->num_vreg, true);
 	if (rc) {
 		pr_err("vreg config failed rc=%d\n", rc);
@@ -769,7 +790,7 @@
 	if (rc) {
 		pr_err("smmu clk register failed for domain[%d] with err:%d\n",
 			smmu_domain.domain, rc);
-		msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
+		msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
 			false);
 		return rc;
 	}
@@ -778,7 +799,7 @@
 	mdss_smmu->reg_bus_clt = mdss_reg_bus_vote_client_create(name);
 	if (IS_ERR(mdss_smmu->reg_bus_clt)) {
 		pr_err("mdss bus client register failed\n");
-		msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
+		msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
 			false);
 		return PTR_ERR(mdss_smmu->reg_bus_clt);
 	}
@@ -791,7 +812,7 @@
 	}
 
 	mdss_smmu->mmu_mapping = arm_iommu_create_mapping(
-		msm_iommu_get_bus(dev), smmu_domain.start, smmu_domain.size);
+		mdss_mmu_get_bus(dev), smmu_domain.start, smmu_domain.size);
 	if (IS_ERR(mdss_smmu->mmu_mapping)) {
 		pr_err("iommu create mapping failed for domain[%d]\n",
 			smmu_domain.domain);
@@ -799,13 +820,6 @@
 		goto disable_power;
 	}
 
-	rc = iommu_domain_set_attr(mdss_smmu->mmu_mapping->domain,
-		DOMAIN_ATTR_COHERENT_HTW_DISABLE, &disable_htw);
-	if (rc) {
-		pr_err("couldn't disable coherent HTW\n");
-		goto release_mapping;
-	}
-
 	if (smmu_domain.domain == MDSS_IOMMU_DOMAIN_SECURE ||
 		smmu_domain.domain == MDSS_IOMMU_DOMAIN_ROT_SECURE) {
 		int secure_vmid = VMID_CP_PIXEL;
@@ -848,7 +862,7 @@
 bus_client_destroy:
 	mdss_reg_bus_vote_client_destroy(mdss_smmu->reg_bus_clt);
 	mdss_smmu->reg_bus_clt = NULL;
-	msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
+	msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg,
 			false);
 	return rc;
 }
diff --git a/drivers/video/fbdev/msm/mdss_smmu.h b/drivers/video/fbdev/msm/mdss_smmu.h
index be2a55f..091af3b 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.h
+++ b/drivers/video/fbdev/msm/mdss_smmu.h
@@ -23,6 +23,7 @@
 #include "mdss_debug.h"
 
 #define MDSS_SMMU_COMPATIBLE "qcom,smmu"
+#define MDSS_SMMU_COMPAT_STR_LEN 10
 #define SMMU_CBN_FSYNR1		0x6c
 
 struct mdss_iommu_map_type {
diff --git a/drivers/video/fbdev/msm/mdss_sync.c b/drivers/video/fbdev/msm/mdss_sync.c
new file mode 100644
index 0000000..ed611e7
--- /dev/null
+++ b/drivers/video/fbdev/msm/mdss_sync.c
@@ -0,0 +1,453 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/fence.h>
+#include <linux/sync_file.h>
+
+#include "mdss_sync.h"
+
+#define MDSS_SYNC_NAME_SIZE		64
+#define MDSS_SYNC_DRIVER_NAME	"mdss"
+
+/**
+ * struct mdss_fence - sync fence context
+ * @base: base sync fence object
+ * @name: name of this sync fence
+ * @fence_list: linked list of outstanding sync fence
+ */
+struct mdss_fence {
+	struct fence base;
+	char name[MDSS_SYNC_NAME_SIZE];
+	struct list_head fence_list;
+};
+
+/**
+ * struct mdss_timeline - sync timeline context
+ * @kref: reference count of timeline
+ * @lock: serialization lock for timeline and fence update
+ * @name: name of timeline
+ * @fence_name: fence name prefix
+ * @next_value: next commit sequence number
+ * @value: current retired sequence number
+ * @context: fence context identifier
+ * @fence_list_head: linked list of outstanding sync fence
+ */
+struct mdss_timeline {
+	struct kref kref;
+	spinlock_t lock;
+	char name[MDSS_SYNC_NAME_SIZE];
+	u32 next_value;
+	u32 value;
+	u64 context;
+	struct list_head fence_list_head;
+};
+
+/*
+ * to_mdss_fence - get mdss fence from fence base object
+ * @fence: Pointer to fence base object
+ */
+static struct mdss_fence *to_mdss_fence(struct fence *fence)
+{
+	return container_of(fence, struct mdss_fence, base);
+}
+
+/*
+ * to_mdss_timeline - get mdss timeline from fence base object
+ * @fence: Pointer to fence base object
+ */
+static struct mdss_timeline *to_mdss_timeline(struct fence *fence)
+{
+	return container_of(fence->lock, struct mdss_timeline, lock);
+}
+
+/*
+ * mdss_free_timeline - Free the given timeline object
+ * @kref: Pointer to timeline kref object.
+ */
+static void mdss_free_timeline(struct kref *kref)
+{
+	struct mdss_timeline *tl =
+		container_of(kref, struct mdss_timeline, kref);
+
+	kfree(tl);
+}
+
+/*
+ * mdss_put_timeline - Put the given timeline object
+ * @tl: Pointer to timeline object.
+ */
+static void mdss_put_timeline(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	kref_put(&tl->kref, mdss_free_timeline);
+}
+
+/*
+ * mdss_get_timeline - Get the given timeline object
+ * @tl: Pointer to timeline object.
+ */
+static void mdss_get_timeline(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	kref_get(&tl->kref);
+}
+
+static const char *mdss_fence_get_driver_name(struct fence *fence)
+{
+	return MDSS_SYNC_DRIVER_NAME;
+}
+
+static const char *mdss_fence_get_timeline_name(struct fence *fence)
+{
+	struct mdss_timeline *tl = to_mdss_timeline(fence);
+
+	return tl->name;
+}
+
+static bool mdss_fence_enable_signaling(struct fence *fence)
+{
+	return true;
+}
+
+static bool mdss_fence_signaled(struct fence *fence)
+{
+	struct mdss_timeline *tl = to_mdss_timeline(fence);
+	bool status;
+
+	status = ((s32) (tl->value - fence->seqno)) >= 0;
+	pr_debug("status:%d fence seq:%d and timeline:%s:%d next %d\n",
+			status, fence->seqno, tl->name,
+			tl->value, tl->next_value);
+	return status;
+}
+
+static void mdss_fence_release(struct fence *fence)
+{
+	struct mdss_fence *f = to_mdss_fence(fence);
+	unsigned long flags;
+
+	spin_lock_irqsave(fence->lock, flags);
+	if (!list_empty(&f->fence_list))
+		list_del(&f->fence_list);
+	spin_unlock_irqrestore(fence->lock, flags);
+	mdss_put_timeline(to_mdss_timeline(fence));
+	kfree_rcu(f, base.rcu);
+}
+
+static void mdss_fence_value_str(struct fence *fence, char *str, int size)
+{
+	snprintf(str, size, "%u", fence->seqno);
+}
+
+static void mdss_fence_timeline_value_str(struct fence *fence, char *str,
+		int size)
+{
+	struct mdss_timeline *tl = to_mdss_timeline(fence);
+
+	snprintf(str, size, "%u", tl->value);
+}
+
+static struct fence_ops mdss_fence_ops = {
+	.get_driver_name = mdss_fence_get_driver_name,
+	.get_timeline_name = mdss_fence_get_timeline_name,
+	.enable_signaling = mdss_fence_enable_signaling,
+	.signaled = mdss_fence_signaled,
+	.wait = fence_default_wait,
+	.release = mdss_fence_release,
+	.fence_value_str = mdss_fence_value_str,
+	.timeline_value_str = mdss_fence_timeline_value_str,
+};
+
+/*
+ * mdss_create_timeline - Create timeline object with the given name
+ * @name: Pointer to name character string.
+ */
+struct mdss_timeline *mdss_create_timeline(const char *name)
+{
+	struct mdss_timeline *tl;
+
+	if (!name) {
+		pr_err("invalid parameters\n");
+		return NULL;
+	}
+
+	tl = kzalloc(sizeof(struct mdss_timeline), GFP_KERNEL);
+	if (!tl)
+		return NULL;
+
+	kref_init(&tl->kref);
+	snprintf(tl->name, sizeof(tl->name), "%s", name);
+	spin_lock_init(&tl->lock);
+	tl->context = fence_context_alloc(1);
+	INIT_LIST_HEAD(&tl->fence_list_head);
+
+	return tl;
+}
+
+/*
+ * mdss_destroy_timeline - Destroy the given timeline object
+ * @tl: Pointer to timeline object.
+ */
+void mdss_destroy_timeline(struct mdss_timeline *tl)
+{
+	mdss_put_timeline(tl);
+}
+
+/*
+ * mdss_inc_timeline_locked - Increment timeline by given amount
+ * @tl: Pointer to timeline object.
+ * @increment: the amount to increase the timeline by.
+ */
+static int mdss_inc_timeline_locked(struct mdss_timeline *tl,
+		int increment)
+{
+	struct mdss_fence *f, *next;
+
+	tl->value += increment;
+	list_for_each_entry_safe(f, next, &tl->fence_list_head, fence_list) {
+		if (fence_is_signaled_locked(&f->base)) {
+			pr_debug("%s signaled\n", f->name);
+			list_del_init(&f->fence_list);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * mdss_resync_timeline - Resync timeline to last committed value
+ * @tl: Pointer to timeline object.
+ */
+void mdss_resync_timeline(struct mdss_timeline *tl)
+{
+	unsigned long flags;
+	s32 val;
+
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	spin_lock_irqsave(&tl->lock, flags);
+	val = tl->next_value - tl->value;
+	if (val > 0) {
+		pr_warn("flush %s:%d\n", tl->name, val);
+		mdss_inc_timeline_locked(tl, val);
+	}
+	spin_unlock_irqrestore(&tl->lock, flags);
+}
+
+/*
+ * mdss_get_sync_fence - Create fence object from the given timeline
+ * @tl: Pointer to timeline object
+ * @timestamp: Pointer to timestamp of the returned fence. Null if not required.
+ * Return: pointer fence created on give time line.
+ */
+struct mdss_fence *mdss_get_sync_fence(
+		struct mdss_timeline *tl, const char *fence_name,
+		u32 *timestamp, int offset)
+{
+	struct mdss_fence *f;
+	unsigned long flags;
+	u32 val;
+
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return NULL;
+	}
+
+	f = kzalloc(sizeof(struct mdss_fence), GFP_KERNEL);
+	if (!f)
+		return NULL;
+
+	INIT_LIST_HEAD(&f->fence_list);
+	spin_lock_irqsave(&tl->lock, flags);
+	val = tl->next_value + offset;
+	tl->next_value += 1;
+	fence_init(&f->base, &mdss_fence_ops, &tl->lock, tl->context, val);
+	list_add_tail(&f->fence_list, &tl->fence_list_head);
+	mdss_get_timeline(tl);
+	spin_unlock_irqrestore(&tl->lock, flags);
+	snprintf(f->name, sizeof(f->name), "%s_%u", fence_name, val);
+
+	if (timestamp)
+		*timestamp = val;
+
+	pr_debug("fence created at val=%u tl->name %s next_value %d value %d offset %d\n",
+			val, tl->name, tl->next_value, tl->value, offset);
+
+	return (struct mdss_fence *) &f->base;
+}
+
+/*
+ * mdss_inc_timeline - Increment timeline by given amount
+ * @tl: Pointer to timeline object.
+ * @increment: the amount to increase the timeline by.
+ */
+int mdss_inc_timeline(struct mdss_timeline *tl, int increment)
+{
+	unsigned long flags;
+	int rc;
+
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&tl->lock, flags);
+	rc = mdss_inc_timeline_locked(tl, increment);
+	spin_unlock_irqrestore(&tl->lock, flags);
+
+	return rc;
+}
+
+/*
+ * mdss_get_timeline_commit_ts - Return commit tick of given timeline
+ * @tl: Pointer to timeline object.
+ */
+u32 mdss_get_timeline_commit_ts(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return 0;
+	}
+
+	return tl->next_value;
+}
+
+/*
+ * mdss_get_timeline_retire_ts - Return retire tick of given timeline
+ * @tl: Pointer to timeline object.
+ */
+u32 mdss_get_timeline_retire_ts(struct mdss_timeline *tl)
+{
+	if (!tl) {
+		pr_err("invalid parameters\n");
+		return 0;
+	}
+
+	return tl->value;
+}
+
+/*
+ * mdss_put_sync_fence - Destroy given fence object
+ * @fence: Pointer to fence object.
+ */
+void mdss_put_sync_fence(struct mdss_fence *fence)
+{
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return;
+	}
+
+	fence_put((struct fence *) fence);
+}
+
+/*
+ * mdss_wait_sync_fence - Wait until fence signal or timeout
+ * @fence: Pointer to fence object.
+ * @timeout: maximum wait time, in msec, for fence to signal.
+ */
+int mdss_wait_sync_fence(struct mdss_fence *fence,
+		long timeout)
+{
+	int rc;
+
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	rc = fence_wait_timeout((struct fence *) fence, false,
+			msecs_to_jiffies(timeout));
+	if (rc > 0) {
+		pr_debug("fence signaled\n");
+		rc = 0;
+	} else if (rc == 0) {
+		pr_debug("fence timeout\n");
+		rc = -ETIMEDOUT;
+	}
+
+	return rc;
+}
+
+/*
+ * mdss_get_fd_sync_fence - Get fence object of given file descriptor
+ * @fd: File description of fence object.
+ */
+struct mdss_fence *mdss_get_fd_sync_fence(int fd)
+{
+	return (struct mdss_fence *) sync_file_get_fence(fd);
+}
+
+/*
+ * mdss_get_sync_fence_fd - Get file descriptor of given fence object
+ * @fence: Pointer to fence object.
+ * Return: File descriptor on success, or error code on error
+ */
+int mdss_get_sync_fence_fd(struct mdss_fence *fence)
+{
+	int fd;
+	struct sync_file *sync_file;
+
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return -EINVAL;
+	}
+
+	fd = get_unused_fd_flags(O_CLOEXEC);
+	if (fd < 0) {
+		pr_err("fail to get unused fd\n");
+		return fd;
+	}
+
+	sync_file = sync_file_create((struct fence *) fence);
+	if (!sync_file) {
+		put_unused_fd(fd);
+		pr_err("failed to create sync file\n");
+		return -ENOMEM;
+	}
+
+	fd_install(fd, sync_file->file);
+
+	return fd;
+}
+
+/*
+ * mdss_put_sync_fence - Destroy given fence object
+ * @fence: Pointer to fence object.
+ * Return: fence name
+ */
+const char *mdss_get_sync_fence_name(struct mdss_fence *fence)
+{
+	if (!fence) {
+		pr_err("invalid parameters\n");
+		return NULL;
+	}
+
+	return fence->name;
+}
diff --git a/drivers/video/fbdev/msm/mdss_sync.h b/drivers/video/fbdev/msm/mdss_sync.h
new file mode 100644
index 0000000..39a1aa7b
--- /dev/null
+++ b/drivers/video/fbdev/msm/mdss_sync.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 MDSS_SYNC_H
+#define MDSS_SYNC_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+
+struct mdss_fence;
+struct mdss_timeline;
+
+#if defined(CONFIG_SYNC_FILE)
+struct mdss_timeline *mdss_create_timeline(const char *name);
+
+void mdss_destroy_timeline(struct mdss_timeline *tl);
+
+struct mdss_fence *mdss_get_sync_fence(
+		struct mdss_timeline *tl, const char *fence_name,
+		u32 *timestamp, int offset);
+
+void mdss_resync_timeline(struct mdss_timeline *tl);
+
+u32 mdss_get_timeline_commit_ts(struct mdss_timeline *tl);
+
+u32 mdss_get_timeline_retire_ts(struct mdss_timeline *tl);
+
+int mdss_inc_timeline(struct mdss_timeline *tl, int increment);
+
+void mdss_put_sync_fence(struct mdss_fence *fence);
+
+int mdss_wait_sync_fence(struct mdss_fence *fence,
+		long timeout);
+
+struct mdss_fence *mdss_get_fd_sync_fence(int fd);
+
+int mdss_get_sync_fence_fd(struct mdss_fence *fence);
+const char *mdss_get_sync_fence_name(struct mdss_fence *fence);
+#else
+static inline
+struct mdss_timeline *mdss_create_timeline(const char *name)
+{
+	return NULL;
+}
+
+static inline
+void mdss_destroy_timeline(struct mdss_timeline *tl)
+{
+}
+
+static inline
+struct mdss_fence *mdss_get_sync_fence(
+		struct mdss_timeline *tl, const char *fence_name,
+		u32 *timestamp, int offset)
+{
+	return NULL;
+}
+
+static inline
+void mdss_resync_timeline(struct mdss_timeline *tl)
+{
+}
+
+static inline
+int mdss_inc_timeline(struct mdss_timeline *tl, int increment)
+{
+	return 0;
+}
+
+static inline
+u32 mdss_get_timeline_commit_ts(struct mdss_timeline *tl)
+{
+	return 0;
+}
+
+static inline
+u32 mdss_get_timeline_retire_ts(struct mdss_timeline *tl)
+{
+	return 0;
+}
+
+static inline
+void mdss_put_sync_fence(struct mdss_fence *fence)
+{
+}
+
+static inline
+int mdss_wait_sync_fence(struct mdss_fence *fence,
+		long timeout)
+{
+	return 0;
+}
+
+static inline
+struct mdss_fence *mdss_get_fd_sync_fence(int fd)
+{
+	return NULL;
+}
+
+static inline
+int mdss_get_sync_fence_fd(struct mdss_fence *fence)
+{
+	return -EBADF;
+}
+const char *mdss_get_sync_fence_name(struct mdss_fence *fence)
+{
+	return NULL;
+}
+}
+#endif
+
+#endif /* MDSS_SYNC_H */
diff --git a/drivers/video/fbdev/msm/mdss_wb.c b/drivers/video/fbdev/msm/mdss_wb.c
index 4b509ec..c8c5d47 100644
--- a/drivers/video/fbdev/msm/mdss_wb.c
+++ b/drivers/video/fbdev/msm/mdss_wb.c
@@ -22,7 +22,8 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/version.h>
-#include <linux/switch.h>
+#include <linux/extcon.h>
+#include <linux/module.h>
 
 #include "mdss_panel.h"
 #include "mdss_wb.h"
@@ -94,6 +95,11 @@
 	return 0;
 }
 
+static const unsigned int mdss_wb_disp_supported_cable[] = {
+	EXTCON_DISP_HMD + 1, /* For WFD */
+	EXTCON_NONE,
+};
+
 static int mdss_wb_dev_init(struct mdss_wb_ctrl *wb_ctrl)
 {
 	int rc = 0;
@@ -103,8 +109,11 @@
 		return -ENODEV;
 	}
 
+	memset(&wb_ctrl->sdev, 0x0, sizeof(wb_ctrl->sdev));
+	wb_ctrl->sdev.supported_cable = mdss_wb_disp_supported_cable;
+	wb_ctrl->sdev.dev.parent = &wb_ctrl->pdev->dev;
 	wb_ctrl->sdev.name = "wfd";
-	rc = switch_dev_register(&wb_ctrl->sdev);
+	rc = extcon_dev_register(&wb_ctrl->sdev);
 	if (rc) {
 		pr_err("Failed to setup switch dev for writeback panel");
 		return rc;
@@ -120,7 +129,7 @@
 		return -ENODEV;
 	}
 
-	switch_dev_unregister(&wb_ctrl->sdev);
+	extcon_dev_unregister(&wb_ctrl->sdev);
 	return 0;
 }
 
diff --git a/drivers/video/fbdev/msm/mdss_wb.h b/drivers/video/fbdev/msm/mdss_wb.h
index 9cc88b6..010a123 100644
--- a/drivers/video/fbdev/msm/mdss_wb.h
+++ b/drivers/video/fbdev/msm/mdss_wb.h
@@ -14,12 +14,12 @@
 #ifndef MDSS_WB_H
 #define MDSS_WB_H
 
-#include <linux/switch.h>
+#include <linux/extcon.h>
 
 struct mdss_wb_ctrl {
 	struct platform_device *pdev;
 	struct mdss_panel_data pdata;
-	struct switch_dev sdev;
+	struct extcon_dev sdev;
 };
 
 #endif
diff --git a/drivers/video/fbdev/msm/mhl_sii8334.c b/drivers/video/fbdev/msm/mhl_sii8334.c
index 5d0ac99..cf45eb6 100644
--- a/drivers/video/fbdev/msm/mhl_sii8334.c
+++ b/drivers/video/fbdev/msm/mhl_sii8334.c
@@ -240,7 +240,7 @@
 {
 	int i, rc = 0;
 	struct device_node *of_node = NULL;
-	struct dss_gpio *temp_gpio = NULL;
+	struct mdss_gpio *temp_gpio = NULL;
 	struct platform_device *hdmi_pdev = NULL;
 	struct device_node *hdmi_tx_node = NULL;
 	int dt_gpio;
@@ -262,7 +262,7 @@
 
 	/* GPIOs */
 	temp_gpio = NULL;
-	temp_gpio = devm_kzalloc(dev, sizeof(struct dss_gpio), GFP_KERNEL);
+	temp_gpio = devm_kzalloc(dev, sizeof(struct mdss_gpio), GFP_KERNEL);
 	pr_debug("%s: gpios allocd\n", __func__);
 	if (!(temp_gpio)) {
 		pr_err("%s: can't alloc %d gpio mem\n", __func__, i);
@@ -283,7 +283,7 @@
 
 	/* PWR */
 	temp_gpio = NULL;
-	temp_gpio = devm_kzalloc(dev, sizeof(struct dss_gpio), GFP_KERNEL);
+	temp_gpio = devm_kzalloc(dev, sizeof(struct mdss_gpio), GFP_KERNEL);
 	pr_debug("%s: gpios allocd\n", __func__);
 	if (!(temp_gpio)) {
 		pr_err("%s: can't alloc %d gpio mem\n", __func__, i);
@@ -303,7 +303,7 @@
 
 	/* INTR */
 	temp_gpio = NULL;
-	temp_gpio = devm_kzalloc(dev, sizeof(struct dss_gpio), GFP_KERNEL);
+	temp_gpio = devm_kzalloc(dev, sizeof(struct mdss_gpio), GFP_KERNEL);
 	pr_debug("%s: gpios allocd\n", __func__);
 	if (!(temp_gpio)) {
 		pr_err("%s: can't alloc %d gpio mem\n", __func__, i);
@@ -1716,7 +1716,7 @@
 static int mhl_gpio_config(struct mhl_tx_ctrl *mhl_ctrl, int on)
 {
 	int ret;
-	struct dss_gpio *temp_reset_gpio, *temp_intr_gpio;
+	struct mdss_gpio *temp_reset_gpio, *temp_intr_gpio;
 
 	/* caused too many line spills */
 	temp_reset_gpio = mhl_ctrl->pdata->gpios[MHL_TX_RESET_GPIO];
diff --git a/drivers/video/fbdev/msm/msm_dba/adv7533.c b/drivers/video/fbdev/msm/msm_dba/adv7533.c
index b628e1a..5b44a49 100644
--- a/drivers/video/fbdev/msm/msm_dba/adv7533.c
+++ b/drivers/video/fbdev/msm/msm_dba/adv7533.c
@@ -125,7 +125,7 @@
 	struct pinctrl_state *pinctrl_state_suspend;
 	bool audio;
 	bool disable_gpios;
-	struct dss_module_power power_data;
+	struct mdss_module_power power_data;
 	bool hdcp_enabled;
 	bool cec_enabled;
 	bool is_power_on;
@@ -433,7 +433,7 @@
 }
 
 static void adv7533_parse_vreg_dt(struct device *dev,
-				struct dss_module_power *mp)
+				struct mdss_module_power *mp)
 {
 	int i, rc = 0;
 	int dt_vreg_total = 0;
@@ -449,7 +449,7 @@
 		goto end;
 	}
 	mp->num_vreg = dt_vreg_total;
-	mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
+	mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) *
 			dt_vreg_total, GFP_KERNEL);
 	if (!mp->vreg_config)
 		goto end;
@@ -1471,7 +1471,7 @@
 static int adv7533_config_vreg(struct adv7533 *pdata, int enable)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 
 	if (!pdata) {
 		pr_err("invalid input\n");
@@ -1486,7 +1486,7 @@
 	}
 
 	if (enable) {
-		rc = msm_dss_config_vreg(&pdata->i2c_client->dev,
+		rc = msm_mdss_config_vreg(&pdata->i2c_client->dev,
 					power_data->vreg_config,
 					power_data->num_vreg, 1);
 		if (rc) {
@@ -1495,7 +1495,7 @@
 			goto exit;
 		}
 	} else {
-		rc = msm_dss_config_vreg(&pdata->i2c_client->dev,
+		rc = msm_mdss_config_vreg(&pdata->i2c_client->dev,
 					power_data->vreg_config,
 					power_data->num_vreg, 0);
 		if (rc) {
@@ -1512,7 +1512,7 @@
 static int adv7533_enable_vreg(struct adv7533 *pdata, int enable)
 {
 	int rc = 0;
-	struct dss_module_power *power_data = NULL;
+	struct mdss_module_power *power_data = NULL;
 
 	if (!pdata) {
 		pr_err("invalid input\n");
@@ -1527,7 +1527,7 @@
 	}
 
 	if (enable) {
-		rc = msm_dss_enable_vreg(power_data->vreg_config,
+		rc = msm_mdss_enable_vreg(power_data->vreg_config,
 					power_data->num_vreg, 1);
 		if (rc) {
 			pr_err("%s: Failed to enable vreg. Err=%d\n",
@@ -1535,7 +1535,7 @@
 			goto exit;
 		}
 	} else {
-		rc = msm_dss_enable_vreg(power_data->vreg_config,
+		rc = msm_mdss_enable_vreg(power_data->vreg_config,
 					power_data->num_vreg, 0);
 		if (rc) {
 			pr_err("%s: Failed to disable vreg. Err=%d\n",
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 05a7fc0..39d26a4 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -2314,7 +2314,7 @@
 			if ((ctrl->ctrl_state & CTRL_STATE_DSI_ACTIVE) &&
 				(i != DSI_CORE_PM))
 				continue;
-			rc = msm_dss_enable_vreg(
+			rc = msm_mdss_enable_vreg(
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, 0);
 			if (rc) {
@@ -2374,7 +2374,7 @@
 				(!pdata->panel_info.cont_splash_enabled) &&
 				(i != DSI_CORE_PM))
 				continue;
-			rc = msm_dss_enable_vreg(
+			rc = msm_mdss_enable_vreg(
 				sdata->power_data[i].vreg_config,
 				sdata->power_data[i].num_vreg, 1);
 			if (rc) {
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index e4b48f3..c56253a 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -1253,7 +1253,7 @@
 	/* Lock all pages first so we can lock the extent safely. */
 	ret = io_ctl_prepare_pages(io_ctl, inode, 0);
 	if (ret)
-		goto out;
+		goto out_unlock;
 
 	lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
 			 &cached_state);
@@ -1346,6 +1346,7 @@
 out_nospc:
 	cleanup_write_cache_enospc(inode, io_ctl, &cached_state, &bitmap_list);
 
+out_unlock:
 	if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
 		up_write(&block_group->data_rwsem);
 
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 1493ceb..ec03cf6 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -114,6 +114,10 @@
 	int who = arg;
 	type = PIDTYPE_PID;
 	if (who < 0) {
+		/* avoid overflow below */
+		if (who == INT_MIN)
+			return;
+
 		type = PIDTYPE_PGID;
 		who = -who;
 	}
diff --git a/fs/nfs_common/grace.c b/fs/nfs_common/grace.c
index fd8c9a5..77d136a 100644
--- a/fs/nfs_common/grace.c
+++ b/fs/nfs_common/grace.c
@@ -30,7 +30,11 @@
 	struct list_head *grace_list = net_generic(net, grace_net_id);
 
 	spin_lock(&grace_lock);
-	list_add(&lm->list, grace_list);
+	if (list_empty(&lm->list))
+		list_add(&lm->list, grace_list);
+	else
+		WARN(1, "double list_add attempt detected in net %x %s\n",
+		     net->ns.inum, (net == &init_net) ? "(init_net)" : "");
 	spin_unlock(&grace_lock);
 }
 EXPORT_SYMBOL_GPL(locks_start_grace);
@@ -104,7 +108,9 @@
 {
 	struct list_head *grace_list = net_generic(net, grace_net_id);
 
-	BUG_ON(!list_empty(grace_list));
+	WARN_ONCE(!list_empty(grace_list),
+		  "net %x %s: grace_list is not empty\n",
+		  net->ns.inum, __func__);
 }
 
 static struct pernet_operations grace_net_ops = {
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 75f942a..81c018e 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -59,10 +59,10 @@
 				gi->gid[i] = exp->ex_anon_gid;
 			else
 				gi->gid[i] = rqgi->gid[i];
-
-			/* Each thread allocates its own gi, no race */
-			groups_sort(gi);
 		}
+
+		/* Each thread allocates its own gi, no race */
+		groups_sort(gi);
 	} else {
 		gi = get_group_info(rqgi);
 	}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9ebb2d7..f463c4e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -63,12 +63,16 @@
 static const stateid_t currentstateid = {
 	.si_generation = 1,
 };
+static const stateid_t close_stateid = {
+	.si_generation = 0xffffffffU,
+};
 
 static u64 current_sessionid = 1;
 
 #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))
 #define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))
 #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
+#define CLOSE_STATEID(stateid)  (!memcmp((stateid), &close_stateid, sizeof(stateid_t)))
 
 /* forward declarations */
 static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
@@ -4866,7 +4870,8 @@
 	struct nfs4_stid *s;
 	__be32 status = nfserr_bad_stateid;
 
-	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
+		CLOSE_STATEID(stateid))
 		return status;
 	/* Client debugging aid. */
 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
@@ -4924,7 +4929,8 @@
 	else if (typemask & NFS4_DELEG_STID)
 		typemask |= NFS4_REVOKED_DELEG_STID;
 
-	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
+	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
+		CLOSE_STATEID(stateid))
 		return nfserr_bad_stateid;
 	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
 	if (status == nfserr_stale_clientid) {
@@ -5175,15 +5181,9 @@
 	status = nfsd4_check_seqid(cstate, sop, seqid);
 	if (status)
 		return status;
-	if (stp->st_stid.sc_type == NFS4_CLOSED_STID
-		|| stp->st_stid.sc_type == NFS4_REVOKED_DELEG_STID)
-		/*
-		 * "Closed" stateid's exist *only* to return
-		 * nfserr_replay_me from the previous step, and
-		 * revoked delegations are kept only for free_stateid.
-		 */
-		return nfserr_bad_stateid;
-	mutex_lock(&stp->st_mutex);
+	status = nfsd4_lock_ol_stateid(stp);
+	if (status != nfs_ok)
+		return status;
 	status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
 	if (status == nfs_ok)
 		status = nfs4_check_fh(current_fh, &stp->st_stid);
@@ -5407,6 +5407,11 @@
 	nfsd4_close_open_stateid(stp);
 	mutex_unlock(&stp->st_mutex);
 
+	/* See RFC5661 sectionm 18.2.4 */
+	if (stp->st_stid.sc_client->cl_minorversion)
+		memcpy(&close->cl_stateid, &close_stateid,
+				sizeof(close->cl_stateid));
+
 	/* put reference from nfs4_preprocess_seqid_op */
 	nfs4_put_stid(&stp->st_stid);
 out:
@@ -7007,6 +7012,10 @@
 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
 	nn->conf_name_tree = RB_ROOT;
 	nn->unconf_name_tree = RB_ROOT;
+	nn->boot_time = get_seconds();
+	nn->grace_ended = false;
+	nn->nfsd4_manager.block_opens = true;
+	INIT_LIST_HEAD(&nn->nfsd4_manager.list);
 	INIT_LIST_HEAD(&nn->client_lru);
 	INIT_LIST_HEAD(&nn->close_lru);
 	INIT_LIST_HEAD(&nn->del_recall_lru);
@@ -7064,9 +7073,6 @@
 	ret = nfs4_state_create_net(net);
 	if (ret)
 		return ret;
-	nn->boot_time = get_seconds();
-	nn->grace_ended = false;
-	nn->nfsd4_manager.block_opens = true;
 	locks_start_grace(net, &nn->nfsd4_manager);
 	nfsd4_client_tracking_init(net);
 	printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c
index fe2cbeb..939aa06 100644
--- a/fs/orangefs/devorangefs-req.c
+++ b/fs/orangefs/devorangefs-req.c
@@ -161,7 +161,7 @@
 	struct orangefs_kernel_op_s *op, *temp;
 	__s32 proto_ver = ORANGEFS_KERNEL_PROTO_VERSION;
 	static __s32 magic = ORANGEFS_DEVREQ_MAGIC;
-	struct orangefs_kernel_op_s *cur_op = NULL;
+	struct orangefs_kernel_op_s *cur_op;
 	unsigned long ret;
 
 	/* We do not support blocking IO. */
@@ -181,6 +181,7 @@
 	}
 
 restart:
+	cur_op = NULL;
 	/* Get next op (if any) from top of list. */
 	spin_lock(&orangefs_request_list_lock);
 	list_for_each_entry_safe(op, temp, &orangefs_request_list, list) {
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index 02cc613..5b2cbe5 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -446,7 +446,7 @@
 static ssize_t orangefs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
 	struct file *file = iocb->ki_filp;
-	loff_t pos = *(&iocb->ki_pos);
+	loff_t pos = iocb->ki_pos;
 	ssize_t rc = 0;
 
 	BUG_ON(iocb->private);
@@ -485,9 +485,6 @@
 		}
 	}
 
-	if (file->f_pos > i_size_read(file->f_mapping->host))
-		orangefs_i_size_write(file->f_mapping->host, file->f_pos);
-
 	rc = generic_write_checks(iocb, iter);
 
 	if (rc <= 0) {
@@ -501,7 +498,7 @@
 	 * pos to the end of the file, so we will wait till now to set
 	 * pos...
 	 */
-	pos = *(&iocb->ki_pos);
+	pos = iocb->ki_pos;
 
 	rc = do_readv_writev(ORANGEFS_IO_WRITE,
 			     file,
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h
index 45dd8f2..f28381a 100644
--- a/fs/orangefs/orangefs-kernel.h
+++ b/fs/orangefs/orangefs-kernel.h
@@ -570,17 +570,6 @@
 	sys_attr.mask = ORANGEFS_ATTR_SYS_ALL_SETABLE;			\
 } while (0)
 
-static inline void orangefs_i_size_write(struct inode *inode, loff_t i_size)
-{
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-	inode_lock(inode);
-#endif
-	i_size_write(inode, i_size);
-#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
-	inode_unlock(inode);
-#endif
-}
-
 static inline void orangefs_set_timeout(struct dentry *dentry)
 {
 	unsigned long time = jiffies + orangefs_dcache_timeout_msecs*HZ/1000;
diff --git a/fs/orangefs/waitqueue.c b/fs/orangefs/waitqueue.c
index abcfa3f..f61b008 100644
--- a/fs/orangefs/waitqueue.c
+++ b/fs/orangefs/waitqueue.c
@@ -28,10 +28,10 @@
  */
 void purge_waiting_ops(void)
 {
-	struct orangefs_kernel_op_s *op;
+	struct orangefs_kernel_op_s *op, *tmp;
 
 	spin_lock(&orangefs_request_list_lock);
-	list_for_each_entry(op, &orangefs_request_list, list) {
+	list_for_each_entry_safe(op, tmp, &orangefs_request_list, list) {
 		gossip_debug(GOSSIP_WAIT_DEBUG,
 			     "pvfs2-client-core: purging op tag %llu %s\n",
 			     llu(op->tag),
diff --git a/fs/pipe.c b/fs/pipe.c
index 8e0d9f2..9faecf1 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1018,13 +1018,19 @@
 
 /*
  * Currently we rely on the pipe array holding a power-of-2 number
- * of pages.
+ * of pages. Returns 0 on error.
  */
 static inline unsigned int round_pipe_size(unsigned int size)
 {
 	unsigned long nr_pages;
 
+	if (size < pipe_min_size)
+		size = pipe_min_size;
+
 	nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	if (nr_pages == 0)
+		return 0;
+
 	return roundup_pow_of_two(nr_pages) << PAGE_SHIFT;
 }
 
@@ -1040,6 +1046,8 @@
 	long ret = 0;
 
 	size = round_pipe_size(arg);
+	if (size == 0)
+		return -EINVAL;
 	nr_pages = size >> PAGE_SHIFT;
 
 	if (!nr_pages)
@@ -1123,13 +1131,18 @@
 int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
 		 size_t *lenp, loff_t *ppos)
 {
+	unsigned int rounded_pipe_max_size;
 	int ret;
 
 	ret = proc_dointvec_minmax(table, write, buf, lenp, ppos);
 	if (ret < 0 || !write)
 		return ret;
 
-	pipe_max_size = round_pipe_size(pipe_max_size);
+	rounded_pipe_max_size = round_pipe_size(pipe_max_size);
+	if (rounded_pipe_max_size == 0)
+		return -EINVAL;
+
+	pipe_max_size = rounded_pipe_max_size;
 	return ret;
 }
 
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 1bfac28..f9246ac 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2985,7 +2985,8 @@
 	pr_info("VFS: Dquot-cache hash table entries: %ld (order %ld,"
 		" %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order));
 
-	register_shrinker(&dqcache_shrinker);
+	if (register_shrinker(&dqcache_shrinker))
+		panic("Cannot register dquot shrinker");
 
 	return 0;
 }
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index dc198bc..edc8ef7 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -513,9 +513,17 @@
 			       "inode has negative prealloc blocks count.");
 #endif
 	while (ei->i_prealloc_count > 0) {
-		reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
-		ei->i_prealloc_block++;
+		b_blocknr_t block_to_free;
+
+		/*
+		 * reiserfs_free_prealloc_block can drop the write lock,
+		 * which could allow another caller to free the same block.
+		 * We can protect against it by modifying the prealloc
+		 * state before calling it.
+		 */
+		block_to_free = ei->i_prealloc_block++;
 		ei->i_prealloc_count--;
+		reiserfs_free_prealloc_block(th, inode, block_to_free);
 		dirty = 1;
 	}
 	if (dirty)
@@ -1128,7 +1136,7 @@
 	hint->prealloc_size = 0;
 
 	if (!hint->formatted_node && hint->preallocate) {
-		if (S_ISREG(hint->inode->i_mode)
+		if (S_ISREG(hint->inode->i_mode) && !IS_PRIVATE(hint->inode)
 		    && hint->inode->i_size >=
 		    REISERFS_SB(hint->th->t_super)->s_alloc_options.
 		    preallocmin * hint->inode->i_sb->s_blocksize)
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 0a6ad4e..e101d70 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -2521,7 +2521,6 @@
 		return err;
 	if (inode->i_size < off + len - towrite)
 		i_size_write(inode, off + len - towrite);
-	inode->i_version++;
 	inode->i_mtime = inode->i_ctime = current_time(inode);
 	mark_inode_dirty(inode);
 	return len - towrite;
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index d31cd1e..f3acecf 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -391,7 +391,7 @@
 	       (ip->i_df.if_flags & XFS_IFEXTENTS));
 	ASSERT(offset <= mp->m_super->s_maxbytes);
 
-	if (offset + count > mp->m_super->s_maxbytes)
+	if ((xfs_ufsize_t)offset + count > mp->m_super->s_maxbytes)
 		count = mp->m_super->s_maxbytes - offset;
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
@@ -1295,7 +1295,7 @@
 	if (mapping_size > size)
 		mapping_size = size;
 	if (offset < i_size_read(inode) &&
-	    offset + mapping_size >= i_size_read(inode)) {
+	    (xfs_ufsize_t)offset + mapping_size >= i_size_read(inode)) {
 		/* limit mapping to block that spans EOF */
 		mapping_size = roundup_64(i_size_read(inode) - offset,
 					  i_blocksize(inode));
@@ -1347,7 +1347,7 @@
 	lockmode = xfs_ilock_data_map_shared(ip);
 
 	ASSERT(offset <= mp->m_super->s_maxbytes);
-	if (offset + size > mp->m_super->s_maxbytes)
+	if ((xfs_ufsize_t)offset + size > mp->m_super->s_maxbytes)
 		size = mp->m_super->s_maxbytes - offset;
 	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size);
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index eca7bae..3f45d98 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -1785,22 +1785,27 @@
 	btp->bt_bdi = blk_get_backing_dev_info(bdev);
 
 	if (xfs_setsize_buftarg_early(btp, bdev))
-		goto error;
+		goto error_free;
 
 	if (list_lru_init(&btp->bt_lru))
-		goto error;
+		goto error_free;
 
 	if (percpu_counter_init(&btp->bt_io_count, 0, GFP_KERNEL))
-		goto error;
+		goto error_lru;
 
 	btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count;
 	btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan;
 	btp->bt_shrinker.seeks = DEFAULT_SEEKS;
 	btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE;
-	register_shrinker(&btp->bt_shrinker);
+	if (register_shrinker(&btp->bt_shrinker))
+		goto error_pcpu;
 	return btp;
 
-error:
+error_pcpu:
+	percpu_counter_destroy(&btp->bt_io_count);
+error_lru:
+	list_lru_destroy(&btp->bt_lru);
+error_free:
 	kmem_free(btp);
 	return NULL;
 }
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 9d06cc3..7a7b3cc 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -1004,14 +1004,22 @@
 	 * holding the lock before removing the dquot from the AIL.
 	 */
 	if ((lip->li_flags & XFS_LI_IN_AIL) &&
-	    lip->li_lsn == qip->qli_flush_lsn) {
+	    ((lip->li_lsn == qip->qli_flush_lsn) ||
+	     (lip->li_flags & XFS_LI_FAILED))) {
 
 		/* xfs_trans_ail_delete() drops the AIL lock. */
 		spin_lock(&ailp->xa_lock);
-		if (lip->li_lsn == qip->qli_flush_lsn)
+		if (lip->li_lsn == qip->qli_flush_lsn) {
 			xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
-		else
+		} else {
+			/*
+			 * Clear the failed state since we are about to drop the
+			 * flush lock
+			 */
+			if (lip->li_flags & XFS_LI_FAILED)
+				xfs_clear_li_failed(lip);
 			spin_unlock(&ailp->xa_lock);
+		}
 	}
 
 	/*
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 2c7a162..664dea1 100644
--- a/fs/xfs/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -137,6 +137,26 @@
 	wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
 }
 
+/*
+ * Callback used to mark a buffer with XFS_LI_FAILED when items in the buffer
+ * have been failed during writeback
+ *
+ * this informs the AIL that the dquot is already flush locked on the next push,
+ * and acquires a hold on the buffer to ensure that it isn't reclaimed before
+ * dirty data makes it to disk.
+ */
+STATIC void
+xfs_dquot_item_error(
+	struct xfs_log_item	*lip,
+	struct xfs_buf		*bp)
+{
+	struct xfs_dquot	*dqp;
+
+	dqp = DQUOT_ITEM(lip)->qli_dquot;
+	ASSERT(!completion_done(&dqp->q_flush));
+	xfs_set_li_failed(lip, bp);
+}
+
 STATIC uint
 xfs_qm_dquot_logitem_push(
 	struct xfs_log_item	*lip,
@@ -144,13 +164,28 @@
 					      __acquires(&lip->li_ailp->xa_lock)
 {
 	struct xfs_dquot	*dqp = DQUOT_ITEM(lip)->qli_dquot;
-	struct xfs_buf		*bp = NULL;
+	struct xfs_buf		*bp = lip->li_buf;
 	uint			rval = XFS_ITEM_SUCCESS;
 	int			error;
 
 	if (atomic_read(&dqp->q_pincount) > 0)
 		return XFS_ITEM_PINNED;
 
+	/*
+	 * The buffer containing this item failed to be written back
+	 * previously. Resubmit the buffer for IO
+	 */
+	if (lip->li_flags & XFS_LI_FAILED) {
+		if (!xfs_buf_trylock(bp))
+			return XFS_ITEM_LOCKED;
+
+		if (!xfs_buf_resubmit_failed_buffers(bp, lip, buffer_list))
+			rval = XFS_ITEM_FLUSHING;
+
+		xfs_buf_unlock(bp);
+		return rval;
+	}
+
 	if (!xfs_dqlock_nowait(dqp))
 		return XFS_ITEM_LOCKED;
 
@@ -242,7 +277,8 @@
 	.iop_unlock	= xfs_qm_dquot_logitem_unlock,
 	.iop_committed	= xfs_qm_dquot_logitem_committed,
 	.iop_push	= xfs_qm_dquot_logitem_push,
-	.iop_committing = xfs_qm_dquot_logitem_committing
+	.iop_committing = xfs_qm_dquot_logitem_committing,
+	.iop_error	= xfs_dquot_item_error
 };
 
 /*
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 98ca9f1..c5f2f1e 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2430,6 +2430,24 @@
 }
 
 /*
+ * Free any local-format buffers sitting around before we reset to
+ * extents format.
+ */
+static inline void
+xfs_ifree_local_data(
+	struct xfs_inode	*ip,
+	int			whichfork)
+{
+	struct xfs_ifork	*ifp;
+
+	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL)
+		return;
+
+	ifp = XFS_IFORK_PTR(ip, whichfork);
+	xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
+}
+
+/*
  * This is called to return an inode to the inode free list.
  * The inode should already be truncated to 0 length and have
  * no pages associated with it.  This routine also assumes that
@@ -2466,6 +2484,9 @@
 	if (error)
 		return error;
 
+	xfs_ifree_local_data(ip, XFS_DATA_FORK);
+	xfs_ifree_local_data(ip, XFS_ATTR_FORK);
+
 	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */
 	ip->i_d.di_flags = 0;
 	ip->i_d.di_dmevmask = 0;
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 530a1d6..07b2e96 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -59,6 +59,23 @@
 	void (*detach)(struct drm_bridge *bridge);
 
 	/**
+	 * @connector_init:
+	 *
+	 * This callback is used to init the connector from bridge side. In some
+	 * cases connector and bridge are created in different modules, and the
+	 * connector ops might need extra info from bridge. This callback offers
+	 * the opportunity to overwrite connector's behavior in external bridge.
+	 *
+	 * The connector_init callback is optional.
+	 *
+	 * RETURNS:
+	 *
+	 * Zero on success, error code on failure.
+	 */
+	int (*connector_init)(struct drm_bridge *bridge,
+				struct drm_connector *connector);
+
+	/**
 	 * @mode_fixup:
 	 *
 	 * This callback is used to validate and adjust a mode. The paramater
@@ -214,5 +231,7 @@
 			struct drm_display_mode *adjusted_mode);
 void drm_bridge_pre_enable(struct drm_bridge *bridge);
 void drm_bridge_enable(struct drm_bridge *bridge);
+int drm_bridge_connector_init(struct drm_bridge *bridge,
+	struct drm_connector *connector);
 
 #endif
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index b28c4a3..9a5114d 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -560,6 +560,7 @@
  * @tile_v_loc: vertical location of this tile
  * @tile_h_size: horizontal size of this tile.
  * @tile_v_size: vertical size of this tile.
+ * @private: connector private data.
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -726,6 +727,8 @@
 	uint8_t num_h_tile, num_v_tile;
 	uint8_t tile_h_loc, tile_v_loc;
 	uint16_t tile_h_size, tile_v_size;
+
+	void *private;
 };
 
 #define obj_to_connector(x) container_of(x, struct drm_connector, base)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 0dbddb3..3c2024d 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -140,6 +140,10 @@
 #define MIPI_DSI_CLOCK_NON_CONTINUOUS	BIT(10)
 /* transmit data in low power */
 #define MIPI_DSI_MODE_LPM		BIT(11)
+/* disable BLLP area */
+#define MIPI_DSI_MODE_VIDEO_BLLP	BIT(12)
+/* disable EOF BLLP area */
+#define MIPI_DSI_MODE_VIDEO_EOF_BLLP	BIT(13)
 
 enum mipi_dsi_pixel_format {
 	MIPI_DSI_FMT_RGB888,
diff --git a/include/dt-bindings/arm/arm-smmu.h b/include/dt-bindings/arm/arm-smmu.h
new file mode 100644
index 0000000..3a1dbd3
--- /dev/null
+++ b/include/dt-bindings/arm/arm-smmu.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DT_ARM_SMMU_H__
+#define __DT_ARM_SMMU_H__
+
+#define ARM_SMMU_OPT_SECURE_CFG_ACCESS  (1 << 0)
+#define ARM_SMMU_OPT_FATAL_ASF		(1 << 1)
+#define ARM_SMMU_OPT_SKIP_INIT		(1 << 2)
+#define ARM_SMMU_OPT_DYNAMIC		(1 << 3)
+#define ARM_SMMU_OPT_3LVL_TABLES	(1 << 4)
+#define ARM_SMMU_OPT_NO_ASID_RETENTION	(1 << 5)
+#define ARM_SMMU_OPT_DISABLE_ATOS	(1 << 6)
+#define ARM_SMMU_OPT_MMU500_ERRATA1	(1 << 7)
+#define ARM_SMMU_OPT_STATIC_CB          (1 << 8)
+#define ARM_SMMU_OPT_HALT               (1 << 9)
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-8952.h b/include/dt-bindings/clock/msm-clocks-8952.h
new file mode 100644
index 0000000..80a95d9
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-8952.h
@@ -0,0 +1,344 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_CLOCKS_8952_H
+#define __MSM_CLOCKS_8952_H
+
+/* clock_gcc controlled clocks */
+
+/* GPLLs */
+#define clk_gpll0_clk_src_8952			0x1617c790
+#define clk_gpll0_ao_clk_src_8952		0x9b4db4e8
+#define clk_gpll0_clk_src_8937			0x94350fc4
+#define clk_gpll0_ao_clk_src_8937		0x923c7546
+#define clk_gpll0_clk_src			0x5933b69f
+#define clk_gpll0_ao_clk_src			0x6b2fb034
+#define clk_gpll0_sleep_clk_src			0x4f89fcf0
+#define clk_gpll0_out_main			0x850fecec
+#define clk_gpll0_out_aux			0x64e55d63
+#define clk_gpll0_misc				0xe06ee816
+#define clk_gpll3_clk_src			0x5b1eccd5
+#define clk_gpll3_out_main			0xf5fc71ab
+#define clk_gpll3_out_aux			0xe72bea1a
+#define clk_gpll4_clk_src			0x10525d57
+#define clk_gpll4_out_main                      0xdca8db2a
+#define clk_gpll6_clk_src			0x17dceaad
+#define clk_gpll6_out_main			0x27b8b7be
+#define clk_a53ss_c0_pll			0xf761da94
+#define clk_a53ss_c1_pll			0xfbc57bbd
+#define clk_a53ss_cci_pll			0x17d32f1e
+
+/* SRCs */
+#define clk_apss_ahb_clk_src			0x36f8495f
+#define clk_blsp1_qup1_i2c_apps_clk_src		0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src		0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src		0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src		0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src		0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src		0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src		0xb2ecce68
+#define clk_gcc_blsp2_ahb_clk			0x8f283c1d
+#define clk_gcc_blsp2_sleep_clk			0x429ca5d2
+#define clk_gcc_blsp2_qup1_spi_apps_clk		0xa32604cc
+#define clk_gcc_blsp2_qup1_i2c_apps_clk		0x9ace11dd
+#define clk_blsp2_qup1_spi_apps_clk_src		0xcc1b8365
+#define clk_blsp2_qup1_i2c_apps_clk_src		0xd6d1e95d
+#define clk_gcc_blsp2_uart1_apps_clk		0x8c3512ff
+#define clk_gcc_blsp2_uart1_sim_clk		0x2ea81633
+#define clk_blsp2_uart1_apps_clk_src		0x562c66dc
+#define clk_gcc_blsp2_qup2_spi_apps_clk		0xbf54ca6d
+#define clk_gcc_blsp2_qup2_i2c_apps_clk		0x1bf9a57e
+#define clk_blsp2_qup2_spi_apps_clk_src		0xd577dc44
+#define clk_blsp2_qup2_i2c_apps_clk_src		0x603b5c51
+#define clk_gcc_blsp2_uart2_apps_clk		0x1e1965a3
+#define clk_gcc_blsp2_uart2_sim_clk		0xca05dfe2
+#define clk_blsp2_uart2_apps_clk_src		0xdd448080
+#define clk_gcc_blsp2_qup3_spi_apps_clk		0xc68509d6
+#define clk_gcc_blsp2_qup3_i2c_apps_clk		0x336d4170
+#define clk_blsp2_qup3_spi_apps_clk_src		0xd04b1e92
+#define clk_blsp2_qup3_i2c_apps_clk_src		0xea82959c
+#define clk_gcc_blsp2_qup4_spi_apps_clk		0x01a72b93
+#define clk_gcc_blsp2_qup4_i2c_apps_clk		0xbd22539d
+#define clk_blsp2_qup4_spi_apps_clk_src		0x25d4a2b1
+#define clk_blsp2_qup4_i2c_apps_clk_src		0x73dc968c
+#define clk_blsp1_qup4_spi_apps_clk_src		0xddb5bbdb
+#define clk_blsp1_uart1_apps_clk_src		0xf8146114
+#define clk_blsp1_uart2_apps_clk_src		0xfc9c2f73
+#define clk_byte0_clk_src			0x75cc885b
+#define clk_cci_clk_src				0x822f3d97
+#define clk_camss_top_ahb_clk_src		0xf92304fb
+#define clk_camss_gp0_clk_src			0x43b063e9
+#define clk_camss_gp1_clk_src			0xa3315f1b
+#define clk_crypto_clk_src			0x37a21414
+#define clk_csi0_clk_src			0x227e65bc
+#define clk_csi1_clk_src			0x6a2a6c36
+#define clk_csi2_clk_src                        0x4113589f
+#define clk_csi0phytimer_clk_src		0xc8a309be
+#define clk_csi1phytimer_clk_src		0x7c0fe23a
+#define clk_esc0_clk_src			0xb41d7c38
+#define clk_gfx3d_clk_src			0x917f76ef
+#define clk_gp1_clk_src				0xad85b97a
+#define clk_gp2_clk_src				0xfb1f0065
+#define clk_gp3_clk_src				0x63b693d6
+#define clk_jpeg0_clk_src			0x9a0a0ac3
+#define clk_mdp_clk_src				0x6dc1f8f1
+#define clk_mclk0_clk_src			0x266b3853
+#define clk_mclk1_clk_src			0xa73cad0c
+#define clk_mclk2_clk_src                       0x42545468
+#define clk_pclk0_clk_src			0xccac1f35
+#define clk_pdm2_clk_src			0x31e494fd
+#define clk_sdcc1_apps_clk_src			0xd4975db2
+#define clk_sdcc1_ice_core_clk_src		0xfd6a4301
+#define clk_sdcc2_apps_clk_src			0xfc46c821
+#define clk_usb_hs_system_clk_src		0x28385546
+#define clk_usb_fs_system_clk_src               0x06ee1762
+#define clk_usb_fs_ic_clk_src			0x25d4acc8
+#define clk_usb_fs_ic_clk_src			0x25d4acc8
+#define clk_gcc_qusb2_phy_clk			0x996884d5
+#define clk_gcc_usb2_hs_phy_only_clk		0x0047179d
+#define clk_vsync_clk_src			0xecb43940
+#define clk_vfe0_clk_src			0xa0c2bd8f
+#define clk_vcodec0_clk_src			0xbc193019
+#define clk_gcc_blsp1_ahb_clk			0x8caa5b4f
+#define clk_gcc_boot_rom_ahb_clk		0xde2adeb1
+#define clk_gcc_crypto_ahb_clk			0x94de4919
+#define clk_gcc_crypto_axi_clk			0xd4415c9b
+#define clk_gcc_crypto_clk			0x00d390d2
+#define clk_gcc_prng_ahb_clk			0x397e7eaa
+#define clk_gcc_qdss_dap_clk			0x7fa9aa73
+#define clk_gcc_apss_tcu_clk			0xaf56a329
+#define clk_gcc_ipa_tbu_clk			0x75bbfb5c
+#define clk_gcc_gfx_tbu_clk			0x18bb9a90
+#define clk_gcc_gtcu_ahb_clk			0xb432168e
+#define clk_gcc_jpeg_tbu_clk			0xcf8fd944
+#define clk_gcc_mdp_tbu_clk			0x82287f76
+#define clk_gcc_smmu_cfg_clk			0x75eaefa5
+#define clk_gcc_venus_tbu_clk			0x7e0b97ce
+#define clk_gcc_vfe_tbu_clk			0x061f2f95
+#define clk_gcc_vfe1_tbu_clk			0x4888e70f
+#define clk_gcc_cpp_tbu_clk			0xab6f19ab
+#define clk_gcc_blsp1_qup1_i2c_apps_clk		0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk		0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk		0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk		0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk		0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk		0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk		0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk		0x80f8722f
+#define clk_gcc_blsp1_uart1_apps_clk		0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk		0xf8a61c96
+#define clk_gcc_camss_cci_ahb_clk		0xa81c11ba
+#define clk_gcc_camss_cci_clk			0xb7dd8824
+#define clk_gcc_camss_csi0_ahb_clk		0x175d672a
+#define clk_gcc_camss_csi0_clk			0x6b01b3e1
+#define clk_gcc_camss_csi0phy_clk		0x06a41ff7
+#define clk_gcc_camss_csi0pix_clk		0x61a8a930
+#define clk_gcc_camss_csi0rdi_clk		0x7053c7ae
+#define clk_gcc_camss_csi1_ahb_clk		0x2c2dc261
+#define clk_gcc_camss_csi1_clk			0x1aba4a8c
+#define clk_gcc_camss_csi1phy_clk		0x0fd1d1fa
+#define clk_gcc_camss_csi1pix_clk		0x87fc98d8
+#define clk_gcc_camss_csi1rdi_clk		0x6ac996fe
+#define clk_gcc_camss_csi2_ahb_clk		0xf3f25940
+#define clk_gcc_camss_csi2_clk			0xb6857fa2
+#define clk_gcc_camss_csi2phy_clk		0xbeeffbcd
+#define clk_gcc_camss_csi2pix_clk		0xa619561a
+#define clk_gcc_camss_csi2rdi_clk		0x019fd3f1
+#define clk_vfe1_clk_src			0x4e357366
+#define clk_gcc_camss_vfe1_clk			0xcaf20d99
+#define clk_gcc_camss_vfe1_ahb_clk		0x634a738a
+#define clk_gcc_camss_vfe1_axi_clk		0xaf7463b3
+#define clk_gcc_vfe1_qdss_at_clk		0xfff1e0be
+#define clk_cpp_clk_src				0x8382f56d
+#define clk_gcc_camss_cpp_clk			0x7118a0de
+#define clk_gcc_camss_cpp_ahb_clk		0x4ac95e14
+#define clk_gcc_camss_cpp_axi_clk		0xbbf73861
+#define clk_gcc_cpp_qdss_at_clk			0x05805d0d
+#define clk_gcc_cpp_qdss_tsctr_div8_clk		0xebd2c356
+#define clk_gcc_camss_csi_vfe0_clk		0xcc73453c
+#define clk_gcc_camss_csi_vfe1_clk		0xb1ef6e8b
+#define clk_gcc_camss_gp0_clk			0xd2bc3892
+#define clk_gcc_camss_gp1_clk			0xe4c013e1
+#define clk_gcc_camss_ispif_ahb_clk		0x3c0a858f
+#define clk_gcc_camss_jpeg0_clk			0x1ed3f032
+#define clk_gcc_camss_jpeg_ahb_clk		0x3bfa7603
+#define clk_gcc_camss_jpeg_axi_clk		0x3e278896
+#define clk_gcc_camss_mclk0_clk			0x80902deb
+#define clk_gcc_camss_mclk1_clk			0x5002d85f
+#define clk_gcc_camss_mclk2_clk                 0x222f8fff
+#define clk_gcc_camss_micro_ahb_clk		0xfbbee8cf
+#define clk_gcc_camss_csi0phytimer_clk		0xf8897589
+#define clk_gcc_camss_csi1phytimer_clk		0x4d26438f
+#define clk_gcc_camss_ahb_clk			0x9894b414
+#define clk_gcc_camss_top_ahb_clk		0x4e814a78
+#define clk_gcc_camss_vfe0_clk			0xaaa3cd97
+#define clk_gcc_camss_vfe_ahb_clk		0x4050f47a
+#define clk_gcc_camss_vfe_axi_clk		0x77fe2384
+#define clk_gcc_sys_mm_noc_axi_clk		0xb75a7187
+#define clk_gcc_oxili_gmem_clk			0x5620913a
+#define clk_gcc_gp1_clk				0x057f7b69
+#define clk_gcc_gp2_clk				0x9bf83ffd
+#define clk_gcc_gp3_clk				0xec6539ee
+#define clk_gcc_mdss_ahb_clk			0xbfb92ed3
+#define clk_gcc_mdss_axi_clk			0x668f51de
+#define clk_gcc_mdss_byte0_clk			0x35da7862
+#define clk_gcc_mdss_esc0_clk			0xaec5cb25
+#define clk_gcc_mdss_mdp_clk			0x22f3521f
+#define clk_gcc_mdss_pclk0_clk			0xcc5c5c77
+#define clk_gcc_mdss_vsync_clk			0x32a09f1f
+#define clk_gcc_mss_cfg_ahb_clk			0x111cde81
+#define clk_gcc_mss_q6_bimc_axi_clk		0x67544d62
+#define clk_gcc_oxili_ahb_clk			0xd15c8a00
+#define clk_gcc_oxili_gfx3d_clk			0x49a51fd9
+#define clk_gcc_oxili_timer_clk			0x1180db06
+#define clk_gcc_oxili_aon_clk			0xae18e54d
+#define clk_gcc_pdm2_clk			0x99d55711
+#define clk_gcc_pdm_ahb_clk			0x365664f6
+#define clk_gcc_sdcc1_ahb_clk			0x691e0caa
+#define clk_gcc_sdcc1_apps_clk			0x9ad6fb96
+#define clk_gcc_sdcc1_ice_core_clk		0x0fd5680a
+#define clk_gcc_sdcc2_ahb_clk			0x23d5727f
+#define clk_gcc_sdcc2_apps_clk			0x861b20ac
+#define clk_gcc_usb2a_phy_sleep_clk		0x6caa736f
+#define clk_gcc_usb_hs_phy_cfg_ahb_clk		0xe13808fd
+#define clk_gcc_usb_hs_ahb_clk			0x72ce8032
+#define clk_gcc_usb_fs_ahb_clk                  0x00e31116
+#define clk_gcc_usb_fs_ic_clk			0xbd533d37
+#define clk_gcc_usb_hs_system_clk		0xa11972e5
+#define clk_gcc_usb_fs_system_clk               0xea3b114c
+#define clk_gcc_venus0_ahb_clk			0x08d778c6
+#define clk_gcc_venus0_axi_clk			0xcdf4c8f6
+#define clk_gcc_venus0_vcodec0_clk		0xf76a02bb
+#define clk_gcc_venus0_core0_vcodec0_clk        0x83a7f549
+#define clk_gcc_venus0_core1_vcodec0_clk        0xa0813de6
+#define clk_gcc_gfx_tcu_clk			0x59505e55
+#define clk_gcc_gtcu_ahb_bridge_clk		0x19d2c5fe
+#define clk_gcc_bimc_gpu_clk			0x19922503
+#define clk_gcc_bimc_gfx_clk			0x3edd69ad
+#define clk_ipa_clk				0xfa685cda
+#define clk_ipa_a_clk				0xeeec2919
+#define clk_mdss_mdp_vote_clk			0x588460a4
+#define clk_mdss_rotator_vote_clk		0x5b1f675e
+
+#define clk_pixel_clk_src                       0x8b6f83d8
+#define clk_byte_clk_src                        0x3a911c53
+#define clk_ext_pclk0_clk_src			0x087c1612
+#define clk_ext_byte0_clk_src			0xfb32f31e
+
+#define clk_dsi_pll0_byte_clk_src		0x44539836
+#define clk_dsi_pll0_pixel_clk_src		0x5767c287
+#define clk_dsi_pll1_byte_clk_src		0x73e88d02
+#define clk_dsi_pll1_pixel_clk_src		0xce233fcf
+#define clk_ext_pclk1_clk_src			0x8067c5a3
+#define clk_ext_byte1_clk_src			0x585ef6d4
+#define clk_byte1_clk_src			0x63c2c955
+#define clk_esc1_clk_src			0x3b0afa42
+#define clk_pclk1_clk_src			0x090f68ac
+#define clk_gcc_mdss_pclk1_clk			0x9a9c430d
+#define clk_gcc_mdss_byte1_clk			0x41f97fd8
+#define clk_gcc_mdss_esc1_clk			0x34653cc7
+#define clk_gcc_dcc_clk				0xd1000c50
+#define clk_gcc_debug_mux_8937			0x917968c2
+
+/* clock_rpm controlled clocks */
+#define clk_pnoc_clk				0xc1296d0f
+#define clk_pnoc_a_clk				0x9bcffee4
+#define clk_pnoc_msmbus_clk			0x2b53b688
+#define clk_pnoc_msmbus_a_clk			0x9753a54f
+#define clk_pnoc_keepalive_a_clk		0x9464f720
+#define clk_pnoc_sps_clk			0x23d3f584
+#define clk_pnoc_usb_a_clk			0x11d6a74e
+#define clk_pnoc_usb_clk                        0x266d8376
+#define clk_snoc_clk				0x2c341aa0
+#define clk_snoc_a_clk				0x8fcef2af
+#define clk_snoc_usb_a_clk			0x34b7821b
+#define clk_snoc_wcnss_a_clk			0xd3949ebc
+#define clk_snoc_usb_clk			0x29f9d73d
+#define clk_snoc_msmbus_clk			0xe6900bb6
+#define clk_snoc_msmbus_a_clk			0x5d4683bd
+#define clk_snoc_mmnoc_axi_clk			0xfedd4bd5
+#define clk_snoc_mmnoc_ahb_clk			0xd2149dbb
+#define clk_sysmmnoc_clk			0xebb1df78
+#define clk_sysmmnoc_a_clk			0x6ca682a2
+#define clk_sysmmnoc_msmbus_clk			0xd61e5721
+#define clk_sysmmnoc_msmbus_a_clk		0x50600f1b
+#define clk_bimc_clk				0x4b80bf00
+#define clk_bimc_a_clk				0x4b25668a
+#define clk_bimc_acpu_a_clk			0x4446311b
+#define clk_bimc_msmbus_clk			0xd212feea
+#define clk_bimc_msmbus_a_clk			0x71d1a499
+#define clk_bimc_usb_a_clk			0xea410834
+#define clk_bimc_wcnss_a_clk			0x5a6df715
+#define clk_bimc_usb_clk			0x9bd2b2bf
+#define clk_bimc_gpu_clk			0xd3e0a327
+#define clk_bimc_gpu_a_clk			0x67f0e9a5
+#define clk_qdss_clk				0x1492202a
+#define clk_qdss_a_clk				0xdd121669
+#define clk_xo_clk_src				0x23f5649f
+#define clk_xo_a_clk_src			0x2fdd2c7c
+#define clk_xo_otg_clk				0x79bca5cc
+#define clk_xo_a2				0xeba5a83d
+#define clk_xo_dwc3_clk				0xfad488ce
+#define clk_xo_ehci_host_clk			0xc7c340b1
+#define clk_xo_lpm_clk				0x2be48257
+#define clk_xo_pil_mss_clk			0xe97a8354
+#define clk_xo_pil_pronto_clk			0x89dae6d0
+#define clk_xo_wlan_clk				0x0116b76f
+#define clk_xo_pil_lpass_clk			0xb72aa4c9
+#define clk_bb_clk1				0xf5304268
+#define clk_bb_clk1_a				0xfa113810
+#define clk_bb_clk1_pin				0x6dd0a779
+#define clk_bb_clk1_a_pin			0x9b637772
+#define clk_bb_clk2				0xfe15cb87
+#define clk_bb_clk2_a				0x59682706
+#define clk_bb_clk2_pin				0x498938e5
+#define clk_bb_clk2_a_pin			0x52513787
+#define clk_rf_clk1				0xaabeea5a
+#define clk_rf_clk1_a				0x72a10cb8
+#define clk_rf_clk1_pin				0x8f463562
+#define clk_rf_clk1_a_pin			0x62549ff6
+#define clk_rf_clk2				0x24a30992
+#define clk_rf_clk2_a				0x944d8bbd
+#define clk_rf_clk2_pin				0xa7c5602a
+#define clk_rf_clk2_a_pin			0x2d75eb4d
+#define clk_div_clk1				0xaa1157a6
+#define clk_div_clk1_a				0x6b943d68
+#define clk_div_clk2				0xd454019f
+#define clk_div_clk2_a				0x4bd7bfa8
+#define clk_ln_bb_clk				0x3ab0b36d
+#define clk_ln_bb_a_clk				0xc7257ea8
+
+
+/* clock_debug controlled clocks */
+#define clk_gcc_debug_mux			0x8121ac15
+#define clk_rpm_debug_mux			0x25cd1f3a
+#define clk_wcnss_m_clk				0x709f430b
+#define clk_apss_debug_pri_mux			0xc691ff55
+#define clk_apss_debug_sec_mux			0xc0b680f9
+#define clk_apss_debug_ter_mux			0x32041c48
+#define clk_apc0_m_clk				0xce1e9473
+#define clk_apc1_m_clk				0x990fbaf7
+#define clk_cci_m_clk				0xec7e8afc
+
+#define clk_a53ssmux_lc				0x71a9377b
+#define clk_a53ssmux_bc				0xb5983c42
+#define clk_a53ssmux_cci			0x15560bd5
+
+#define clk_a53_lc_clk				0xc69f0878
+#define clk_a53_bc_clk				0xcf28e63a
+#define clk_cci_clk                             0x96854074
+
+#define clk_audio_ap_clk			0x312ac429
+#define clk_audio_pmi_clk			0xb7ba2274
+#define clk_audio_lpass_mclk			0x575ec22b
+
+#endif
diff --git a/include/dt-bindings/clock/msm-clocks-8996.h b/include/dt-bindings/clock/msm-clocks-8996.h
new file mode 100644
index 0000000..1f515f2
--- /dev/null
+++ b/include/dt-bindings/clock/msm-clocks-8996.h
@@ -0,0 +1,548 @@
+/* Copyright (c) 2014-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.
+ */
+
+#ifndef __MSM_CLOCKS_8996_H
+#define __MSM_CLOCKS_8996_H
+
+/* clock_gcc controlled clocks */
+#define clk_cxo_clk_src			0x79e95308
+#define clk_pnoc_clk			0x4325d220
+#define clk_pnoc_a_clk			0x2808c12b
+#define clk_bimc_clk			0x4b80bf00
+#define clk_bimc_a_clk			0x4b25668a
+#define clk_cnoc_clk			0xd5ccb7f4
+#define clk_cnoc_a_clk			0xd8fe2ccc
+#define clk_snoc_clk			0x2c341aa0
+#define clk_snoc_a_clk			0x8fcef2af
+#define clk_bb_clk1			0xf5304268
+#define clk_bb_clk1_ao			0xfa113810
+#define clk_bb_clk1_pin			0x6dd0a779
+#define clk_bb_clk1_pin_ao		0x9b637772
+#define clk_bb_clk2			0xfe15cb87
+#define clk_bb_clk2_ao			0x59682706
+#define clk_bb_clk2_pin			0x498938e5
+#define clk_bb_clk2_pin_ao		0x52513787
+#define clk_bimc_msmbus_clk		0xd212feea
+#define clk_bimc_msmbus_a_clk		0x71d1a499
+#define clk_ce1_a_clk			0x44a833fe
+#define clk_cnoc_msmbus_clk		0x62228b5d
+#define clk_cnoc_msmbus_a_clk		0x67442955
+#define clk_cxo_clk_src_ao		0x64eb6004
+#define clk_cxo_dwc3_clk		0xf79c19f6
+#define clk_cxo_lpm_clk			0x94adbf3d
+#define clk_cxo_otg_clk			0x4eec0bb9
+#define clk_cxo_pil_lpass_clk		0xe17f0ff6
+#define clk_cxo_pil_ssc_clk		0x81832015
+#define clk_div_clk1			0xaa1157a6
+#define clk_div_clk1_ao			0x6b943d68
+#define clk_div_clk2			0xd454019f
+#define clk_div_clk2_ao			0x53f9e788
+#define clk_div_clk3			0xa9a55a68
+#define clk_div_clk3_ao			0x3d6725a8
+#define clk_ipa_a_clk			0xeeec2919
+#define clk_ipa_clk			0xfa685cda
+#define clk_ln_bb_clk			0x3ab0b36d
+#define clk_ln_bb_a_clk			0xc7257ea8
+#define clk_ln_bb_clk_pin		0x1b1c476a
+#define clk_ln_bb_a_clk_pin		0x9cbb5411
+#define clk_mcd_ce1_clk			0xbb615d26
+#define clk_pnoc_keepalive_a_clk	0xf8f91f0b
+#define clk_pnoc_msmbus_clk		0x38b95c77
+#define clk_pnoc_msmbus_a_clk		0x8c9b4e93
+#define clk_pnoc_pm_clk			0xd6f7dfb9
+#define clk_pnoc_sps_clk		0xd482ecc7
+#define clk_qdss_a_clk			0xdd121669
+#define clk_qdss_clk			0x1492202a
+#define clk_rf_clk1			0xaabeea5a
+#define clk_rf_clk1_ao			0x72a10cb8
+#define clk_rf_clk1_pin			0x8f463562
+#define clk_rf_clk1_pin_ao		0x62549ff6
+#define clk_rf_clk2			0x24a30992
+#define clk_rf_clk2_ao			0x944d8bbd
+#define clk_rf_clk2_pin			0xa7c5602a
+#define clk_rf_clk2_pin_ao		0x2d75eb4d
+#define clk_snoc_msmbus_clk		0xe6900bb6
+#define clk_snoc_msmbus_a_clk		0x5d4683bd
+#define clk_mcd_ce1_clk			0xbb615d26
+#define clk_qcedev_ce1_clk		0x293f97b0
+#define clk_qcrypto_ce1_clk		0xa6ac14df
+#define clk_qseecom_ce1_clk		0xaa858373
+#define clk_scm_ce1_clk			0xd8ebcc62
+#define clk_ce1_clk			0x42229c55
+#define clk_gcc_ce1_ahb_m_clk		0x2eb28c01
+#define clk_gcc_ce1_axi_m_clk		0xc174dfba
+#define clk_measure_only_bimc_hmss_axi_clk	0xc1cc4f11
+#define clk_aggre1_noc_clk		0x049abba8
+#define clk_aggre1_noc_a_clk		0xc12e4220
+#define clk_aggre2_noc_clk		0xaa681404
+#define clk_aggre2_noc_a_clk		0xcab67089
+#define clk_mmssnoc_axi_rpm_clk		0x4d7f8cdc
+#define clk_mmssnoc_axi_rpm_a_clk	0xfbea899b
+#define clk_mmssnoc_axi_clk		0xdb4b31e6
+#define clk_mmssnoc_axi_a_clk		0xd4970614
+#define clk_mmssnoc_gds_clk		0x06a22afa
+
+#define clk_gpll0			0x1ebe3bc4
+#define clk_gpll0_ao			0xa1368304
+#define clk_gpll0_out_main		0xe9374de7
+#define clk_gpll4			0xb3b5d85b
+#define clk_gpll4_out_main		0xa9a0ab9d
+#define clk_ufs_axi_clk_src		0x297ca380
+#define clk_pcie_aux_clk_src		0xebc50566
+#define clk_usb30_master_clk_src	0xc6262f89
+#define clk_usb20_master_clk_src	0x5680ac83
+#define clk_ufs_ice_core_clk_src	0xda8e7119
+#define clk_blsp1_qup1_i2c_apps_clk_src 0x17f78f5e
+#define clk_blsp1_qup1_spi_apps_clk_src 0xf534c4fa
+#define clk_blsp1_qup2_i2c_apps_clk_src 0x8de71c79
+#define clk_blsp1_qup2_spi_apps_clk_src 0x33cf809a
+#define clk_blsp1_qup3_i2c_apps_clk_src 0xf161b902
+#define clk_blsp1_qup3_spi_apps_clk_src 0x5e95683f
+#define clk_blsp1_qup4_i2c_apps_clk_src 0xb2ecce68
+#define clk_blsp1_qup4_spi_apps_clk_src 0xddb5bbdb
+#define clk_blsp1_qup5_i2c_apps_clk_src 0x71ea7804
+#define clk_blsp1_qup5_spi_apps_clk_src 0x9752f35f
+#define clk_blsp1_qup6_i2c_apps_clk_src 0x28806803
+#define clk_blsp1_qup6_spi_apps_clk_src 0x44a1edc4
+#define clk_blsp1_uart1_apps_clk_src	0xf8146114
+#define clk_blsp1_uart2_apps_clk_src	0xfc9c2f73
+#define clk_blsp1_uart3_apps_clk_src	0x600497f2
+#define clk_blsp1_uart4_apps_clk_src	0x56bff15c
+#define clk_blsp1_uart5_apps_clk_src	0x218ef697
+#define clk_blsp1_uart6_apps_clk_src	0x8fbdbe4c
+#define clk_blsp2_qup1_i2c_apps_clk_src 0xd6d1e95d
+#define clk_blsp2_qup1_spi_apps_clk_src 0xcc1b8365
+#define clk_blsp2_qup2_i2c_apps_clk_src 0x603b5c51
+#define clk_blsp2_qup2_spi_apps_clk_src 0xd577dc44
+#define clk_blsp2_qup3_i2c_apps_clk_src 0xea82959c
+#define clk_blsp2_qup3_spi_apps_clk_src 0xd04b1e92
+#define clk_blsp2_qup4_i2c_apps_clk_src 0x73dc968c
+#define clk_blsp2_qup4_spi_apps_clk_src 0x25d4a2b1
+#define clk_blsp2_qup5_i2c_apps_clk_src 0xcc3698bd
+#define clk_blsp2_qup5_spi_apps_clk_src 0xfa0cf45e
+#define clk_blsp2_qup6_i2c_apps_clk_src 0x2fa53151
+#define clk_blsp2_qup6_spi_apps_clk_src 0x5ca86755
+#define clk_blsp2_uart1_apps_clk_src	0x562c66dc
+#define clk_blsp2_uart2_apps_clk_src	0xdd448080
+#define clk_blsp2_uart3_apps_clk_src	0x46b2e90f
+#define clk_blsp2_uart4_apps_clk_src	0x23a093d2
+#define clk_blsp2_uart5_apps_clk_src	0xe067616a
+#define clk_blsp2_uart6_apps_clk_src	0xe02d2829
+#define clk_gp1_clk_src			0xad85b97a
+#define clk_gp2_clk_src			0xfb1f0065
+#define clk_gp3_clk_src			0x63b693d6
+#define clk_hmss_rbcpr_clk_src		0xedd9a474
+#define clk_pdm2_clk_src		0x31e494fd
+#define clk_sdcc1_apps_clk_src		0xd4975db2
+#define clk_sdcc2_apps_clk_src		0xfc46c821
+#define clk_sdcc3_apps_clk_src		0xea34c7f4
+#define clk_sdcc4_apps_clk_src		0x7aaaaa0c
+#define clk_tsif_ref_clk_src		0x4e9042d1
+#define clk_usb20_mock_utmi_clk_src	0xc3aaeecb
+#define clk_usb30_mock_utmi_clk_src	0xa024a976
+#define clk_usb3_phy_aux_clk_src	0x15eec63c
+#define clk_gcc_qusb2phy_prim_reset	0x07550fa1
+#define clk_gcc_qusb2phy_sec_reset	0x3f3a87d0
+#define clk_gcc_periph_noc_usb20_ahb_clk	0xfb9f26e9
+#define clk_gcc_mmss_gcc_dbg_clk	0xe89d461c
+#define clk_cpu_dbg_clk			0x6550dfa9
+#define clk_gcc_blsp1_ahb_clk		0x8caa5b4f
+#define clk_gcc_blsp1_qup1_i2c_apps_clk 0xc303fae9
+#define clk_gcc_blsp1_qup1_spi_apps_clk 0x759a76b0
+#define clk_gcc_blsp1_qup2_i2c_apps_clk 0x1076f220
+#define clk_gcc_blsp1_qup2_spi_apps_clk 0x3e77d48f
+#define clk_gcc_blsp1_qup3_i2c_apps_clk 0x9e25ac82
+#define clk_gcc_blsp1_qup3_spi_apps_clk 0xfb978880
+#define clk_gcc_blsp1_qup4_i2c_apps_clk 0xd7f40f6f
+#define clk_gcc_blsp1_qup4_spi_apps_clk 0x80f8722f
+#define clk_gcc_blsp1_qup5_i2c_apps_clk 0xacae5604
+#define clk_gcc_blsp1_qup5_spi_apps_clk 0xbf3e15d7
+#define clk_gcc_blsp1_qup6_i2c_apps_clk 0x5c6ad820
+#define clk_gcc_blsp1_qup6_spi_apps_clk 0x780d9f85
+#define clk_gcc_blsp1_uart1_apps_clk	0xc7c62f90
+#define clk_gcc_blsp1_uart2_apps_clk	0xf8a61c96
+#define clk_gcc_blsp1_uart3_apps_clk	0xc3298bd7
+#define clk_gcc_blsp1_uart4_apps_clk	0x26be16c0
+#define clk_gcc_blsp1_uart5_apps_clk	0x28a6bc74
+#define clk_gcc_blsp1_uart6_apps_clk	0x28fd3466
+#define clk_gcc_blsp2_ahb_clk		0x8f283c1d
+#define clk_gcc_blsp2_qup1_i2c_apps_clk 0x9ace11dd
+#define clk_gcc_blsp2_qup1_spi_apps_clk 0xa32604cc
+#define clk_gcc_blsp2_qup2_i2c_apps_clk 0x1bf9a57e
+#define clk_gcc_blsp2_qup2_spi_apps_clk 0xbf54ca6d
+#define clk_gcc_blsp2_qup3_i2c_apps_clk 0x336d4170
+#define clk_gcc_blsp2_qup3_spi_apps_clk 0xc68509d6
+#define clk_gcc_blsp2_qup4_i2c_apps_clk 0xbd22539d
+#define clk_gcc_blsp2_qup4_spi_apps_clk 0x01a72b93
+#define clk_gcc_blsp2_qup5_i2c_apps_clk 0xe2b2ce1d
+#define clk_gcc_blsp2_qup5_spi_apps_clk 0xf40999cd
+#define clk_gcc_blsp2_qup6_i2c_apps_clk 0x894bcea4
+#define clk_gcc_blsp2_qup6_spi_apps_clk 0xfe1bd34a
+#define clk_gcc_blsp2_uart1_apps_clk	0x8c3512ff
+#define clk_gcc_blsp2_uart2_apps_clk	0x1e1965a3
+#define clk_gcc_blsp2_uart3_apps_clk	0x382415ab
+#define clk_gcc_blsp2_uart4_apps_clk	0x87a44b42
+#define clk_gcc_blsp2_uart5_apps_clk	0x5cd30649
+#define clk_gcc_blsp2_uart6_apps_clk	0x8feee5ab
+#define clk_gcc_boot_rom_ahb_clk	0xde2adeb1
+#define clk_gcc_gp1_clk			0x057f7b69
+#define clk_gcc_gp2_clk			0x9bf83ffd
+#define clk_gcc_gp3_clk			0xec6539ee
+#define clk_gcc_hmss_rbcpr_clk		0x699183be
+#define clk_gcc_mmss_noc_cfg_ahb_clk	0xb41a9d99
+#define clk_gcc_pcie_0_aux_clk		0x3d2e3ece
+#define clk_gcc_pcie_0_cfg_ahb_clk	0x4dd325c3
+#define clk_gcc_pcie_0_mstr_axi_clk	0x3f85285b
+#define clk_gcc_pcie_0_slv_axi_clk	0xd69638a1
+#define clk_gcc_pcie_0_pipe_clk		0x4f37621e
+#define clk_gcc_pcie_0_phy_reset	0xdc3201c1
+#define clk_gcc_pcie_1_aux_clk		0xc9bb962c
+#define clk_gcc_pcie_1_cfg_ahb_clk	0xb6338658
+#define clk_gcc_pcie_1_mstr_axi_clk	0xc20f6269
+#define clk_gcc_pcie_1_slv_axi_clk	0xd54e40d6
+#define clk_gcc_pcie_1_pipe_clk		0xc1627422
+#define clk_gcc_pcie_1_phy_reset	0x674481bb
+#define clk_gcc_pcie_2_aux_clk		0xa4dc7ae8
+#define clk_gcc_pcie_2_cfg_ahb_clk	0x4f1d3121
+#define clk_gcc_pcie_2_mstr_axi_clk	0x9e81724a
+#define clk_gcc_pcie_2_slv_axi_clk	0x7990d8b2
+#define clk_gcc_pcie_2_pipe_clk		0xa757a834
+#define clk_gcc_pcie_2_phy_reset	0x82634880
+#define clk_gcc_pcie_phy_reset		0x9bc3c959
+#define clk_gcc_pcie_phy_com_reset	0x8bf513e6
+#define clk_gcc_pcie_phy_nocsr_com_phy_reset	0x0c16a2da
+#define clk_gcc_pcie_phy_aux_clk	0x4746e74f
+#define clk_gcc_pcie_phy_cfg_ahb_clk	0x8533671a
+#define clk_gcc_pdm2_clk		0x99d55711
+#define clk_gcc_pdm_ahb_clk		0x365664f6
+#define clk_gcc_prng_ahb_clk		0x397e7eaa
+#define clk_gcc_sdcc1_ahb_clk		0x691e0caa
+#define clk_gcc_sdcc1_apps_clk		0x9ad6fb96
+#define clk_gcc_sdcc2_ahb_clk		0x23d5727f
+#define clk_gcc_sdcc2_apps_clk		0x861b20ac
+#define clk_gcc_sdcc3_ahb_clk		0x565b2c03
+#define clk_gcc_sdcc3_apps_clk		0x0b27aeac
+#define clk_gcc_sdcc4_ahb_clk		0x64f3e6a8
+#define clk_gcc_sdcc4_apps_clk		0xbf7c4dc8
+#define clk_gcc_tsif_ahb_clk		0x88d2822c
+#define clk_gcc_tsif_ref_clk		0x8f1ed2c2
+#define clk_gcc_ufs_ahb_clk		0x1914bb84
+#define clk_gcc_ufs_axi_clk		0x47c743a7
+#define clk_gcc_ufs_ice_core_clk	0x310b0710
+#define clk_gcc_ufs_rx_cfg_clk		0xa6747786
+#define clk_gcc_ufs_rx_symbol_0_clk	0x7f43251c
+#define clk_gcc_ufs_rx_symbol_1_clk	0x03182fde
+#define clk_gcc_ufs_tx_cfg_clk		0xba2cf8b5
+#define clk_gcc_ufs_tx_symbol_0_clk	0x6a9f747a
+#define clk_gcc_ufs_unipro_core_clk	0x2daf7fd2
+#define clk_gcc_ufs_sys_clk_core_clk	0x360e5ac8
+#define clk_gcc_ufs_tx_symbol_clk_core_clk	0xf6fb0df7
+#define clk_gcc_usb20_master_clk	0x24c3b66a
+#define clk_gcc_usb20_mock_utmi_clk	0xe8db8203
+#define clk_gcc_usb20_sleep_clk		0x6e8cb4b2
+#define clk_gcc_usb30_master_clk	0xb3b4e2cb
+#define clk_gcc_usb30_mock_utmi_clk	0xa800b65a
+#define clk_gcc_usb30_sleep_clk		0xd0b65c92
+#define clk_gcc_usb3_phy_aux_clk	0x0d9a36e0
+#define clk_gcc_usb3_phy_pipe_clk	0xf279aff2
+#define clk_gcc_usb_phy_cfg_ahb2phy_clk	0xd1231a0e
+#define clk_gcc_aggre0_cnoc_ahb_clk	0x53a35559
+#define clk_gcc_aggre0_snoc_axi_clk	0x3c446400
+#define clk_gcc_aggre0_noc_qosgen_extref_clk	0x8c4356ba
+#define clk_hlos1_vote_lpass_core_smmu_clk	0x3aaa1743
+#define clk_hlos1_vote_lpass_adsp_smmu_clk	0xc76f702f
+#define clk_gcc_usb3_phy_reset		0x03d559f1
+#define clk_gcc_usb3phy_phy_reset	0xb1a4f885
+#define clk_gcc_usb3_clkref_clk		0xb6cc8f01
+#define clk_gcc_hdmi_clkref_clk		0x4d4eec04
+#define clk_gcc_edp_clkref_clk		0xa8685c3f
+#define clk_gcc_ufs_clkref_clk		0x92aa126f
+#define clk_gcc_pcie_clkref_clk		0xa2e247fa
+#define clk_gcc_rx2_usb2_clkref_clk	0x27ec24ba
+#define clk_gcc_rx1_usb2_clkref_clk	0x53351d25
+#define clk_gcc_smmu_aggre0_ahb_clk	0x47a06ce4
+#define clk_gcc_smmu_aggre0_axi_clk	0x3cac4a6c
+#define clk_gcc_sys_noc_usb3_axi_clk	0x94d26800
+#define clk_gcc_sys_noc_ufs_axi_clk	0x19d38312
+#define clk_gcc_aggre2_usb3_axi_clk	0xd5822a8e
+#define clk_gcc_aggre2_ufs_axi_clk	0xb31e5191
+#define clk_gcc_mmss_gpll0_div_clk	0xdd06848d
+#define clk_gcc_mmss_bimc_gfx_clk	0xe4f28754
+#define clk_gcc_bimc_gfx_clk		0x3edd69ad
+#define clk_gcc_qspi_ahb_clk		0x96969dc8
+#define clk_gcc_qspi_ser_clk		0xfaf1e266
+#define clk_qspi_ser_clk_src		0x426676ee
+#define clk_sdcc1_ice_core_clk_src	0xfd6a4301
+#define clk_gcc_sdcc1_ice_core_clk	0x0fd5680a
+#define clk_gcc_mss_cfg_ahb_clk		0x111cde81
+#define clk_gcc_mss_snoc_axi_clk	0x0e71de85
+#define clk_gcc_mss_q6_bimc_axi_clk	0x67544d62
+#define clk_gcc_mss_mnoc_bimc_axi_clk	0xf665d03f
+#define clk_gpll0_out_msscc		0x7d794829
+#define clk_gcc_debug_mux_v2		0xf7e749f0
+#define clk_gcc_dcc_ahb_clk		0xfa14a88c
+#define clk_gcc_aggre0_noc_mpu_cfg_ahb_clk	0x5c1bb8e2
+
+/* clock_mmss controlled clocks */
+#define clk_mmsscc_xo			0x05e63704
+#define clk_mmsscc_gpll0		0xe900c515
+#define clk_mmsscc_gpll0_div		0x73892e05
+#define clk_mmsscc_mmssnoc_ahb		0x7b4bd6f7
+#define clk_mmpll0			0xdd83b751
+#define clk_mmpll0_out_main		0x2f996a31
+#define clk_mmpll1			0x6da7fb90
+#define clk_mmpll1_out_main		0xa0d3a7da
+#define clk_mmpll4			0x22c063c1
+#define clk_mmpll4_out_main		0xfb21c2fd
+#define clk_mmpll3			0x18c76899
+#define clk_mmpll3_out_main		0x6eb6328f
+#define clk_ahb_clk_src			0x86f49203
+#define clk_mmpll2			0x1190e4d8
+#define clk_mmpll2_out_main		0x1e9e24a8
+#define clk_mmpll8			0xd06ad45e
+#define clk_mmpll8_out_main		0x75b1f386
+#define clk_mmpll9			0x1c50684c
+#define clk_mmpll9_out_main		0x16b74937
+#define clk_mmpll5			0xa41e1936
+#define clk_mmpll5_out_main		0xcc1897bf
+#define clk_csi0_clk_src		0x227e65bc
+#define clk_vfe0_clk_src		0xa0c2bd8f
+#define clk_vfe1_clk_src		0x4e357366
+#define clk_csi1_clk_src		0x6a2a6c36
+#define clk_csi2_clk_src		0x4113589f
+#define clk_csi3_clk_src		0xfd934012
+#define clk_maxi_clk_src		0x52c09777
+#define clk_cpp_clk_src			0x8382f56d
+#define clk_jpeg0_clk_src		0x9a0a0ac3
+#define clk_jpeg2_clk_src		0x5ad927f3
+#define clk_jpeg_dma_clk_src		0xb68afcea
+#define clk_mdp_clk_src			0x6dc1f8f1
+#define clk_video_core_clk_src		0x8be4c944
+#define clk_fd_core_clk_src		0xe4799ab7
+#define clk_cci_clk_src			0x822f3d97
+#define clk_csiphy0_3p_clk_src		0xd2474b12
+#define clk_csiphy1_3p_clk_src		0x46a02aff
+#define clk_csiphy2_3p_clk_src		0x1447813f
+#define clk_camss_gp0_clk_src		0x6b57cfe6
+#define clk_camss_gp1_clk_src		0xf735368a
+#define clk_jpeg_dma_clk_src		0xb68afcea
+#define clk_mclk0_clk_src		0x266b3853
+#define clk_mclk1_clk_src		0xa73cad0c
+#define clk_mclk2_clk_src		0x42545468
+#define clk_mclk3_clk_src		0x2bfbb714
+#define clk_csi0phytimer_clk_src	0xc8a309be
+#define clk_csi1phytimer_clk_src	0x7c0fe23a
+#define clk_csi2phytimer_clk_src	0x62ffea9c
+#define clk_rbbmtimer_clk_src		0x17649ecc
+#define clk_esc0_clk_src		0xb41d7c38
+#define clk_esc1_clk_src		0x3b0afa42
+#define clk_hdmi_clk_src		0xb40aeea9
+#define clk_vsync_clk_src		0xecb43940
+#define clk_rbcpr_clk_src		0x2c2e9af2
+#define clk_video_subcore0_clk_src	0x88d79636
+#define clk_video_subcore1_clk_src	0x4966930c
+#define clk_mmss_bto_ahb_clk		0xfdf8c361
+#define clk_camss_ahb_clk		0xc4ff91d4
+#define clk_camss_cci_ahb_clk		0x04c4441a
+#define clk_camss_cci_clk		0xd6cb5eb9
+#define clk_camss_cpp_ahb_clk		0x12e9a87b
+#define clk_camss_cpp_clk		0xb82f366b
+#define clk_camss_cpp_axi_clk		0x5598c804
+#define clk_camss_cpp_vbif_ahb_clk	0xb5f31be4
+#define clk_camss_csi0_ahb_clk		0x6e29c972
+#define clk_camss_csi0_clk		0x30862ddb
+#define clk_camss_csi0phy_clk		0x2cecfb84
+#define clk_camss_csi0pix_clk		0x6946f77b
+#define clk_camss_csi0rdi_clk		0x83645ef5
+#define clk_camss_csi1_ahb_clk		0xccc15f06
+#define clk_camss_csi1_clk		0xb150f052
+#define clk_camss_csi1phy_clk		0xb989f06d
+#define clk_camss_csi1pix_clk		0x58d19bf3
+#define clk_camss_csi1rdi_clk		0x4d2f3352
+#define clk_camss_csi2_ahb_clk		0x92d02d75
+#define clk_camss_csi2_clk		0x74fc92e8
+#define clk_camss_csi2phy_clk		0xda05d9d8
+#define clk_camss_csi2pix_clk		0xf8ed0731
+#define clk_camss_csi2rdi_clk		0xdc1b2081
+#define clk_camss_csi3_ahb_clk		0xee5e459c
+#define clk_camss_csi3_clk		0x39488fdd
+#define clk_camss_csi3phy_clk		0x8b6063b9
+#define clk_camss_csi3pix_clk		0xd82bd467
+#define clk_camss_csi3rdi_clk		0xb6750046
+#define clk_camss_csi_vfe0_clk		0x3023937a
+#define clk_camss_csi_vfe1_clk		0xe66fa522
+#define clk_camss_csiphy0_3p_clk	0xf2a54f5a
+#define clk_camss_csiphy1_3p_clk	0x8bf70cb2
+#define clk_camss_csiphy2_3p_clk	0x1c14c939
+#define clk_camss_gp0_clk		0xcee7e51d
+#define clk_camss_gp1_clk		0x41f1c2e3
+#define clk_camss_ispif_ahb_clk		0x9a212c6d
+#define clk_camss_jpeg0_clk		0x0b0e2db7
+#define clk_camss_jpeg2_clk		0xd7291c8d
+#define clk_camss_jpeg_ahb_clk		0x1f47fd28
+#define clk_camss_jpeg_axi_clk		0x9e5545c8
+#define clk_camss_jpeg_dma_clk		0x2336e65d
+#define clk_camss_mclk0_clk		0xcf0c61e0
+#define clk_camss_mclk1_clk		0xd1410ed4
+#define clk_camss_mclk2_clk		0x851286f2
+#define clk_camss_mclk3_clk		0x4db11c45
+#define clk_camss_micro_ahb_clk		0x33a23277
+#define clk_camss_csi0phytimer_clk	0xff93b3c8
+#define clk_camss_csi1phytimer_clk	0x6c399ab6
+#define clk_camss_csi2phytimer_clk	0x24f47f49
+#define clk_camss_top_ahb_clk		0x8f8b2d33
+#define clk_camss_vfe_ahb_clk		0x595197bc
+#define clk_camss_vfe_axi_clk		0x273d4c31
+#define clk_camss_vfe0_ahb_clk		0x4652833c
+#define clk_camss_vfe0_clk		0x1e9bb8c4
+#define clk_camss_vfe0_stream_clk	0x22835fa4
+#define clk_camss_vfe1_ahb_clk		0x6a56abd3
+#define clk_camss_vfe1_clk		0x5bffa69b
+#define clk_camss_vfe1_stream_clk	0x92f849b9
+#define clk_fd_ahb_clk			0x868a2c5c
+#define clk_fd_core_clk			0x3badcae4
+#define clk_fd_core_uar_clk		0x7e624e15
+#define clk_gpu_ahb_clk			0xf97f1d43
+#define clk_gpu_aon_isense_clk		0xa9e9b297
+#define clk_gpu_gx_gfx3d_clk		0xb7ece823
+#define clk_gpu_mx_clk			0xb80ccedf
+#define clk_gpu_gx_rbbmtimer_clk	0xdeba634e
+#define clk_mdss_ahb_clk		0x684ccb41
+#define clk_mdss_axi_clk		0xcc07d687
+#define clk_mdss_esc0_clk		0x28cafbe6
+#define clk_mdss_esc1_clk		0xc22c6883
+#define clk_mdss_hdmi_ahb_clk		0x01cef516
+#define clk_mdss_hdmi_clk		0x097a6de9
+#define clk_mdss_mdp_clk		0x618336ac
+#define clk_mdss_vsync_clk		0x42a022d3
+#define clk_mmss_misc_ahb_clk		0xea30b0e7
+#define clk_mmss_misc_cxo_clk		0xe620cd80
+#define clk_mmagic_bimc_noc_cfg_ahb_clk 0x12d5ba72
+#define clk_mmagic_camss_axi_clk	0xa8b1c16b
+#define clk_mmagic_camss_noc_cfg_ahb_clk 0x5182c819
+#define clk_mmss_mmagic_cfg_ahb_clk	0x5e94a822
+#define clk_mmagic_mdss_axi_clk		0xa0359d10
+#define clk_mmagic_mdss_noc_cfg_ahb_clk 0x9c6d5482
+#define clk_mmagic_video_axi_clk	0x7b9219c3
+#define clk_mmagic_video_noc_cfg_ahb_clk 0x5124d256
+#define clk_mmss_mmagic_ahb_clk		0x3d15f2b0
+#define clk_mmss_mmagic_maxi_clk	0xbdaf5af7
+#define clk_mmss_rbcpr_ahb_clk		0x623ba55f
+#define clk_mmss_rbcpr_clk		0x69a23a6f
+#define clk_mmss_spdm_cpp_clk		0xefe35cd2
+#define clk_mmss_spdm_jpeg_dma_clk	0xcb7bd5a0
+#define clk_smmu_cpp_ahb_clk		0x3ad82d84
+#define clk_smmu_cpp_axi_clk		0xa6bb2f4a
+#define clk_smmu_jpeg_ahb_clk		0x10c436ec
+#define clk_smmu_jpeg_axi_clk		0x41112f37
+#define clk_smmu_mdp_ahb_clk		0x04994cb2
+#define clk_smmu_mdp_axi_clk		0x7fd71687
+#define clk_smmu_rot_ahb_clk		0xa30772c9
+#define clk_smmu_rot_axi_clk		0xfed7c078
+#define clk_smmu_vfe_ahb_clk		0x4dabebe7
+#define clk_smmu_vfe_axi_clk		0xde483725
+#define clk_smmu_video_ahb_clk		0x2d738e2c
+#define clk_smmu_video_axi_clk		0xe2b5b887
+#define clk_video_ahb_clk		0x90775cfb
+#define clk_video_axi_clk		0xe6c16dba
+#define clk_video_core_clk		0x7e876ec3
+#define clk_video_maxi_clk		0x97749db6
+#define clk_video_subcore0_clk		0xb6f63e6c
+#define clk_video_subcore1_clk		0x26c29cb4
+#define clk_vmem_ahb_clk		0xab6223ff
+#define clk_vmem_maxi_clk		0x15ef32db
+#define clk_mmss_debug_mux		0xe646ffda
+#define clk_mmss_gcc_dbg_clk		0xafa4d48a
+#define clk_gfx3d_clk_src		0x917f76ef
+#define clk_extpclk_clk_src		0xb2c31abd
+#define clk_mdss_byte0_clk		0xf5a03f64
+#define clk_mdss_byte1_clk		0xb8c7067d
+#define clk_mdss_extpclk_clk		0xfa5aadb0
+#define clk_mdss_pclk0_clk		0x3487234a
+#define clk_mdss_pclk1_clk		0xd5804246
+#define clk_gpu_gcc_dbg_clk		0x0ccc42cd
+#define clk_mdss_mdp_vote_clk		0x588460a4
+#define clk_mdss_rotator_vote_clk	0x5b1f675e
+#define clk_mmpll2_postdiv_clk		0x4fdeaaba
+#define clk_mmpll8_postdiv_clk		0xedf57882
+#define clk_mmpll9_postdiv_clk		0x3064b618
+#define clk_gfx3d_clk_src_v2		0x4210acb7
+#define clk_byte0_clk_src		0x75cc885b
+#define clk_byte1_clk_src		0x63c2c955
+#define clk_pclk0_clk_src		0xccac1f35
+#define clk_pclk1_clk_src		0x090f68ac
+#define clk_ext_byte0_clk_src		0xfb32f31e
+#define clk_ext_byte1_clk_src		0x585ef6d4
+#define clk_ext_pclk0_clk_src		0x087c1612
+#define clk_ext_pclk1_clk_src		0x8067c5a3
+
+/* clock_debug controlled clocks */
+#define clk_gcc_debug_mux		0x8121ac15
+
+/* external multimedia clocks */
+#define clk_dsi0pll_pixel_clk_mux	0x792379e1
+#define clk_dsi0pll_byte_clk_mux	0x60e83f06
+#define clk_dsi0pll_byte_clk_src	0xbbaa30be
+#define clk_dsi0pll_pixel_clk_src	0x45b3260f
+#define clk_dsi0pll_n2_div_clk		0x1474c213
+#define clk_dsi0pll_post_n1_div_clk	0xdab8c389
+#define clk_dsi0pll_vco_clk		0x15940d40
+#define clk_dsi1pll_pixel_clk_mux	0x36458019
+#define clk_dsi1pll_byte_clk_mux	0xb5a42b7b
+#define clk_dsi1pll_byte_clk_src	0x63930a8f
+#define clk_dsi1pll_pixel_clk_src	0x0e4c9b56
+#define clk_dsi1pll_n2_div_clk		0x2c9d4007
+#define clk_dsi1pll_post_n1_div_clk	0x03020041
+#define clk_dsi1pll_vco_clk		0x99797b50
+#define clk_mdss_dsi1_vco_clk_src	0xfcd15658
+#define clk_hdmi_vco_clk		0x66003284
+
+#define clk_dsi0pll_shadow_byte_clk_src	0x177c029c
+#define clk_dsi0pll_shadow_pixel_clk_src	0x98ae3c92
+#define clk_dsi0pll_shadow_n2_div_clk	0xd5f0dad9
+#define clk_dsi0pll_shadow_post_n1_div_clk	0x1f7c8cf8
+#define clk_dsi0pll_shadow_vco_clk	0xb100ca83
+#define clk_dsi1pll_shadow_byte_clk_src	0xfc021ce5
+#define clk_dsi1pll_shadow_pixel_clk_src	0xdcca3ffc
+#define clk_dsi1pll_shadow_n2_div_clk		0x189541bf
+#define clk_dsi1pll_shadow_post_n1_div_clk	0x1637020e
+#define clk_dsi1pll_shadow_vco_clk		0x68d8b6f7
+
+/* CPU clocks */
+#define clk_pwrcl_clk 0xc554130e
+#define clk_pwrcl_pll 0x25454ca1
+#define clk_pwrcl_alt_pll 0xc445471b
+#define clk_pwrcl_pll_main 0x28948e22
+#define clk_pwrcl_alt_pll_main 0x25c8270e
+#define clk_pwrcl_hf_mux 0x77706ae6
+#define clk_pwrcl_lf_mux 0xd99e334d
+#define clk_perfcl_clk 0x58869997
+#define clk_perfcl_pll 0x97dcec1c
+#define clk_perfcl_alt_pll 0xfe2eaea1
+#define clk_perfcl_pll_main 0x0dbf0c0b
+#define clk_perfcl_alt_pll_main 0x0b892aab
+#define clk_perfcl_hf_mux 0x9e8bbe59
+#define clk_perfcl_lf_mux 0x2f9c278d
+#define clk_cbf_pll 0xfe2e96a3
+#define clk_cbf_pll_main 0x2b05cf95
+#define clk_cbf_hf_mux 0x71244f73
+#define clk_cbf_clk 0x48e9e16b
+#define clk_xo_ao 0x428c856d
+#define clk_sys_apcsaux_clk 0x0b0dd513
+#define clk_cpu_debug_mux 0xc7acaa31
+
+/* Audio External Clocks */
+#define clk_audio_ap_clk 0x312ac429
+#define clk_audio_pmi_clk 0xb7ba2274
+#define clk_audio_ap_clk2 0xf0fbaf5b
+#define clk_audio_lpass_mclk2 0x0122abee
+#endif
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
index 7e1394c..36d34b1 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -62,47 +62,44 @@
 #define GCC_GP2_CLK_SRC						44
 #define GCC_GP3_CLK						45
 #define GCC_GP3_CLK_SRC						46
-#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_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
+#define GCC_PCIE_0_CLKREF_CLK					47
+#define GCC_PCIE_AUX_CLK					48
+#define GCC_PCIE_AUX_PHY_CLK_SRC				49
+#define GCC_PCIE_CFG_AHB_CLK					50
+#define GCC_PCIE_MSTR_AXI_CLK					51
+#define GCC_PCIE_PHY_REFGEN_CLK					52
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC				53
+#define GCC_PCIE_PIPE_CLK					54
+#define GCC_PCIE_SLEEP_CLK					55
+#define GCC_PCIE_SLV_AXI_CLK					56
+#define GCC_PCIE_SLV_Q2A_AXI_CLK				57
+#define GCC_PDM2_CLK						58
+#define GCC_PDM2_CLK_SRC					59
+#define GCC_PDM_AHB_CLK						60
+#define GCC_PDM_XO4_CLK						61
+#define GCC_PRNG_AHB_CLK					62
+#define GCC_SDCC1_AHB_CLK					63
+#define GCC_SDCC1_APPS_CLK					64
+#define GCC_SDCC1_APPS_CLK_SRC					65
+#define GCC_SPMI_FETCHER_AHB_CLK				66
+#define GCC_SPMI_FETCHER_CLK					67
+#define GCC_SPMI_FETCHER_CLK_SRC				68
+#define GCC_SYS_NOC_CPUSS_AHB_CLK				69
+#define GCC_SYS_NOC_USB3_CLK					70
+#define GCC_USB30_MASTER_CLK					71
+#define GCC_USB30_MASTER_CLK_SRC				72
+#define GCC_USB30_MOCK_UTMI_CLK					73
+#define GCC_USB30_MOCK_UTMI_CLK_SRC				74
+#define GCC_USB30_SLEEP_CLK					75
+#define GCC_USB3_PHY_AUX_CLK					76
+#define GCC_USB3_PHY_AUX_CLK_SRC				77
+#define GCC_USB3_PHY_PIPE_CLK					78
+#define GCC_USB3_PRIM_CLKREF_CLK				79
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK				80
+#define GPLL0							81
+#define GPLL0_OUT_EVEN						82
+#define GPLL4							83
+#define GPLL4_OUT_EVEN						84
 
 /* CPU clocks */
 #define CLOCK_A7SS						0
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 75ffd3b..7995940 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -36,7 +36,10 @@
 };
 
 struct bpf_map {
-	atomic_t refcnt;
+	/* 1st cacheline with read-mostly members of which some
+	 * are also accessed in fast-path (e.g. ops, max_entries).
+	 */
+	const struct bpf_map_ops *ops ____cacheline_aligned;
 	enum bpf_map_type map_type;
 	u32 key_size;
 	u32 value_size;
@@ -44,10 +47,15 @@
 	u32 map_flags;
 	u32 pages;
 	bool unpriv_array;
-	struct user_struct *user;
-	const struct bpf_map_ops *ops;
-	struct work_struct work;
+	/* 7 bytes hole */
+
+	/* 2nd cacheline with misc members to avoid false sharing
+	 * particularly with refcounting.
+	 */
+	struct user_struct *user ____cacheline_aligned;
+	atomic_t refcnt;
 	atomic_t usercnt;
+	struct work_struct work;
 };
 
 struct bpf_map_type_list {
diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h
index 2189935..a951fd1 100644
--- a/include/linux/cacheinfo.h
+++ b/include/linux/cacheinfo.h
@@ -71,6 +71,7 @@
 	struct cacheinfo *info_list;
 	unsigned int num_levels;
 	unsigned int num_leaves;
+	bool cpu_map_populated;
 };
 
 /*
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 793255d..53a061e 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -42,6 +42,8 @@
 					 * to first consumer that enables clk
 					 */
 #define CLK_IS_MEASURE          BIT(14) /* measure clock */
+/* do not call clk_change_rate on the clock's children */
+#define CLK_CHILD_NO_RATE_PROP	BIT(15)
 
 struct clk;
 struct clk_hw;
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 0d442e3..47f5ba6 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -199,7 +199,7 @@
 extern void clockevents_resume(void);
 
 # ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
-#  ifdef CONFIG_ARCH_HAS_TICK_BROADCAST
+#  if defined(CONFIG_ARCH_HAS_TICK_BROADCAST) && defined(CONFIG_SMP)
 extern void tick_broadcast(const struct cpumask *mask);
 #  else
 #   define tick_broadcast	NULL
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index 32c3d42..fabfc0b 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -272,11 +272,16 @@
 				struct device *dev, struct device_node *node);
 extern struct coresight_cti_data *of_get_coresight_cti_data(
 				struct device *dev, struct device_node *node);
+extern int of_get_coresight_csr_name(struct device_node *node,
+				const char **csr_name);
+
 #else
 static inline struct coresight_platform_data *of_get_coresight_platform_data(
 	struct device *dev, struct device_node *node) { return NULL; }
 static inline struct coresight_cti_data *of_get_coresight_cti_data(
 		struct device *dev, struct device_node *node) { return NULL; }
+static inline int of_get_coresight_csr_name(struct device_node *node,
+		const char **csr_name){ return -EINVAL; }
 #endif
 
 #ifdef CONFIG_PID_NS
diff --git a/include/linux/fb.h b/include/linux/fb.h
index a964d07..2b9ece8 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -303,10 +303,18 @@
 	int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
 			unsigned long arg);
 
+	/* perform fb specific ioctl v2 (optional) - provides file param */
+	int (*fb_ioctl_v2)(struct fb_info *info, unsigned int cmd,
+					unsigned long arg, struct file *file);
+
 	/* Handle 32bit compat ioctl (optional) */
-	int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
+	int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd,
 			unsigned long arg);
 
+	/* Handle 32bit compat ioctl (optional) */
+	int (*fb_compat_ioctl_v2)(struct fb_info *info, unsigned int cmd,
+				  unsigned long arg, struct file *file);
+
 	/* perform fb specific mmap */
 	int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
 
@@ -475,6 +483,7 @@
 	struct fb_cmap cmap;		/* Current cmap */
 	struct list_head modelist;      /* mode list */
 	struct fb_videomode *mode;	/* current mode */
+	struct file *file;		/* current file node */
 
 #ifdef CONFIG_FB_BACKLIGHT
 	/* assigned backlight device */
diff --git a/include/linux/input/synaptics_dsx_v2_6.h b/include/linux/input/synaptics_dsx_v2_6.h
index 2b91bc0..52241e5 100644
--- a/include/linux/input/synaptics_dsx_v2_6.h
+++ b/include/linux/input/synaptics_dsx_v2_6.h
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
  * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -57,6 +58,7 @@
  * @x_flip: x flip flag
  * @y_flip: y flip flag
  * @swap_axes: swap axes flag
+ * @resume_in_workqueue: defer resume function to workqueue
  * @irq_gpio: attention interrupt GPIO
  * @irq_on_state: attention interrupt active state
  * @power_gpio: power switch GPIO
@@ -84,6 +86,7 @@
 	bool x_flip;
 	bool y_flip;
 	bool swap_axes;
+	bool resume_in_workqueue;
 	int irq_gpio;
 	int irq_on_state;
 	int power_gpio;
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index bbc65ef..3562047 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -14,6 +14,7 @@
 #include <linux/hrtimer.h>
 #include <linux/kref.h>
 #include <linux/workqueue.h>
+#include <linux/sched.h>
 
 #include <linux/atomic.h>
 #include <asm/ptrace.h>
@@ -498,6 +499,13 @@
 	return this_cpu_read(ksoftirqd);
 }
 
+static inline bool ksoftirqd_running_on(int cpu)
+{
+	struct task_struct *tsk = per_cpu(ksoftirqd, cpu);
+
+	return tsk && (tsk->state == TASK_RUNNING);
+}
+
 /* Tasklets --- multithreaded analogue of BHs.
 
    Main feature differing them of generic softirqs: tasklet
diff --git a/include/linux/leds-qpnp-flash.h b/include/linux/leds-qpnp-flash.h
index 1fe6e17..e3b9cf1 100644
--- a/include/linux/leds-qpnp-flash.h
+++ b/include/linux/leds-qpnp-flash.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -21,7 +21,14 @@
 
 #define FLASH_LED_PREPARE_OPTIONS_MASK	GENMASK(3, 0)
 
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+#if (defined CONFIG_LEDS_QPNP_FLASH || defined CONFIG_LEDS_QPNP_FLASH_V2)
+extern int (*qpnp_flash_led_prepare)(struct led_trigger *trig, int options,
 					int *max_current);
-
+#else
+static inline int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
+					int *max_current)
+{
+	return -ENODEV;
+}
+#endif
 #endif
diff --git a/include/linux/mdss_io_util.h b/include/linux/mdss_io_util.h
index 028f3e3..dd0b17c 100644
--- a/include/linux/mdss_io_util.h
+++ b/include/linux/mdss_io_util.h
@@ -28,26 +28,26 @@
 #define DEV_WARN(fmt, args...)  pr_warn(fmt, ##args)
 #define DEV_ERR(fmt, args...)   pr_err(fmt, ##args)
 
-struct dss_io_data {
+struct mdss_io_data {
 	u32 len;
 	void __iomem *base;
 };
 
-void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug);
-u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug);
-void dss_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug);
+void mdss_reg_w(struct mdss_io_data *io, u32 offset, u32 value, u32 debug);
+u32 mdss_reg_r(struct mdss_io_data *io, u32 offset, u32 debug);
+void mdss_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug);
 
-#define DSS_REG_W_ND(io, offset, val)  dss_reg_w(io, offset, val, false)
-#define DSS_REG_W(io, offset, val)     dss_reg_w(io, offset, val, true)
-#define DSS_REG_R_ND(io, offset)       dss_reg_r(io, offset, false)
-#define DSS_REG_R(io, offset)          dss_reg_r(io, offset, true)
+#define DSS_REG_W_ND(io, offset, val)  mdss_reg_w(io, offset, val, false)
+#define DSS_REG_W(io, offset, val)     mdss_reg_w(io, offset, val, true)
+#define DSS_REG_R_ND(io, offset)       mdss_reg_r(io, offset, false)
+#define DSS_REG_R(io, offset)          mdss_reg_r(io, offset, true)
 
-enum dss_vreg_type {
+enum mdss_vreg_type {
 	DSS_REG_LDO,
 	DSS_REG_VS,
 };
 
-enum dss_vreg_mode {
+enum mdss_vreg_mode {
 	DSS_REG_MODE_ENABLE,
 	DSS_REG_MODE_DISABLE,
 	DSS_REG_MODE_LP,
@@ -55,7 +55,7 @@
 	DSS_REG_MODE_MAX,
 };
 
-struct dss_vreg {
+struct mdss_vreg {
 	struct regulator *vreg; /* vreg handle */
 	char vreg_name[32];
 	int min_voltage;
@@ -67,51 +67,52 @@
 	int post_off_sleep;
 };
 
-struct dss_gpio {
+struct mdss_gpio {
 	unsigned int gpio;
 	unsigned int value;
 	char gpio_name[32];
 };
 
-enum dss_clk_type {
+enum mdss_clk_type {
 	DSS_CLK_AHB, /* no set rate. rate controlled through rpm */
 	DSS_CLK_PCLK,
 	DSS_CLK_OTHER,
 };
 
-struct dss_clk {
+struct mdss_clk {
 	struct clk *clk; /* clk handle */
 	char clk_name[32];
-	enum dss_clk_type type;
+	enum mdss_clk_type type;
 	unsigned long rate;
 };
 
-struct dss_module_power {
+struct mdss_module_power {
 	unsigned int num_vreg;
-	struct dss_vreg *vreg_config;
+	struct mdss_vreg *vreg_config;
 	unsigned int num_gpio;
-	struct dss_gpio *gpio_config;
+	struct mdss_gpio *gpio_config;
 	unsigned int num_clk;
-	struct dss_clk *clk_config;
+	struct mdss_clk *clk_config;
 };
 
-int msm_dss_ioremap_byname(struct platform_device *pdev,
-	struct dss_io_data *io_data, const char *name);
-void msm_dss_iounmap(struct dss_io_data *io_data);
+int msm_mdss_ioremap_byname(struct platform_device *pdev,
+	struct mdss_io_data *io_data, const char *name);
+void msm_mdss_iounmap(struct mdss_io_data *io_data);
 
-int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
-int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
+int msm_mdss_enable_gpio(struct mdss_gpio *in_gpio, int num_gpio, int enable);
+int msm_mdss_gpio_enable(struct mdss_gpio *in_gpio, int num_gpio, int enable);
 
-int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
+int msm_mdss_config_vreg(struct device *dev, struct mdss_vreg *in_vreg,
 	int num_vreg, int config);
-int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg,	int enable);
-int msm_dss_config_vreg_opt_mode(struct dss_vreg *in_vreg, int num_vreg,
-	 enum dss_vreg_mode mode);
+int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable);
+int msm_mdss_config_vreg_opt_mode(struct mdss_vreg *in_vreg, int num_vreg,
+	 enum mdss_vreg_mode mode);
 
-int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
-void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
-int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
-int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
+int msm_mdss_get_clk(struct device *dev, struct mdss_clk *clk_arry,
+		     int num_clk);
+void msm_mdss_put_clk(struct mdss_clk *clk_arry, int num_clk);
+int msm_mdss_clk_set_rate(struct mdss_clk *clk_arry, int num_clk);
+int msm_mdss_enable_clk(struct mdss_clk *clk_arry, int num_clk, int enable);
 
 int mdss_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
 		       uint8_t reg_offset, uint8_t *read_buf);
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 25ed105..20ee90c 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -737,6 +737,12 @@
 	MLX5_CAP_PORT_TYPE_ETH = 0x1,
 };
 
+enum {
+	MLX5_CAP_UMR_FENCE_STRONG	= 0x0,
+	MLX5_CAP_UMR_FENCE_SMALL	= 0x1,
+	MLX5_CAP_UMR_FENCE_NONE		= 0x2,
+};
+
 struct mlx5_ifc_cmd_hca_cap_bits {
 	u8         reserved_at_0[0x80];
 
@@ -838,7 +844,9 @@
 	u8         striding_rq[0x1];
 	u8         reserved_at_201[0x2];
 	u8         ipoib_basic_offloads[0x1];
-	u8         reserved_at_205[0xa];
+	u8         reserved_at_205[0x5];
+	u8         umr_fence[0x2];
+	u8         reserved_at_20c[0x3];
 	u8         drain_sigerr[0x1];
 	u8         cmdif_checksum[0x2];
 	u8         sigerr_cqe[0x1];
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 16155d0..932e99c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1901,6 +1901,7 @@
 /* page_alloc.c */
 extern int min_free_kbytes;
 extern int watermark_scale_factor;
+extern int extra_free_kbytes;
 
 /* nommu.c */
 extern atomic_long_t mmap_pages_allocated;
diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h
index afaa08a20..d5a5457 100644
--- a/include/linux/msm_hdmi.h
+++ b/include/linux/msm_hdmi.h
@@ -1,10 +1,6 @@
 /* include/linux/msm_hdmi.h
  *
-<<<<<<< HEAD
  * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
-=======
- * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
->>>>>>> dfa46f9... fbdev: msm: fix compilation error
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 164abe2..61c557a 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -272,8 +272,11 @@
 	POWER_SUPPLY_PROP_SDP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_CONNECTOR_TYPE,
 	POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
+	POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
 	POWER_SUPPLY_PROP_MIN_ICL,
 	POWER_SUPPLY_PROP_MOISTURE_DETECTED,
+	POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
+	POWER_SUPPLY_PROP_RECHARGE_SOC,
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
 	/* Properties of type `const char *' */
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 14e8d79..8933742 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -184,6 +184,11 @@
 /* PMI632 */
 #define PMI632_SUBTYPE	0x25
 
+/* PM855 */
+#define PM855_SUBTYPE		0x1E
+#define PM855L_SUBTYPE		0x1F
+#define PM855B_SUBTYPE		0x20
+
 /* PMI8998 REV_ID */
 #define PMI8998_V1P0_REV1	0x00
 #define PMI8998_V1P0_REV2	0x00
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 62c770d..290e2b2 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1777,7 +1777,7 @@
 	u32 init_load_pct;
 	u64 last_wake_ts;
 	u64 last_switch_out_ts;
-	u64 last_cpu_selected_ts;
+	u64 last_enqueued_ts;
 	struct related_thread_group *grp;
 	struct list_head grp_list;
 	u64 cpu_cycles;
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
index 12bd032..3e97574 100644
--- a/include/linux/sched/sysctl.h
+++ b/include/linux/sched/sysctl.h
@@ -34,6 +34,7 @@
 extern unsigned int sysctl_sched_boost;
 extern unsigned int sysctl_sched_group_upmigrate_pct;
 extern unsigned int sysctl_sched_group_downmigrate_pct;
+extern unsigned int sysctl_sched_walt_rotate_big_tasks;
 
 extern int
 walt_proc_update_handler(struct ctl_table *table, int write,
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 972dabc..6acd229 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -84,6 +84,8 @@
  * @db_reg_phs_addr_lsb: IPA channel doorbell register's physical address LSB
  * @mapped_db_reg_phs_addr_lsb: doorbell LSB IOVA address mapped with IOMMU
  * @db_reg_phs_addr_msb: IPA channel doorbell register's physical address MSB
+ * @sgt_trb_xfer_ring: USB TRB ring related sgtable entries
+ * @sgt_data_buff: Data buffer related sgtable entries
  */
 struct usb_gsi_request {
 	void *buf_base_addr;
@@ -93,6 +95,8 @@
 	u32 db_reg_phs_addr_lsb;
 	dma_addr_t mapped_db_reg_phs_addr_lsb;
 	u32 db_reg_phs_addr_msb;
+	struct sg_table sgt_trb_xfer_ring;
+	struct sg_table sgt_data_buff;
 };
 
 /*
@@ -474,6 +478,9 @@
  * @deactivated: True if gadget is deactivated - in deactivated state it cannot
  *	be connected.
  * @connected: True if gadget is connected.
+ * @bam2bam_func_enabled; Indicates function using bam2bam is enabled or not.
+ * @extra_buf_alloc: Extra allocation size for AXI prefetch so that out of
+ * boundary access is protected.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -527,6 +534,9 @@
 	unsigned			deactivated:1;
 	unsigned			connected:1;
 	bool				remote_wakeup;
+	bool				bam2bam_func_enabled;
+	u32				extra_buf_alloc;
+	bool				l1_supported;
 };
 #define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))
 
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
new file mode 100644
index 0000000..c3e980e
--- /dev/null
+++ b/include/linux/usb/msm_hsusb.h
@@ -0,0 +1,357 @@
+/* include/linux/usb/msm_hsusb.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_HSUSB_H
+#define __ASM_ARCH_MSM_HSUSB_H
+
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/clk.h>
+#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
+#include <linux/power_supply.h>
+#include <linux/cdev.h>
+#include <linux/usb_bam.h>
+#include <linux/extcon.h>
+#include <linux/regulator/driver.h>
+/**
+ * Requested USB votes for NOC frequency
+ *
+ * USB_NOC_NOM_VOTE    Vote for NOM set of NOC frequencies
+ * USB_NOC_SVS_VOTE    Vote for SVS set of NOC frequencies
+ *
+ */
+enum usb_noc_mode {
+	USB_NOC_NOM_VOTE = 0,
+	USB_NOC_SVS_VOTE,
+	USB_NOC_NUM_VOTE,
+};
+
+/**
+ * Different states involved in USB charger detection.
+ *
+ * USB_CHG_STATE_UNDEFINED	USB charger is not connected or detection
+ *                              process is not yet started.
+ * USB_CHG_STATE_IN_PROGRESS	Charger detection in progress
+ * USB_CHG_STATE_WAIT_FOR_DCD	Waiting for Data pins contact.
+ * USB_CHG_STATE_DCD_DONE	Data pin contact is detected.
+ * USB_CHG_STATE_PRIMARY_DONE	Primary detection is completed (Detects
+ *                              between SDP and DCP/CDP).
+ * USB_CHG_STATE_SECONDARY_DONE	Secondary detection is completed (Detects
+ *                              between DCP and CDP).
+ * USB_CHG_STATE_DETECTED	USB charger type is determined.
+ *
+ */
+enum usb_chg_state {
+	USB_CHG_STATE_UNDEFINED = 0,
+	USB_CHG_STATE_IN_PROGRESS,
+	USB_CHG_STATE_WAIT_FOR_DCD,
+	USB_CHG_STATE_DCD_DONE,
+	USB_CHG_STATE_PRIMARY_DONE,
+	USB_CHG_STATE_SECONDARY_DONE,
+	USB_CHG_STATE_DETECTED,
+};
+
+/**
+ * USB charger types
+ *
+ * USB_INVALID_CHARGER	Invalid USB charger.
+ * USB_SDP_CHARGER	Standard downstream port. Refers to a downstream port
+ *                      on USB2.0 compliant host/hub.
+ * USB_DCP_CHARGER	Dedicated charger port (AC charger/ Wall charger).
+ * USB_CDP_CHARGER	Charging downstream port. Enumeration can happen and
+ *                      IDEV_CHG_MAX can be drawn irrespective of USB state.
+ * USB_NONCOMPLIANT_CHARGER A non-compliant charger pull DP and DM to specific
+ *			    voltages between 2.0-3.3v for identification.
+ *
+ */
+enum usb_chg_type {
+	USB_INVALID_CHARGER = 0,
+	USB_SDP_CHARGER,
+	USB_DCP_CHARGER,
+	USB_CDP_CHARGER,
+	USB_NONCOMPLIANT_CHARGER,
+	USB_FLOATED_CHARGER,
+};
+
+/**
+ * Maintain state for hvdcp external charger status
+ * DEFAULT	This is used when DCP is detected
+ * ACTIVE	This is used when ioctl is called to block LPM
+ * INACTIVE	This is used when ioctl is called to unblock LPM
+ */
+
+enum usb_ext_chg_status {
+	DEFAULT = 1,
+	ACTIVE,
+	INACTIVE,
+};
+
+/**
+ * USB ID state
+ */
+enum usb_id_state {
+	USB_ID_GROUND = 0,
+	USB_ID_FLOAT,
+};
+
+#define USB_NUM_BUS_CLOCKS      3
+
+/**
+ * struct msm_otg: OTG driver data. Shared by HCD and DCD.
+ * @otg: USB OTG Transceiver structure.
+ * @pdata: otg device platform data.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @async_irq: IRQ number used by some controllers during low power state
+ * @phy_irq: IRQ number assigned for PHY to notify events like id and line
+		state changes.
+ * @pclk: clock struct of iface_clk.
+ * @core_clk: clock struct of core_bus_clk.
+ * @sleep_clk: clock struct of sleep_clk for USB PHY.
+ * @phy_reset_clk: clock struct of phy_reset_clk for USB PHY. This clock is
+		a reset only clock and resets the PHY, ULPI bridge and
+		CSR wrapper.
+ * @phy_por_clk: clock struct of phy_por_clk for USB PHY. This clock is
+		a reset only clock and resets only the PHY (POR).
+ * @phy_csr_clk: clock struct of phy_csr_clk for USB PHY. This clock is
+		required to access PHY CSR registers via AHB2PHY interface.
+ * @bus_clks: bimc/snoc/pcnoc clock struct.
+ * @core_reset: Reset control for core_clk
+ * @phy_reset: Reset control for phy_reset_clk
+ * @phy_por_reset: Reset control for phy_por_clk
+ * @default_noc_mode: default frequency for NOC clocks - SVS or NOM
+ * @core_clk_rate: core clk max frequency
+ * @regs: ioremapped register base address.
+ * @usb_phy_ctrl_reg: relevant PHY_CTRL_REG register base address.
+ * @inputs: OTG state machine inputs(Id, SessValid etc).
+ * @sm_work: OTG state machine work.
+ * @sm_work_pending: OTG state machine work is pending, queued post pm_resume
+ * @resume_pending: USB h/w lpm_exit pending. Done on next sm_work run
+ * @pm_suspended: OTG device is system(PM) suspended.
+ * @pm_notify: Notifier to receive system wide PM transition events.
+		It is used to defer wakeup events processing until
+		system is RESUMED.
+ * @in_lpm: indicates low power mode (LPM) state.
+ * @async_int: IRQ line on which ASYNC interrupt arrived in LPM.
+ * @cur_power: The amount of mA available from downstream port.
+ * @otg_wq: Strict order otg workqueue for OTG works (SM/ID/SUSPEND).
+ * @chg_work: Charger detection work.
+ * @chg_state: The state of charger detection process.
+ * @chg_type: The type of charger attached.
+ * @bus_perf_client: Bus performance client handle to request BUS bandwidth
+ * @host_bus_suspend: indicates host bus suspend or not.
+ * @device_bus_suspend: indicates device bus suspend or not.
+ * @bus_clks_enabled: indicates pcnoc/snoc/bimc clocks are on or not.
+ * @chg_check_timer: The timer used to implement the workaround to detect
+ *               very slow plug in of wall charger.
+ * @bc1p2_current_max: Max charging current allowed as per bc1.2 chg detection
+ * @typec_current_max: Max charging current allowed as per type-c chg detection
+ * @is_ext_chg_dcp: To indicate whether charger detected by external entity
+		SMB hardware is DCP charger or not.
+ * @ext_id_irq: IRQ for ID interrupt.
+ * @phy_irq_pending: Gets set when PHY IRQ arrives in LPM.
+ * @id_state: Indicates USBID line status.
+ * @rm_pulldown: Indicates pulldown status on D+ and D- data lines.
+ * @extcon_vbus: Used for VBUS notification registration.
+ * @extcon_id: Used for ID notification registration.
+ * @vbus_nb: Notification callback for VBUS event.
+ * @id_nb: Notification callback for ID event.
+ * @dpdm_desc: Regulator descriptor for D+ and D- voting.
+ * @dpdm_rdev: Regulator class device for dpdm regulator.
+ * @dbg_idx: Dynamic debug buffer Index.
+ * @dbg_lock: Dynamic debug buffer Lock.
+ * @buf: Dynamic Debug Buffer.
+ * @max_nominal_system_clk_rate: max freq at which system clock can run in
+		nominal mode.
+ */
+struct msm_otg {
+	struct usb_phy phy;
+	struct msm_otg_platform_data *pdata;
+	struct platform_device *pdev;
+	int irq;
+	int async_irq;
+	int phy_irq;
+	struct clk *xo_clk;
+	struct clk *pclk;
+	struct clk *core_clk;
+	struct clk *sleep_clk;
+	struct clk *phy_reset_clk;
+	struct clk *phy_por_clk;
+	struct clk *phy_csr_clk;
+	struct clk *bus_clks[USB_NUM_BUS_CLOCKS];
+	struct clk *phy_ref_clk;
+	struct reset_control *core_reset;
+	struct reset_control *phy_reset;
+	struct reset_control *phy_por_reset;
+	long core_clk_rate;
+	long core_clk_svs_rate;
+	long core_clk_nominal_rate;
+	enum usb_noc_mode default_noc_mode;
+	struct resource *io_res;
+	void __iomem *regs;
+	void __iomem *phy_csr_regs;
+	void __iomem *usb_phy_ctrl_reg;
+#define ID		0
+#define B_SESS_VLD	1
+#define A_BUS_SUSPEND	14
+#define B_FALSE_SDP	18
+	unsigned long inputs;
+	struct work_struct sm_work;
+	bool sm_work_pending;
+	bool resume_pending;
+	atomic_t pm_suspended;
+	struct notifier_block pm_notify;
+	atomic_t in_lpm;
+	bool err_event_seen;
+	int async_int;
+	unsigned int cur_power;
+	struct workqueue_struct *otg_wq;
+	struct delayed_work chg_work;
+	struct delayed_work id_status_work;
+	enum usb_chg_state chg_state;
+	enum usb_chg_type chg_type;
+	unsigned int dcd_time;
+	unsigned long caps;
+	uint32_t bus_perf_client;
+	bool host_bus_suspend;
+	bool device_bus_suspend;
+	bool bus_clks_enabled;
+	struct timer_list chg_check_timer;
+	/*
+	 * Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
+	 * analog regulators while going to low power mode.
+	 * Currently only 28nm PHY has the support to allowing PHY
+	 * power collapse since it doesn't have leakage currents while
+	 * turning off the power rails.
+	 */
+#define ALLOW_PHY_POWER_COLLAPSE	BIT(0)
+	/*
+	 * Allow PHY RETENTION mode before turning off the digital
+	 * voltage regulator(VDDCX).
+	 */
+#define ALLOW_PHY_RETENTION		BIT(1)
+	/*
+	 * Allow putting the core in Low Power mode, when
+	 * USB bus is suspended but cable is connected.
+	 */
+#define ALLOW_LPM_ON_DEV_SUSPEND	BIT(2)
+	/*
+	 * Allowing PHY regulators LPM puts the HSUSB 3.3v and 1.8v
+	 * analog regulators into LPM while going to USB low power mode.
+	 */
+#define ALLOW_PHY_REGULATORS_LPM	BIT(3)
+	/*
+	 * Allow PHY RETENTION mode before turning off the digital
+	 * voltage regulator(VDDCX) during host mode.
+	 */
+#define ALLOW_HOST_PHY_RETENTION	BIT(4)
+	/*
+	 * Allow VDD minimization without putting PHY into retention
+	 * for fixing PHY current leakage issue when LDOs ar turned off.
+	 */
+#define ALLOW_VDD_MIN_WITH_RETENTION_DISABLED BIT(5)
+
+	/*
+	 * PHY can keep D+ pull-up during peripheral bus suspend and
+	 * D+/D- pull-down during host bus suspend without any
+	 * re-work. This is possible only when PHY DVDD is supplied
+	 * by a PMIC LDO (unlike VDDCX/VDDMX).
+	 */
+#define ALLOW_BUS_SUSPEND_WITHOUT_REWORK BIT(6)
+	unsigned long lpm_flags;
+#define PHY_PWR_COLLAPSED		BIT(0)
+#define PHY_RETENTIONED			BIT(1)
+#define XO_SHUTDOWN			BIT(2)
+#define CLOCKS_DOWN			BIT(3)
+#define PHY_REGULATORS_LPM	BIT(4)
+	int reset_counter;
+	unsigned int online;
+	unsigned int host_mode;
+	unsigned int bc1p2_current_max;
+	unsigned int typec_current_max;
+
+	dev_t ext_chg_dev;
+	struct cdev ext_chg_cdev;
+	struct class *ext_chg_class;
+	struct device *ext_chg_device;
+	bool ext_chg_opened;
+	enum usb_ext_chg_status ext_chg_active;
+	struct completion ext_chg_wait;
+	struct pinctrl *phy_pinctrl;
+	bool is_ext_chg_dcp;
+	struct qpnp_vadc_chip	*vadc_dev;
+	int ext_id_irq;
+	bool phy_irq_pending;
+	enum usb_id_state id_state;
+	bool rm_pulldown;
+	struct extcon_dev       *extcon_vbus;
+	struct extcon_dev       *extcon_id;
+	struct notifier_block   vbus_nb;
+	struct notifier_block   id_nb;
+	struct regulator_desc	dpdm_rdesc;
+	struct regulator_dev	*dpdm_rdev;
+/* Maximum debug message length */
+#define DEBUG_MSG_LEN   128UL
+/* Maximum number of messages */
+#define DEBUG_MAX_MSG   256UL
+	unsigned int dbg_idx;
+	rwlock_t dbg_lock;
+
+	char (buf[DEBUG_MAX_MSG])[DEBUG_MSG_LEN];   /* buffer */
+	unsigned int vbus_state;
+	unsigned int usb_irq_count;
+	int pm_qos_latency;
+	struct pm_qos_request pm_qos_req_dma;
+	struct delayed_work perf_vote_work;
+};
+
+struct ci13xxx_platform_data {
+	u8 usb_core_id;
+	/*
+	 * value of 2^(log2_itc-1) will be used as the interrupt threshold
+	 * (ITC), when log2_itc is between 1 to 7.
+	 */
+	int log2_itc;
+	bool l1_supported;
+	bool enable_ahb2ahb_bypass;
+	bool enable_streaming;
+	bool enable_axi_prefetch;
+};
+
+#ifdef CONFIG_USB_BAM
+void msm_bam_set_usb_host_dev(struct device *dev);
+bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable);
+int msm_do_bam_disable_enable(enum usb_ctrl ctrl);
+#else
+static inline void msm_bam_set_usb_host_dev(struct device *dev) {}
+static inline bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable)
+{
+	return true;
+}
+int msm_do_bam_disable_enable(enum usb_ctrl ctrl) { return true; }
+#endif
+#ifdef CONFIG_USB_CI13XXX_MSM
+void msm_hw_soft_reset(void);
+#else
+static inline void msm_hw_soft_reset(void)
+{
+}
+#endif
+
+#endif
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 974c379..2f90ddc 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -21,10 +21,14 @@
 
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
+#define USB_GENCONFIG        (MSM_USB_BASE + 0x009C)
 #define USB_GENCONFIG_2      (MSM_USB_BASE + 0x00a0)
 #define ULPI_TX_PKT_EN_CLR_FIX	BIT(19)
 
 #define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
+#define USB_HS_APF_CTRL      (MSM_USB_BASE + 0x0380)
+
+#define APF_CTRL_EN		BIT(0)
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
 #define USB_PORTSC           (MSM_USB_BASE + 0x0184)
@@ -34,15 +38,32 @@
 #define USB_PHY_CTRL2        (MSM_USB_BASE + 0x0278)
 
 #define GENCONFIG_2_SESS_VLD_CTRL_EN	BIT(7)
+#define GENCONFIG_2_LINESTATE_DIFF_WAKEUP_EN	BIT(12)
+#define GENCONFIG_2_DPSE_DMSE_HV_INTR_EN	BIT(15)
 #define USBCMD_SESS_VLD_CTRL		BIT(25)
 
 #define USBCMD_RESET   2
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
 
+#define AHB2AHB_BYPASS          BIT(31)
+#define AHB2AHB_BYPASS_BIT_MASK        BIT(31)
+#define AHB2AHB_BYPASS_CLEAR   (0 << 31)
+#define USB_L1_EP_CTRL       (MSM_USB_BASE + 0x0250)
+#define USB_L1_CONFIG        (MSM_USB_BASE + 0x0254)
+
+#define L1_CONFIG_LPM_EN        BIT(4)
+#define L1_CONFIG_REMOTE_WAKEUP BIT(5)
+#define L1_CONFIG_GATE_SYS_CLK	BIT(7)
+#define L1_CONFIG_PHY_LPM	BIT(10)
+#define L1_CONFIG_PLL		BIT(11)
+
 #define PORTSC_PHCD            (1 << 23) /* phy suspend mode */
 #define PORTSC_PTS_MASK        (3 << 30)
 #define PORTSC_PTS_ULPI        (2 << 30)
 #define PORTSC_PTS_SERIAL      (3 << 30)
+#define PORTSC_LS	       (3 << 10)
+#define PORTSC_LS_DM	       (1 << 10)
+#define PORTSC_CCS	       (1 << 0)
 
 #define USB_ULPI_VIEWPORT    (MSM_USB_BASE + 0x0170)
 #define ULPI_RUN              (1 << 30)
@@ -52,6 +73,10 @@
 #define ULPI_DATA(n)          ((n) & 255)
 #define ULPI_DATA_READ(n)     (((n) >> 8) & 255)
 
+#define GENCONFIG_BAM_DISABLE (1 << 13)
+#define GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE (1 << 4)
+#define GENCONFIG_ULPI_SERIAL_EN (1 << 5)
+
 /* synopsys 28nm phy registers */
 #define ULPI_PWR_CLK_MNG_REG	0x88
 #define OTG_COMP_DISABLE	BIT(0)
@@ -63,10 +88,16 @@
 #define ASYNC_INTR_CTRL         (1 << 29) /* Enable async interrupt */
 #define ULPI_STP_CTRL           (1 << 30) /* Block communication with PHY */
 #define PHY_RETEN               (1 << 1) /* PHY retention enable/disable */
+#define PHY_IDHV_INTEN          (1 << 8) /* PHY ID HV interrupt */
+#define PHY_OTGSESSVLDHV_INTEN  (1 << 9) /* PHY Session Valid HV int. */
+#define PHY_CLAMP_DPDMSE_EN	(1 << 21) /* PHY mpm DP DM clamp enable */
+#define PHY_POR_BIT_MASK        BIT(0)
 #define PHY_POR_ASSERT		(1 << 0) /* USB2 28nm PHY POR ASSERT */
+#define PHY_POR_DEASSERT        (0 << 0) /* USB2 28nm PHY POR DEASSERT */
 
 /* OTG definitions */
 #define OTGSC_INTSTS_MASK	(0x7f << 16)
+#define OTGSC_IDPU		(1 << 5)
 #define OTGSC_ID		(1 << 8)
 #define OTGSC_BSV		(1 << 11)
 #define OTGSC_IDIS		(1 << 16)
@@ -74,4 +105,29 @@
 #define OTGSC_IDIE		(1 << 24)
 #define OTGSC_BSVIE		(1 << 27)
 
+/* USB PHY CSR registers and bit definitions */
+
+#define USB_PHY_CSR_PHY_CTRL_COMMON0 (MSM_USB_PHY_CSR_BASE + 0x078)
+#define SIDDQ BIT(2)
+
+#define USB_PHY_CSR_PHY_CTRL1 (MSM_USB_PHY_CSR_BASE + 0x08C)
+#define ID_HV_CLAMP_EN_N BIT(1)
+
+#define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094)
+#define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2)
+
+#define USB2_PHY_USB_PHY_IRQ_CMD (MSM_USB_PHY_CSR_BASE + 0x0D0)
+#define USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS (MSM_USB_PHY_CSR_BASE + 0x05C)
+
+#define USB2_PHY_USB_PHY_INTERRUPT_CLEAR0 (MSM_USB_PHY_CSR_BASE + 0x0DC)
+#define USB2_PHY_USB_PHY_INTERRUPT_CLEAR1 (MSM_USB_PHY_CSR_BASE + 0x0E0)
+
+#define USB2_PHY_USB_PHY_INTERRUPT_MASK1 (MSM_USB_PHY_CSR_BASE + 0x0D8)
+
+#define USB_PHY_IDDIG_1_0 BIT(7)
+
+#define USB_PHY_IDDIG_RISE_MASK BIT(0)
+#define USB_PHY_IDDIG_FALL_MASK BIT(1)
+#define USB_PHY_ID_MASK (USB_PHY_IDDIG_RISE_MASK | USB_PHY_IDDIG_FALL_MASK)
+
 #endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 64aa52e..d999b3c 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -58,6 +58,7 @@
 	OTG_STATE_B_SRP_INIT,
 	OTG_STATE_B_PERIPHERAL,
 	OTG_STATE_B_SUSPEND,
+	OTG_STATE_B_CHARGER,
 
 	/* extra dual-role default-b states */
 	OTG_STATE_B_WAIT_ACON,
@@ -141,6 +142,10 @@
 
 	/* reset the PHY clocks */
 	int     (*reset)(struct usb_phy *x);
+
+	/* for notification of usb_phy_dbg_events */
+	void    (*dbg_event)(struct usb_phy *x,
+			char *event, int msg1, int msg2);
 	int	(*disable_chirp)(struct usb_phy *x, bool disable);
 };
 
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 623b6f0..83904c9 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -72,6 +72,8 @@
 	unsigned long flags;
 	enum hal_buffer buffer_type;
 	struct dma_mapping_info mapping_info;
+	int mem_type;
+	void *smem_priv;
 };
 
 enum smem_cache_ops {
@@ -104,6 +106,8 @@
 int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
 int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
 int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_release_buffers(void *instance, int buffer_type);
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
 int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
 int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
diff --git a/include/net/arp.h b/include/net/arp.h
index 5e0f891..1b3f869 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -19,6 +19,9 @@
 
 static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key)
 {
+	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
+		key = INADDR_ANY;
+
 	return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev);
 }
 
diff --git a/include/net/cnss.h b/include/net/cnss.h
new file mode 100644
index 0000000..368d01e
--- /dev/null
+++ b/include/net/cnss.h
@@ -0,0 +1,266 @@
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _NET_CNSS_H_
+#define _NET_CNSS_H_
+
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_CNSS
+#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
+#define CNSS_MAX_FILE_NAME	20
+#define PINCTRL_SLEEP  0
+#define PINCTRL_ACTIVE 1
+
+enum cnss_bus_width_type {
+	CNSS_BUS_WIDTH_NONE,
+	CNSS_BUS_WIDTH_LOW,
+	CNSS_BUS_WIDTH_MEDIUM,
+	CNSS_BUS_WIDTH_HIGH
+};
+
+enum cnss_cc_src {
+	CNSS_SOURCE_CORE,
+	CNSS_SOURCE_11D,
+	CNSS_SOURCE_USER
+};
+
+/* FW image files */
+struct cnss_fw_files {
+	char image_file[CNSS_MAX_FILE_NAME];
+	char board_data[CNSS_MAX_FILE_NAME];
+	char otp_data[CNSS_MAX_FILE_NAME];
+	char utf_file[CNSS_MAX_FILE_NAME];
+	char utf_board_data[CNSS_MAX_FILE_NAME];
+	char epping_file[CNSS_MAX_FILE_NAME];
+	char evicted_data[CNSS_MAX_FILE_NAME];
+};
+
+struct cnss_wlan_runtime_ops {
+	int (*runtime_suspend)(struct pci_dev *pdev);
+	int (*runtime_resume)(struct pci_dev *pdev);
+};
+
+struct cnss_wlan_driver {
+	char *name;
+	int  (*probe)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*remove)(struct pci_dev *pdev);
+	int  (*reinit)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*shutdown)(struct pci_dev *pdev);
+	void (*crash_shutdown)(struct pci_dev *pdev);
+	int  (*suspend)(struct pci_dev *pdev, pm_message_t state);
+	int  (*resume)(struct pci_dev *pdev);
+	void (*modem_status)(struct pci_dev *, int state);
+	void (*update_status)(struct pci_dev *pdev, uint32_t status);
+	struct cnss_wlan_runtime_ops *runtime_ops;
+	const struct pci_device_id *id_table;
+};
+
+/*
+ * codeseg_total_bytes: Total bytes across all the codesegment blocks
+ * num_codesegs: No of Pages used
+ * codeseg_size: Size of each segment. Should be power of 2 and multiple of 4K
+ * codeseg_size_log2: log2(codeseg_size)
+ * codeseg_busaddr: Physical address of the DMAble memory;4K aligned
+ */
+
+#define CODESWAP_MAX_CODESEGS 16
+struct codeswap_codeseg_info {
+	u32   codeseg_total_bytes;
+	u32   num_codesegs;
+	u32   codeseg_size;
+	u32   codeseg_size_log2;
+	void *codeseg_busaddr[CODESWAP_MAX_CODESEGS];
+};
+
+struct image_desc_info {
+	dma_addr_t fw_addr;
+	u32 fw_size;
+	dma_addr_t bdata_addr;
+	u32 bdata_size;
+};
+
+/* platform capabilities */
+enum cnss_platform_cap_flag {
+	CNSS_HAS_EXTERNAL_SWREG = 0x01,
+	CNSS_HAS_UART_ACCESS = 0x02,
+};
+
+struct cnss_platform_cap {
+	u32 cap_flag;
+};
+
+/* WLAN driver status */
+enum cnss_driver_status {
+	CNSS_UNINITIALIZED,
+	CNSS_INITIALIZED,
+	CNSS_LOAD_UNLOAD
+};
+
+enum cnss_runtime_request {
+	CNSS_PM_RUNTIME_GET,
+	CNSS_PM_RUNTIME_PUT,
+	CNSS_PM_RUNTIME_MARK_LAST_BUSY,
+	CNSS_PM_RUNTIME_RESUME,
+	CNSS_PM_RUNTIME_PUT_NOIDLE,
+	CNSS_PM_REQUEST_RESUME,
+	CNSS_PM_RUNTIME_PUT_AUTO,
+	CNSS_PM_GET_NORESUME,
+};
+
+extern int cnss_get_fw_image(struct image_desc_info *image_desc_info);
+extern void cnss_runtime_init(struct device *dev, int auto_delay);
+extern void cnss_runtime_exit(struct device *dev);
+extern void cnss_wlan_pci_link_down(void);
+extern int cnss_pcie_shadow_control(struct pci_dev *dev, bool enable);
+extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
+extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
+extern int cnss_get_fw_files(struct cnss_fw_files *pfw_files);
+extern int cnss_get_fw_files_for_target(struct cnss_fw_files *pfw_files,
+					u32 target_type, u32 target_version);
+extern void cnss_get_qca9377_fw_files(struct cnss_fw_files *pfw_files,
+					u32 size, u32 tufello_dual_fw);
+
+extern int cnss_request_bus_bandwidth(int bandwidth);
+
+#ifdef CONFIG_CNSS_SECURE_FW
+extern int cnss_get_sha_hash(const u8 *data, u32 data_len,
+					u8 *hash_idx, u8 *out);
+extern void *cnss_get_fw_ptr(void);
+#endif
+
+extern int cnss_get_codeswap_struct(struct codeswap_codeseg_info *swap_seg);
+extern int cnss_get_bmi_setup(void);
+
+#ifdef CONFIG_PCI_MSM
+extern int cnss_wlan_pm_control(bool vote);
+#endif
+extern void cnss_lock_pm_sem(void);
+extern void cnss_release_pm_sem(void);
+
+extern void cnss_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_request_pm_qos(u32 qos_val);
+extern void cnss_remove_pm_qos(void);
+
+extern void cnss_pci_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_pci_request_pm_qos(u32 qos_val);
+extern void cnss_pci_remove_pm_qos(void);
+
+extern void cnss_sdio_request_pm_qos_type(int latency_type, u32 qos_val);
+extern void cnss_sdio_request_pm_qos(u32 qos_val);
+extern void cnss_sdio_remove_pm_qos(void);
+
+extern int cnss_get_platform_cap(struct cnss_platform_cap *cap);
+extern void cnss_set_driver_status(enum cnss_driver_status driver_status);
+
+#ifndef CONFIG_WCNSS_MEM_PRE_ALLOC
+static inline int wcnss_pre_alloc_reset(void) { return 0; }
+#endif
+
+extern int msm_pcie_enumerate(u32 rc_idx);
+extern int cnss_auto_suspend(void);
+extern int cnss_auto_resume(void);
+extern int cnss_prevent_auto_suspend(const char *caller_func);
+extern int cnss_allow_auto_suspend(const char *caller_func);
+extern int cnss_is_auto_suspend_allowed(const char *caller_func);
+
+extern int cnss_pm_runtime_request(struct device *dev, enum
+		cnss_runtime_request request);
+extern void cnss_set_cc_source(enum cnss_cc_src cc_source);
+extern enum cnss_cc_src cnss_get_cc_source(void);
+#endif
+
+extern void cnss_pm_wake_lock_init(struct wakeup_source *ws, const char *name);
+extern void cnss_pm_wake_lock(struct wakeup_source *ws);
+
+extern void cnss_device_crashed(void);
+extern void cnss_device_self_recovery(void);
+extern void *cnss_get_virt_ramdump_mem(unsigned long *size);
+
+extern void cnss_schedule_recovery_work(void);
+extern int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len);
+extern u8 *cnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len);
+
+enum {
+	CNSS_RESET_SOC = 0,
+	CNSS_RESET_SUBSYS_COUPLED,
+	CNSS_RESET_LEVEL_MAX
+};
+extern int cnss_get_restart_level(void);
+
+struct cnss_sdio_wlan_driver {
+	const char *name;
+	const struct sdio_device_id *id_table;
+	int (*probe)(struct sdio_func *, const struct sdio_device_id *);
+	void (*remove)(struct sdio_func *);
+	int (*reinit)(struct sdio_func *, const struct sdio_device_id *);
+	void (*shutdown)(struct sdio_func *);
+	void (*crash_shutdown)(struct sdio_func *);
+	int (*suspend)(struct device *);
+	int (*resume)(struct device *);
+};
+
+extern int cnss_sdio_wlan_register_driver(
+	struct cnss_sdio_wlan_driver *driver);
+extern void cnss_sdio_wlan_unregister_driver(
+	struct cnss_sdio_wlan_driver *driver);
+
+typedef void (*oob_irq_handler_t)(void *dev_para);
+extern int cnss_wlan_query_oob_status(void);
+extern int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler,
+	    void *pm_oob);
+extern int cnss_wlan_unregister_oob_irq_handler(void *pm_oob);
+
+
+extern void cnss_dump_stack(struct task_struct *task);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern void cnss_init_work(struct work_struct *work, work_func_t func);
+extern void cnss_flush_delayed_work(void *dwork);
+extern void cnss_flush_work(void *work);
+extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec);
+extern void cnss_pm_wake_lock_release(struct wakeup_source *ws);
+extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws);
+extern void cnss_get_monotonic_boottime(struct timespec *ts);
+extern void cnss_get_boottime(struct timespec *ts);
+extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t
+				   func);
+extern int cnss_vendor_cmd_reply(struct sk_buff *skb);
+extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu);
+extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count);
+extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
+					u16 buf_len);
+extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len);
+extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len);
+extern int cnss_common_request_bus_bandwidth(struct device *dev, int
+					     bandwidth);
+extern void cnss_common_device_crashed(struct device *dev);
+extern void cnss_common_device_self_recovery(struct device *dev);
+extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long
+					      *size);
+extern void cnss_common_schedule_recovery_work(struct device *dev);
+extern int cnss_common_set_wlan_mac_address(struct device *dev, const u8 *in,
+					    uint32_t len);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern int cnss_power_up(struct device *dev);
+extern int cnss_power_down(struct device *dev);
+extern int cnss_sdio_configure_spdt(bool state);
+
+extern int cnss_common_register_tsf_captured_handler(struct device *dev,
+						     irq_handler_t handler,
+						     void *ctx);
+extern int cnss_common_unregister_tsf_captured_handler(struct device *dev,
+						       void *ctx);
+#endif /* _NET_CNSS_H_ */
diff --git a/include/net/cnss_logger.h b/include/net/cnss_logger.h
new file mode 100644
index 0000000..f06ec9b
--- /dev/null
+++ b/include/net/cnss_logger.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _NET_CNSS_LOGGER_H_
+#define _NET_CNSS_LOGGER_H_
+
+struct sk_buff;
+struct wiphy;
+
+#ifdef CONFIG_CNSS_LOGGER
+int cnss_logger_event_register(int radio, int event,
+			       int (*cb)(struct sk_buff *skb));
+int cnss_logger_event_unregister(int radio, int event,
+				 int (*cb)(struct sk_buff *skb));
+int cnss_logger_device_register(struct wiphy *wiphy, const char *name);
+int cnss_logger_device_unregister(int radio, struct wiphy *wiphy);
+int cnss_logger_nl_ucast(struct sk_buff *skb, int portid, int flag);
+int cnss_logger_nl_bcast(struct sk_buff *skb, int portid, int flag);
+#else
+static inline int cnss_logger_event_register(int radio, int event,
+					     int (*cb)(struct sk_buff *skb))
+{
+	return 0;
+}
+static inline int cnss_logger_event_unregister(int radio, int event,
+					       int (*cb)(struct sk_buff *skb))
+{
+	return 0;
+}
+static inline int cnss_logger_device_register(struct wiphy *wiphy,
+					      const char *name)
+{
+	return 0;
+}
+static inline int cnss_logger_device_unregister(int radio, struct wiphy *wiphy)
+{
+	return 0;
+}
+static inline int cnss_logger_nl_ucast(struct sk_buff *skb, int portid,
+				       int flag)
+{
+	return 0;
+}
+static inline int cnss_logger_nl_bcast(struct sk_buff *skb, int portid,
+				       int flag)
+{
+	return 0;
+}
+#endif /* CONFIG_CNSS_LOGGER */
+#endif /* _NET_CNSS_H_ */
+
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 615ce0a..e64210c 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -290,6 +290,7 @@
 			   int flags);
 int ip6_flowlabel_init(void);
 void ip6_flowlabel_cleanup(void);
+bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np);
 
 static inline void fl6_sock_release(struct ip6_flowlabel *fl)
 {
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 0940598..23102da 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -213,6 +213,11 @@
 	return net1 == net2;
 }
 
+static inline int check_net(const struct net *net)
+{
+	return atomic_read(&net->count) != 0;
+}
+
 void net_drop_ns(void *);
 
 #else
@@ -237,6 +242,11 @@
 	return 1;
 }
 
+static inline int check_net(const struct net *net)
+{
+	return 1;
+}
+
 #define net_drop_ns NULL
 #endif
 
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index 505e82b..a872c9a 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -108,10 +108,16 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda670")
 #define early_machine_is_msm8953()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8953")
+#define early_machine_is_msm8937()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8937")
 #define early_machine_is_sdm450()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm450")
 #define early_machine_is_sdm632()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm632")
+#define early_machine_is_sdm439()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm439")
+#define early_machine_is_sdm429()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm429")
 #else
 #define of_board_is_sim()		0
 #define of_board_is_rumi()		0
@@ -155,8 +161,11 @@
 #define early_machine_is_qcs605()	0
 #define early_machine_is_sda670()	0
 #define early_machine_is_msm8953()	0
+#define early_machine_is_msm8937()	0
 #define early_machine_is_sdm450()	0
 #define early_machine_is_sdm632()	0
+#define early_machine_is_sdm439()	0
+#define early_machine_is_sdm429()	0
 #endif
 
 #define PLATFORM_SUBTYPE_MDM	1
@@ -225,6 +234,9 @@
 	MSM_CPU_SDM450,
 	MSM_CPU_SDM632,
 	MSM_CPU_SDA632,
+	MSM_CPU_8937,
+	MSM_CPU_SDM439,
+	MSM_CPU_SDM429,
 };
 
 struct msm_soc_info {
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 0125cde..63f2baf 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -596,8 +596,8 @@
 
 TRACE_EVENT(sched_load_to_gov,
 
-	TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy),
-	TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy),
+	TP_PROTO(struct rq *rq, u64 aggr_grp_load, u32 tt_load, u64 freq_aggr_thresh, u64 load, int policy, int big_task_rotation),
+	TP_ARGS(rq, aggr_grp_load, tt_load, freq_aggr_thresh, load, policy, big_task_rotation),
 
 	TP_STRUCT__entry(
 		__field(	int,	cpu			)
@@ -612,6 +612,7 @@
 		__field(	u64,	grp_nt_ps		)
 		__field(	u64,	pl			)
 		__field(	u64,    load			)
+		__field(	int,    big_task_rotation	)
 	),
 
 	TP_fast_assign(
@@ -627,13 +628,15 @@
 		__entry->grp_nt_ps	= rq->grp_time.nt_prev_runnable_sum;
 		__entry->pl		= rq->walt_stats.pred_demands_sum;
 		__entry->load		= load;
+		__entry->big_task_rotation = big_task_rotation;
 	),
 
-	TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu",
+	TP_printk("cpu=%d policy=%d ed_task_pid=%d aggr_grp_load=%llu freq_aggr_thresh=%llu tt_load=%llu rq_ps=%llu grp_rq_ps=%llu nt_ps=%llu grp_nt_ps=%llu pl=%llu load=%llu big_task_rotation=%d",
 		__entry->cpu, __entry->policy, __entry->ed_task_pid,
 		__entry->aggr_grp_load, __entry->freq_aggr_thresh,
 		__entry->tt_load, __entry->rq_ps, __entry->grp_rq_ps,
-		__entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load)
+		__entry->nt_ps, __entry->grp_nt_ps, __entry->pl, __entry->load,
+		__entry->big_task_rotation)
 );
 #endif
 
diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h
index 73f4938..8a0e4cf 100644
--- a/include/uapi/linux/msm_mdp.h
+++ b/include/uapi/linux/msm_mdp.h
@@ -1410,6 +1410,11 @@
 	MDP_CSC_ITU_R_709,
 };
 
+/*
+ * These definitions are a continuation of the mdp_color_space enum above
+ */
+#define MDP_CSC_ITU_R_2020	(MDP_CSC_ITU_R_709 + 1)
+#define MDP_CSC_ITU_R_2020_FR	(MDP_CSC_ITU_R_2020 + 1)
 enum {
 	mdp_igc_v1_7 = 1,
 	mdp_igc_vmax,
diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h
index 05a105b..1a2a7e2c 100644
--- a/include/uapi/linux/msm_mdp_ext.h
+++ b/include/uapi/linux/msm_mdp_ext.h
@@ -34,9 +34,9 @@
  * To allow proper structure padding for 64bit/32bit target
  */
 #ifdef __LP64
-#define MDP_LAYER_COMMIT_V1_PAD 3
+#define MDP_LAYER_COMMIT_V1_PAD 2
 #else
-#define MDP_LAYER_COMMIT_V1_PAD 4
+#define MDP_LAYER_COMMIT_V1_PAD 3
 #endif
 
 /*
@@ -350,8 +350,11 @@
 	/* Buffer attached with output layer. Device uses it for commit call */
 	struct mdp_layer_buffer		buffer;
 
+	/* color space of the destination */
+	enum mdp_color_space            color_space;
+
 	/* 32bits reserved value for future usage. */
-	uint32_t			reserved[6];
+	uint32_t			reserved[5];
 };
 
 /*
@@ -389,6 +392,18 @@
 	uint64_t	__user scale;
 };
 
+/* Enable Deterministic Frame Rate Control (FRC) */
+#define MDP_VIDEO_FRC_ENABLE (1 << 0)
+
+struct mdp_frc_info {
+	/* flags to control FRC feature */
+	uint32_t flags;
+	/* video frame count per frame */
+	uint32_t frame_cnt;
+	/* video timestamp per frame in millisecond unit */
+	int64_t timestamp;
+};
+
 /*
  * Commit structure holds layer stack send by client for validate and commit
  * call. If layers are different between validate and commit call then commit
@@ -467,6 +482,9 @@
 	 */
 	uint32_t		dest_scaler_cnt;
 
+	/* FRC info per device which contains frame count and timestamp */
+	struct mdp_frc_info __user *frc_info;
+
 	/* 32-bits reserved value for future usage. */
 	uint32_t		reserved[MDP_LAYER_COMMIT_V1_PAD];
 };
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 1df8c41..7e72600 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -371,7 +371,7 @@
 enum v4l2_mpeg_video_header_mode {
 	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
 	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
-
+	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME		= 2,
 };
 #define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
 #define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE		(V4L2_CID_MPEG_BASE+218)
@@ -382,6 +382,7 @@
 	V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE		= 0,
 	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB		= 1,
 	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES	= 2,
+	V4L2_MPEG_VIDEO_MULTI_SLICE_GOB			= 3,
 };
 #define V4L2_CID_MPEG_VIDEO_VBV_SIZE			(V4L2_CID_MPEG_BASE+222)
 #define V4L2_CID_MPEG_VIDEO_DEC_PTS			(V4L2_CID_MPEG_BASE+223)
@@ -662,6 +663,9 @@
 	V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_ON = 1,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+1)
+
 #define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT   (V4L2_CID_MPEG_MSM_VIDC_BASE+2)
 enum v4l2_mpeg_vidc_video_stream_format {
 	V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES         = 0,
@@ -719,6 +723,8 @@
 	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE = 0,
 	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC = 1,
 	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM = 2,
+	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE = 3,
+	V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE = 4,
 };
 #define V4L2_CID_MPEG_VIDC_VIDEO_IR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+13)
 
@@ -741,6 +747,8 @@
 	V4L2_MPEG_VIDC_EXTRADATA_NONE = 0,
 	V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION = 1,
 	V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO = 2,
+	V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP = 3,
+	V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP = 4,
 	V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP = 5,
 	V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING = 6,
 	V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE = 7,
@@ -835,6 +843,11 @@
 	V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH			= 5,
 };
 
+enum v4l2_mpeg_vidc_video_mvc_layout {
+	V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL = 0,
+	V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM = 1
+};
+
 #define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 25)
 
@@ -859,6 +872,14 @@
 #define V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 30)
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT       \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE+31)
+enum v4l2_mpeg_vidc_video_alloc_mode_type {
+	V4L2_MPEG_VIDC_VIDEO_STATIC = 0,
+	V4L2_MPEG_VIDC_VIDEO_RING = 1,
+	V4L2_MPEG_VIDC_VIDEO_DYNAMIC = 2,
+};
+
 #define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 32)
 
@@ -1070,6 +1091,39 @@
 	V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51 = 10,
 };
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 68)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 69)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 70)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY	\
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 71)
+enum v4l2_mpeg_vidc_video_assembly {
+	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0,
+	V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE\
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 72)
+enum v4l2_mpeg_vidc_video_h263_profile {
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE = 0,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING	= 1,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE = 2,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2 = 3,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3 = 4,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION = 5,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET = 6,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE = 7,
+	V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY = 8,
+};
+
+#define V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 97)
+#define V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 98)
 #define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 99)
 #define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \
@@ -1165,6 +1219,144 @@
 #define V4L2_CID_MPEG_VIDC_VENC_MAX_FLL \
 	(V4L2_CID_MPEG_MSM_VIDC_BASE + 128)
 
+#define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL \
+	(V4L2_CID_MPEG_MSM_VIDC_BASE + 129)
+enum v4l2_mpeg_vidc_perf_level {
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL	= 0,
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE	= 1,
+	V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO	= 2,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE + 130)
+#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE + 131)
+#define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE + 132)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 135)
+
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 136)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 137)
+enum v4l2_mpeg_vidc_video_h264_vui_bitstream_restrict {
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED = 0,
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 138)
+enum v4l2_mpeg_vidc_video_deinterlace {
+	V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 139)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 140)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 141)
+enum v4l2_mpeg_vidc_video_rate_control_timestamp_mode {
+	V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR = 0,
+	V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE = 1,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 142)
+enum vl42_mpeg_vidc_video_enable_initial_qp {
+	V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME = 0x1,
+	V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME = 0x2,
+	V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME = 0x4,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 143)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 144)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 145)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 146)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE	 \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 147)
+enum v4l2_mpeg_vidc_video_perf_mode {
+	V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY = 1,
+	V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE = 2
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MBI_STATISTICS_MODE	\
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 148)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_CONFIG_QP \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 149)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_PIC_ORDER_CNT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 150)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 151)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 152)
+
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 153)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2 \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 154)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 155)
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 156)
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 157)
+enum v4l2_mpeg_vidc_video_h263_level {
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0 = 0,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0 = 1,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0 = 2,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0 = 3,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5 = 4,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0 = 5,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0 = 6,
+	V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 158)
+
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT (V4L2_CID_MPEG_MSM_VIDC_BASE+159)
+
+enum v4l2_mpeg_vidc_video_divx_format_type {
+		V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4 = 0,
+		V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5 = 1,
+		V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6 = 2,
+};
+
+enum v4l2_mpeg_vidc_video_mbi_statistics_mode {
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1 = 1,
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_2 = 2,
+	V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_3 = 3,
+};
+
+enum vl42_mpeg_vidc_video_h264_svc_nal {
+	V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED = 0,
+	V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED = 1,
+};
+
+enum v4l2_mpeg_vidc_video_h264_vui_timing_info {
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0,
+	V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
+};
+
 /*  Camera class control IDs */
 
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 71772c3..d8a954e 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -2,7 +2,7 @@
  *  Video for Linux Two header file
  *
  *  Copyright (C) 1999-2012 the contributors
- *  Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -612,7 +612,10 @@
 #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
 #define V4L2_PIX_FMT_VP8      v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
 #define V4L2_PIX_FMT_VP9      v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
+#define V4L2_PIX_FMT_DIVX_311  v4l2_fourcc('D', 'I', 'V', '3') /* DIVX311     */
+#define V4L2_PIX_FMT_DIVX      v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX        */
 #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_HEVC_HYBRID v4l2_fourcc('H', 'V', 'C', 'H')
 #define V4L2_PIX_FMT_TME v4l2_fourcc('T', 'M', 'E', '0') /* for TME stream */
 
 /*  Vendor-specific formats   */
@@ -1011,11 +1014,15 @@
 #define V4L2_QCOM_BUF_FLAG_CODECCONFIG		0x00020000
 #define V4L2_QCOM_BUF_FLAG_EOSEQ		0x00040000
 #define V4L2_QCOM_BUF_TIMESTAMP_INVALID		0x00080000
+#define V4L2_MSM_BUF_FLAG_MBAFF			0x00100000
 #define V4L2_QCOM_BUF_FLAG_DECODEONLY		0x00200000
 #define V4L2_QCOM_BUF_DATA_CORRUPT		0x00400000
+#define V4L2_QCOM_BUF_DROP_FRAME		0x00800000
 #define V4L2_QCOM_BUF_INPUT_UNSUPPORTED		0x01000000
 #define V4L2_QCOM_BUF_FLAG_EOS			0x02000000
 #define V4L2_QCOM_BUF_FLAG_READONLY		0x04000000
+#define V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND	0x08000000
+#define V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP	0x10000000
 #define V4L2_QCOM_BUF_FLAG_PERF_MODE		0x20000000
 #define V4L2_MSM_BUF_FLAG_DEFER			0x40000000
 #define V4L2_QCOM_BUF_FLAG_IDRFRAME		0x80000000
diff --git a/include/uapi/media/msm_vidc.h b/include/uapi/media/msm_vidc.h
index 63fd555..59fab2f 100644
--- a/include/uapi/media/msm_vidc.h
+++ b/include/uapi/media/msm_vidc.h
@@ -242,6 +242,8 @@
 	MSM_VIDC_EXTRADATA_NONE = 0x00000000,
 	MSM_VIDC_EXTRADATA_MB_QUANTIZATION = 0x00000001,
 	MSM_VIDC_EXTRADATA_INTERLACE_VIDEO = 0x00000002,
+	MSM_VIDC_EXTRADATA_VC1_FRAMEDISP = 0x00000003,
+	MSM_VIDC_EXTRADATA_VC1_SEQDISP = 0x00000004,
 	MSM_VIDC_EXTRADATA_TIMESTAMP = 0x00000005,
 	MSM_VIDC_EXTRADATA_S3D_FRAME_PACKING = 0x00000006,
 	MSM_VIDC_EXTRADATA_FRAME_RATE = 0x00000007,
@@ -411,7 +413,7 @@
 /*enum msm_vidc_pic_struct */
 #define MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED 0x0
 #define MSM_VIDC_PIC_STRUCT_PROGRESSIVE 0x1
-
+#define MSM_VIDC_PIC_STRUCT_UNKNOWN 0XFFFFFFFF
 /*default when layer ID isn't specified*/
 #define MSM_VIDC_ALL_LAYER_ID 0xFF
 
diff --git a/include/uapi/scsi/sg.h b/include/uapi/scsi/sg.h
index 08d3beb..2ce6d73 100644
--- a/include/uapi/scsi/sg.h
+++ b/include/uapi/scsi/sg.h
@@ -198,7 +198,6 @@
 #define SG_DEFAULT_RETRIES 0
 
 /* Defaults, commented if they differ from original sg driver */
-#define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
 #define SG_DEF_KEEP_ORPHAN 0
 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
diff --git a/init/Kconfig b/init/Kconfig
index d4a2e32..2e57658 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1760,6 +1760,13 @@
 	  Enable the bpf() system call that allows to manipulate eBPF
 	  programs and maps via file descriptors.
 
+config BPF_JIT_ALWAYS_ON
+	bool "Permanently enable BPF JIT and remove BPF interpreter"
+	depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT
+	help
+	  Enables BPF JIT and removes BPF interpreter to avoid
+	  speculative execution of BPF instructions by the interpreter
+
 config SHMEM
 	bool "Use full shmem filesystem" if EXPERT
 	default y
diff --git a/ipc/msg.c b/ipc/msg.c
index e12307d..ff10d43 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -763,7 +763,10 @@
 	if (*msgtyp == 0)
 		return SEARCH_ANY;
 	if (*msgtyp < 0) {
-		*msgtyp = -*msgtyp;
+		if (*msgtyp == LONG_MIN) /* -LONG_MIN is undefined */
+			*msgtyp = LONG_MAX;
+		else
+			*msgtyp = -*msgtyp;
 		return SEARCH_LESSEQUAL;
 	}
 	if (msgflg & MSG_EXCEPT)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index aa6d981..879ca84 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -458,6 +458,7 @@
 }
 EXPORT_SYMBOL_GPL(__bpf_call_base);
 
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 /**
  *	__bpf_prog_run - run eBPF program on a given context
  *	@ctx: is the data we are operating on
@@ -641,7 +642,7 @@
 		DST = tmp;
 		CONT;
 	ALU_MOD_X:
-		if (unlikely(SRC == 0))
+		if (unlikely((u32)SRC == 0))
 			return 0;
 		tmp = (u32) DST;
 		DST = do_div(tmp, (u32) SRC);
@@ -660,7 +661,7 @@
 		DST = div64_u64(DST, SRC);
 		CONT;
 	ALU_DIV_X:
-		if (unlikely(SRC == 0))
+		if (unlikely((u32)SRC == 0))
 			return 0;
 		tmp = (u32) DST;
 		do_div(tmp, (u32) SRC);
@@ -715,7 +716,7 @@
 		struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
 		struct bpf_array *array = container_of(map, struct bpf_array, map);
 		struct bpf_prog *prog;
-		u64 index = BPF_R3;
+		u32 index = BPF_R3;
 
 		if (unlikely(index >= array->map.max_entries))
 			goto out;
@@ -923,6 +924,13 @@
 }
 STACK_FRAME_NON_STANDARD(__bpf_prog_run); /* jump table */
 
+#else
+static unsigned int __bpf_prog_ret0(void *ctx, const struct bpf_insn *insn)
+{
+	return 0;
+}
+#endif
+
 bool bpf_prog_array_compatible(struct bpf_array *array,
 			       const struct bpf_prog *fp)
 {
@@ -970,7 +978,11 @@
  */
 struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
 {
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 	fp->bpf_func = (void *) __bpf_prog_run;
+#else
+	fp->bpf_func = (void *) __bpf_prog_ret0;
+#endif
 
 	/* eBPF JITs can rewrite the program in case constant
 	 * blinding is active. However, in case of error during
@@ -979,6 +991,12 @@
 	 * be JITed, but falls back to the interpreter.
 	 */
 	fp = bpf_int_jit_compile(fp);
+#ifdef CONFIG_BPF_JIT_ALWAYS_ON
+	if (!fp->jited) {
+		*err = -ENOTSUPP;
+		return fp;
+	}
+#endif
 	bpf_prog_lock_ro(fp);
 
 	/* The tail call compatibility check can only be done at
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 19c44cf..076e4a0 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -702,6 +702,13 @@
 	return __is_pointer_value(env->allow_ptr_leaks, &env->cur_state.regs[regno]);
 }
 
+static bool is_ctx_reg(struct bpf_verifier_env *env, int regno)
+{
+	const struct bpf_reg_state *reg = &env->cur_state.regs[regno];
+
+	return reg->type == PTR_TO_CTX;
+}
+
 static int check_ptr_alignment(struct bpf_verifier_env *env,
 			       struct bpf_reg_state *reg, int off, int size)
 {
@@ -896,6 +903,12 @@
 		return -EACCES;
 	}
 
+	if (is_ctx_reg(env, insn->dst_reg)) {
+		verbose("BPF_XADD stores into R%d context is not allowed\n",
+			insn->dst_reg);
+		return -EACCES;
+	}
+
 	/* check whether atomic_add can read the memory */
 	err = check_mem_access(env, insn->dst_reg, insn->off,
 			       BPF_SIZE(insn->code), BPF_READ, -1);
@@ -1843,6 +1856,11 @@
 			return -EINVAL;
 		}
 
+		if (opcode == BPF_ARSH && BPF_CLASS(insn->code) != BPF_ALU64) {
+			verbose("BPF_ARSH not supported for 32 bit ALU\n");
+			return -EINVAL;
+		}
+
 		if ((opcode == BPF_LSH || opcode == BPF_RSH ||
 		     opcode == BPF_ARSH) && BPF_SRC(insn->code) == BPF_K) {
 			int size = BPF_CLASS(insn->code) == BPF_ALU64 ? 64 : 32;
@@ -3007,6 +3025,12 @@
 			if (err)
 				return err;
 
+			if (is_ctx_reg(env, insn->dst_reg)) {
+				verbose("BPF_ST stores into R%d context is not allowed\n",
+					insn->dst_reg);
+				return -EACCES;
+			}
+
 			/* check that memory (dst_reg + off) is writeable */
 			err = check_mem_access(env, insn->dst_reg, insn->off,
 					       BPF_SIZE(insn->code), BPF_WRITE,
@@ -3386,6 +3410,24 @@
 
 
 	for (i = 0; i < insn_cnt; i++, insn++) {
+		if (insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
+		    insn->code == (BPF_ALU | BPF_DIV | BPF_X)) {
+			/* due to JIT bugs clear upper 32-bits of src register
+			 * before div/mod operation
+			 */
+			insn_buf[0] = BPF_MOV32_REG(insn->src_reg, insn->src_reg);
+			insn_buf[1] = *insn;
+			cnt = 2;
+			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
+			if (!new_prog)
+				return -ENOMEM;
+
+			delta    += cnt - 1;
+			env->prog = prog = new_prog;
+			insn      = new_prog->insnsi + i + delta;
+			continue;
+		}
+
 		if (insn->code != (BPF_JMP | BPF_CALL))
 			continue;
 
diff --git a/kernel/futex.c b/kernel/futex.c
index 88bad86..bb2265a 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1711,6 +1711,9 @@
 	struct futex_q *this, *next;
 	WAKE_Q(wake_q);
 
+	if (nr_wake < 0 || nr_requeue < 0)
+		return -EINVAL;
+
 	if (requeue_pi) {
 		/*
 		 * Requeue PI only works on two distinct uaddrs. This
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 7b02ae6..31b45b7 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -775,6 +775,7 @@
 	if (!(flags & ENQUEUE_RESTORE))
 		sched_info_queued(rq, p);
 	p->sched_class->enqueue_task(rq, p, flags);
+	walt_update_last_enqueue(p);
 	trace_sched_enq_deq_task(p, 1, cpumask_bits(&p->cpus_allowed)[0]);
 }
 
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index cc5a97c..c0a8a2a 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -482,6 +482,7 @@
 
 	sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg,
 				 &max_nr, &big_max_nr);
+	walt_rotation_checkpoint(big_avg);
 
 	spin_lock_irqsave(&state_lock, flags);
 	for_each_cluster(cluster, index) {
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index da8261d..0a295ac 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -724,6 +724,8 @@
 		if (unlikely(dl_se->dl_boosted || !start_dl_timer(p)))
 			return;
 		dl_se->dl_throttled = 1;
+		if (dl_se->runtime > 0)
+			dl_se->runtime = 0;
 	}
 }
 
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 1ff2e5e..55c3957 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -11430,6 +11430,141 @@
 	return rc;
 }
 
+#ifdef CONFIG_SCHED_WALT
+struct walt_rotate_work {
+	struct work_struct w;
+	struct task_struct *src_task;
+	struct task_struct *dst_task;
+	int src_cpu;
+	int dst_cpu;
+};
+
+static DEFINE_PER_CPU(struct walt_rotate_work, walt_rotate_works);
+
+static void walt_rotate_work_func(struct work_struct *work)
+{
+	struct walt_rotate_work *wr = container_of(work,
+				struct walt_rotate_work, w);
+
+	migrate_swap(wr->src_task, wr->dst_task);
+
+	put_task_struct(wr->src_task);
+	put_task_struct(wr->dst_task);
+
+	clear_reserved(wr->src_cpu);
+	clear_reserved(wr->dst_cpu);
+}
+
+void walt_rotate_work_init(void)
+{
+	int i;
+
+	for_each_possible_cpu(i) {
+		struct walt_rotate_work *wr = &per_cpu(walt_rotate_works, i);
+
+		INIT_WORK(&wr->w, walt_rotate_work_func);
+	}
+}
+
+#define WALT_ROTATION_THRESHOLD_NS	16000000
+static void walt_check_for_rotation(struct rq *src_rq)
+{
+	u64 wc, wait, max_wait = 0, run, max_run = 0;
+	int deserved_cpu = nr_cpu_ids, dst_cpu = nr_cpu_ids;
+	int i, src_cpu = cpu_of(src_rq);
+	struct rq *dst_rq;
+	struct walt_rotate_work *wr = NULL;
+
+	if (!walt_rotation_enabled)
+		return;
+
+	if (got_boost_kick())
+		return;
+
+	if (is_max_capacity_cpu(src_cpu))
+		return;
+
+	wc = ktime_get_ns();
+	for_each_possible_cpu(i) {
+		struct rq *rq = cpu_rq(i);
+
+		if (is_max_capacity_cpu(i))
+			break;
+
+		if (is_reserved(i))
+			continue;
+
+		if (!rq->misfit_task || rq->curr->sched_class !=
+						&fair_sched_class)
+			continue;
+
+		wait = wc - rq->curr->last_enqueued_ts;
+		if (wait > max_wait) {
+			max_wait = wait;
+			deserved_cpu = i;
+		}
+	}
+
+	if (deserved_cpu != src_cpu)
+		return;
+
+	for_each_possible_cpu(i) {
+		struct rq *rq = cpu_rq(i);
+
+		if (!is_max_capacity_cpu(i))
+			continue;
+
+		if (is_reserved(i))
+			continue;
+
+		if (rq->curr->sched_class != &fair_sched_class)
+			continue;
+
+		if (rq->nr_running > 1)
+			continue;
+
+		run = wc - rq->curr->last_enqueued_ts;
+
+		if (run < WALT_ROTATION_THRESHOLD_NS)
+			continue;
+
+		if (run > max_run) {
+			max_run = run;
+			dst_cpu = i;
+		}
+	}
+
+	if (dst_cpu == nr_cpu_ids)
+		return;
+
+	dst_rq = cpu_rq(dst_cpu);
+
+	double_rq_lock(src_rq, dst_rq);
+	if (dst_rq->curr->sched_class == &fair_sched_class) {
+		get_task_struct(src_rq->curr);
+		get_task_struct(dst_rq->curr);
+
+		mark_reserved(src_cpu);
+		mark_reserved(dst_cpu);
+		wr = &per_cpu(walt_rotate_works, src_cpu);
+
+		wr->src_task = src_rq->curr;
+		wr->dst_task = dst_rq->curr;
+
+		wr->src_cpu = src_cpu;
+		wr->dst_cpu = dst_cpu;
+	}
+	double_rq_unlock(src_rq, dst_rq);
+
+	if (wr)
+		queue_work_on(src_cpu, system_highpri_wq, &wr->w);
+}
+#else
+static inline void walt_check_for_rotation(struct rq *rq)
+{
+}
+#endif
+
 static DEFINE_RAW_SPINLOCK(migration_lock);
 void check_for_migration(struct rq *rq, struct task_struct *p)
 {
@@ -11459,6 +11594,8 @@
 					&rq->active_balance_work);
 				return;
 			}
+		} else {
+			walt_check_for_rotation(rq);
 		}
 		raw_spin_unlock(&migration_lock);
 	}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 5508248..e0aa30d 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -943,8 +943,8 @@
 };
 extern void sched_setnuma(struct task_struct *p, int node);
 extern int migrate_task_to(struct task_struct *p, int cpu);
-extern int migrate_swap(struct task_struct *, struct task_struct *);
 #endif /* CONFIG_NUMA_BALANCING */
+extern int migrate_swap(struct task_struct *cur, struct task_struct *p);
 
 #ifdef CONFIG_SMP
 
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index b7da03f..23fd885 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -88,6 +88,9 @@
 
 __read_mostly unsigned int sysctl_sched_cpu_high_irqload = (10 * NSEC_PER_MSEC);
 
+unsigned int sysctl_sched_walt_rotate_big_tasks;
+unsigned int walt_rotation_enabled;
+
 /*
  * sched_window_stats_policy and sched_ravg_hist_size have a 'sysctl' copy
  * associated with them. This is required for atomic update of those variables
@@ -316,7 +319,8 @@
 	struct task_struct *p;
 	int loop_max = 10;
 
-	if (sched_boost_policy() == SCHED_BOOST_NONE || !rq->cfs.h_nr_running)
+	if ((!walt_rotation_enabled && sched_boost_policy() ==
+			SCHED_BOOST_NONE) || !rq->cfs.h_nr_running)
 		return 0;
 
 	rq->ed_task = NULL;
@@ -487,7 +491,7 @@
 
 done:
 	trace_sched_load_to_gov(rq, aggr_grp_load, tt_load, freq_aggr_thresh,
-				load, reporting_policy);
+				load, reporting_policy, walt_rotation_enabled);
 	return load;
 }
 
@@ -2019,7 +2023,7 @@
 
 	wallclock = ktime_get_ns();
 	p->ravg.mark_start = p->last_wake_ts = wallclock;
-	p->last_cpu_selected_ts = wallclock;
+	p->last_enqueued_ts = wallclock;
 	p->last_switch_out_ts = 0;
 	update_task_cpu_cycles(p, cpu_of(rq));
 }
@@ -3143,6 +3147,19 @@
 		core_ctl_check(this_rq()->window_start);
 }
 
+void walt_rotation_checkpoint(int nr_big)
+{
+	if (!hmp_capable())
+		return;
+
+	if (!sysctl_sched_walt_rotate_big_tasks || sched_boost() != NO_BOOST) {
+		walt_rotation_enabled = 0;
+		return;
+	}
+
+	walt_rotation_enabled = nr_big >= num_possible_cpus();
+}
+
 int walt_proc_update_handler(struct ctl_table *table, int write,
 			     void __user *buffer, size_t *lenp,
 			     loff_t *ppos)
@@ -3178,6 +3195,8 @@
 	cpumask_set_cpu(cpu_of(rq), &rq->freq_domain_cpumask);
 	init_irq_work(&walt_migration_irq_work, walt_irq_work);
 	init_irq_work(&walt_cpufreq_irq_work, walt_irq_work);
+	walt_rotate_work_init();
+
 	rq->walt_stats.cumulative_runnable_avg = 0;
 	rq->window_start = 0;
 	rq->cum_window_start = 0;
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index c8780cf..da53ea4 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -291,9 +291,20 @@
 	return sysctl_sched_is_big_little ? prev_cpu : min_power_cpu;
 }
 
+static inline void walt_update_last_enqueue(struct task_struct *p)
+{
+	p->last_enqueued_ts = ktime_get_ns();
+}
+extern void walt_rotate_work_init(void);
+extern void walt_rotation_checkpoint(int nr_big);
+extern unsigned int walt_rotation_enabled;
+
 #else /* CONFIG_SCHED_WALT */
 
 static inline void walt_sched_init(struct rq *rq) { }
+static inline void walt_rotate_work_init(void) { }
+static inline void walt_rotation_checkpoint(int nr_big) { }
+static inline void walt_update_last_enqueue(struct task_struct *p) { }
 
 static inline void update_task_ravg(struct task_struct *p, struct rq *rq,
 				int event, u64 wallclock, u64 irqtime) { }
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index dea7e55..b057784 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -127,7 +127,9 @@
 static int __maybe_unused four = 4;
 static unsigned long one_ul = 1;
 static int one_hundred = 100;
+#ifdef CONFIG_PERF_EVENTS
 static int one_thousand = 1000;
+#endif
 #ifdef CONFIG_PRINTK
 static int ten_thousand = 10000;
 #endif
@@ -323,6 +325,15 @@
 		.extra1         = &zero,
 		.extra2		= &three,
 	},
+	{
+		.procname	= "sched_walt_rotate_big_tasks",
+		.data		= &sysctl_sched_walt_rotate_big_tasks,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &one,
+	},
 #endif
 	{
 		.procname	= "sched_upmigrate",
@@ -1572,8 +1583,16 @@
 		.maxlen		= sizeof(watermark_scale_factor),
 		.mode		= 0644,
 		.proc_handler	= watermark_scale_factor_sysctl_handler,
-		.extra1		= &one,
-		.extra2		= &one_thousand,
+		.extra1		= &zero,
+		.extra2		= &zero,
+	},
+	{
+		.procname	= "extra_free_kbytes",
+		.data		= &extra_free_kbytes,
+		.maxlen		= sizeof(extra_free_kbytes),
+		.mode		= 0644,
+		.proc_handler	= min_free_kbytes_sysctl_handler,
+		.extra1		= &zero,
 	},
 	{
 		.procname	= "percpu_pagelist_fraction",
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index a01a71f..38b008e 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -652,7 +652,9 @@
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
 {
 	base->expires_next.tv64 = KTIME_MAX;
+	base->hang_detected = 0;
 	base->hres_active = 0;
+	base->next_timer = NULL;
 }
 
 /*
@@ -1582,6 +1584,7 @@
 		timerqueue_init_head(&cpu_base->clock_base[i].active);
 	}
 
+	cpu_base->active_bases = 0;
 	cpu_base->cpu = cpu;
 	hrtimer_init_hres(cpu_base);
 	return 0;
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 5b5d016..a6f8a44 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -208,7 +208,6 @@
 
 static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]);
 struct timer_base timer_base_deferrable;
-static atomic_t deferrable_pending;
 
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
 unsigned int sysctl_timer_migration = 1;
@@ -1489,6 +1488,8 @@
 
 
 #ifdef CONFIG_SMP
+static atomic_t deferrable_pending;
+
 /*
  * check_pending_deferrable_timers - Check for unbound deferrable timer expiry
  * @cpu - Current CPU
@@ -1669,6 +1670,27 @@
 	spin_unlock_irq(&base->lock);
 }
 
+#ifdef CONFIG_SMP
+static inline bool should_this_cpu_run_deferrable_timers(void)
+{
+	int tick_cpu = READ_ONCE(tick_do_timer_cpu);
+
+	if (atomic_cmpxchg(&deferrable_pending, 1, 0) &&
+			tick_cpu == TICK_DO_TIMER_NONE)
+		return true;
+
+	if (tick_cpu == smp_processor_id())
+		return true;
+
+	return (tick_cpu >= 0 && ksoftirqd_running_on(tick_cpu));
+}
+#else
+static inline bool should_this_cpu_run_deferrable_timers(void)
+{
+	return true;
+}
+#endif
+
 /*
  * This function runs timers and the timer-tq in bottom half context.
  */
@@ -1693,9 +1715,7 @@
 	if (IS_ENABLED(CONFIG_NO_HZ_COMMON))
 		__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
 
-	if ((atomic_cmpxchg(&deferrable_pending, 1, 0) &&
-		tick_do_timer_cpu == TICK_DO_TIMER_NONE) ||
-		tick_do_timer_cpu == smp_processor_id())
+	if (should_this_cpu_run_deferrable_timers())
 		__run_timers(&timer_base_deferrable);
 }
 
@@ -1709,7 +1729,7 @@
 	hrtimer_run_queues();
 	/* Raise the softirq only if required. */
 	if (time_before(jiffies, base->clk)) {
-		if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active)
+		if (!IS_ENABLED(CONFIG_NO_HZ_COMMON))
 			return;
 		/* CPU is awake, so check the deferrable base. */
 		base++;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 72687f4..b15316a 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2201,6 +2201,7 @@
 {
 	struct trace_event_call *call, *p;
 	const char *last_system = NULL;
+	bool first = false;
 	int last_i;
 	int i;
 
@@ -2208,15 +2209,28 @@
 	list_for_each_entry_safe(call, p, &ftrace_events, list) {
 		/* events are usually grouped together with systems */
 		if (!last_system || call->class->system != last_system) {
+			first = true;
 			last_i = 0;
 			last_system = call->class->system;
 		}
 
+		/*
+		 * Since calls are grouped by systems, the likelyhood that the
+		 * next call in the iteration belongs to the same system as the
+		 * previous call is high. As an optimization, we skip seaching
+		 * for a map[] that matches the call's system if the last call
+		 * was from the same system. That's what last_i is for. If the
+		 * call has the same system as the previous call, then last_i
+		 * will be the index of the first map[] that has a matching
+		 * system.
+		 */
 		for (i = last_i; i < len; i++) {
 			if (call->class->system == map[i]->system) {
 				/* Save the first system if need be */
-				if (!last_i)
+				if (first) {
 					last_i = i;
+					first = false;
+				}
 				update_event_printk(call, map[i]);
 			}
 		}
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 9aea3480..5ef61bd 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -50,6 +50,7 @@
 #include <linux/uaccess.h>
 #include <linux/bug.h>
 #include <linux/delay.h>
+#include <linux/nmi.h>
 
 #include "workqueue_internal.h"
 
@@ -4431,6 +4432,12 @@
 			if (pwq->nr_active || !list_empty(&pwq->delayed_works))
 				show_pwq(pwq);
 			spin_unlock_irqrestore(&pwq->pool->lock, flags);
+			/*
+			 * We could be printing a lot from atomic context, e.g.
+			 * sysrq-t -> show_workqueue_state(). Avoid triggering
+			 * hard lockup.
+			 */
+			touch_nmi_watchdog();
 		}
 	}
 
@@ -4458,6 +4465,12 @@
 		pr_cont("\n");
 	next_pool:
 		spin_unlock_irqrestore(&pool->lock, flags);
+		/*
+		 * We could be printing a lot from atomic context, e.g.
+		 * sysrq-t -> show_workqueue_state(). Avoid triggering
+		 * hard lockup.
+		 */
+		touch_nmi_watchdog();
 	}
 
 	rcu_read_unlock_sched();
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 2e38502..98da752 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -5646,9 +5646,8 @@
 				return NULL;
 			}
 		}
-		/* We don't expect to fail. */
 		if (*err) {
-			pr_cont("FAIL to attach err=%d len=%d\n",
+			pr_cont("FAIL to prog_create err=%d len=%d\n",
 				*err, fprog.len);
 			return NULL;
 		}
@@ -5671,6 +5670,10 @@
 		 * checks.
 		 */
 		fp = bpf_prog_select_runtime(fp, err);
+		if (*err) {
+			pr_cont("FAIL to select_runtime err=%d\n", *err);
+			return NULL;
+		}
 		break;
 	}
 
@@ -5856,8 +5859,8 @@
 				pass_cnt++;
 				continue;
 			}
-
-			return err;
+			err_cnt++;
+			continue;
 		}
 
 		pr_cont("jited:%u ", fp->jited);
diff --git a/mm/cma.c b/mm/cma.c
index 2984dac..5fc1809 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -61,7 +61,7 @@
 }
 
 static unsigned long cma_bitmap_aligned_mask(const struct cma *cma,
-					     int align_order)
+					     unsigned int align_order)
 {
 	if (align_order <= cma->order_per_bit)
 		return 0;
@@ -69,17 +69,14 @@
 }
 
 /*
- * Find a PFN aligned to the specified order and return an offset represented in
- * order_per_bits.
+ * Find the offset of the base PFN from the specified align_order.
+ * The value returned is represented in order_per_bits.
  */
 static unsigned long cma_bitmap_aligned_offset(const struct cma *cma,
-					       int align_order)
+					       unsigned int align_order)
 {
-	if (align_order <= cma->order_per_bit)
-		return 0;
-
-	return (ALIGN(cma->base_pfn, (1UL << align_order))
-		- cma->base_pfn) >> cma->order_per_bit;
+	return (cma->base_pfn & ((1UL << align_order) - 1))
+		>> cma->order_per_bit;
 }
 
 static unsigned long cma_bitmap_pages_to_bits(const struct cma *cma,
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 9a20a55..9b59170 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1454,6 +1454,8 @@
 			if (page_count(page) == 0)
 				continue;
 			scan_block(page, page + 1, NULL);
+			if (!(pfn % (MAX_SCAN_SIZE / sizeof(*page))))
+				cond_resched();
 		}
 	}
 	put_online_mems();
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 37d63b2..34eec18 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5560,7 +5560,7 @@
 		next = page->lru.next;
 
 		VM_BUG_ON_PAGE(PageLRU(page), page);
-		VM_BUG_ON_PAGE(page_count(page), page);
+		VM_BUG_ON_PAGE(!PageHWPoison(page) && page_count(page), page);
 
 		if (!page->mem_cgroup)
 			continue;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index b335423..43622c6 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -535,6 +535,13 @@
 		 */
 		ClearPageActive(p);
 		ClearPageUnevictable(p);
+
+		/*
+		 * Poisoned page might never drop its ref count to 0 so we have
+		 * to uncharge it manually from its memcg.
+		 */
+		mem_cgroup_uncharge(p);
+
 		/*
 		 * drop the page count elevated by isolate_lru_page()
 		 */
diff --git a/mm/mmap.c b/mm/mmap.c
index 621db7f..5df92da 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2250,7 +2250,8 @@
 		gap_addr = TASK_SIZE;
 
 	next = vma->vm_next;
-	if (next && next->vm_start < gap_addr) {
+	if (next && next->vm_start < gap_addr &&
+			(next->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
 		if (!(next->vm_flags & VM_GROWSUP))
 			return -ENOMEM;
 		/* Check that both stack segments have the same anon_vma? */
@@ -2334,7 +2335,8 @@
 	if (gap_addr > address)
 		return -ENOMEM;
 	prev = vma->vm_prev;
-	if (prev && prev->vm_end > gap_addr) {
+	if (prev && prev->vm_end > gap_addr &&
+			(prev->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
 		if (!(prev->vm_flags & VM_GROWSDOWN))
 			return -ENOMEM;
 		/* Check that both stack segments have the same anon_vma? */
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 63b19a3..d3ea11f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -254,9 +254,21 @@
 #endif
 };
 
+/*
+ * Try to keep at least this much lowmem free.  Do not allow normal
+ * allocations below this point, only high priority ones. Automatically
+ * tuned according to the amount of memory in the system.
+ */
 int min_free_kbytes = 1024;
 int user_min_free_kbytes = -1;
-int watermark_scale_factor = 10;
+int watermark_scale_factor;
+
+/*
+ * Extra memory for the system to try freeing. Used to temporarily
+ * free memory, to make space for new workloads. Anyone can allocate
+ * down to the min watermarks controlled by min_free_kbytes above.
+ */
+int extra_free_kbytes;
 
 static unsigned long __meminitdata nr_kernel_pages;
 static unsigned long __meminitdata nr_all_pages;
@@ -2887,9 +2899,6 @@
 		if (!area->nr_free)
 			continue;
 
-		if (alloc_harder)
-			return true;
-
 		for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) {
 #ifdef CONFIG_CMA
 			/*
@@ -2909,6 +2918,9 @@
 			return true;
 		}
 #endif
+		if (alloc_harder &&
+			!list_empty(&area->free_list[MIGRATE_HIGHATOMIC]))
+			return true;
 	}
 	return false;
 }
@@ -3276,6 +3288,46 @@
 	return NULL;
 }
 
+#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	struct zone *zone;
+	struct zoneref *z;
+
+	/* Let costly order requests check for compaction progress */
+	if (order > PAGE_ALLOC_COSTLY_ORDER)
+		return false;
+
+	/*
+	 * For (0 < order < PAGE_ALLOC_COSTLY_ORDER) allow the shrinkers
+	 * to run and free up memory. Do not let these allocations fail
+	 * if shrinkers can free up memory. This is similar to
+	 * should_compact_retry implementation for !CONFIG_COMPACTION.
+	 */
+	for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
+				ac->high_zoneidx, ac->nodemask) {
+		unsigned long available;
+
+		available = zone_reclaimable_pages(zone);
+		available +=
+			zone_page_state_snapshot(zone, NR_FREE_PAGES);
+
+		if (__zone_watermark_ok(zone, 0, min_wmark_pages(zone),
+			ac_classzone_idx(ac), alloc_flags, available))
+			return true;
+	}
+
+	return false;
+}
+#else
+static inline bool
+should_compact_lmk_retry(struct alloc_context *ac, int order, int alloc_flags)
+{
+	return false;
+}
+#endif
+
 static inline bool
 should_compact_retry(struct alloc_context *ac, int order, int alloc_flags,
 		     enum compact_result compact_result,
@@ -3288,6 +3340,9 @@
 	if (!order)
 		return false;
 
+	if (should_compact_lmk_retry(ac, order, alloc_flags))
+		return true;
+
 	if (compaction_made_progress(compact_result))
 		(*compaction_retries)++;
 
@@ -3525,7 +3580,8 @@
 	 * their order will become available due to high fragmentation so
 	 * always increment the no progress counter for them
 	 */
-	if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER)
+	if ((did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		*no_progress_loops = 0;
 	else
 		(*no_progress_loops)++;
@@ -3803,7 +3859,8 @@
 	 * implementation of the compaction depends on the sufficient amount
 	 * of free memory (see __compaction_suitable)
 	 */
-	if (did_some_progress > 0 &&
+	if ((did_some_progress > 0 ||
+			IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER)) &&
 			should_compact_retry(ac, order, alloc_flags,
 				compact_result, &compact_priority,
 				&compaction_retries))
@@ -6742,6 +6799,7 @@
 static void __setup_per_zone_wmarks(void)
 {
 	unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
+	unsigned long pages_low = extra_free_kbytes >> (PAGE_SHIFT - 10);
 	unsigned long lowmem_pages = 0;
 	struct zone *zone;
 	unsigned long flags;
@@ -6753,11 +6811,14 @@
 	}
 
 	for_each_zone(zone) {
-		u64 tmp;
+		u64 min, low;
 
 		spin_lock_irqsave(&zone->lock, flags);
-		tmp = (u64)pages_min * zone->managed_pages;
-		do_div(tmp, lowmem_pages);
+		min = (u64)pages_min * zone->managed_pages;
+		do_div(min, lowmem_pages);
+		low = (u64)pages_low * zone->managed_pages;
+		do_div(low, vm_total_pages);
+
 		if (is_highmem(zone)) {
 			/*
 			 * __GFP_HIGH and PF_MEMALLOC allocations usually don't
@@ -6778,7 +6839,7 @@
 			 * If it's a lowmem zone, reserve a number of pages
 			 * proportionate to the zone's size.
 			 */
-			zone->watermark[WMARK_MIN] = tmp;
+			zone->watermark[WMARK_MIN] = min;
 		}
 
 		/*
@@ -6786,12 +6847,13 @@
 		 * scale factor in proportion to available memory, but
 		 * ensure a minimum size on small systems.
 		 */
-		tmp = max_t(u64, tmp >> 2,
+		min = max_t(u64, min >> 2,
 			    mult_frac(zone->managed_pages,
 				      watermark_scale_factor, 10000));
 
-		zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + tmp;
-		zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + tmp * 2;
+		zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + low + min;
+		zone->watermark[WMARK_HIGH] =
+					min_wmark_pages(zone) + low + min * 2;
 
 		spin_unlock_irqrestore(&zone->lock, flags);
 	}
@@ -6872,7 +6934,7 @@
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
  *	that we can call two helper functions whenever min_free_kbytes
- *	changes.
+ *	or extra_free_kbytes changes.
  */
 int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
 	void __user *buffer, size_t *length, loff_t *ppos)
diff --git a/mm/vmscan.c b/mm/vmscan.c
index bb18b47..2740973 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -212,7 +212,8 @@
 
 	nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) +
 		zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE);
-	if (get_nr_swap_pages() > 0)
+	if (get_nr_swap_pages() > 0
+			|| IS_ENABLED(CONFIG_ANDROID_LOW_MEMORY_KILLER))
 		nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) +
 			zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON);
 
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 5488e4a..ac1552d 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -722,13 +722,12 @@
 	if (unlikely(!net_eq(dev_net(dev), &init_net)))
 		goto drop;
 
-	if (WARN_ONCE(dev->type != ARPHRD_CAN ||
-		      skb->len != CAN_MTU ||
-		      cfd->len > CAN_MAX_DLEN,
-		      "PF_CAN: dropped non conform CAN skbuf: "
-		      "dev type %d, len %d, datalen %d\n",
-		      dev->type, skb->len, cfd->len))
+	if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU ||
+		     cfd->len > CAN_MAX_DLEN)) {
+		pr_warn_once("PF_CAN: dropped non conform CAN skbuf: dev type %d, len %d, datalen %d\n",
+			     dev->type, skb->len, cfd->len);
 		goto drop;
+	}
 
 	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
@@ -746,13 +745,12 @@
 	if (unlikely(!net_eq(dev_net(dev), &init_net)))
 		goto drop;
 
-	if (WARN_ONCE(dev->type != ARPHRD_CAN ||
-		      skb->len != CANFD_MTU ||
-		      cfd->len > CANFD_MAX_DLEN,
-		      "PF_CAN: dropped non conform CAN FD skbuf: "
-		      "dev type %d, len %d, datalen %d\n",
-		      dev->type, skb->len, cfd->len))
+	if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU ||
+		     cfd->len > CANFD_MAX_DLEN)) {
+		pr_warn_once("PF_CAN: dropped non conform CAN FD skbuf: dev type %d, len %d, datalen %d\n",
+			     dev->type, skb->len, cfd->len);
 		goto drop;
+	}
 
 	can_receive(skb, dev);
 	return NET_RX_SUCCESS;
diff --git a/net/core/dev.c b/net/core/dev.c
index e0217f8..ca40d8e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3139,10 +3139,21 @@
 		hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
 
 		/* + transport layer */
-		if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
-			hdr_len += tcp_hdrlen(skb);
-		else
-			hdr_len += sizeof(struct udphdr);
+		if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
+			const struct tcphdr *th;
+			struct tcphdr _tcphdr;
+
+			th = skb_header_pointer(skb, skb_transport_offset(skb),
+						sizeof(_tcphdr), &_tcphdr);
+			if (likely(th))
+				hdr_len += __tcp_hdrlen(th);
+		} else {
+			struct udphdr _udphdr;
+
+			if (skb_header_pointer(skb, skb_transport_offset(skb),
+					       sizeof(_udphdr), &_udphdr))
+				hdr_len += sizeof(struct udphdr);
+		}
 
 		if (shinfo->gso_type & SKB_GSO_DODGY)
 			gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
diff --git a/net/core/filter.c b/net/core/filter.c
index 5e42e0e..c385c55 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -451,6 +451,10 @@
 			    convert_bpf_extensions(fp, &insn))
 				break;
 
+			if (fp->code == (BPF_ALU | BPF_DIV | BPF_X) ||
+			    fp->code == (BPF_ALU | BPF_MOD | BPF_X))
+				*insn++ = BPF_MOV32_REG(BPF_REG_X, BPF_REG_X);
+
 			*insn = BPF_RAW_INSN(fp->code, BPF_REG_A, BPF_REG_X, 0, fp->k);
 			break;
 
@@ -1015,11 +1019,9 @@
 		 */
 		goto out_err_free;
 
-	/* We are guaranteed to never error here with cBPF to eBPF
-	 * transitions, since there's no issue with type compatibility
-	 * checks on program arrays.
-	 */
 	fp = bpf_prog_select_runtime(fp, &err);
+	if (err)
+		goto out_err_free;
 
 	kfree(old_prog);
 	return fp;
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 32e4e01..862d63e 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -550,8 +550,8 @@
 out_good:
 	ret = true;
 
-	key_control->thoff = (u16)nhoff;
 out:
+	key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
 	key_basic->n_proto = proto;
 	key_basic->ip_proto = ip_proto;
 
@@ -559,7 +559,6 @@
 
 out_bad:
 	ret = false;
-	key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
 	goto out;
 }
 EXPORT_SYMBOL(__skb_flow_dissect);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index b91cecc..7d07d6b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -497,7 +497,7 @@
 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
 
-	hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
+	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
 
 	if (n->parms->dead) {
 		rc = ERR_PTR(-EINVAL);
@@ -509,7 +509,7 @@
 	     n1 != NULL;
 	     n1 = rcu_dereference_protected(n1->next,
 			lockdep_is_held(&tbl->lock))) {
-		if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
+		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
 			if (want_ref)
 				neigh_hold(n1);
 			rc = n1;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index a7f05f0..1b46190 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -292,7 +292,13 @@
 		.data		= &bpf_jit_enable,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
+#ifndef CONFIG_BPF_JIT_ALWAYS_ON
 		.proc_handler	= proc_dointvec
+#else
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &one,
+		.extra2		= &one,
+#endif
 	},
 # ifdef CONFIG_HAVE_EBPF_JIT
 	{
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 5e3a730..7753681 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -140,6 +140,9 @@
 
 	ccid2_pr_debug("RTO_EXPIRE\n");
 
+	if (sk->sk_state == DCCP_CLOSED)
+		goto out;
+
 	/* back-off timer */
 	hc->tx_rto <<= 1;
 	if (hc->tx_rto > DCCP_RTO_MAX)
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 51b27ae..e60517e 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -223,11 +223,16 @@
 
 static int arp_constructor(struct neighbour *neigh)
 {
-	__be32 addr = *(__be32 *)neigh->primary_key;
+	__be32 addr;
 	struct net_device *dev = neigh->dev;
 	struct in_device *in_dev;
 	struct neigh_parms *parms;
+	u32 inaddr_any = INADDR_ANY;
 
+	if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
+		memcpy(neigh->primary_key, &inaddr_any, arp_tbl.key_len);
+
+	addr = *(__be32 *)neigh->primary_key;
 	rcu_read_lock();
 	in_dev = __in_dev_get_rcu(dev);
 	if (!in_dev) {
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 7bff0c6..9c7a4ce 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -332,7 +332,7 @@
 		return htonl(INADDR_ANY);
 
 	for_ifa(in_dev) {
-		if (inet_ifa_match(fl4->saddr, ifa))
+		if (fl4->saddr == ifa->ifa_local)
 			return fl4->saddr;
 	} endfor_ifa(in_dev);
 
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index bf071f3..cb3f08c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2224,6 +2224,9 @@
 			tcp_send_active_reset(sk, GFP_ATOMIC);
 			__NET_INC_STATS(sock_net(sk),
 					LINUX_MIB_TCPABORTONMEMORY);
+		} else if (!check_net(sock_net(sk))) {
+			/* Not possible to send reset; just close */
+			tcp_set_state(sk, TCP_CLOSE);
 		}
 	}
 
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index bc68da3..366b1be 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -32,6 +32,9 @@
 static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
 					netdev_features_t features)
 {
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4))
+		return ERR_PTR(-EINVAL);
+
 	if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
 		return ERR_PTR(-EINVAL);
 
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index d3d3ef6..4be66e4 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -82,11 +82,19 @@
  *  to prevent DoS attacks. It is called when a retransmission timeout
  *  or zero probe timeout occurs on orphaned socket.
  *
+ *  Also close if our net namespace is exiting; in that case there is no
+ *  hope of ever communicating again since all netns interfaces are already
+ *  down (or about to be down), and we need to release our dst references,
+ *  which have been moved to the netns loopback interface, so the namespace
+ *  can finish exiting.  This condition is only possible if we are a kernel
+ *  socket, as those do not hold references to the namespace.
+ *
  *  Criteria is still not confirmed experimentally and may change.
  *  We kill the socket, if:
  *  1. If number of orphaned sockets exceeds an administratively configured
  *     limit.
  *  2. If we have strong memory pressure.
+ *  3. If our net namespace is exiting.
  */
 static int tcp_out_of_resources(struct sock *sk, bool do_reset)
 {
@@ -115,6 +123,13 @@
 		__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY);
 		return 1;
 	}
+
+	if (!check_net(sock_net(sk))) {
+		/* Not possible to send reset; just close */
+		tcp_done(sk);
+		return 1;
+	}
+
 	return 0;
 }
 
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 6401574..f4f616e 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -205,6 +205,9 @@
 		goto out;
 	}
 
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP))
+		goto out;
+
 	if (!pskb_may_pull(skb, sizeof(struct udphdr)))
 		goto out;
 
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index a7d0c01..21bd54f 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -337,11 +337,12 @@
 
 	nt->dev = dev;
 	nt->net = dev_net(dev);
-	ip6gre_tnl_link_config(nt, 1);
 
 	if (register_netdevice(dev) < 0)
 		goto failed_free;
 
+	ip6gre_tnl_link_config(nt, 1);
+
 	/* Can use a lockless transmit, unless we generate output sequences */
 	if (!(nt->parms.o_flags & TUNNEL_SEQ))
 		dev->features |= NETIF_F_LLTX;
@@ -1267,7 +1268,6 @@
 
 static int ip6gre_tap_init(struct net_device *dev)
 {
-	struct ip6_tnl *tunnel;
 	int ret;
 
 	ret = ip6gre_tunnel_init_common(dev);
@@ -1276,10 +1276,6 @@
 
 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 
-	tunnel = netdev_priv(dev);
-
-	ip6gre_tnl_link_config(tunnel, 1);
-
 	return 0;
 }
 
@@ -1374,7 +1370,6 @@
 
 	nt->dev = dev;
 	nt->net = dev_net(dev);
-	ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
 
 	dev->features		|= GRE6_FEATURES;
 	dev->hw_features	|= GRE6_FEATURES;
@@ -1400,6 +1395,11 @@
 	if (err)
 		goto out;
 
+	ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
+
+	if (tb[IFLA_MTU])
+		ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
+
 	dev_hold(dev);
 	ip6gre_tunnel_link(ign, nt);
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index dd93836..55ca65c 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -165,7 +165,7 @@
 			    !(IP6CB(skb)->flags & IP6SKB_REROUTED));
 }
 
-static bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np)
+bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np)
 {
 	if (!np->autoflowlabel_set)
 		return ip6_default_np_autolabel(net);
@@ -1268,14 +1268,16 @@
 	v6_cork->tclass = ipc6->tclass;
 	if (rt->dst.flags & DST_XFRM_TUNNEL)
 		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
-		      rt->dst.dev->mtu : dst_mtu(&rt->dst);
+		      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(&rt->dst);
 	else
 		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
-		      rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+		      READ_ONCE(rt->dst.dev->mtu) : dst_mtu(rt->dst.path);
 	if (np->frag_size < mtu) {
 		if (np->frag_size)
 			mtu = np->frag_size;
 	}
+	if (mtu < IPV6_MIN_MTU)
+		return -EINVAL;
 	cork->base.fragsize = mtu;
 	if (dst_allfrag(rt->dst.path))
 		cork->base.flags |= IPCORK_ALLFRAG;
@@ -1806,6 +1808,7 @@
 	cork.base.flags = 0;
 	cork.base.addr = 0;
 	cork.base.opt = NULL;
+	cork.base.dst = NULL;
 	v6_cork.opt = NULL;
 	err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6);
 	if (err) {
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 6e3871c..bcea985 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1316,7 +1316,7 @@
 		break;
 
 	case IPV6_AUTOFLOWLABEL:
-		val = np->autoflowlabel;
+		val = ip6_autoflowlabel(sock_net(sk), np);
 		break;
 
 	default:
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 5edfe66..64ec233 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -263,6 +263,7 @@
 			 * this case. -DaveM
 			 */
 			pr_debug("end of fragment not rounded to 8 bytes.\n");
+			inet_frag_kill(&fq->q, &nf_frags);
 			return -EPROTO;
 		}
 		if (end > fq->q.len) {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f7e685f..558d566 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -393,14 +393,11 @@
 	struct net_device *loopback_dev =
 		dev_net(dev)->loopback_dev;
 
-	if (dev != loopback_dev) {
-		if (idev && idev->dev == dev) {
-			struct inet6_dev *loopback_idev =
-				in6_dev_get(loopback_dev);
-			if (loopback_idev) {
-				rt->rt6i_idev = loopback_idev;
-				in6_dev_put(idev);
-			}
+	if (idev && idev->dev != loopback_dev) {
+		struct inet6_dev *loopback_idev = in6_dev_get(loopback_dev);
+		if (loopback_idev) {
+			rt->rt6i_idev = loopback_idev;
+			in6_dev_put(idev);
 		}
 	}
 }
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
index d883c92..278e49c 100644
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -46,6 +46,9 @@
 {
 	struct tcphdr *th;
 
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
+		return ERR_PTR(-EINVAL);
+
 	if (!pskb_may_pull(skb, sizeof(*th)))
 		return ERR_PTR(-EINVAL);
 
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index e7d378c..2bd2087 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -55,6 +55,9 @@
 		const struct ipv6hdr *ipv6h;
 		struct udphdr *uh;
 
+		if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP))
+			goto out;
+
 		if (!pskb_may_pull(skb, sizeof(struct udphdr)))
 			goto out;
 
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 94bf810..6482b00 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -401,6 +401,11 @@
 #endif
 	int len;
 
+	if (sp->sadb_address_len <
+	    DIV_ROUND_UP(sizeof(*sp) + offsetofend(typeof(*addr), sa_family),
+			 sizeof(uint64_t)))
+		return -EINVAL;
+
 	switch (addr->sa_family) {
 	case AF_INET:
 		len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t));
@@ -511,6 +516,9 @@
 		uint16_t ext_type;
 		int ext_len;
 
+		if (len < sizeof(*ehdr))
+			return -EINVAL;
+
 		ext_len  = ehdr->sadb_ext_len;
 		ext_len *= sizeof(uint64_t);
 		ext_type = ehdr->sadb_ext_type;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index b747c96..fed598a 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -788,7 +788,7 @@
 	struct mesh_path *mpath;
 	u8 ttl, flags, hopcount;
 	const u8 *orig_addr;
-	u32 orig_sn, metric, metric_txsta, interval;
+	u32 orig_sn, new_metric, orig_metric, last_hop_metric, interval;
 	bool root_is_gate;
 
 	ttl = rann->rann_ttl;
@@ -799,7 +799,7 @@
 	interval = le32_to_cpu(rann->rann_interval);
 	hopcount = rann->rann_hopcount;
 	hopcount++;
-	metric = le32_to_cpu(rann->rann_metric);
+	orig_metric = le32_to_cpu(rann->rann_metric);
 
 	/*  Ignore our own RANNs */
 	if (ether_addr_equal(orig_addr, sdata->vif.addr))
@@ -816,7 +816,10 @@
 		return;
 	}
 
-	metric_txsta = airtime_link_metric_get(local, sta);
+	last_hop_metric = airtime_link_metric_get(local, sta);
+	new_metric = orig_metric + last_hop_metric;
+	if (new_metric < orig_metric)
+		new_metric = MAX_METRIC;
 
 	mpath = mesh_path_lookup(sdata, orig_addr);
 	if (!mpath) {
@@ -829,7 +832,7 @@
 	}
 
 	if (!(SN_LT(mpath->sn, orig_sn)) &&
-	    !(mpath->sn == orig_sn && metric < mpath->rann_metric)) {
+	    !(mpath->sn == orig_sn && new_metric < mpath->rann_metric)) {
 		rcu_read_unlock();
 		return;
 	}
@@ -847,7 +850,7 @@
 	}
 
 	mpath->sn = orig_sn;
-	mpath->rann_metric = metric + metric_txsta;
+	mpath->rann_metric = new_metric;
 	mpath->is_root = true;
 	/* Recording RANNs sender address to send individually
 	 * addressed PREQs destined for root mesh STA */
@@ -867,7 +870,7 @@
 		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
 				       orig_sn, 0, NULL, 0, broadcast_addr,
 				       hopcount, ttl, interval,
-				       metric + metric_txsta, 0, sdata);
+				       new_metric, 0, sdata);
 	}
 
 	rcu_read_unlock();
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index 28d0653..3f49912 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -17,6 +17,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/capability.h>
 #include <net/netlink.h>
 #include <net/sock.h>
 
@@ -392,6 +393,9 @@
 	struct nfnl_cthelper *nlcth;
 	int ret = 0;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
 		return -EINVAL;
 
@@ -595,6 +599,9 @@
 	struct nfnl_cthelper *nlcth;
 	bool tuple_set = false;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (nlh->nlmsg_flags & NLM_F_DUMP) {
 		struct netlink_dump_control c = {
 			.dump = nfnl_cthelper_dump_table,
@@ -661,6 +668,9 @@
 	struct nfnl_cthelper *nlcth, *n;
 	int j = 0, ret;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (tb[NFCTH_NAME])
 		helper_name = nla_data(tb[NFCTH_NAME]);
 
diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c
index 2455b69..b589a62 100644
--- a/net/netfilter/xt_osf.c
+++ b/net/netfilter/xt_osf.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 
+#include <linux/capability.h>
 #include <linux/if.h>
 #include <linux/inetdevice.h>
 #include <linux/ip.h>
@@ -69,6 +70,9 @@
 	struct xt_osf_finger *kf = NULL, *sf;
 	int err = 0;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!osf_attrs[OSF_ATTR_FINGER])
 		return -EINVAL;
 
@@ -113,6 +117,9 @@
 	struct xt_osf_finger *sf;
 	int err = -ENOENT;
 
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
 	if (!osf_attrs[OSF_ATTR_FINGER])
 		return -EINVAL;
 
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index ec87467..313a6dd 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -161,10 +161,13 @@
 #endif
 
 	if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
-		struct udphdr _hdr, *hp;
+		struct udphdr *hp;
+		struct tcphdr _hdr;
 
 		hp = skb_header_pointer(skb, ip_hdrlen(skb),
-					sizeof(_hdr), &_hdr);
+					iph->protocol == IPPROTO_UDP ?
+					sizeof(*hp) : sizeof(_hdr),
+					&_hdr);
 		if (hp == NULL)
 			return NULL;
 
@@ -370,9 +373,11 @@
 	}
 
 	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
-		struct udphdr _hdr, *hp;
+		struct udphdr *hp;
+		struct tcphdr _hdr;
 
-		hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+		hp = skb_header_pointer(skb, thoff, tproto == IPPROTO_UDP ?
+					sizeof(*hp) : sizeof(_hdr), &_hdr);
 		if (hp == NULL)
 			return NULL;
 
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 0792541..1668916 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -1789,14 +1789,11 @@
 
 #define MAX_ACTIONS_BUFSIZE	(32 * 1024)
 
-static struct sw_flow_actions *nla_alloc_flow_actions(int size, bool log)
+static struct sw_flow_actions *nla_alloc_flow_actions(int size)
 {
 	struct sw_flow_actions *sfa;
 
-	if (size > MAX_ACTIONS_BUFSIZE) {
-		OVS_NLERR(log, "Flow action size %u bytes exceeds max", size);
-		return ERR_PTR(-EINVAL);
-	}
+	WARN_ON_ONCE(size > MAX_ACTIONS_BUFSIZE);
 
 	sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
 	if (!sfa)
@@ -1869,12 +1866,15 @@
 	new_acts_size = ksize(*sfa) * 2;
 
 	if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
-		if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size)
+		if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size) {
+			OVS_NLERR(log, "Flow action size exceeds max %u",
+				  MAX_ACTIONS_BUFSIZE);
 			return ERR_PTR(-EMSGSIZE);
+		}
 		new_acts_size = MAX_ACTIONS_BUFSIZE;
 	}
 
-	acts = nla_alloc_flow_actions(new_acts_size, log);
+	acts = nla_alloc_flow_actions(new_acts_size);
 	if (IS_ERR(acts))
 		return (void *)acts;
 
@@ -2500,7 +2500,7 @@
 {
 	int err;
 
-	*sfa = nla_alloc_flow_actions(nla_len(attr), log);
+	*sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));
 	if (IS_ERR(*sfa))
 		return PTR_ERR(*sfa);
 
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index 8faf7a7..50dd516 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -453,6 +453,13 @@
 	}
 
 	ep = &config->muxed_ep[mux_id];
+	if (!ep->refcount) {
+		LOGD("Packet on %s:%d; has no logical endpoint config",
+		     skb->dev->name, mux_id);
+
+		rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP);
+		return RX_HANDLER_CONSUMED;
+	}
 
 	skb->dev = ep->egress_dev;
 
diff --git a/net/rmnet_data/rmnet_data_stats.h b/net/rmnet_data/rmnet_data_stats.h
index 366e486..75ed434 100644
--- a/net/rmnet_data/rmnet_data_stats.h
+++ b/net/rmnet_data/rmnet_data_stats.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016, 2018 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -39,6 +39,7 @@
 	RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0,
 	RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM,
 	RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED,
+	RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP,
 	RMNET_STATS_SKBFREE_MAX
 };
 
diff --git a/net/sctp/offload.c b/net/sctp/offload.c
index 4f5a2b5..6300f28 100644
--- a/net/sctp/offload.c
+++ b/net/sctp/offload.c
@@ -44,6 +44,9 @@
 	struct sk_buff *segs = ERR_PTR(-EINVAL);
 	struct sctphdr *sh;
 
+	if (!(skb_shinfo(skb)->gso_type & SKB_GSO_SCTP))
+		goto out;
+
 	sh = sctp_hdr(skb);
 	if (!pskb_may_pull(skb, sizeof(*sh)))
 		goto out;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7181ce6..c472b83 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -83,7 +83,7 @@
 static int sctp_writeable(struct sock *sk);
 static void sctp_wfree(struct sk_buff *skb);
 static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
-				size_t msg_len, struct sock **orig_sk);
+				size_t msg_len);
 static int sctp_wait_for_packet(struct sock *sk, int *err, long *timeo_p);
 static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
 static int sctp_wait_for_accept(struct sock *sk, long timeo);
@@ -332,16 +332,14 @@
 	if (len < sizeof (struct sockaddr))
 		return NULL;
 
+	if (!opt->pf->af_supported(addr->sa.sa_family, opt))
+		return NULL;
+
 	/* V4 mapped address are really of AF_INET family */
 	if (addr->sa.sa_family == AF_INET6 &&
-	    ipv6_addr_v4mapped(&addr->v6.sin6_addr)) {
-		if (!opt->pf->af_supported(AF_INET, opt))
-			return NULL;
-	} else {
-		/* Does this PF support this AF? */
-		if (!opt->pf->af_supported(addr->sa.sa_family, opt))
-			return NULL;
-	}
+	    ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
+	    !opt->pf->af_supported(AF_INET, opt))
+		return NULL;
 
 	/* If we get this far, af is valid. */
 	af = sctp_get_af_specific(addr->sa.sa_family);
@@ -1958,7 +1956,7 @@
 	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 	if (!sctp_wspace(asoc)) {
 		/* sk can be changed by peel off when waiting for buf. */
-		err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len, &sk);
+		err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
 		if (err) {
 			if (err == -ESRCH) {
 				/* asoc is already dead. */
@@ -7441,12 +7439,12 @@
 
 /* Helper function to wait for space in the sndbuf.  */
 static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
-				size_t msg_len, struct sock **orig_sk)
+				size_t msg_len)
 {
 	struct sock *sk = asoc->base.sk;
-	int err = 0;
 	long current_timeo = *timeo_p;
 	DEFINE_WAIT(wait);
+	int err = 0;
 
 	pr_debug("%s: asoc:%p, timeo:%ld, msg_len:%zu\n", __func__, asoc,
 		 *timeo_p, msg_len);
@@ -7475,17 +7473,13 @@
 		release_sock(sk);
 		current_timeo = schedule_timeout(current_timeo);
 		lock_sock(sk);
-		if (sk != asoc->base.sk) {
-			release_sock(sk);
-			sk = asoc->base.sk;
-			lock_sock(sk);
-		}
+		if (sk != asoc->base.sk)
+			goto do_error;
 
 		*timeo_p = current_timeo;
 	}
 
 out:
-	*orig_sk = sk;
 	finish_wait(&asoc->wait, &wait);
 
 	/* Release the association's refcnt.  */
diff --git a/net/socket.c b/net/socket.c
index fc0b609..bd9679f 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2566,6 +2566,15 @@
 
 core_initcall(sock_init);	/* early initcall */
 
+static int __init jit_init(void)
+{
+#ifdef CONFIG_BPF_JIT_ALWAYS_ON
+	bpf_jit_enable = 1;
+#endif
+	return 0;
+}
+pure_initcall(jit_init);
+
 #ifdef CONFIG_PROC_FS
 void socket_seq_show(struct seq_file *seq)
 {
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index e01c825..d24d14e 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2381,6 +2381,7 @@
 	case -ECONNREFUSED:
 	case -ECONNRESET:
 	case -ENETUNREACH:
+	case -EHOSTUNREACH:
 	case -EADDRINUSE:
 	case -ENOBUFS:
 		/* retry with existing socket, after a delay */
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 2775332..5b3e1ea 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1848,36 +1848,38 @@
 
 	if (strcmp(name, tipc_bclink_name) == 0) {
 		err = tipc_nl_add_bc_link(net, &msg);
-		if (err) {
-			nlmsg_free(msg.skb);
-			return err;
-		}
+		if (err)
+			goto err_free;
 	} else {
 		int bearer_id;
 		struct tipc_node *node;
 		struct tipc_link *link;
 
 		node = tipc_node_find_by_name(net, name, &bearer_id);
-		if (!node)
-			return -EINVAL;
+		if (!node) {
+			err = -EINVAL;
+			goto err_free;
+		}
 
 		tipc_node_read_lock(node);
 		link = node->links[bearer_id].link;
 		if (!link) {
 			tipc_node_read_unlock(node);
-			nlmsg_free(msg.skb);
-			return -EINVAL;
+			err = -EINVAL;
+			goto err_free;
 		}
 
 		err = __tipc_nl_add_link(net, &msg, link, 0);
 		tipc_node_read_unlock(node);
-		if (err) {
-			nlmsg_free(msg.skb);
-			return err;
-		}
+		if (err)
+			goto err_free;
 	}
 
 	return genlmsg_reply(msg.skb, info);
+
+err_free:
+	nlmsg_free(msg.skb);
+	return err;
 }
 
 int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info)
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index ff9887f..7fe91b1 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -54,7 +54,8 @@
 
 country AR:
 	(2402 - 2482 @ 40), (36)
-	(5170 - 5330 @ 160), (23)
+	(5170 - 5250 @ 80), (23), AUTO-BW
+	(5250 - 5330 @ 80), (36), AUTO-BW
 	(5490 - 5590 @ 80), (36)
 	(5650 - 5730 @ 80), (36)
 	(5735 - 5835 @ 80), (36)
diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch
index ac5f1267..aab8585 100644
--- a/scripts/const_structs.checkpatch
+++ b/scripts/const_structs.checkpatch
@@ -9,7 +9,6 @@
 dev_pm_ops
 dma_map_ops
 driver_info
-drm_connector_funcs
 drm_encoder_funcs
 drm_encoder_helper_funcs
 ethtool_ops
diff --git a/scripts/gdb/linux/tasks.py b/scripts/gdb/linux/tasks.py
index 1bf949c..f6ab3cc 100644
--- a/scripts/gdb/linux/tasks.py
+++ b/scripts/gdb/linux/tasks.py
@@ -96,6 +96,8 @@
         thread_info_addr = task.address + ia64_task_size
         thread_info = thread_info_addr.cast(thread_info_ptr_type)
     else:
+        if task.type.fields()[0].type == thread_info_type.get_type():
+            return task['thread_info']
         thread_info = task['stack'].cast(thread_info_ptr_type)
     return thread_info.dereference()
 
diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c
index f0bbf9c..16ed516 100644
--- a/security/pfe/pfk_ice.c
+++ b/security/pfe/pfk_ice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -138,6 +138,7 @@
 		if (ret1)
 			pr_err("%s: Invalidate Key Error: %d\n", __func__,
 					ret1);
+		goto out;
 	}
 	ret = qcom_ice_setup_ice_hw((const char *)s_type, false);
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 082b20c..051ee18 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -78,8 +78,7 @@
 
 static struct sidtab sidtab;
 struct policydb policydb;
-int ss_initialized;
-
+int ss_initialized __aligned(0x1000) __attribute__((section(".bss_rtic")));
 /*
  * The largest sequence number that has been used when
  * providing an access decision to the access vector cache.
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 25deca44..9ccf6a5 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -582,7 +582,6 @@
 {
 	u_int64_t n = (u_int64_t) a * b;
 	if (c == 0) {
-		snd_BUG_ON(!n);
 		*r = 0;
 		return UINT_MAX;
 	}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 45ef591..16580a8 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -221,6 +221,7 @@
 	rwlock_init(&client->ports_lock);
 	mutex_init(&client->ports_mutex);
 	INIT_LIST_HEAD(&client->ports_list_head);
+	mutex_init(&client->ioctl_mutex);
 
 	/* find free slot in the client table */
 	spin_lock_irqsave(&clients_lock, flags);
@@ -2127,7 +2128,9 @@
 			return -EFAULT;
 	}
 
+	mutex_lock(&client->ioctl_mutex);
 	err = handler->func(client, &buf);
+	mutex_unlock(&client->ioctl_mutex);
 	if (err >= 0) {
 		/* Some commands includes a bug in 'dir' field. */
 		if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT ||
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index c661425..0611e1e 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -61,6 +61,7 @@
 	struct list_head ports_list_head;
 	rwlock_t ports_lock;
 	struct mutex ports_mutex;
+	struct mutex ioctl_mutex;
 	int convert32;		/* convert 32->64bit */
 
 	/* output pool */
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 80bbadc..d6e079f 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -408,6 +408,7 @@
 	/*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
 
 	/* codec SSID */
+	SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122),
 	SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
 	SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
 	SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4ef3b00..71a058f 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5617,6 +5617,7 @@
 	SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
 	SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
 	SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
+	SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
 	SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index 7712e2b..4783648 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -122,7 +122,7 @@
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER_PLUS:
 		if (get_endpoint(alts, 0)->bInterval >= 1 &&
-		    get_endpoint(alts, 0)->bInterval <= 4)
+		    get_endpoint(alts, 0)->bInterval <= 16)
 			return get_endpoint(alts, 0)->bInterval - 1;
 		break;
 	default:
diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c
index 1c14c25..4b36323 100644
--- a/tools/gpio/gpio-event-mon.c
+++ b/tools/gpio/gpio-event-mon.c
@@ -23,6 +23,7 @@
 #include <getopt.h>
 #include <inttypes.h>
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <linux/gpio.h>
 
 int monitor_device(const char *device_name,
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index d897702..faacf0c 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include "elf.h"
 #include "warn.h"
@@ -370,7 +371,8 @@
 
 	elf->fd = open(name, O_RDONLY);
 	if (elf->fd == -1) {
-		perror("open");
+		fprintf(stderr, "objtool: Can't open '%s': %s\n",
+			name, strerror(errno));
 		goto err;
 	}
 
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index cffdd9c..ff37531 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -19,18 +19,18 @@
 
 include $(srctree)/tools/scripts/Makefile.arch
 
-$(call detected_var,ARCH)
+$(call detected_var,SRCARCH)
 
 NO_PERF_REGS := 1
 
 # Additional ARCH settings for ppc
-ifeq ($(ARCH),powerpc)
+ifeq ($(SRCARCH),powerpc)
   NO_PERF_REGS := 0
   LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
 endif
 
 # Additional ARCH settings for x86
-ifeq ($(ARCH),x86)
+ifeq ($(SRCARCH),x86)
   $(call detected,CONFIG_X86)
   ifeq (${IS_64_BIT}, 1)
     CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated
@@ -43,12 +43,12 @@
   NO_PERF_REGS := 0
 endif
 
-ifeq ($(ARCH),arm)
+ifeq ($(SRCARCH),arm)
   NO_PERF_REGS := 0
   LIBUNWIND_LIBS = -lunwind -lunwind-arm
 endif
 
-ifeq ($(ARCH),arm64)
+ifeq ($(SRCARCH),arm64)
   NO_PERF_REGS := 0
   LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
 endif
@@ -61,7 +61,7 @@
 # Disable it on all other architectures in case libdw unwind
 # support is detected in system. Add supported architectures
 # to the check.
-ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
+ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm))
   NO_LIBDW_DWARF_UNWIND := 1
 endif
 
@@ -115,9 +115,9 @@
 FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
 FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
 
-FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi
+FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi -I$(srctree)/tools/include/uapi
 # include ARCH specific config
--include $(src-perf)/arch/$(ARCH)/Makefile
+-include $(src-perf)/arch/$(SRCARCH)/Makefile
 
 ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
   CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
@@ -205,12 +205,12 @@
 endif
 
 CFLAGS += -I$(src-perf)/util/include
-CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
+CFLAGS += -I$(src-perf)/arch/$(SRCARCH)/include
 CFLAGS += -I$(srctree)/tools/include/uapi
 CFLAGS += -I$(srctree)/tools/include/
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/uapi
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/include/
-CFLAGS += -I$(srctree)/tools/arch/$(ARCH)/
+CFLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/uapi
+CFLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/include/
+CFLAGS += -I$(srctree)/tools/arch/$(SRCARCH)/
 
 # $(obj-perf)      for generated common-cmds.h
 # $(obj-perf)/util for generated bison/flex headers
@@ -321,7 +321,7 @@
 
   ifndef NO_DWARF
     ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
-      msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
+      msg := $(warning DWARF register mappings have not been defined for architecture $(SRCARCH), DWARF support disabled);
       NO_DWARF := 1
     else
       CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
@@ -346,7 +346,7 @@
         CFLAGS += -DHAVE_BPF_PROLOGUE
         $(call detected,CONFIG_BPF_PROLOGUE)
       else
-        msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
+        msg := $(warning BPF prologue is not supported by architecture $(SRCARCH), missing regs_query_register_offset());
       endif
     else
       msg := $(warning DWARF support is off, BPF prologue is disabled);
@@ -372,7 +372,7 @@
   endif
 endif
 
-ifeq ($(ARCH),powerpc)
+ifeq ($(SRCARCH),powerpc)
   ifndef NO_DWARF
     CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
   endif
@@ -453,7 +453,7 @@
 endif
 
 ifndef NO_LOCAL_LIBUNWIND
-  ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
+  ifeq ($(SRCARCH),$(filter $(SRCARCH),arm arm64))
     $(call feature_check,libunwind-debug-frame)
     ifneq ($(feature-libunwind-debug-frame), 1)
       msg := $(warning No debug_frame support found in libunwind);
@@ -717,7 +717,7 @@
       NO_PERF_READ_VDSO32 := 1
     endif
   endif
-  ifneq ($(ARCH), x86)
+  ifneq ($(SRCARCH), x86)
     NO_PERF_READ_VDSOX32 := 1
   endif
   ifndef NO_PERF_READ_VDSOX32
@@ -746,7 +746,7 @@
 endif
 
 ifndef NO_AUXTRACE
-  ifeq ($(ARCH),x86)
+  ifeq ($(SRCARCH),x86)
     ifeq ($(feature-get_cpuid), 0)
       msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables support for auxtrace/Intel PT, please install a newer gcc);
       NO_AUXTRACE := 1
@@ -793,7 +793,7 @@
 ETC_PERFCONFIG = etc/perfconfig
 endif
 ifndef lib
-ifeq ($(ARCH)$(IS_64_BIT), x861)
+ifeq ($(SRCARCH)$(IS_64_BIT), x861)
 lib = lib64
 else
 lib = lib
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index ef52d1e..2b92ffe 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -192,7 +192,7 @@
 
 ifeq ($(config),0)
 include $(srctree)/tools/scripts/Makefile.arch
--include arch/$(ARCH)/Makefile
+-include arch/$(SRCARCH)/Makefile
 endif
 
 # The FEATURE_DUMP_EXPORT holds location of the actual
diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build
index 109eb75..d9b6af8 100644
--- a/tools/perf/arch/Build
+++ b/tools/perf/arch/Build
@@ -1,2 +1,2 @@
 libperf-y += common.o
-libperf-y += $(ARCH)/
+libperf-y += $(SRCARCH)/
diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
index 9213a12..999a4e8 100644
--- a/tools/perf/pmu-events/Build
+++ b/tools/perf/pmu-events/Build
@@ -2,7 +2,7 @@
 
 jevents-y	+= json.o jsmn.o jevents.o
 pmu-events-y	+= pmu-events.o
-JDIR		=  pmu-events/arch/$(ARCH)
+JDIR		=  pmu-events/arch/$(SRCARCH)
 JSON		=  $(shell [ -d $(JDIR) ] &&				\
 			find $(JDIR) -name '*.json' -o -name 'mapfile.csv')
 #
@@ -10,4 +10,4 @@
 # directory and create tables in pmu-events.c.
 #
 $(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JEVENTS)
-	$(Q)$(call echo-cmd,gen)$(JEVENTS) $(ARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V)
+	$(Q)$(call echo-cmd,gen)$(JEVENTS) $(SRCARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V)
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 8a4ce49..546250a 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -71,7 +71,7 @@
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)echo ';' >> $@
 
-ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64 powerpc))
+ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc))
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 endif
 
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 5337f49..28bdb48 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -826,7 +826,7 @@
 
 /*
  * default get_cpuid(): nothing gets recorded
- * actual implementation must be in arch/$(ARCH)/util/header.c
+ * actual implementation must be in arch/$(SRCARCH)/util/header.c
  */
 int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused)
 {
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c
index c25a74a..2bb3eef 100644
--- a/tools/power/cpupower/bench/system.c
+++ b/tools/power/cpupower/bench/system.c
@@ -61,7 +61,7 @@
 
 	dprintf("set %s as cpufreq governor\n", governor);
 
-	if (cpupower_is_cpu_online(cpu) != 0) {
+	if (cpupower_is_cpu_online(cpu) != 1) {
 		perror("cpufreq_cpu_exists");
 		fprintf(stderr, "error: cpu %u does not exist\n", cpu);
 		return -1;
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
index 1b5da00..5b3205f 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
@@ -130,15 +130,18 @@
 {
 	int num;
 	char *tmp;
+	int this_cpu;
+
+	this_cpu = sched_getcpu();
 
 	/* Assume idle state count is the same for all CPUs */
-	cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(0);
+	cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(this_cpu);
 
 	if (cpuidle_sysfs_monitor.hw_states_num <= 0)
 		return NULL;
 
 	for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
-		tmp = cpuidle_state_name(0, num);
+		tmp = cpuidle_state_name(this_cpu, num);
 		if (tmp == NULL)
 			continue;
 
@@ -146,7 +149,7 @@
 		strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
 		free(tmp);
 
-		tmp = cpuidle_state_desc(0, num);
+		tmp = cpuidle_state_desc(this_cpu, num);
 		if (tmp == NULL)
 			continue;
 		strncpy(cpuidle_cstates[num].desc, tmp,	CSTATE_DESC_LEN - 1);
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
index ac73710..1517a23 100644
--- a/tools/usb/usbip/libsrc/usbip_common.c
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -215,9 +215,16 @@
 		       struct usbip_usb_interface *uinf)
 {
 	char busid[SYSFS_BUS_ID_SIZE];
+	int size;
 	struct udev_device *sif;
 
-	sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
+	size = snprintf(busid, sizeof(busid), "%s:%d.%d",
+			udev->busid, udev->bConfigurationValue, i);
+	if (size < 0 || (unsigned int)size >= sizeof(busid)) {
+		err("busid length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(busid));
+		return -1;
+	}
 
 	sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
 	if (!sif) {
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c
index 9d41522..6ff7b60 100644
--- a/tools/usb/usbip/libsrc/usbip_host_common.c
+++ b/tools/usb/usbip/libsrc/usbip_host_common.c
@@ -40,13 +40,20 @@
 static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
 {
 	char status_attr_path[SYSFS_PATH_MAX];
+	int size;
 	int fd;
 	int length;
 	char status;
 	int value = 0;
 
-	snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
-		 udev->path);
+	size = snprintf(status_attr_path, sizeof(status_attr_path),
+			"%s/usbip_status", udev->path);
+	if (size < 0 || (unsigned int)size >= sizeof(status_attr_path)) {
+		err("usbip_status path length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(status_attr_path));
+		return -1;
+	}
+
 
 	fd = open(status_attr_path, O_RDONLY);
 	if (fd < 0) {
@@ -218,6 +225,7 @@
 {
 	char attr_name[] = "usbip_sockfd";
 	char sockfd_attr_path[SYSFS_PATH_MAX];
+	int size;
 	char sockfd_buff[30];
 	int ret;
 
@@ -237,10 +245,20 @@
 	}
 
 	/* only the first interface is true */
-	snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
-		 edev->udev.path, attr_name);
+	size = snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
+			edev->udev.path, attr_name);
+	if (size < 0 || (unsigned int)size >= sizeof(sockfd_attr_path)) {
+		err("exported device path length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(sockfd_attr_path));
+		return -1;
+	}
 
-	snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+	size = snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+	if (size < 0 || (unsigned int)size >= sizeof(sockfd_buff)) {
+		err("socket length %i >= %lu or < 0", size,
+		    (long unsigned)sizeof(sockfd_buff));
+		return -1;
+	}
 
 	ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
 				    strlen(sockfd_buff));
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index ad92047..1274f32 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -55,12 +55,12 @@
 
 	while (*c != '\0') {
 		int port, status, speed, devid;
-		unsigned long socket;
+		int sockfd;
 		char lbusid[SYSFS_BUS_ID_SIZE];
 
-		ret = sscanf(c, "%d %d %d %x %lx %31s\n",
+		ret = sscanf(c, "%d %d %d %x %u %31s\n",
 				&port, &status, &speed,
-				&devid, &socket, lbusid);
+				&devid, &sockfd, lbusid);
 
 		if (ret < 5) {
 			dbg("sscanf failed: %d", ret);
@@ -69,7 +69,7 @@
 
 		dbg("port %d status %d speed %d devid %x",
 				port, status, speed, devid);
-		dbg("socket %lx lbusid %s", socket, lbusid);
+		dbg("sockfd %u lbusid %s", sockfd, lbusid);
 
 
 		/* if a device is connected, look at it */
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
index d7599d9..73d8eee 100644
--- a/tools/usb/usbip/src/usbip.c
+++ b/tools/usb/usbip/src/usbip.c
@@ -176,6 +176,8 @@
 			break;
 		case '?':
 			printf("usbip: invalid option\n");
+			/* Terminate after printing error */
+			/* FALLTHRU */
 		default:
 			usbip_usage();
 			goto out;
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
index fa46141..e121cfb 100644
--- a/tools/usb/usbip/src/usbip_bind.c
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -144,6 +144,7 @@
 	int rc;
 	struct udev *udev;
 	struct udev_device *dev;
+	const char *devpath;
 
 	/* Check whether the device with this bus ID exists. */
 	udev = udev_new();
@@ -152,8 +153,16 @@
 		err("device with the specified bus ID does not exist");
 		return -1;
 	}
+	devpath = udev_device_get_devpath(dev);
 	udev_unref(udev);
 
+	/* If the device is already attached to vhci_hcd - bail out */
+	if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
+		err("bind loop detected: device: %s is attached to %s\n",
+		    devpath, USBIP_VHCI_DRV_NAME);
+		return -1;
+	}
+
 	rc = unbind_other(busid);
 	if (rc == UNBIND_ST_FAILED) {
 		err("could not unbind driver from device on busid %s", busid);
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
index f1b38e8..d65a9f4 100644
--- a/tools/usb/usbip/src/usbip_list.c
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -187,6 +187,7 @@
 	const char *busid;
 	char product_name[128];
 	int ret = -1;
+	const char *devpath;
 
 	/* Create libudev context. */
 	udev = udev_new();
@@ -209,6 +210,14 @@
 		path = udev_list_entry_get_name(dev_list_entry);
 		dev = udev_device_new_from_syspath(udev, path);
 
+		/* Ignore devices attached to vhci_hcd */
+		devpath = udev_device_get_devpath(dev);
+		if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
+			dbg("Skip the device %s already attached to %s\n",
+			    devpath, USBIP_VHCI_DRV_NAME);
+			continue;
+		}
+
 		/* Get device information. */
 		idVendor = udev_device_get_sysattr_value(dev, "idVendor");
 		idProduct = udev_device_get_sysattr_value(dev, "idProduct");