Merge "fbdev: msm: Clean up copyrights marking & fix naming issues"
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/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 55cd383..42153e1 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
@@ -230,7 +237,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/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/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-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
new file mode 100644
index 0000000..8e17f80
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
@@ -0,0 +1,310 @@
+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,micro-usb
+  Usage:      optional
+  Value type: <empty>
+  Definition: Boolean flag which indicates that the platform only support
+		micro usb port.
+
+- 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/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index deed94d..6c172c1 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -984,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.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 2755df2..b64570b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -283,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";
@@ -754,6 +890,7 @@
 			qcom,additional-mapping =
 			/* modem tables in IMEM */
 			<0x14686000 0x14686000 0x3000>;
+			qcom,ipa-q6-smem-size = <16384>;
 		};
 
 		ipa_smmu_wlan: ipa_smmu_wlan {
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 89ed48a..98c0aa6 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
@@ -399,9 +400,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
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 1e9d7ae..38e79f5 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
@@ -411,9 +412,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
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 405e34d..5122af2 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -65,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.platforms b/arch/arm64/Kconfig.platforms
index b7640d3..1de858e 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -181,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 9877324..961921b 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -169,7 +169,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 +201,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)
@@ -293,6 +292,8 @@
 	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 \
 	sdm450-mtp.dtb \
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/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..d0eff96
--- /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"
+	};
+};
+
+&pmi8950_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pmi8950_charger {
+	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.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
new file mode 100644
index 0000000..285727d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -0,0 +1,623 @@
+/*
+ * 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"
+
+&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;
+	};
+
+	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-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
index 4fa5cd1..cb59ac3 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -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
@@ -55,6 +55,9 @@
 		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 {
@@ -63,6 +66,8 @@
 		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 {
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.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 2861fd5..71cba8a 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -164,6 +164,7 @@
 #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"
@@ -1876,6 +1877,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 903f170a..7724714 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -502,7 +502,7 @@
 
 		trips {
 			pm660_vbat_adc: vbat-adc {
-				temperature = <3300>;
+				temperature = <3200>;
 				hysteresis = <100>;
 				type = "passive";
 			};
@@ -532,7 +532,7 @@
 
 		trips {
 			vbat-low {
-				temperature = <3100>;
+				temperature = <2800>;
 				hysteresis = <0>;
 				type = "passive";
 			};
@@ -548,7 +548,7 @@
 
 		trips {
 			vbat-too-low {
-				temperature = <2900>;
+				temperature = <2600>;
 				hysteresis = <0>;
 				type = "passive";
 			};
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index bab5774..4e82cfe 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -587,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-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/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 0a98528..5226e74 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -13,6 +13,20 @@
 
 #include "msm8953-qrd.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";
 };
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/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-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index 75a2762..88aad0c 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -134,6 +134,27 @@
 
 		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,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>;
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.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 47c03e2..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";
 		};
 
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-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index bd8ae70..6034b6d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -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>
 
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 880018c..f651cc0 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -55,6 +55,8 @@
 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
@@ -293,6 +295,8 @@
 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
@@ -307,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
@@ -361,6 +366,11 @@
 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
@@ -467,6 +477,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
@@ -498,6 +509,7 @@
 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
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index bc0265f..e0e3cdc 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -59,6 +59,8 @@
 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
@@ -303,6 +305,8 @@
 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
@@ -317,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
@@ -372,6 +377,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
@@ -479,6 +489,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
@@ -517,6 +528,7 @@
 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
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 11c95ea..ff3bb70 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -573,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 6aa09e5..01687f5 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -590,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/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 223c9b6..e5ca5ab 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -367,6 +367,7 @@
 	int qos_request;
 	struct mutex map_mutex;
 	struct mutex fl_map_mutex;
+	int refcount;
 };
 
 static struct fastrpc_apps gfa;
@@ -2006,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) {
@@ -2605,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)
@@ -2898,6 +2901,7 @@
 		}
 	}
 	fl->ssrcount = me->channel[cid].ssrcount;
+	fl->refcount = 1;
 	if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) ||
 	    (me->channel[cid].chan == NULL)) {
 		if (me->glink) {
@@ -2971,6 +2975,7 @@
 	if (debugfs_file != NULL)
 		fl->debugfs_file = debugfs_file;
 	fl->qos_request = 0;
+	fl->refcount = 0;
 	filp->private_data = fl;
 	mutex_init(&fl->map_mutex);
 	mutex_init(&fl->fl_map_mutex);
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/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 694b483..6e1674b 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -375,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;
 }
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/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..406743f 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
@@ -774,62 +746,30 @@
 			"qcom,gpu-quirk-limit-uche-gbif-rw" },
 };
 
-#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 +777,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 +1098,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 +1176,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..a506f47 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
@@ -175,9 +175,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 +465,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 +538,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 c734123..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 */
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_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/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_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_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/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/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/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/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 f3ab5be..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;
 }
@@ -5119,6 +5119,7 @@
 		return 0;
 	}
 
+	mutex_lock(&inst->flush_lock);
 	/* enable in flush */
 	inst->in_flush = true;
 
@@ -5172,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");
@@ -6584,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 */
@@ -6664,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..df50ca5
--- /dev/null
+++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_res_parse.c
@@ -0,0 +1,1652 @@
+/* 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>
+
+enum clock_properties {
+	CLOCK_PROP_HAS_SCALING = 1 << 0,
+};
+
+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 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);
+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);
+	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/misc/qseecom.c b/drivers/misc/qseecom.c
index b5ad125..232b4ae 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -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,10 +1857,11 @@
 	int ret = 0;
 	struct qseecom_continue_blocked_request_ireq ireq;
 	struct qseecom_command_scm_resp continue_resp;
-	bool found_app = false;
-	unsigned long flags;
+	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");
@@ -1891,140 +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 */
-	sigfillset(&new_sigset);
-	sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
-
 	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);
-
-	sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
-	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;
-}
-
-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;
-	sigset_t new_sigset;
-	sigset_t 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 */
-	sigfillset(&new_sigset);
-	sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
-
-	do {
-		qseecom.app_block_ref_cnt++;
-		mutex_unlock(&app_access_lock);
-		wait_event_freezable(
-			list_ptr->listener_block_app_wq,
-			!list_ptr->listener_in_use);
-		mutex_lock(&app_access_lock);
-		qseecom.app_block_ref_cnt--;
-	}  while (list_ptr->listener_in_use);
-
-	sigprocmask(SIG_SETMASK, &old_sigset, NULL);
-
-	/* 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;
-		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);
+		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;
 		}
+		ptr_app->blocked_on_listener_id = resp->data;
+
+		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);
+
+		/* sleep until listener is available */
+		sigfillset(&new_sigset);
+		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+
+		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);
+
+		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));
+		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/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/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/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/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_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 2b55c2d..a3db092 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -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;
 	}
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_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 01c0736..da3b399 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -5973,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;
@@ -6089,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/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/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 819fbf0..93692fa 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -321,6 +321,7 @@
 	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),
 	/* Local extensions of type int64_t */
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/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
new file mode 100644
index 0000000..d1031ba
--- /dev/null
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -0,0 +1,2071 @@
+/* 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_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 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->micro_usb_mode = of_property_read_bool(node, "qcom,micro-usb");
+
+	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,
+};
+
+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->micro_usb_mode) &&
+			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->micro_usb_mode)
+			val->intval = POWER_SUPPLY_TYPEC_NONE;
+		else
+			val->intval = chg->typec_mode;
+		break;
+	case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
+		if (chg->micro_usb_mode)
+			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->micro_usb_mode)
+			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;
+	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->micro_usb_mode) &&
+			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->micro_usb_mode)
+		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,
+				MICRO_USB_STATE_CHANGE_INT_EN_BIT |
+				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;
+	}
+
+	return rc;
+}
+
+static int smb5_init_hw(struct smb5 *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	int rc;
+	u8 val;
+
+	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);
+	if (chip->dt.usb_icl_ua < 0)
+		chip->dt.usb_icl_ua = chg->default_icl_ua;
+
+	/* 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, true, chg->batt_profile_fcc_ua);
+	vote(chg->fv_votable,
+		BATT_PROFILE_VOTER, true, 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->micro_usb_mode, 0);
+
+	/*
+	 * 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->micro_usb_mode)
+		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 power role for DRP 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);
+
+	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	= default_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->param = smb5_params;
+	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->name = "pm855b_charger";
+
+	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);
+		goto cleanup;
+	}
+
+	rc = smblib_init(chg);
+	if (rc < 0) {
+		pr_err("Smblib_init failed rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	/* 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;
+	}
+
+	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 cleanup;
+	}
+
+	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 cleanup;
+	}
+
+	device_init_wakeup(chg->dev, true);
+
+	pr_info("QPNP SMB5 probed successfully\n");
+
+	return rc;
+
+cleanup:
+	smb5_free_interrupts(chg);
+	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->micro_usb_mode)
+		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..ff7da6c
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -0,0 +1,3614 @@
+/* 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_icl_override(struct smb_charger *chg, bool override)
+{
+	int rc;
+
+	rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG,
+				ICL_OVERRIDE_AFTER_APSD_BIT,
+				override ? ICL_OVERRIDE_AFTER_APSD_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
+
+	return rc;
+}
+
+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;
+}
+
+/********************
+ * 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 *
+ ********************/
+
+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_err(chg, "%s: %d is out of range [%d, %d]\n",
+				param->name, val_u, param->min_u, param->max_u);
+			return -EINVAL;
+		}
+
+		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 override;
+
+	/* 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 override_suspend_config;
+
+	/* configure current */
+	if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+		&& (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 enable_icl_changed_interrupt;
+		}
+	} 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 enable_icl_changed_interrupt;
+		}
+	}
+
+override_suspend_config:
+	/* determine if override needs to be enforced */
+	override = true;
+	if (icl_ua == INT_MAX) {
+		/* remove override if no voters - hw defaults is desired */
+		override = false;
+	} else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
+		if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
+			/* For std cable with type = SDP never override */
+			override = false;
+		else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP
+			&& icl_ua == 1500000)
+			/*
+			 * For std cable with type = CDP override only if
+			 * current is not 1500mA
+			 */
+			override = false;
+	}
+
+	/* enforce override */
+	rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
+		USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
+
+	rc = smblib_icl_override(chg, override);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
+		goto enable_icl_changed_interrupt;
+	}
+
+	/* 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 enable_icl_changed_interrupt;
+	}
+
+enable_icl_changed_interrupt:
+	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->micro_usb_mode)
+		&& (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;
+
+	/* 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;
+}
+
+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_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_PD:
+		val->intval = MICRO_12V;
+	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;
+
+	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);
+		extcon_set_state_sync(chg->extcon, EXTCON_USB, 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->micro_usb_mode)
+		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_notify_extcon_props(struct smb_charger *chg, int id)
+{
+	union extcon_property_value val;
+	union power_supply_propval prop_val;
+
+	smblib_get_prop_typec_cc_orientation(chg, &prop_val);
+	val.intval = ((prop_val.intval == 2) ? 1 : 0);
+	extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_TYPEC_POLARITY, val);
+
+	val.intval = true;
+	extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_SS, val);
+}
+
+static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
+}
+
+static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
+}
+
+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 (chg->micro_usb_mode)
+			extcon_set_state_sync(chg->extcon, EXTCON_USB,
+					true);
+		/* if not DCP then no hvdcp timeout happens. Enable pd here */
+		vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
+				false, 0);
+		if (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->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
+			&& !chg->uusb_apsd_rerun_done) {
+		/*
+		 * Force re-run APSD to handle slow insertion related
+		 * charger-mis-detection.
+		 */
+		chg->uusb_apsd_rerun_done = true;
+		smblib_rerun_apsd(chg);
+		return IRQ_HANDLED;
+	}
+
+	smblib_handle_apsd_done(chg,
+		(bool)(stat & APSD_DTC_STATUS_DONE_BIT));
+
+	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_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->micro_usb_mode) {
+		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;
+	}
+
+	if (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 | U_USB_GROUND_BIT));
+	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, otg);
+	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_3 = 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;
+		}
+
+		rc = smblib_register_notifier(chg);
+		if (rc < 0) {
+			smblib_err(chg,
+				"Couldn't register notifier 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;
+			}
+		}
+		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..8633ba0
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -0,0 +1,502 @@
+/* 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 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;
+	bool			micro_usb_mode;
+	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;
+
+	/* 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_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);
+
+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_boost_current(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_icl_override(struct smb_charger *chg, bool override);
+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..1534f7c
--- /dev/null
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -0,0 +1,345 @@
+/* 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_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_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)
+
+/********************************
+ *  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/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 e3a50e3..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;
@@ -2367,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;
@@ -2382,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);
@@ -2403,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;
@@ -2444,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);
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index cef3c77..ada7d5e 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) \
@@ -602,6 +603,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);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 685b384..0e83971 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -595,6 +595,10 @@
 	[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
@@ -1535,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/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/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/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/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/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index cc1a0ea..19f3f18 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -824,6 +824,7 @@
 			return ret;
 		}
 		qphy->dpdm_enable = true;
+		qusb_phy_reset(qphy);
 	}
 
 	return ret;
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/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 6ac2c4b..74b698c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -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/include/linux/power_supply.h b/include/linux/power_supply.h
index 164abe2..21dd697 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -272,6 +272,7 @@
 	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,
 	/* Local extensions of type int64_t */
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/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/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/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index cbfe7e4..a872c9a 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -114,6 +114,10 @@
 	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
@@ -160,6 +164,8 @@
 #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
@@ -228,7 +234,9 @@
 	MSM_CPU_SDM450,
 	MSM_CPU_SDM632,
 	MSM_CPU_SDA632,
-	MSM_CPU_8937
+	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/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/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/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 a01c821..b057784 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -325,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",
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);
 		}
 	}
 }