Merge "ARM: dts: msm: Add memory dump device for SDM845" into msm-4.9
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
new file mode 100644
index 0000000..8598d0c
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt
@@ -0,0 +1,63 @@
+QTI PDC interrupt controller
+
+PDC is QTI's platform parent interrupt controller that serves as wakeup source.
+
+Newer QTI SOCs are replacing MPM (MSM sleep Power Manager) with PDC (Power
+Domain Controller) to manage subsystem wakeups and resources during sleep.
+This driver marks the wakeup interrupts in APSS PDC such that it monitors the
+interrupts when the system is asleep, wakes up the APSS when one of these
+interrupts occur and replays it to the subsystem interrupt controller after it
+becomes operational.
+
+Earlier MPM architecture used arch-extension of GIC interrupt
+controller to mark enabled wake-up interrupts and monitor these when the
+system goes to sleep. Since the arch-extensions are no-longer available
+on newer kernel versions, this driver is implemented as hierarchical irq
+domain.  GIC is parent interrupt controller at the highest level.
+Platform interrupt controller PDC is next in hierarchy, followed by others.
+This driver only configures the interrupts, does not handle them.
+
+PDC interrupt configuration involves programming of 2 set of registers:
+IRQ_ENABLE_BANK    - Enable the irq
+IRQ_i_CFG          - Configure the interrupt i
+
+Properties:
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Should contain "qcom,pdc-<target>"
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Specifies the base physical address for PDC hardware
+			block for DRV2.
+
+- interrupt-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: Specifies the number of cells needed to encode an interrupt source.
+			Value must be 3.
+			The encoding of these cells are same as described in
+			Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
+
+- interrupt-parent:
+	Usage: required
+	Value type: <phandle>
+	Definition: Specifies the interrupt parent necessary for hierarchical domain to operate.
+
+- interrupt-controller:
+	Usage: required
+	Value type: <bool>
+	Definition: Identifies the node as an interrupt controller.
+
+Example:
+
+pdcgic: interrupt-controller@0xb220000{
+	compatible = "qcom,pdc-sdm845";
+	reg = <0xb220000 0x30000>;
+	#interrupt-cells = <3>;
+	interrupt-parent = <&intc>;
+	interrupt-controller;
+};
diff --git a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
index 0295e1b..937ccb9 100644
--- a/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-sde-rotator.txt
@@ -81,6 +81,32 @@
 				limits.
 - qcom,mdss-rot-vbif-qos-setting: This array is used to program vbif qos remapper register
 				  priority for rotator clients.
+- qcom,mdss-rot-cdp-setting:	Integer array of size two, to indicate client driven
+				prefetch is available or not. Index 0 represents
+				if CDP is enabled for read and index 1, if CDP
+				is enabled for write operation.
+- qcom,mdss-rot-qos-lut		A 4 cell property with the format of <rd_lut_0,
+				rd_lut_1, wr_lut_0, wr_lut_1> indicating the qos
+				lut settings for the rotator sspp and writeback
+				client.
+- qcom,mdss-rot-danger-lut	A two cell property with the format of <rd_lut,
+				wr_lut> indicating the danger lut settings for
+				the rotator sspp and writeback client.
+- qcom,mdss-rot-safe-lut	A two cell property with the format of <rd_lut,
+				wr_lut> indicating the safe lut settings for the
+				rotator sspp and writeback client.
+- qcom,mdss-inline-rot-qos-lut:	A 4 cell property with the format of <rd_lut_0,
+				rd_lut_1, wr_lut_0, wr_lut_1> indicating the qos
+				lut settings for the inline rotator sspp and
+				writeback client.
+- qcom,mdss-inline-rot-danger-lut: A two cell property with the format of
+				<rd_lut, wr_lut> indicating the danger lut
+				settings for the inline rotator sspp and
+				writeback client.
+- qcom,mdss-inline-rot-safe-lut: A two cell property with the format of
+				<rd_lut, wr_lut> indicating the safe lut
+				settings for the inline rotator sspp and
+				writeback client.
 - qcom,mdss-rot-mode:		This is integer value indicates operation mode
 				of the rotator device
 - qcom,mdss-sbuf-headroom:	This integer value indicates stream buffer headroom in lines.
@@ -146,9 +172,19 @@
 		/* VBIF QoS remapper settings*/
 		qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>;
 
+		com,mdss-rot-cdp-setting = <1 1>;
+
 		qcom,mdss-default-ot-rd-limit = <8>;
 		qcom,mdss-default-ot-wr-limit = <16>;
 
+		qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>;
+		qcom,mdss-rot-danger-lut = <0x0 0x0>;
+		qcom,mdss-rot-safe-lut = <0x0000ffff 0x0>;
+
+		qcom,mdss-inline-rot-qos-lut = <0x0 0x0 0x00112233 0x44556677>;
+		qcom,mdss-inline-rot-danger-lut = <0x0 0x0000ffff>;
+		qcom,mdss-inline-rot-safe-lut = <0x0 0x0000ff00>;
+
 		qcom,mdss-sbuf-headroom = <20>;
 		cache-slice-names = "rotator";
 		cache-slices = <&llcc 4>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index b51996d..0aaac6f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -14,6 +14,27 @@
 #include <dt-bindings/gpio/gpio.h>
 
 /{
+	bluetooth: bt_wcn3990 {
+		compatible = "qca,wcn3990";
+		qca,bt-vdd-io-supply = <&pm8998_s3>;
+		qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+		qca,bt-vdd-core-supply = <&pm8998_l7>;
+		qca,bt-vdd-pa-supply = <&pm8998_l17>;
+		qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+		qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+		qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+		qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+		qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+		qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+		qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+		qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+	};
+
 	qrd_batterydata: qcom,battery-data {
 		qcom,batt-id-range-pct = <15>;
 		#include "fg-gen3-batterydata-itech-3000mah.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 7ae63af..19b8744 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -36,7 +36,7 @@
 			reg = <0x3500 0x100>;
 			regulator-name = "pm8998_s12";
 			regulator-min-microvolt = <568000>;
-			regulator-max-microvolt = <1056000>;
+			regulator-max-microvolt = <1136000>;
 			qcom,enable-time = <500>;
 			regulator-always-on;
 		};
@@ -114,9 +114,9 @@
 				regulator-max-microvolt = <19>;
 
 				qcom,cpr-fuse-corners = <4>;
-				qcom,cpr-fuse-combos = <16>;
-				qcom,cpr-speed-bins = <2>;
-				qcom,cpr-speed-bin-corners = <19 19>;
+				qcom,cpr-fuse-combos = <24>;
+				qcom,cpr-speed-bins = <3>;
+				qcom,cpr-speed-bin-corners = <19 19 19>;
 				qcom,cpr-corners = <19>;
 
 				qcom,cpr-corner-fmax-map = <6 12 17 19>;
@@ -137,6 +137,11 @@
 					<568000  568000  568000  568000  568000
 					 568000  568000  568000  568000  584000
 					 584000  584000  632000  632000  632000
+					 632000  672000  712000  712000>,
+					/* Speed bin 2 */
+					<568000  568000  568000  568000  568000
+					 568000  568000  568000  568000  584000
+					 584000  584000  632000  632000  632000
 					 632000  672000  712000  712000>;
 
 				qcom,cpr-floor-to-ceiling-max-range =
@@ -146,13 +151,30 @@
 					 32000  32000  40000  40000>;
 
 				qcom,corner-frequencies =
+					/* Speed bin 0 */
 					<300000000  422400000  499200000
 					 576000000  652800000  748800000
 					 825600000  902400000  979200000
 					1056000000 1132800000 1209600000
 					1286400000 1363200000 1440000000
 					1516800000 1593600000 1651200000
-					1708800000>;
+					1708800000>,
+					/* Speed bin 1 */
+					<300000000  422400000  499200000
+					 576000000  652800000  748800000
+					 825600000  902400000  979200000
+					1056000000 1132800000 1209600000
+					1286400000 1363200000 1440000000
+					1516800000 1593600000 1651200000
+					1708800000>,
+					/* Speed bin 2 */
+					<300000000  422400000  499200000
+					 576000000  652800000  748800000
+					 825600000  902400000  979200000
+					1056000000 1132800000 1209600000
+					1286400000 1363200000 1440000000
+					1516800000 1593600000 1670400000
+					1747200000>;
 
 				qcom,cpr-ro-scaling-factor =
 					<2594 2795 2576 2761 2469 2673 2198
@@ -185,6 +207,8 @@
 					/* Speed bin 0 */
 					<0 1 1 1 1 1 1 1>,
 					/* Speed bin 1 */
+					<0 1 1 1 1 1 1 1>,
+					/* Speed bin 2 */
 					<0 1 1 1 1 1 1 1>;
 				qcom,allow-aging-open-loop-voltage-adjustment =
 					<1>;
@@ -201,20 +225,41 @@
 			apc0_l3_vreg: regulator {
 				regulator-name = "apc0_l3_corner";
 				regulator-min-microvolt = <1>;
-				regulator-max-microvolt = <11>;
+				regulator-max-microvolt = <13>;
 
 				qcom,cpr-fuse-corners = <4>;
-				qcom,cpr-fuse-combos = <16>;
-				qcom,cpr-speed-bins = <2>;
-				qcom,cpr-speed-bin-corners = <11 11>;
-				qcom,cpr-corners = <11>;
+				qcom,cpr-fuse-combos = <24>;
+				qcom,cpr-speed-bins = <3>;
+				qcom,cpr-speed-bin-corners = <11 11 13>;
+				qcom,cpr-corners =
+					/* Speed bin 0 */
+					<11 11 11 11 11 11 11 11>,
+					/* Speed bin 1 */
+					<11 11 11 11 11 11 11 11>,
+					/* Speed bin 2 */
+					<13 13 13 13 13 13 13 13>;
 
-				qcom,cpr-corner-fmax-map = <4 7 9 11>;
+				qcom,cpr-corner-fmax-map =
+					/* Speed bin 0 */
+					<4 7 9 11>,
+					/* Speed bin 1 */
+					<4 7 9 11>,
+					/* Speed bin 2 */
+					<4 7 9 13>;
 
 				qcom,cpr-voltage-ceiling =
+					/* Speed bin 0 */
 					<872000  872000  872000  872000  872000
 					 872000  872000  872000  928000  996000
-					 996000>;
+					 996000>,
+					/* Speed bin 1 */
+					<872000  872000  872000  872000  872000
+					 872000  872000  872000  928000  996000
+					 996000>,
+					/* Speed bin 2 */
+					<872000  872000  872000  872000  872000
+					 872000  872000  872000  928000  996000
+					 996000  996000  996000>;
 
 				qcom,cpr-voltage-floor =
 					/* Speed bin 0 */
@@ -224,18 +269,43 @@
 					/* Speed bin 1 */
 					<568000  568000  568000  568000  568000
 					 584000  584000  632000  672000  712000
-					 712000>;
+					 712000>,
+					/* Speed bin 2 */
+					<568000  568000  568000  568000  568000
+					 584000  584000  632000  672000  712000
+					 712000  712000  712000>;
 
 				qcom,cpr-floor-to-ceiling-max-range =
+					/* Speed bin 0 */
 					<32000  32000  32000  32000  32000
 					 32000  32000  32000  32000  40000
-					 40000>;
+					 40000>,
+					/* Speed bin 1 */
+					<32000  32000  32000  32000  32000
+					 32000  32000  32000  32000  40000
+					 40000>,
+					/* Speed bin 2 */
+					<32000  32000  32000  32000  32000
+					 32000  32000  32000  32000  40000
+					 40000  40000  40000>;
 
 				qcom,corner-frequencies =
+					/* Speed bin 0 */
 					<300000000  422400000  499200000
 					 576000000  652800000  729600000
 					 806400000  883200000  960000000
-					1036800000 1094400000>;
+					1036800000 1094400000>,
+					/* Speed bin 1 */
+					<300000000  422400000  499200000
+					 576000000  652800000  729600000
+					 806400000  883200000  960000000
+					1036800000 1094400000>,
+					/* Speed bin 2 */
+					<300000000  422400000  499200000
+					 576000000  652800000  729600000
+					 806400000  883200000  960000000
+					1036800000 1113600000 1209600000
+					1305600000>;
 
 				qcom,cpr-ro-scaling-factor =
 					<2857 3056 2828 2952 2699 2796 2447
@@ -262,12 +332,14 @@
 				qcom,cpr-scaled-open-loop-voltage-as-ceiling;
 
 				qcom,cpr-aging-max-voltage-adjustment = <15000>;
-				qcom,cpr-aging-ref-corner = <11>;
+				qcom,cpr-aging-ref-corner = <11 11 13>;
 				qcom,cpr-aging-ro-scaling-factor = <1620>;
 				qcom,allow-aging-voltage-adjustment =
 					/* Speed bin 0 */
 					<0 1 1 1 1 1 1 1>,
 					/* Speed bin 1 */
+					<0 1 1 1 1 1 1 1>,
+					/* Speed bin 2 */
 					<0 1 1 1 1 1 1 1>;
 				qcom,allow-aging-open-loop-voltage-adjustment =
 					<1>;
@@ -320,7 +392,7 @@
 		qcom,cpr-panic-reg-name-list =
 			"APSS_GOLD_CPRH_STATUS_0", "GOLD_SAW4_PMIC_STS";
 
-		qcom,cpr-aging-ref-voltage = <1056000>;
+		qcom,cpr-aging-ref-voltage = <1136000>;
 		vdd-supply = <&pm8998_s12>;
 
 		thread@0 {
@@ -333,23 +405,27 @@
 			apc1_perfcl_vreg: regulator {
 				regulator-name = "apc1_perfcl_corner";
 				regulator-min-microvolt = <1>;
-				regulator-max-microvolt = <26>;
+				regulator-max-microvolt = <27>;
 
 				qcom,cpr-fuse-corners = <3>;
-				qcom,cpr-fuse-combos = <16>;
-				qcom,cpr-speed-bins = <2>;
-				qcom,cpr-speed-bin-corners = <22 24>;
+				qcom,cpr-fuse-combos = <24>;
+				qcom,cpr-speed-bins = <3>;
+				qcom,cpr-speed-bin-corners = <22 24 25>;
 				qcom,cpr-corners =
 					/* Speed bin 0 */
 					<22 22 22 22 22 22 22 22>,
 					/* Speed bin 1 */
-					<24 24 24 24 24 24 24 24>;
+					<24 24 24 24 24 24 24 24>,
+					/* Speed bin 2 */
+					<25 25 25 25 25 25 25 25>;
 
 				qcom,cpr-corner-fmax-map =
 					/* Speed bin 0 */
 					<10 17 22>,
 					/* Speed bin 1 */
-					<10 17 24>;
+					<10 17 24>,
+					/* Speed bin 2 */
+					<10 17 25>;
 
 				qcom,cpr-voltage-ceiling =
 					/* Speed bin 0 */
@@ -357,13 +433,20 @@
 					 828000  828000  828000  828000  828000
 					 828000  828000  828000  828000  828000
 					 828000  828000  884000  952000  952000
-					1056000 1056000>,
+					1136000 1136000>,
 					/* Speed bin 1 */
 					<828000  828000  828000  828000  828000
 					 828000  828000  828000  828000  828000
 					 828000  828000  828000  828000  828000
 					 828000  828000  884000  952000  952000
-					1056000 1056000 1056000 1056000>;
+					1136000 1136000 1136000 1136000>,
+					/* Speed bin 2 */
+					<828000  828000  828000  828000  828000
+					 828000  828000  828000  828000  828000
+					 828000  828000  828000  828000  828000
+					 828000  828000  884000  952000  952000
+					1136000 1136000 1136000 1136000
+					1136000>;
 
 				qcom,cpr-voltage-floor =
 					/* Speed bin 0 */
@@ -377,7 +460,14 @@
 					 568000  568000  568000  568000  568000
 					 584000  584000  632000  632000  632000
 					 632000  632000  672000  712000  712000
-					 772000  772000  772000  772000>;
+					 772000  772000  772000  772000>,
+					/* Speed bin 2 */
+					<568000  568000  568000  568000  568000
+					 568000  568000  568000  568000  568000
+					 584000  584000  632000  632000  632000
+					 632000  632000  672000  712000  712000
+					 772000  772000  772000  772000
+					 772000>;
 
 				qcom,cpr-floor-to-ceiling-max-range =
 					/* Speed bin 0 */
@@ -391,7 +481,13 @@
 					 32000  32000  32000  32000  32000
 					 32000  32000  32000  32000  32000
 					 32000  32000  40000  40000  40000
-					 40000  40000  40000  40000>;
+					 40000  40000  40000  40000>,
+					/* Speed bin 2 */
+					<32000  32000  32000  32000  32000
+					 32000  32000  32000  32000  32000
+					 32000  32000  32000  32000  32000
+					 32000  32000  40000  40000  40000
+					 40000  40000  40000  40000  40000>;
 
 				qcom,corner-frequencies =
 					/* Speed bin 0 */
@@ -411,7 +507,17 @@
 					1267200000 1344000000 1420800000
 					1497600000 1574400000 1651200000
 					1728000000 1804800000 1881600000
-					1958400000 2035200000 2092800000>;
+					1958400000 2035200000 2092800000>,
+					/* Speed bin 2 */
+					<300000000  422400000  499200000
+					 576000000  652800000  729600000
+					 806400000  883200000  960000000
+					1036800000 1113600000 1190400000
+					1267200000 1344000000 1420800000
+					1497600000 1574400000 1651200000
+					1728000000 1804800000 1881600000
+					1958400000 2035200000 2112000000
+					2208000000>;
 
 				qcom,cpr-ro-scaling-factor =
 					<2857 3056 2828 2952 2699 2796 2447
@@ -442,6 +548,15 @@
 					<     0      0      0>,
 					<     0      0      0>,
 					<     0      0      0>,
+					<     0      0      0>,
+					/* Speed bin 2 */
+					<100000 100000 100000>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
 					<     0      0      0>;
 
 				qcom,cpr-closed-loop-voltage-fuse-adjustment =
@@ -462,6 +577,15 @@
 					<     0      0      0>,
 					<     0      0      0>,
 					<     0      0      0>,
+					<     0      0      0>,
+					/* Speed bin 2 */
+					<100000 100000 100000>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
 					<     0      0      0>;
 
 				qcom,allow-voltage-interpolation;
@@ -469,12 +593,14 @@
 				qcom,cpr-scaled-open-loop-voltage-as-ceiling;
 
 				qcom,cpr-aging-max-voltage-adjustment = <15000>;
-				qcom,cpr-aging-ref-corner = <22 24>;
+				qcom,cpr-aging-ref-corner = <22 24 25>;
 				qcom,cpr-aging-ro-scaling-factor = <1700>;
 				qcom,allow-aging-voltage-adjustment =
 					/* Speed bin 0 */
 					<0 1 1 1 1 1 1 1>,
 					/* Speed bin 1 */
+					<0 1 1 1 1 1 1 1>,
+					/* Speed bin 2 */
 					<0 1 1 1 1 1 1 1>;
 				qcom,allow-aging-open-loop-voltage-adjustment =
 					<1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index afaac40..c806627 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1718,7 +1718,7 @@
 	qcom,ssc@5c00000 {
 		compatible = "qcom,pil-tz-generic";
 		reg = <0x5c00000 0x4000>;
-		interrupts = <0 377 1>;
+		interrupts = <0 494 1>;
 
 		vdd_cx-supply = <&pm8998_l27_level>;
 		vdd_px-supply = <&pm8998_lvs2>;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 5dcdf46..2d7b174 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -142,7 +142,8 @@
 void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
 				     struct dsi_mode_info *mode,
 				     u32 h_stride,
-				     u32 vc_id);
+				     u32 vc_id,
+				     struct dsi_rect *roi);
 void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
 void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl);
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index f187ad1..39b797e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1558,7 +1558,6 @@
 
 int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl)
 {
-	struct dsi_mode_info video_timing;
 	int rc = 0;
 
 	if (!dsi_ctrl) {
@@ -1568,12 +1567,6 @@
 
 	mutex_lock(&dsi_ctrl->ctrl_lock);
 
-	/* replace video mode width with actual roi width */
-	memcpy(&video_timing, &dsi_ctrl->host_config.video_timing,
-			sizeof(video_timing));
-	video_timing.h_active = dsi_ctrl->roi.w;
-	video_timing.v_active = dsi_ctrl->roi.h;
-
 	dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw,
 					&dsi_ctrl->host_config.lane_map);
 
@@ -1586,9 +1579,10 @@
 					&dsi_ctrl->host_config.u.cmd_engine);
 
 		dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
-				&video_timing,
-				video_timing.h_active * 3,
-				0x0);
+				&dsi_ctrl->host_config.video_timing,
+				dsi_ctrl->host_config.video_timing.h_active * 3,
+				0x0,
+				&dsi_ctrl->roi);
 		dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true);
 	} else {
 		dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
@@ -1690,7 +1684,8 @@
 		dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
 				&dsi_ctrl->host_config.video_timing,
 				dsi_ctrl->host_config.video_timing.h_active * 3,
-				0x0);
+				0x0,
+				NULL);
 	} else {
 		dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
 					&dsi_ctrl->host_config.common_config,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 859d707..bb72807 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -319,7 +319,8 @@
 	void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl,
 				 struct dsi_mode_info *mode,
 				 u32 h_stride,
-				 u32 vc_id);
+				 u32 vc_id,
+				 struct dsi_rect *roi);
 
 	/**
 	 * ctrl_en() - enable DSI controller engine
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 48c2370..a024c43 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -19,6 +19,7 @@
 #include "dsi_ctrl_hw.h"
 #include "dsi_ctrl_reg.h"
 #include "dsi_hw.h"
+#include "dsi_panel.h"
 
 #define MMSS_MISC_CLAMP_REG_OFF           0x0014
 #define DSI_CTRL_DYNAMIC_FORCE_ON         (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21))
@@ -234,21 +235,36 @@
 void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
 				     struct dsi_mode_info *mode,
 				     u32 h_stride,
-				     u32 vc_id)
+				     u32 vc_id,
+				     struct dsi_rect *roi)
 {
-	u32 reg = 0;
 	u32 width_final, stride_final;
+	u32 height_final;
+	u32 stream_total = 0, stream_ctrl = 0;
+	u32 reg_ctrl = 0, reg_ctrl2 = 0;
+
+	if (roi && (!roi->w || !roi->h))
+		return;
 
 	if (mode->dsc_enabled && mode->dsc) {
+		u32 reg = 0;
 		u32 offset = 0;
-		u32 reg_ctrl, reg_ctrl2;
+		int pic_width, this_frame_slices, intf_ip_w;
+		struct msm_display_dsc_info dsc;
+
+		memcpy(&dsc, mode->dsc, sizeof(dsc));
+		pic_width = roi ? roi->w : mode->h_active;
+		this_frame_slices = pic_width / dsc.slice_width;
+		intf_ip_w = this_frame_slices * dsc.slice_width;
+		dsi_dsc_pclk_param_calc(&dsc, intf_ip_w);
 
 		if (vc_id != 0)
 			offset = 16;
 		reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL);
 		reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2);
-		width_final = mode->dsc->pclk_per_line;
-		stride_final = mode->dsc->bytes_per_pkt;
+		width_final = dsc.pclk_per_line;
+		stride_final = dsc.bytes_per_pkt;
+		height_final = roi ? roi->h : mode->v_active;
 
 		reg = 0x39 << 8;
 		/*
@@ -258,34 +274,45 @@
 		 * 2 == 4 pkt
 		 * 3 pkt is not support
 		 */
-		if (mode->dsc->pkt_per_line == 4)
-			reg |= (mode->dsc->pkt_per_line - 2) << 6;
+		if (dsc.pkt_per_line == 4)
+			reg |= (dsc.pkt_per_line - 2) << 6;
 		else
-			reg |= (mode->dsc->pkt_per_line - 1) << 6;
-		reg |= mode->dsc->eol_byte_num << 4;
+			reg |= (dsc.pkt_per_line - 1) << 6;
+		reg |= dsc.eol_byte_num << 4;
 		reg |= 1;
 
 		reg_ctrl &= ~(0xFFFF << offset);
 		reg_ctrl |= (reg << offset);
 		reg_ctrl2 &= ~(0xFFFF << offset);
-		reg_ctrl2 |= (mode->dsc->bytes_in_slice << offset);
+		reg_ctrl2 |= (dsc.bytes_in_slice << offset);
 		DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl);
 		DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2);
+
+		pr_debug("ctrl %d reg_ctrl 0x%x reg_ctrl2 0x%x\n", ctrl->index,
+				reg_ctrl, reg_ctrl2);
+	} else if (roi) {
+		width_final = roi->w;
+		stride_final = roi->w * 3;
+		height_final = roi->h;
 	} else {
 		width_final = mode->h_active;
 		stride_final = h_stride;
+		height_final = mode->v_active;
 	}
 
-	reg = (stride_final + 1) << 16;
-	reg |= (vc_id & 0x3) << 8;
-	reg |= 0x39; /* packet data type */
+	stream_ctrl = (stride_final + 1) << 16;
+	stream_ctrl |= (vc_id & 0x3) << 8;
+	stream_ctrl |= 0x39; /* packet data type */
 
-	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, reg);
-	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, reg);
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, stream_ctrl);
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, stream_ctrl);
 
-	reg = (mode->v_active << 16) | width_final;
-	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, reg);
-	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, reg);
+	stream_total = (height_final << 16) | width_final;
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, stream_total);
+	DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, stream_total);
+
+	pr_debug("ctrl %d stream_ctrl 0x%x stream_total 0x%x\n", ctrl->index,
+			stream_ctrl, stream_total);
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index 4c9fbbe..f254af5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -249,4 +249,6 @@
 int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
 		struct dsi_rect *roi);
 
+void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
+
 #endif /* _DSI_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index a457938..79fcfb7 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -612,12 +612,15 @@
 	int i;
 
 	if (!dim_layer->rect.w || !dim_layer->rect.h) {
-		SDE_DEBUG("empty dim layer\n");
+		SDE_DEBUG("empty dim_layer\n");
 		return;
 	}
 
 	cstate = to_sde_crtc_state(crtc->state);
 
+	SDE_DEBUG("dim_layer - flags:%d, stage:%d\n",
+			dim_layer->flags, dim_layer->stage);
+
 	split_dim_layer.stage = dim_layer->stage;
 	split_dim_layer.color_fill = dim_layer->color_fill;
 
@@ -651,9 +654,13 @@
 		} else {
 			split_dim_layer.rect.x =
 					split_dim_layer.rect.x -
-					cstate->lm_bounds[i].w;
+						cstate->lm_bounds[i].x;
 		}
 
+		SDE_DEBUG("split_dim_layer - LM:%d, rect:{%d,%d,%d,%d}}\n",
+			i, split_dim_layer.rect.x, split_dim_layer.rect.y,
+			split_dim_layer.rect.w, split_dim_layer.rect.h);
+
 		lm = mixer[i].hw_lm;
 		mixer[i].mixer_op_mode |= 1 << split_dim_layer.stage;
 		lm->ops.setup_dim_layer(lm, &split_dim_layer);
@@ -858,9 +865,24 @@
 	sde_crtc = to_sde_crtc(crtc);
 	crtc_state = to_sde_crtc_state(state);
 
-	for (i = 0; i < sde_crtc->num_mixers; i++) {
-		if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i]))
-			disp_bitmask |= BIT(i);
+	/* pingpong split: one ROI, one LM, two physical displays */
+	if (crtc_state->is_ppsplit) {
+		u32 lm_split_width = crtc_state->lm_bounds[0].w / 2;
+		struct sde_rect *roi = &crtc_state->lm_roi[0];
+
+		if (sde_kms_rect_is_null(roi))
+			disp_bitmask = 0;
+		else if ((u32)roi->x + (u32)roi->w <= lm_split_width)
+			disp_bitmask = BIT(0);		/* left only */
+		else if (roi->x >= lm_split_width)
+			disp_bitmask = BIT(1);		/* right only */
+		else
+			disp_bitmask = BIT(0) | BIT(1); /* left and right */
+	} else {
+		for (i = 0; i < sde_crtc->num_mixers; i++) {
+			if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i]))
+				disp_bitmask |= BIT(i);
+		}
 	}
 
 	SDE_DEBUG("affected displays 0x%x\n", disp_bitmask);
@@ -881,9 +903,6 @@
 	sde_crtc = to_sde_crtc(crtc);
 	crtc_state = to_sde_crtc_state(state);
 
-	if (sde_crtc->num_mixers == 1)
-		return 0;
-
 	if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
 		SDE_ERROR("%s: unsupported number of mixers: %d\n",
 				sde_crtc->name, sde_crtc->num_mixers);
@@ -891,9 +910,41 @@
 	}
 
 	/*
-	 * On certain HW, ROIs must be centered on the split between LMs,
-	 * and be of equal width.
+	 * If using pingpong split: one ROI, one LM, two physical displays
+	 * then the ROI must be centered on the panel split boundary and
+	 * be of equal width across the split.
 	 */
+	if (crtc_state->is_ppsplit) {
+		u16 panel_split_width;
+		u32 display_mask;
+
+		roi[0] = &crtc_state->lm_roi[0];
+
+		if (sde_kms_rect_is_null(roi[0]))
+			return 0;
+
+		display_mask = _sde_crtc_get_displays_affected(crtc, state);
+		if (display_mask != (BIT(0) | BIT(1)))
+			return 0;
+
+		panel_split_width = crtc_state->lm_bounds[0].w / 2;
+		if (roi[0]->x + roi[0]->w / 2 != panel_split_width) {
+			SDE_ERROR("%s: roi x %d w %d split %d\n",
+					sde_crtc->name, roi[0]->x, roi[0]->w,
+					panel_split_width);
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	/*
+	 * On certain HW, if using 2 LM, ROIs must be split evenly between the
+	 * LMs and be of equal width.
+	 */
+	if (sde_crtc->num_mixers == 1)
+		return 0;
+
 	roi[0] = &crtc_state->lm_roi[0];
 	roi[1] = &crtc_state->lm_roi[1];
 
@@ -1181,6 +1232,69 @@
 	_sde_crtc_program_lm_output_roi(crtc);
 }
 
+static void _sde_crtc_swap_mixers_for_right_partial_update(
+		struct drm_crtc *crtc)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *cstate;
+	struct drm_encoder *drm_enc;
+	bool is_right_only;
+	bool encoder_in_dsc_merge = false;
+
+	if (!crtc || !crtc->state)
+		return;
+
+	sde_crtc = to_sde_crtc(crtc);
+	cstate = to_sde_crtc_state(crtc->state);
+
+	if (sde_crtc->num_mixers != CRTC_DUAL_MIXERS)
+		return;
+
+	drm_for_each_encoder(drm_enc, crtc->dev) {
+		if (drm_enc->crtc == crtc &&
+				sde_encoder_is_dsc_merge(drm_enc)) {
+			encoder_in_dsc_merge = true;
+			break;
+		}
+	}
+
+	/**
+	 * For right-only partial update with DSC merge, we swap LM0 & LM1.
+	 * This is due to two reasons:
+	 * - On 8996, there is a DSC HW requirement that in DSC Merge Mode,
+	 *   the left DSC must be used, right DSC cannot be used alone.
+	 *   For right-only partial update, this means swap layer mixers to map
+	 *   Left LM to Right INTF. On later HW this was relaxed.
+	 * - In DSC Merge mode, the physical encoder has already registered
+	 *   PP0 as the master, to switch to right-only we would have to
+	 *   reprogram to be driven by PP1 instead.
+	 * To support both cases, we prefer to support the mixer swap solution.
+	 */
+	if (!encoder_in_dsc_merge)
+		return;
+
+	is_right_only = sde_kms_rect_is_null(&cstate->lm_roi[0]) &&
+			!sde_kms_rect_is_null(&cstate->lm_roi[1]);
+
+	if (is_right_only && !sde_crtc->mixers_swapped) {
+		/* right-only update swap mixers */
+		swap(sde_crtc->mixers[0], sde_crtc->mixers[1]);
+		sde_crtc->mixers_swapped = true;
+	} else if (!is_right_only && sde_crtc->mixers_swapped) {
+		/* left-only or full update, swap back */
+		swap(sde_crtc->mixers[0], sde_crtc->mixers[1]);
+		sde_crtc->mixers_swapped = false;
+	}
+
+	SDE_DEBUG("%s: right_only %d swapped %d, mix0->lm%d, mix1->lm%d\n",
+			sde_crtc->name, is_right_only, sde_crtc->mixers_swapped,
+			sde_crtc->mixers[0].hw_lm->idx - LM_0,
+			sde_crtc->mixers[1].hw_lm->idx - LM_0);
+	SDE_EVT32(DRMID(crtc), is_right_only, sde_crtc->mixers_swapped,
+			sde_crtc->mixers[0].hw_lm->idx - LM_0,
+			sde_crtc->mixers[1].hw_lm->idx - LM_0);
+}
+
 /**
  * _sde_crtc_blend_setup - configure crtc mixers
  * @crtc: Pointer to drm crtc structure
@@ -1226,6 +1340,8 @@
 			lm->ops.clear_dim_layer(lm);
 	}
 
+	_sde_crtc_swap_mixers_for_right_partial_update(crtc);
+
 	/* initialize stage cfg */
 	memset(&sde_crtc->stage_cfg, 0, sizeof(struct sde_hw_stage_cfg));
 
@@ -1534,26 +1650,28 @@
 {
 	struct sde_drm_dim_layer_v1 dim_layer_v1;
 	struct sde_drm_dim_layer_cfg *user_cfg;
+	struct sde_hw_dim_layer *dim_layer;
 	u32 count, i;
 
 	if (!cstate) {
 		SDE_ERROR("invalid cstate\n");
 		return;
 	}
+	dim_layer = cstate->dim_layer;
 
 	if (!usr_ptr) {
-		SDE_DEBUG("dim layer data removed\n");
+		SDE_DEBUG("dim_layer data removed\n");
 		return;
 	}
 
 	if (copy_from_user(&dim_layer_v1, usr_ptr, sizeof(dim_layer_v1))) {
-		SDE_ERROR("failed to copy dim layer data\n");
+		SDE_ERROR("failed to copy dim_layer data\n");
 		return;
 	}
 
 	count = dim_layer_v1.num_layers;
-	if (!count || (count > SDE_MAX_DIM_LAYERS)) {
-		SDE_ERROR("invalid number of Dim Layers:%d", count);
+	if (count > SDE_MAX_DIM_LAYERS) {
+		SDE_ERROR("invalid number of dim_layers:%d", count);
 		return;
 	}
 
@@ -1561,22 +1679,31 @@
 	cstate->num_dim_layers = count;
 	for (i = 0; i < count; i++) {
 		user_cfg = &dim_layer_v1.layer_cfg[i];
-		cstate->dim_layer[i].flags = user_cfg->flags;
-		cstate->dim_layer[i].stage = user_cfg->stage + SDE_STAGE_0;
 
-		cstate->dim_layer[i].rect.x = user_cfg->rect.x1;
-		cstate->dim_layer[i].rect.y = user_cfg->rect.y1;
-		cstate->dim_layer[i].rect.w = user_cfg->rect.x2 -
-						user_cfg->rect.x1 + 1;
-		cstate->dim_layer[i].rect.h = user_cfg->rect.y2 -
-						user_cfg->rect.y1 + 1;
+		dim_layer[i].flags = user_cfg->flags;
+		dim_layer[i].stage = user_cfg->stage + SDE_STAGE_0;
 
-		cstate->dim_layer[i].color_fill = (struct sde_mdss_color) {
+		dim_layer[i].rect.x = user_cfg->rect.x1;
+		dim_layer[i].rect.y = user_cfg->rect.y1;
+		dim_layer[i].rect.w = user_cfg->rect.x2 - user_cfg->rect.x1;
+		dim_layer[i].rect.h = user_cfg->rect.y2 - user_cfg->rect.y1;
+
+		dim_layer[i].color_fill = (struct sde_mdss_color) {
 				user_cfg->color_fill.color_0,
 				user_cfg->color_fill.color_1,
 				user_cfg->color_fill.color_2,
 				user_cfg->color_fill.color_3,
 		};
+
+		SDE_DEBUG("dim_layer[%d] - flags:%d, stage:%d\n",
+				i, dim_layer[i].flags, dim_layer[i].stage);
+		SDE_DEBUG(" rect:{%d,%d,%d,%d}, color:{%d,%d,%d,%d}\n",
+				dim_layer[i].rect.x, dim_layer[i].rect.y,
+				dim_layer[i].rect.w, dim_layer[i].rect.h,
+				dim_layer[i].color_fill.color_0,
+				dim_layer[i].color_fill.color_1,
+				dim_layer[i].color_fill.color_2,
+				dim_layer[i].color_fill.color_3);
 	}
 }
 
@@ -1700,6 +1827,23 @@
 	mutex_unlock(&sde_crtc->crtc_lock);
 }
 
+static void _sde_crtc_setup_is_ppsplit(struct drm_crtc_state *state)
+{
+	int i;
+	struct sde_crtc_state *cstate;
+
+	cstate = to_sde_crtc_state(state);
+
+	cstate->is_ppsplit = false;
+	for (i = 0; i < cstate->num_connectors; i++) {
+		struct drm_connector *conn = cstate->connectors[i];
+
+		if (sde_connector_get_topology_name(conn) ==
+				SDE_RM_TOPOLOGY_PPSPLIT)
+			cstate->is_ppsplit = true;
+	}
+}
+
 static void _sde_crtc_setup_lm_bounds(struct drm_crtc *crtc,
 		struct drm_crtc_state *state)
 {
@@ -1764,6 +1908,7 @@
 
 	if (!sde_crtc->num_mixers) {
 		_sde_crtc_setup_mixers(crtc);
+		_sde_crtc_setup_is_ppsplit(crtc->state);
 		_sde_crtc_setup_lm_bounds(crtc, crtc->state);
 	}
 
@@ -2486,6 +2631,7 @@
 
 	mixer_width = sde_crtc_mixer_width(sde_crtc, mode);
 
+	_sde_crtc_setup_is_ppsplit(state);
 	_sde_crtc_setup_lm_bounds(crtc, state);
 
 	 /* get plane state for all drm planes associated with crtc state */
@@ -2508,9 +2654,10 @@
 		/* check dim layer stage with every plane */
 		for (i = 0; i < cstate->num_dim_layers; i++) {
 			if (pstates[cnt].stage == cstate->dim_layer[i].stage) {
-				SDE_ERROR("plane%d/dimlayer in same stage:%d\n",
-						plane->base.id,
-						cstate->dim_layer[i].stage);
+				SDE_ERROR(
+					"plane:%d/dim_layer:%i-same stage:%d\n",
+					plane->base.id, i,
+					cstate->dim_layer[i].stage);
 				rc = -EINVAL;
 				goto end;
 			}
@@ -2781,16 +2928,18 @@
 	msm_property_install_blob(&sde_crtc->property_info, "capabilities",
 		DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
 
-	if (catalog->has_dim_layer) {
-		msm_property_install_volatile_range(&sde_crtc->property_info,
-			"dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
-	}
-
 	msm_property_install_volatile_range(&sde_crtc->property_info,
 		"sde_drm_roi_v1", 0x0, 0, ~0, 0, CRTC_PROP_ROI_V1);
 
 	sde_kms_info_reset(info);
 
+	if (catalog->has_dim_layer) {
+		msm_property_install_volatile_range(&sde_crtc->property_info,
+			"dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
+		sde_kms_info_add_keyint(info, "dim_layer_v1_max_layers",
+				SDE_MAX_DIM_LAYERS);
+	}
+
 	sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion);
 	sde_kms_info_add_keyint(info, "max_linewidth",
 			catalog->max_mixer_width);
@@ -2990,6 +3139,7 @@
 	struct drm_display_mode *mode;
 	struct drm_framebuffer *fb;
 	struct drm_plane_state *state;
+	struct sde_crtc_state *cstate;
 
 	int i, out_width;
 
@@ -2998,6 +3148,7 @@
 
 	sde_crtc = s->private;
 	crtc = &sde_crtc->base;
+	cstate = to_sde_crtc_state(crtc->state);
 
 	mutex_lock(&sde_crtc->crtc_lock);
 	mode = &crtc->state->adjusted_mode;
@@ -3022,6 +3173,23 @@
 
 	seq_puts(s, "\n");
 
+	for (i = 0; i < cstate->num_dim_layers; i++) {
+		struct sde_hw_dim_layer *dim_layer = &cstate->dim_layer[i];
+
+		seq_printf(s, "\tdim_layer:%d] stage:%d flags:%d\n",
+				i, dim_layer->stage, dim_layer->flags);
+		seq_printf(s, "\tdst_x:%d dst_y:%d dst_w:%d dst_h:%d\n",
+				dim_layer->rect.x, dim_layer->rect.y,
+				dim_layer->rect.w, dim_layer->rect.h);
+		seq_printf(s,
+			"\tcolor_0:%d color_1:%d color_2:%d color_3:%d\n",
+				dim_layer->color_fill.color_0,
+				dim_layer->color_fill.color_1,
+				dim_layer->color_fill.color_2,
+				dim_layer->color_fill.color_3);
+		seq_puts(s, "\n");
+	}
+
 	drm_atomic_crtc_for_each_plane(plane, crtc) {
 		pstate = to_sde_plane_state(plane->state);
 		state = plane->state;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 6a22115..9ef6f25 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -108,6 +108,8 @@
  * @name          : ASCII description of this crtc
  * @num_ctls      : Number of ctl paths in use
  * @num_mixers    : Number of mixers in use
+ * @mixers_swapped: Whether the mixers have been swapped for left/right update
+ *                  especially in the case of DSC Merge.
  * @mixers        : List of active mixers
  * @event         : Pointer to last received drm vblank event. If there is a
  *                  pending vblank event, this will be non-null.
@@ -147,6 +149,7 @@
 	/* HW Resources reserved for the crtc */
 	u32 num_ctls;
 	u32 num_mixers;
+	bool mixers_swapped;
 	struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS];
 
 	struct drm_pending_vblank_event *event;
@@ -251,6 +254,7 @@
  * @num_connectors: Number of associated drm connectors
  * @intf_mode     : Interface mode of the primary connector
  * @rsc_client    : sde rsc client when mode is valid
+ * @is_ppsplit    : Whether current topology requires PPSplit special handling
  * @crtc_roi      : Current CRTC ROI. Possibly sub-rectangle of mode.
  *                  Origin top left of CRTC.
  * @lm_bounds     : LM boundaries based on current mode full resolution, no ROI.
@@ -277,6 +281,7 @@
 	struct sde_rsc_client *rsc_client;
 	bool rsc_update;
 
+	bool is_ppsplit;
 	struct sde_rect crtc_roi;
 	struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
 	struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index f11ba51..e3ad960 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -123,8 +123,11 @@
  * @cur_master:		Pointer to the current master in this mode. Optimization
  *			Only valid after enable. Cleared as disable.
  * @hw_pp		Handle to the pingpong blocks used for the display. No.
- *                      pingpong blocks can be different than num_phys_encs.
+ *			pingpong blocks can be different than num_phys_encs.
  * @hw_dsc:		Array of DSC block handles used for the display.
+ * @intfs_swapped	Whether or not the phys_enc interfaces have been swapped
+ *			for partial update right-only cases, such as pingpong
+ *			split where virtual pingpong does not generate IRQs
  * @crtc_vblank_cb:	Callback into the upper layer / CRTC for
  *			notification of the VBLANK
  * @crtc_vblank_cb_data:	Data from upper layer for VBLANK notification
@@ -155,6 +158,8 @@
  * @topology:                   topology of the display
  * @mode_set_complete:          flag to indicate modeset completion
  * @rsc_cfg:			rsc configuration
+ * @cur_conn_roi:		current connector roi
+ * @prv_conn_roi:		previous connector roi to optimize if unchanged
  */
 struct sde_encoder_virt {
 	struct drm_encoder base;
@@ -169,6 +174,8 @@
 	struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
 	struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
 
+	bool intfs_swapped;
+
 	void (*crtc_vblank_cb)(void *);
 	void *crtc_vblank_cb_data;
 
@@ -195,17 +202,51 @@
 	bool mode_set_complete;
 
 	struct sde_encoder_rsc_config rsc_cfg;
+	struct sde_rect cur_conn_roi;
+	struct sde_rect prv_conn_roi;
 };
 
 #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
 
-inline bool _sde_is_dsc_enabled(struct sde_encoder_virt *sde_enc)
+bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc)
+
 {
-	struct msm_compression_info *comp_info = &sde_enc->disp_info.comp_info;
+	struct sde_encoder_virt *sde_enc;
+	struct msm_compression_info *comp_info;
+
+	if (!drm_enc)
+		return false;
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	comp_info = &sde_enc->disp_info.comp_info;
 
 	return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
 }
 
+bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc)
+{
+	enum sde_rm_topology_name topology;
+	struct sde_encoder_virt *sde_enc;
+	struct drm_connector *drm_conn;
+
+	if (!drm_enc)
+		return false;
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	if (!sde_enc->cur_master)
+		return false;
+
+	drm_conn = sde_enc->cur_master->connector;
+	if (!drm_conn)
+		return false;
+
+	topology = sde_connector_get_topology_name(drm_conn);
+	if (topology == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE)
+		return true;
+
+	return false;
+}
+
 static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
 								bool enable)
 {
@@ -320,7 +361,22 @@
 
 	sde_enc = to_sde_encoder_virt(phys_enc->parent);
 	hw_mdptop = phys_enc->hw_mdptop;
-	cfg.en = phys_enc->split_role != ENC_ROLE_SOLO;
+
+	/**
+	 * disable split modes since encoder will be operating in as the only
+	 * encoder, either for the entire use case in the case of, for example,
+	 * single DSI, or for this frame in the case of left/right only partial
+	 * update.
+	 */
+	if (phys_enc->split_role == ENC_ROLE_SOLO) {
+		if (hw_mdptop->ops.setup_split_pipe)
+			hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
+		if (hw_mdptop->ops.setup_pp_split)
+			hw_mdptop->ops.setup_pp_split(hw_mdptop, &cfg);
+		return;
+	}
+
+	cfg.en = true;
 	cfg.mode = phys_enc->intf_mode;
 	cfg.intf = interface;
 
@@ -334,8 +390,7 @@
 	else
 		cfg.pp_split_slave = INTF_MAX;
 
-	if (phys_enc->split_role != ENC_ROLE_SLAVE) {
-		/* master/solo encoder */
+	if (phys_enc->split_role == ENC_ROLE_MASTER) {
 		SDE_DEBUG_ENC(sde_enc, "enable %d\n", cfg.en);
 
 		if (hw_mdptop->ops.setup_split_pipe)
@@ -555,8 +610,14 @@
 
 static void _sde_encoder_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc,
 		struct sde_hw_pingpong *hw_pp, struct msm_display_dsc_info *dsc,
-		u32 common_mode, bool ich_reset)
+		u32 common_mode, bool ich_reset, bool enable)
 {
+	if (!enable) {
+		if (hw_pp->ops.disable_dsc)
+			hw_pp->ops.disable_dsc(hw_pp);
+		return;
+	}
+
 	if (hw_dsc->ops.dsc_config)
 		hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, ich_reset);
 
@@ -570,9 +631,27 @@
 		hw_pp->ops.enable_dsc(hw_pp);
 }
 
+static void _sde_encoder_get_connector_roi(
+		struct sde_encoder_virt *sde_enc,
+		struct sde_rect *merged_conn_roi)
+{
+	struct drm_connector *drm_conn;
+	struct sde_connector_state *c_state;
+
+	if (!sde_enc || !merged_conn_roi)
+		return;
+
+	drm_conn = sde_enc->phys_encs[0]->connector;
+
+	if (!drm_conn || !drm_conn->state)
+		return;
+
+	c_state = to_sde_connector_state(drm_conn->state);
+	sde_kms_rect_merge_rectangles(&c_state->rois, merged_conn_roi);
+}
+
 static int _sde_encoder_dsc_1_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc)
 {
-	int pic_width, pic_height;
 	int this_frame_slices;
 	int intf_ip_w, enc_ip_w;
 	int ich_res, dsc_common_mode = 0;
@@ -580,22 +659,18 @@
 	struct sde_hw_pingpong *hw_pp = sde_enc->hw_pp[0];
 	struct sde_hw_dsc *hw_dsc = sde_enc->hw_dsc[0];
 	struct sde_encoder_phys *enc_master = sde_enc->cur_master;
-	struct sde_hw_mdp *hw_mdp_top  = enc_master->hw_mdptop;
+	const struct sde_rect *roi = &sde_enc->cur_conn_roi;
 	struct msm_display_dsc_info *dsc =
 		&sde_enc->disp_info.comp_info.dsc_info;
 
-	if (dsc == NULL || hw_dsc == NULL || hw_pp == NULL ||
-						hw_mdp_top == NULL) {
+	if (dsc == NULL || hw_dsc == NULL || hw_pp == NULL || !enc_master) {
 		SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
 		return -EINVAL;
 	}
 
-	pic_width = dsc->pic_width;
-	pic_height = dsc->pic_height;
+	_sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h);
 
-	_sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
-
-	this_frame_slices = pic_width / dsc->slice_width;
+	this_frame_slices = roi->w / dsc->slice_width;
 	intf_ip_w = this_frame_slices * dsc->slice_width;
 	_sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
 
@@ -608,132 +683,208 @@
 		dsc_common_mode = DSC_MODE_VIDEO;
 
 	SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
-		pic_width, pic_height, dsc_common_mode);
-	SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
-			dsc_common_mode);
+		roi->w, roi->h, dsc_common_mode);
+	SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, dsc_common_mode);
 
 	_sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, dsc, dsc_common_mode,
-			ich_res);
+			ich_res, true);
 
 	return 0;
 }
-static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc,
+		struct sde_encoder_kickoff_params *params)
 {
-	int pic_width, pic_height;
 	int this_frame_slices;
 	int intf_ip_w, enc_ip_w;
 	int ich_res, dsc_common_mode;
 
 	struct sde_encoder_phys *enc_master = sde_enc->cur_master;
-	struct sde_hw_dsc *l_hw_dsc = sde_enc->hw_dsc[0];
-	struct sde_hw_dsc *r_hw_dsc = sde_enc->hw_dsc[1];
-	struct sde_hw_pingpong *l_hw_pp = sde_enc->hw_pp[0];
-	struct sde_hw_pingpong *r_hw_pp = sde_enc->hw_pp[1];
-	struct sde_hw_mdp *hw_mdp_top  = enc_master->hw_mdptop;
-	struct msm_display_dsc_info *dsc =
-		&sde_enc->disp_info.comp_info.dsc_info;
+	const struct sde_rect *roi = &sde_enc->cur_conn_roi;
+	struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+	struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
+	struct msm_display_dsc_info dsc[MAX_CHANNELS_PER_ENC];
+	bool half_panel_partial_update;
+	int i;
 
-	if (l_hw_dsc == NULL || r_hw_dsc == NULL || hw_mdp_top == NULL ||
-		l_hw_pp == NULL || r_hw_pp == NULL) {
-		SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
-		return -EINVAL;
+	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+		hw_pp[i] = sde_enc->hw_pp[i];
+		hw_dsc[i] = sde_enc->hw_dsc[i];
+
+		if (!hw_pp[i] || !hw_dsc[i]) {
+			SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
+			return -EINVAL;
+		}
 	}
 
-	pic_width = dsc->pic_width * sde_enc->display_num_of_h_tiles;
-	pic_height = dsc->pic_height;
+	half_panel_partial_update =
+			hweight_long(params->affected_displays) == 1;
 
-	_sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
-
-	this_frame_slices = pic_width / dsc->slice_width;
-	intf_ip_w = this_frame_slices * dsc->slice_width;
-
-	intf_ip_w /= 2;
-	_sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
-
-	enc_ip_w = intf_ip_w;
-	_sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
-
-	ich_res = _sde_encoder_dsc_ich_reset_override_needed(false, dsc);
-
-	dsc_common_mode = DSC_MODE_SPLIT_PANEL;
+	dsc_common_mode = 0;
+	if (!half_panel_partial_update)
+		dsc_common_mode |= DSC_MODE_SPLIT_PANEL;
 	if (enc_master->intf_mode == INTF_MODE_VIDEO)
 		dsc_common_mode |= DSC_MODE_VIDEO;
 
-	SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
-		pic_width, pic_height, dsc_common_mode);
-	SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
-			dsc_common_mode);
+	memcpy(&dsc[0], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[0]));
+	memcpy(&dsc[1], &sde_enc->disp_info.comp_info.dsc_info, sizeof(dsc[1]));
 
-	_sde_encoder_dsc_pipe_cfg(l_hw_dsc, l_hw_pp, dsc, dsc_common_mode,
-			ich_res);
-	_sde_encoder_dsc_pipe_cfg(r_hw_dsc, r_hw_pp, dsc, dsc_common_mode,
-			ich_res);
+	/*
+	 * Since both DSC use same pic dimension, set same pic dimension
+	 * to both DSC structures.
+	 */
+	_sde_encoder_dsc_update_pic_dim(&dsc[0], roi->w, roi->h);
+	_sde_encoder_dsc_update_pic_dim(&dsc[1], roi->w, roi->h);
+
+	this_frame_slices = roi->w / dsc[0].slice_width;
+	intf_ip_w = this_frame_slices * dsc[0].slice_width;
+
+	if (!half_panel_partial_update)
+		intf_ip_w /= 2;
+
+	/*
+	 * In this topology when both interfaces are active, they have same
+	 * load so intf_ip_w will be same.
+	 */
+	_sde_encoder_dsc_pclk_param_calc(&dsc[0], intf_ip_w);
+	_sde_encoder_dsc_pclk_param_calc(&dsc[1], intf_ip_w);
+
+	/*
+	 * In this topology, since there is no dsc_merge, uncompressed input
+	 * to encoder and interface is same.
+	 */
+	enc_ip_w = intf_ip_w;
+	_sde_encoder_dsc_initial_line_calc(&dsc[0], enc_ip_w);
+	_sde_encoder_dsc_initial_line_calc(&dsc[1], enc_ip_w);
+
+	/*
+	 * __is_ich_reset_override_needed should be called only after
+	 * updating pic dimension, mdss_panel_dsc_update_pic_dim.
+	 */
+	ich_res = _sde_encoder_dsc_ich_reset_override_needed(
+			half_panel_partial_update, &dsc[0]);
+
+	SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
+			roi->w, roi->h, dsc_common_mode);
+
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		bool active = !!((1 << i) & params->affected_displays);
+
+		SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h,
+				dsc_common_mode, i, active);
+		_sde_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], &dsc[i],
+				dsc_common_mode, ich_res, active);
+	}
 
 	return 0;
 }
 
-static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc,
+		struct sde_encoder_kickoff_params *params)
 {
-	int pic_width, pic_height;
 	int this_frame_slices;
 	int intf_ip_w, enc_ip_w;
 	int ich_res, dsc_common_mode;
 
 	struct sde_encoder_phys *enc_master = sde_enc->cur_master;
-	struct sde_hw_dsc *l_hw_dsc = sde_enc->hw_dsc[0];
-	struct sde_hw_dsc *r_hw_dsc = sde_enc->hw_dsc[1];
-	struct sde_hw_pingpong *l_hw_pp = sde_enc->hw_pp[0];
-	struct sde_hw_pingpong *r_hw_pp = sde_enc->hw_pp[1];
-	struct sde_hw_mdp *hw_mdp_top  = enc_master->hw_mdptop;
+	const struct sde_rect *roi = &sde_enc->cur_conn_roi;
+	struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
+	struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
 	struct msm_display_dsc_info *dsc =
 		&sde_enc->disp_info.comp_info.dsc_info;
+	bool half_panel_partial_update;
+	int i;
 
-	if (l_hw_dsc == NULL || r_hw_dsc == NULL || hw_mdp_top == NULL ||
-					l_hw_pp == NULL || r_hw_pp == NULL) {
-		SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
-		return -EINVAL;
+	for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+		hw_pp[i] = sde_enc->hw_pp[i];
+		hw_dsc[i] = sde_enc->hw_dsc[i];
+
+		if (!hw_pp[i] || !hw_dsc[i]) {
+			SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n");
+			return -EINVAL;
+		}
 	}
 
-	pic_width = dsc->pic_width;
-	pic_height = dsc->pic_height;
-	_sde_encoder_dsc_update_pic_dim(dsc, pic_width, pic_height);
+	half_panel_partial_update =
+			hweight_long(params->affected_displays) == 1;
 
-	this_frame_slices = pic_width / dsc->slice_width;
+	dsc_common_mode = 0;
+	if (!half_panel_partial_update)
+		dsc_common_mode |= DSC_MODE_SPLIT_PANEL | DSC_MODE_MULTIPLEX;
+	if (enc_master->intf_mode == INTF_MODE_VIDEO)
+		dsc_common_mode |= DSC_MODE_VIDEO;
+
+	_sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h);
+
+	this_frame_slices = roi->w / dsc->slice_width;
 	intf_ip_w = this_frame_slices * dsc->slice_width;
 	_sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w);
 
 	/*
-	 * when using 2 encoders for the same stream, no. of slices
-	 * need to be same on both the encoders.
+	 * dsc merge case: when using 2 encoders for the same stream,
+	 * no. of slices need to be same on both the encoders.
 	 */
 	enc_ip_w = intf_ip_w / 2;
 	_sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w);
 
-	ich_res = _sde_encoder_dsc_ich_reset_override_needed(false, dsc);
-
-	dsc_common_mode = DSC_MODE_MULTIPLEX | DSC_MODE_SPLIT_PANEL;
-	if (enc_master->intf_mode == INTF_MODE_VIDEO)
-		dsc_common_mode |= DSC_MODE_VIDEO;
+	ich_res = _sde_encoder_dsc_ich_reset_override_needed(
+			half_panel_partial_update, dsc);
 
 	SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n",
-		pic_width, pic_height, dsc_common_mode);
-	SDE_EVT32(DRMID(&sde_enc->base), pic_width, pic_height,
-			dsc_common_mode);
+			roi->w, roi->h, dsc_common_mode);
+	SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h,
+			dsc_common_mode, i, params->affected_displays);
 
-	_sde_encoder_dsc_pipe_cfg(l_hw_dsc, l_hw_pp, dsc, dsc_common_mode,
-			ich_res);
-	_sde_encoder_dsc_pipe_cfg(r_hw_dsc, r_hw_pp, dsc, dsc_common_mode,
-			ich_res);
+	_sde_encoder_dsc_pipe_cfg(hw_dsc[0], hw_pp[0], dsc, dsc_common_mode,
+			ich_res, true);
+	_sde_encoder_dsc_pipe_cfg(hw_dsc[1], hw_pp[1], dsc, dsc_common_mode,
+			ich_res, !half_panel_partial_update);
 
 	return 0;
 }
 
-static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc)
+static int _sde_encoder_update_roi(struct drm_encoder *drm_enc)
+{
+	struct sde_encoder_virt *sde_enc;
+	struct drm_connector *drm_conn;
+	struct drm_display_mode *adj_mode;
+	struct sde_rect roi;
+
+	if (!drm_enc || !drm_enc->crtc || !drm_enc->crtc->state)
+		return -EINVAL;
+	sde_enc = to_sde_encoder_virt(drm_enc);
+
+	if (!sde_enc->cur_master)
+		return -EINVAL;
+
+	adj_mode = &sde_enc->base.crtc->state->adjusted_mode;
+	drm_conn = sde_enc->cur_master->connector;
+
+	_sde_encoder_get_connector_roi(sde_enc, &roi);
+	if (sde_kms_rect_is_null(&roi)) {
+		roi.w = adj_mode->hdisplay;
+		roi.h = adj_mode->vdisplay;
+	}
+
+	memcpy(&sde_enc->prv_conn_roi, &sde_enc->cur_conn_roi,
+			sizeof(sde_enc->prv_conn_roi));
+	memcpy(&sde_enc->cur_conn_roi, &roi, sizeof(sde_enc->cur_conn_roi));
+
+	return 0;
+}
+
+static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc,
+		struct sde_encoder_kickoff_params *params)
 {
 	enum sde_rm_topology_name topology;
-	struct drm_connector *drm_conn = sde_enc->phys_encs[0]->connector;
+	struct drm_connector *drm_conn;
 	int ret = 0;
 
+	if (!sde_enc || !params || !sde_enc->phys_encs[0] ||
+			!sde_enc->phys_encs[0]->connector)
+		return -EINVAL;
+
+	drm_conn = sde_enc->phys_encs[0]->connector;
+
 	topology = sde_connector_get_topology_name(drm_conn);
 	if (topology == SDE_RM_TOPOLOGY_NONE) {
 		SDE_ERROR_ENC(sde_enc, "topology not set yet\n");
@@ -743,15 +894,19 @@
 	SDE_DEBUG_ENC(sde_enc, "\n");
 	SDE_EVT32(DRMID(&sde_enc->base));
 
+	if (sde_kms_rect_is_equal(&sde_enc->cur_conn_roi,
+			&sde_enc->prv_conn_roi))
+		return ret;
+
 	switch (topology) {
 	case SDE_RM_TOPOLOGY_SINGLEPIPE_DSC:
 		ret = _sde_encoder_dsc_1_lm_1_enc_1_intf(sde_enc);
 		break;
 	case SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE:
-		ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc);
+		ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc, params);
 		break;
 	case SDE_RM_TOPOLOGY_DUALPIPE_DSC:
-		ret = _sde_encoder_dsc_2_lm_2_enc_2_intf(sde_enc);
+		ret = _sde_encoder_dsc_2_lm_2_enc_2_intf(sde_enc, params);
 		break;
 	default:
 		SDE_ERROR_ENC(sde_enc, "No DSC support for topology %d",
@@ -1217,7 +1372,6 @@
 	struct sde_kms *sde_kms;
 	struct sde_hw_mdp *hw_mdptop;
 	int i = 0;
-	int ret = 0;
 	struct sde_watchdog_te_status te_cfg = { 0 };
 
 	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
@@ -1252,12 +1406,6 @@
 				sde_enc->cur_master->hw_mdptop,
 				sde_kms->catalog);
 
-	if (_sde_is_dsc_enabled(sde_enc)) {
-		ret = _sde_encoder_dsc_setup(sde_enc);
-		if (ret)
-			SDE_ERROR_ENC(sde_enc, "failed to setup DSC:%d\n", ret);
-	}
-
 	if (hw_mdptop->ops.setup_vsync_sel) {
 		for (i = 0; i < sde_enc->num_phys_encs; i++)
 			te_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;
@@ -1763,6 +1911,65 @@
 	spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
 }
 
+static void _sde_encoder_ppsplit_swap_intf_for_right_only_update(
+		struct drm_encoder *drm_enc,
+		unsigned long *affected_displays,
+		int num_active_phys)
+{
+	struct sde_encoder_virt *sde_enc;
+	struct sde_encoder_phys *master;
+	enum sde_rm_topology_name topology;
+	bool is_right_only;
+
+	if (!drm_enc || !affected_displays)
+		return;
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	master = sde_enc->cur_master;
+	if (!master || !master->connector)
+		return;
+
+	topology = sde_connector_get_topology_name(master->connector);
+	if (topology != SDE_RM_TOPOLOGY_PPSPLIT)
+		return;
+
+	/*
+	 * For pingpong split, the slave pingpong won't generate IRQs. For
+	 * right-only updates, we can't swap pingpongs, or simply swap the
+	 * master/slave assignment, we actually have to swap the interfaces
+	 * so that the master physical encoder will use a pingpong/interface
+	 * that generates irqs on which to wait.
+	 */
+	is_right_only = !test_bit(0, affected_displays) &&
+			test_bit(1, affected_displays);
+
+	if (is_right_only && !sde_enc->intfs_swapped) {
+		/* right-only update swap interfaces */
+		swap(sde_enc->phys_encs[0]->intf_idx,
+				sde_enc->phys_encs[1]->intf_idx);
+		sde_enc->intfs_swapped = true;
+	} else if (!is_right_only && sde_enc->intfs_swapped) {
+		/* left-only or full update, swap back */
+		swap(sde_enc->phys_encs[0]->intf_idx,
+				sde_enc->phys_encs[1]->intf_idx);
+		sde_enc->intfs_swapped = false;
+	}
+
+	SDE_DEBUG_ENC(sde_enc,
+			"right_only %d swapped %d phys0->intf%d, phys1->intf%d\n",
+			is_right_only, sde_enc->intfs_swapped,
+			sde_enc->phys_encs[0]->intf_idx - INTF_0,
+			sde_enc->phys_encs[1]->intf_idx - INTF_0);
+	SDE_EVT32(DRMID(drm_enc), is_right_only, sde_enc->intfs_swapped,
+			sde_enc->phys_encs[0]->intf_idx - INTF_0,
+			sde_enc->phys_encs[1]->intf_idx - INTF_0,
+			*affected_displays);
+
+	/* ppsplit always uses master since ppslave invalid for irqs*/
+	if (num_active_phys == 1)
+		*affected_displays = BIT(0);
+}
+
 static void _sde_encoder_update_master(struct drm_encoder *drm_enc,
 		struct sde_encoder_kickoff_params *params)
 {
@@ -1785,6 +1992,10 @@
 	SDE_DEBUG_ENC(sde_enc, "affected_displays 0x%lx num_active_phys %d\n",
 			params->affected_displays, num_active_phys);
 
+	/* for left/right only update, ppsplit master switches interface */
+	_sde_encoder_ppsplit_swap_intf_for_right_only_update(drm_enc,
+			&params->affected_displays, num_active_phys);
+
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		enum sde_enc_split_role prv_role, new_role;
 		bool active;
@@ -1814,6 +2025,9 @@
 		SDE_DEBUG_ENC(sde_enc, "pp %d role prv %d new %d active %d\n",
 				phys->hw_pp->idx - PINGPONG_0, prv_role,
 				phys->split_role, active);
+		SDE_EVT32(DRMID(drm_enc), params->affected_displays,
+				phys->hw_pp->idx - PINGPONG_0, prv_role,
+				phys->split_role, active, num_active_phys);
 	}
 }
 
@@ -1892,6 +2106,8 @@
 
 	_sde_encoder_update_master(drm_enc, params);
 
+	_sde_encoder_update_roi(drm_enc);
+
 	if (sde_enc->cur_master && sde_enc->cur_master->connector) {
 		rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector);
 		if (rc)
@@ -1899,6 +2115,12 @@
 					sde_enc->cur_master->connector->base.id,
 					rc);
 	}
+
+	if (sde_encoder_is_dsc_enabled(drm_enc)) {
+		rc = _sde_encoder_dsc_setup(sde_enc, params);
+		if (rc)
+			SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n", rc);
+	}
 }
 
 void sde_encoder_kickoff(struct drm_encoder *drm_enc)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 7292a12..6ef245b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -149,6 +149,20 @@
 void sde_encoder_virt_restore(struct drm_encoder *encoder);
 
 /**
+ * sde_encoder_is_dsc_enabled - check if encoder is in DSC mode
+ * @drm_enc: Pointer to drm encoder object
+ * @Return: true if encoder is in DSC mode
+ */
+bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc);
+
+/**
+ * sde_encoder_is_dsc_merge - check if encoder is in DSC merge mode
+ * @drm_enc: Pointer to drm encoder object
+ * @Return: true if encoder is in DSC merge mode
+ */
+bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc);
+
+/**
  * sde_encoder_init - initialize virtual encoder object
  * @dev:        Pointer to drm device structure
  * @disp_info:  Pointer to display information structure
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 572bd9e..53f5b89 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -615,7 +615,8 @@
 			phys_enc->hw_pp->idx - PINGPONG_0);
 	drm_mode_debug_printmodeline(&phys_enc->cached_mode);
 
-	_sde_encoder_phys_cmd_update_intf_cfg(phys_enc);
+	if (!_sde_encoder_phys_is_ppsplit_slave(phys_enc))
+		_sde_encoder_phys_cmd_update_intf_cfg(phys_enc);
 	sde_encoder_phys_cmd_tearcheck_config(phys_enc);
 }
 
@@ -832,15 +833,28 @@
 		struct sde_encoder_phys *phys_enc,
 		enum sde_enc_split_role role)
 {
-	struct sde_encoder_phys_cmd *cmd_enc =
-		to_sde_encoder_phys_cmd(phys_enc);
-	enum sde_enc_split_role old_role = phys_enc->split_role;
+	struct sde_encoder_phys_cmd *cmd_enc;
+	enum sde_enc_split_role old_role;
+	bool is_ppsplit;
+
+	if (!phys_enc)
+		return;
+
+	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+	old_role = phys_enc->split_role;
+	is_ppsplit = _sde_encoder_phys_is_ppsplit(phys_enc);
+
+	phys_enc->split_role = role;
 
 	SDE_DEBUG_CMDENC(cmd_enc, "old role %d new role %d\n",
 			old_role, role);
 
-	phys_enc->split_role = role;
-	if (role == ENC_ROLE_SKIP || role == old_role)
+	/*
+	 * ppsplit solo needs to reprogram because intf may have swapped without
+	 * role changing on left-only, right-only back-to-back commits
+	 */
+	if (!(is_ppsplit && role == ENC_ROLE_SOLO) &&
+			(role == old_role || role == ENC_ROLE_SKIP))
 		return;
 
 	sde_encoder_helper_split_config(phys_enc, phys_enc->intf_idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_kms_utils.c b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
index dcc0bd5..b77d64d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms_utils.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
@@ -166,7 +166,7 @@
 	r = min((r1->x + r1->w), (r2->x + r2->w));
 	b = min((r1->y + r1->h), (r2->y + r2->h));
 
-	if (r < l || b < t) {
+	if (r <= l || b <= t) {
 		memset(result, 0, sizeof(*result));
 	} else {
 		result->x = l;
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 41515bb..ee50a61 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -299,3 +299,5 @@
 config STM32_EXTI
 	bool
 	select IRQ_DOMAIN
+
+source "drivers/irqchip/qcom/Kconfig"
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 987bd89..450059c 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -75,3 +75,4 @@
 obj-$(CONFIG_EZNPS_GIC)			+= irq-eznps.o
 obj-$(CONFIG_ARCH_ASPEED)		+= irq-aspeed-vic.o
 obj-$(CONFIG_STM32_EXTI) 		+= irq-stm32-exti.o
+obj-$(CONFIG_QTI_PDC)			+= qcom/
diff --git a/drivers/irqchip/qcom/Kconfig b/drivers/irqchip/qcom/Kconfig
new file mode 100644
index 0000000..e4a7a88
--- /dev/null
+++ b/drivers/irqchip/qcom/Kconfig
@@ -0,0 +1,15 @@
+config QTI_PDC
+        bool "QTI PDC"
+        depends on ARCH_QCOM
+	select IRQ_DOMAIN
+	select IRQ_DOMAIN_HIERARCHY
+        help
+          QTI Power Domain Controller driver to manage and configure wakeup
+          IRQs
+
+config QTI_PDC_SDM845
+        bool "QTI PDC SDM845"
+        select QTI_PDC
+        default y if ARCH_SDM845
+        help
+          QTI Power Domain Controller for SDM845
diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile
new file mode 100644
index 0000000..1b7856d
--- /dev/null
+++ b/drivers/irqchip/qcom/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_QTI_PDC)			+= pdc.o
+obj-$(CONFIG_QTI_PDC_SDM845)		+= pdc-sdm845.o
diff --git a/drivers/irqchip/qcom/pdc-sdm845.c b/drivers/irqchip/qcom/pdc-sdm845.c
new file mode 100644
index 0000000..178cf1f0
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc-sdm845.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/irqchip.h>
+#include "pdc.h"
+
+static struct pdc_pin sdm845_data[] = {
+	{0, 512}, /* rpmh_wake */
+	{1, 513}, /* ee0_apps_hlos_spmi_periph_irq */
+	{2, 514}, /* ee1_apps_trustzone_spmi_periph_irq */
+	{3, 515}, /* secure_wdog_expired */
+	{4, 516}, /* secure_wdog_bark_irq */
+	{5, 517}, /* aop_wdog_expired_irq */
+	{6, 518}, /* qmp_usb3_lfps_rxterm_irq */
+	{7, 519}, /* qmp_usb3_lfps_rxterm_irq */
+	{8, 520}, /* eud_p0_dmse_int_mx */
+	{9, 521}, /* eud_p0_dpse_int_mx */
+	{10, 522}, /* eud_p1_dmse_int_mx */
+	{11, 523}, /* eud_p1_dpse_int_mx */
+	{12, 524}, /* eud_int_mx[1] */
+	{13, 525}, /* ssc_xpu_irq_summary */
+	{14, 526}, /* wd_bite_apps */
+	{15, 527}, /* ssc_vmidmt_irq_summary */
+	{16, 528}, /* q6ss_irq_out_apps_ipc[4] */
+	{17, 529}, /* not-connected */
+	{18, 530}, /* aoss_pmic_arb_mpu_xpu_summary_irq */
+	{19, 531}, /* apps_pdc_irq_in_19 */
+	{20, 532}, /* apps_pdc_irq_in_20 */
+	{21, 533}, /* apps_pdc_irq_in_21 */
+	{22, 534}, /* pdc_apps_epcb_timeout_summary_irq */
+	{23, 535}, /* spmi_protocol_irq */
+	{24, 536}, /* tsense0_tsense_max_min_int */
+	{25, 537}, /* tsense1_tsense_max_min_int */
+	{26, 538}, /* tsense0_upper_lower_intr */
+	{27, 539}, /* tsense1_upper_lower_intr */
+	{28, 540}, /* tsense0_critical_intr */
+	{29, 541}, /* tsense1_critical_intr */
+	{30, 542}, /* core_bi_px_gpio_1 */
+	{31, 543}, /* core_bi_px_gpio_3 */
+	{32, 544}, /* core_bi_px_gpio_5 */
+	{33, 545}, /* core_bi_px_gpio_10 */
+	{34, 546}, /* core_bi_px_gpio_11 */
+	{35, 547}, /* core_bi_px_gpio_20 */
+	{36, 548}, /* core_bi_px_gpio_22 */
+	{37, 549}, /* core_bi_px_gpio_24 */
+	{38, 550}, /* core_bi_px_gpio_26 */
+	{39, 551}, /* core_bi_px_gpio_30 */
+	{41, 553}, /* core_bi_px_gpio_32 */
+	{42, 554}, /* core_bi_px_gpio_34 */
+	{43, 555}, /* core_bi_px_gpio_36 */
+	{44, 556}, /* core_bi_px_gpio_37 */
+	{45, 557}, /* core_bi_px_gpio_38 */
+	{46, 558}, /* core_bi_px_gpio_39 */
+	{47, 559}, /* core_bi_px_gpio_40 */
+	{49, 561}, /* core_bi_px_gpio_43 */
+	{50, 562}, /* core_bi_px_gpio_44 */
+	{51, 563}, /* core_bi_px_gpio_46 */
+	{52, 564}, /* core_bi_px_gpio_48 */
+	{54, 566}, /* core_bi_px_gpio_52 */
+	{55, 567}, /* core_bi_px_gpio_53 */
+	{56, 568}, /* core_bi_px_gpio_54 */
+	{57, 569}, /* core_bi_px_gpio_56 */
+	{58, 570}, /* core_bi_px_gpio_57 */
+	{59, 571}, /* core_bi_px_gpio_58 */
+	{60, 572}, /* core_bi_px_gpio_59 */
+	{61, 573}, /* core_bi_px_gpio_60 */
+	{62, 574}, /* core_bi_px_gpio_61 */
+	{63, 575}, /* core_bi_px_gpio_62 */
+	{64, 576}, /* core_bi_px_gpio_63 */
+	{65, 577}, /* core_bi_px_gpio_64 */
+	{66, 578}, /* core_bi_px_gpio_66 */
+	{67, 579}, /* core_bi_px_gpio_68 */
+	{68, 580}, /* core_bi_px_gpio_71 */
+	{69, 581}, /* core_bi_px_gpio_73 */
+	{70, 582}, /* core_bi_px_gpio_77 */
+	{71, 583}, /* core_bi_px_gpio_78 */
+	{72, 584}, /* core_bi_px_gpio_79 */
+	{73, 585}, /* core_bi_px_gpio_80 */
+	{74, 586}, /* core_bi_px_gpio_84 */
+	{75, 587}, /* core_bi_px_gpio_85 */
+	{76, 588}, /* core_bi_px_gpio_86 */
+	{77, 589}, /* core_bi_px_gpio_88 */
+	{79, 591}, /* core_bi_px_gpio_91 */
+	{80, 592}, /* core_bi_px_gpio_92 */
+	{81, 593}, /* core_bi_px_gpio_95 */
+	{82, 594}, /* core_bi_px_gpio_96 */
+	{83, 595}, /* core_bi_px_gpio_97 */
+	{84, 596}, /* core_bi_px_gpio_101 */
+	{85, 597}, /* core_bi_px_gpio_103 */
+	{86, 598}, /* core_bi_px_gpio_104 */
+	{87, 599}, /* core_bi_px_to_mpm[6] */
+	{88, 600}, /* core_bi_px_to_mpm[0] */
+	{89, 601}, /* core_bi_px_to_mpm[1] */
+	{90, 602}, /* core_bi_px_gpio_115 */
+	{91, 603}, /* core_bi_px_gpio_116 */
+	{92, 604}, /* core_bi_px_gpio_117 */
+	{93, 605}, /* core_bi_px_gpio_118 */
+	{94, 641}, /* core_bi_px_gpio_119 */
+	{95, 642}, /* core_bi_px_gpio_120 */
+	{96, 643}, /* core_bi_px_gpio_121 */
+	{97, 644}, /* core_bi_px_gpio_122 */
+	{98, 645}, /* core_bi_px_gpio_123 */
+	{99, 646}, /* core_bi_px_gpio_124 */
+	{100, 647}, /* core_bi_px_gpio_125 */
+	{101, 648}, /* core_bi_px_to_mpm[5] */
+	{102, 649}, /* core_bi_px_gpio_127 */
+	{103, 650}, /* core_bi_px_gpio_128 */
+	{104, 651}, /* core_bi_px_gpio_129 */
+	{105, 652}, /* core_bi_px_gpio_130 */
+	{106, 653}, /* core_bi_px_gpio_132 */
+	{107, 654}, /* core_bi_px_gpio_133 */
+	{108, 655}, /* core_bi_px_gpio_145 */
+	{119, 666}, /* core_bi_px_to_mpm[2] */
+	{120, 667}, /* core_bi_px_to_mpm[3] */
+	{121, 668}, /* core_bi_px_to_mpm[4] */
+	{122, 669}, /* core_bi_px_gpio_41 */
+	{123, 670}, /* core_bi_px_gpio_89 */
+	{124, 671}, /* core_bi_px_gpio_31 */
+	{125, 672}, /* core_bi_px_gpio_49 */
+	{-1}
+};
+
+static int __init qcom_pdc_gic_init(struct device_node *node,
+		struct device_node *parent)
+{
+	return qcom_pdc_init(node, parent, sdm845_data);
+}
+
+IRQCHIP_DECLARE(pdc_sdm845, "qcom,pdc-sdm845", qcom_pdc_gic_init);
diff --git a/drivers/irqchip/qcom/pdc.c b/drivers/irqchip/qcom/pdc.c
new file mode 100644
index 0000000..923552f
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc.c
@@ -0,0 +1,299 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "pdc.h"
+#define CREATE_TRACE_POINTS
+#include "trace/events/pdc.h"
+
+#define MAX_IRQS 126
+#define CLEAR_INTR(reg, intr) (reg & ~(1 << intr))
+#define ENABLE_INTR(reg, intr) (reg | (1 << intr))
+
+enum pdc_register_offsets {
+	IRQ_ENABLE_BANK = 0x10,
+	IRQ_i_CFG = 0x110,
+};
+
+static DEFINE_SPINLOCK(pdc_lock);
+static void __iomem *pdc_base;
+
+static int get_pdc_pin(irq_hw_number_t hwirq, void *data)
+{
+	int i;
+	struct pdc_pin *pdc_data = (struct pdc_pin *) data;
+
+	for (i = 0; pdc_data[i].pin >= 0; i++) {
+		if (pdc_data[i].hwirq == hwirq)
+			return pdc_data[i].pin;
+	}
+
+	return -EINVAL;
+}
+
+static inline int pdc_enable_intr(struct irq_data *d, bool on)
+{
+	int pin_out = get_pdc_pin(d->hwirq, d->chip_data);
+	unsigned int index, mask;
+	u32 enable, r_enable;
+	unsigned long flags;
+
+	if (pin_out < 0)
+		return 0;
+
+	index = pin_out / 32;
+	mask = pin_out % 32;
+	spin_lock_irqsave(&pdc_lock, flags);
+
+	enable = readl_relaxed(pdc_base + IRQ_ENABLE_BANK + (index *
+					sizeof(uint32_t)));
+	if (on)
+		enable = ENABLE_INTR(enable, mask);
+	else
+		enable = CLEAR_INTR(enable, mask);
+
+	writel_relaxed(enable, pdc_base + IRQ_ENABLE_BANK + (index *
+						sizeof(uint32_t)));
+
+	do {
+		r_enable = readl_relaxed(pdc_base + IRQ_ENABLE_BANK +
+					(index * sizeof(uint32_t)));
+		if (r_enable == enable)
+			break;
+		udelay(5);
+	} while (1);
+
+	spin_unlock_irqrestore(&pdc_lock, flags);
+
+	trace_irq_pin_config("enable", (u32)pin_out, (u32)d->hwirq,
+			0, on);
+
+	return 0;
+}
+
+static void qcom_pdc_gic_mask(struct irq_data *d)
+{
+	pdc_enable_intr(d, false);
+	irq_chip_mask_parent(d);
+}
+
+static void qcom_pdc_gic_unmask(struct irq_data *d)
+{
+	pdc_enable_intr(d, true);
+	irq_chip_unmask_parent(d);
+}
+
+static void qcom_pdc_gic_enable(struct irq_data *d)
+{
+	pdc_enable_intr(d, true);
+	irq_chip_enable_parent(d);
+}
+
+static void qcom_pdc_gic_disable(struct irq_data *d)
+{
+	pdc_enable_intr(d, false);
+	irq_chip_disable_parent(d);
+}
+
+/*
+ * GIC does not handle falling edge or active low. To allow falling edge and
+ * active low interrupts to be handled at GIC, PDC has an inverter that inverts
+ * falling edge into a rising edge and active low into an active high.
+ * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to
+ * set as per the table below.
+ * (polarity, falling edge, rising edge )  ORIG          POL CONV     POLARITY
+ * 3'b0 00  Level sensitive active low    (~~~|_____)   (___|~~~~~)   LOW
+ * 3'b0 01  Rising edge sensitive         (___|~~|__)   (~~~|__|~~)   NOT USED
+ * 3'b0 10  Falling edge sensitive        (~~~|__|~~)   (___|~~|__)   LOW
+ * 3'b0 11  Dual Edge sensitive                                       NOT USED
+ * 3'b1 00  Level senstive active High    (___|~~~~~)   (___|~~~~~)   HIGH
+ * 3'b1 01  Falling Edge sensitive        (~~~|__|~~)   (~~~|__|~~)   NOT USED
+ * 3'b1 10  Rising edge sensitive         (___|~~|__)   (___|~~|__)   HIGH
+ * 3'b1 11  Dual Edge sensitive                                       HIGH
+ */
+enum pdc_irq_config_bits {
+	POLARITY_LOW = 0, //0 00
+	FALLING_EDGE = 2, //0 10
+	POLARITY_HIGH = 4,//1 00
+	RISING_EDGE = 6,  //1 10
+	DUAL_EDGE = 7,    //1 11
+};
+
+static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
+{
+	int pin_out = get_pdc_pin(d->hwirq, d->chip_data);
+	u32 pdc_type = 0, config;
+
+	if (pin_out < 0)
+		goto fwd_to_parent;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		pdc_type = RISING_EDGE;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		pdc_type = FALLING_EDGE;
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		pdc_type = DUAL_EDGE;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		pdc_type = POLARITY_HIGH;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		pdc_type = POLARITY_LOW;
+		break;
+	default:
+		pdc_type = POLARITY_HIGH;
+		break;
+	}
+	writel_relaxed(pdc_type, pdc_base + IRQ_i_CFG +
+			(pin_out * sizeof(uint32_t)));
+
+	do {
+		config = readl_relaxed(pdc_base + IRQ_i_CFG +
+				(pin_out * sizeof(uint32_t)));
+		if (config == pdc_type)
+			break;
+		udelay(5);
+	} while (1);
+
+	trace_irq_pin_config("type_config", (u32)pin_out, (u32)d->hwirq,
+			pdc_type, 0);
+
+	/*
+	 * If type is edge triggered, forward that as Rising edge as PDC
+	 * takes care of converting falling edge to rising edge signal
+	 */
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+		type = IRQ_TYPE_EDGE_RISING;
+
+	/*
+	 * If type is level, then forward that as level high as PDC
+	 * takes care of converting falling edge to rising edge signal
+	 */
+	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+		type = IRQ_TYPE_LEVEL_HIGH;
+
+fwd_to_parent:
+
+	return irq_chip_set_type_parent(d, type);
+}
+
+static struct irq_chip qcom_pdc_gic_chip = {
+	.name			= "PDC-GIC",
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_mask		= qcom_pdc_gic_mask,
+	.irq_enable		= qcom_pdc_gic_enable,
+	.irq_unmask		= qcom_pdc_gic_unmask,
+	.irq_disable		= qcom_pdc_gic_disable,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+	.irq_set_type		= qcom_pdc_gic_set_type,
+	.flags			= IRQCHIP_MASK_ON_SUSPEND |
+					IRQCHIP_SET_TYPE_MASKED |
+					IRQCHIP_SKIP_SET_WAKE,
+	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
+#ifdef CONFIG_SMP
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+#endif
+};
+
+static int qcom_pdc_translate(struct irq_domain *d,
+	struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
+{
+	return d->parent->ops->translate(d->parent, fwspec, hwirq, type);
+}
+
+static int qcom_pdc_alloc(struct irq_domain *domain,
+	unsigned int virq, unsigned int nr_irqs, void *data)
+{
+	struct irq_fwspec *fwspec = data;
+	struct irq_fwspec parent_fwspec;
+	irq_hw_number_t hwirq;
+	int i;
+	unsigned int type;
+	int ret;
+
+	ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
+	if (ret)
+		return -EINVAL;
+
+	for (i = 0; i < nr_irqs; i++)
+		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+			&qcom_pdc_gic_chip, domain->host_data);
+
+	parent_fwspec = *fwspec;
+	parent_fwspec.fwnode = domain->parent->fwnode;
+
+	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
+					    &parent_fwspec);
+}
+
+static const struct irq_domain_ops qcom_pdc_ops = {
+	.translate	= qcom_pdc_translate,
+	.alloc		= qcom_pdc_alloc,
+	.free		= irq_domain_free_irqs_common,
+};
+
+int qcom_pdc_init(struct device_node *node,
+		struct device_node *parent, void *data)
+{
+	struct irq_domain *parent_domain;
+	int ret;
+	struct irq_domain *pdc_domain;
+
+	pdc_base = of_iomap(node, 0);
+	if (!pdc_base) {
+		pr_err("%s(): unable to map PDC registers\n", node->full_name);
+		return -ENXIO;
+	}
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		pr_err("unable to obtain PDC parent domain\n");
+		ret = -ENXIO;
+		goto failure;
+	}
+
+	pdc_domain = irq_domain_add_hierarchy(parent_domain, 0, MAX_IRQS,
+			node, &qcom_pdc_ops, data);
+	if (!pdc_domain) {
+		pr_err("GIC domain add failed\n");
+		ret = -ENOMEM;
+		goto failure;
+	}
+
+	pdc_domain->name = "qcom,pdc";
+
+	return 0;
+
+failure:
+	iounmap(pdc_base);
+
+	return ret;
+}
+EXPORT_SYMBOL(qcom_pdc_init);
diff --git a/drivers/irqchip/qcom/pdc.h b/drivers/irqchip/qcom/pdc.h
new file mode 100644
index 0000000..7c4d89c
--- /dev/null
+++ b/drivers/irqchip/qcom/pdc.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/device.h>
+
+struct pdc_pin {
+	int pin;
+	irq_hw_number_t hwirq;
+};
+
+int qcom_pdc_init(struct device_node *node,
+		struct device_node *parent, void *data);
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 76dd1f3..5a4e6e9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -59,15 +59,22 @@
 		}
 
 		if (!bubble_state) {
-			CDBG("%s: Sync success: fd 0x%x\n", __func__,
+			CDBG("%s: Sync with success: fd 0x%x\n", __func__,
 				   req_isp->fence_map_out[j].sync_id);
-			cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+			rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
 				CAM_SYNC_STATE_SIGNALED_SUCCESS);
+			if (rc)
+				pr_err("%s: Sync failed with rc = %d\n",
+					__func__, rc);
+
 		} else if (!req_isp->bubble_report) {
-			CDBG("%s: Sync failure: fd 0x%x\n", __func__,
+			CDBG("%s: Sync with failure: fd 0x%x\n", __func__,
 				   req_isp->fence_map_out[j].sync_id);
-			cam_sync_signal(req_isp->fence_map_out[j].sync_id,
+			rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id,
 				CAM_SYNC_STATE_SIGNALED_ERROR);
+			if (rc)
+				pr_err("%s: Sync failed with rc = %d\n",
+					__func__, rc);
 		} else {
 			/*
 			 * Ignore the buffer done if bubble detect is on
@@ -277,7 +284,7 @@
 
 	ctx_isp->frame_id++;
 	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
-	pr_err("%s: next substate %d\n", __func__,
+	CDBG("%s: next substate %d\n", __func__,
 		ctx_isp->substate_activated);
 
 	return rc;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 259e773..49085d7 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1493,19 +1493,6 @@
 	if (i == ctx->num_base)
 		master_base_idx = ctx->base[0].idx;
 
-	/* Stop the master CIDs first */
-	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
-			master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
-
-	/* stop rest of the CIDs  */
-	for (i = 0; i < ctx->num_base; i++) {
-		if (i == master_base_idx)
-			continue;
-		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
-			ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
-	}
-
-
 	/* Stop the master CSID path first */
 	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
 			master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
@@ -1519,6 +1506,18 @@
 			ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
 	}
 
+	/* Stop the master CIDs first */
+	cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+			master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+
+	/* stop rest of the CIDs  */
+	for (i = 0; i < ctx->num_base; i++) {
+		if (i == master_base_idx)
+			continue;
+		cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
+			ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+	}
+
 	if (cam_cdm_stream_off(ctx->cdm_handle))
 		pr_err("%s%d: CDM stream off failed %d\n",
 			__func__, __LINE__, ctx->cdm_handle);
@@ -2884,7 +2883,7 @@
 	int i, j;
 	struct cam_iommu_handle cdm_handles;
 
-	pr_info("%s: Enter\n", __func__);
+	CDBG("%s: Enter\n", __func__);
 
 	memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr));
 
@@ -3037,7 +3036,7 @@
 	hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update;
 	hw_mgr_intf->hw_config = cam_ife_mgr_config_hw;
 
-	pr_info("%s: Exit\n", __func__);
+	CDBG("%s: Exit\n", __func__);
 	return 0;
 end:
 	if (rc) {
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 6306df3..3ec9aa6 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1133,7 +1133,7 @@
 	if (rc)
 		return rc;
 
-	/**
+	/*
 	 * configure the IPP and enable the time stamp capture.
 	 * enable the HW measrurement blocks
 	 */
@@ -1417,7 +1417,7 @@
 	if (rc)
 		return rc;
 
-	/**
+	/*
 	 * RDI path config and enable the time stamp capture
 	 * Enable the measurement blocks
 	 */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index 34243e6..15b8a2d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -227,9 +227,10 @@
 {
 	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
 	u32 ot_lim;
-	u32 reg_off_vbif_lim_conf = (params->xin_id / 4) * 4 +
-		params->reg_off_vbif_lim_conf;
-	u32 bit_off_vbif_lim_conf = (params->xin_id % 4) * 8;
+	u32 reg_off_vbif_lim_conf = ((params->xin_id / mdata->npriority_lvl)
+					* mdata->npriority_lvl)
+					+ params->reg_off_vbif_lim_conf;
+	u32 bit_off_vbif_lim_conf = (params->xin_id % mdata->npriority_lvl) * 8;
 	u32 reg_val;
 	u32 sts;
 	bool forced_on;
@@ -420,6 +421,136 @@
 	}
 }
 
+static void sde_mdp_parse_cdp_setting(struct platform_device *pdev,
+		struct sde_rot_data_type *mdata)
+{
+	int rc;
+	u32 len, data[SDE_ROT_OP_MAX] = {0};
+
+	len = sde_mdp_parse_dt_prop_len(pdev,
+			"qcom,mdss-rot-cdp-setting");
+	if (len == SDE_ROT_OP_MAX) {
+		rc = sde_mdp_parse_dt_handler(pdev,
+			"qcom,mdss-rot-cdp-setting", data, len);
+		if (rc) {
+			SDEROT_ERR("invalid CDP setting\n");
+			goto end;
+		}
+
+		set_bit(SDE_QOS_CDP, mdata->sde_qos_map);
+		mdata->enable_cdp[SDE_ROT_RD] = data[SDE_ROT_RD];
+		mdata->enable_cdp[SDE_ROT_WR] = data[SDE_ROT_WR];
+		return;
+	}
+end:
+	clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
+}
+
+static void sde_mdp_parse_rot_lut_setting(struct platform_device *pdev,
+		struct sde_rot_data_type *mdata)
+{
+	int rc;
+	u32 len, data[4];
+
+	len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-qos-lut");
+	if (len == 4) {
+		rc = sde_mdp_parse_dt_handler(pdev,
+			"qcom,mdss-rot-qos-lut", data, len);
+		if (!rc) {
+			mdata->lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0];
+			mdata->lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1];
+			mdata->lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2];
+			mdata->lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3];
+			set_bit(SDE_QOS_LUT, mdata->sde_qos_map);
+		} else {
+			SDEROT_DBG("qos lut setting not found\n");
+		}
+	}
+
+	len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-danger-lut");
+	if (len == SDE_ROT_OP_MAX) {
+		rc = sde_mdp_parse_dt_handler(pdev,
+			"qcom,mdss-rot-danger-lut", data, len);
+		if (!rc) {
+			mdata->lut_cfg[SDE_ROT_RD].danger_lut
+							= data[SDE_ROT_RD];
+			mdata->lut_cfg[SDE_ROT_WR].danger_lut
+							= data[SDE_ROT_WR];
+			set_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map);
+		} else {
+			SDEROT_DBG("danger lut setting not found\n");
+		}
+	}
+
+	len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-safe-lut");
+	if (len == SDE_ROT_OP_MAX) {
+		rc = sde_mdp_parse_dt_handler(pdev,
+			"qcom,mdss-rot-safe-lut", data, len);
+		if (!rc) {
+			mdata->lut_cfg[SDE_ROT_RD].safe_lut = data[SDE_ROT_RD];
+			mdata->lut_cfg[SDE_ROT_WR].safe_lut = data[SDE_ROT_WR];
+			set_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map);
+		} else {
+			SDEROT_DBG("safe lut setting not found\n");
+		}
+	}
+}
+
+static void sde_mdp_parse_inline_rot_lut_setting(struct platform_device *pdev,
+		struct sde_rot_data_type *mdata)
+{
+	int rc;
+	u32 len, data[4];
+
+	len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-qos-lut");
+	if (len == 4) {
+		rc = sde_mdp_parse_dt_handler(pdev,
+			"qcom,mdss-inline-rot-qos-lut", data, len);
+		if (!rc) {
+			mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0];
+			mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1];
+			mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2];
+			mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3];
+			set_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map);
+		} else {
+			SDEROT_DBG("inline qos lut setting not found\n");
+		}
+	}
+
+	len = sde_mdp_parse_dt_prop_len(pdev,
+				"qcom,mdss-inline-rot-danger-lut");
+	if (len == SDE_ROT_OP_MAX) {
+		rc = sde_mdp_parse_dt_handler(pdev,
+			"qcom,mdss-inline-rot-danger-lut", data, len);
+		if (!rc) {
+			mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut
+							= data[SDE_ROT_RD];
+			mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut
+							= data[SDE_ROT_WR];
+			set_bit(SDE_INLINE_QOS_DANGER_LUT,
+					mdata->sde_inline_qos_map);
+		} else {
+			SDEROT_DBG("inline danger lut setting not found\n");
+		}
+	}
+
+	len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-safe-lut");
+	if (len == SDE_ROT_OP_MAX) {
+		rc = sde_mdp_parse_dt_handler(pdev,
+			"qcom,mdss-inline-rot-safe-lut", data, len);
+		if (!rc) {
+			mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut
+							= data[SDE_ROT_RD];
+			mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut
+							= data[SDE_ROT_WR];
+			set_bit(SDE_INLINE_QOS_SAFE_LUT,
+					mdata->sde_inline_qos_map);
+		} else {
+			SDEROT_DBG("inline safe lut setting not found\n");
+		}
+	}
+}
+
 static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
 		struct sde_rot_data_type *mdata)
 {
@@ -444,8 +575,14 @@
 		SDEROT_DBG(
 			"Could not read optional property: highest bank bit\n");
 
+	sde_mdp_parse_cdp_setting(pdev, mdata);
+
 	sde_mdp_parse_vbif_qos(pdev, mdata);
 
+	sde_mdp_parse_rot_lut_setting(pdev, mdata);
+
+	sde_mdp_parse_inline_rot_lut_setting(pdev, mdata);
+
 	mdata->mdp_base = mdata->sde_io.base + SDE_MDP_OFFSET;
 
 	return 0;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 9194b44..ee2561f 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -40,6 +40,9 @@
 #define SDE_MDP_HW_REV_301	SDE_MDP_REV(3, 0, 1)	/* 8998 v1.1 */
 #define SDE_MDP_HW_REV_400	SDE_MDP_REV(4, 0, 0)	/* sdm845 v1.0 */
 
+#define SDE_MDP_VBIF_4_LEVEL_REMAPPER	4
+#define SDE_MDP_VBIF_8_LEVEL_REMAPPER	8
+
 struct sde_mult_factor {
 	uint32_t numer;
 	uint32_t denom;
@@ -77,9 +80,19 @@
 	SDE_QOS_PER_PIPE_LUT,
 	SDE_QOS_SIMPLIFIED_PREFILL,
 	SDE_QOS_VBLANK_PANIC_CTRL,
+	SDE_QOS_LUT,
+	SDE_QOS_DANGER_LUT,
+	SDE_QOS_SAFE_LUT,
 	SDE_QOS_MAX,
 };
 
+enum sde_inline_qos_settings {
+	SDE_INLINE_QOS_LUT,
+	SDE_INLINE_QOS_DANGER_LUT,
+	SDE_INLINE_QOS_SAFE_LUT,
+	SDE_INLINE_QOS_MAX,
+};
+
 /**
  * enum sde_rot_type: SDE rotator HW version
  * @SDE_ROT_TYPE_V1_0: V1.0 HW version
@@ -115,6 +128,12 @@
 	SDE_MAX_BUS_CLIENTS
 };
 
+enum sde_rot_op {
+	SDE_ROT_RD,
+	SDE_ROT_WR,
+	SDE_ROT_OP_MAX
+};
+
 enum sde_rot_regdump_access {
 	SDE_ROT_REGDUMP_READ,
 	SDE_ROT_REGDUMP_WRITE,
@@ -165,6 +184,13 @@
 	enum sde_rot_regdump_access access;
 };
 
+struct sde_rot_lut_cfg {
+	u32 creq_lut_0;
+	u32 creq_lut_1;
+	u32 danger_lut;
+	u32 safe_lut;
+};
+
 struct sde_rot_data_type {
 	u32 mdss_version;
 
@@ -177,6 +203,7 @@
 
 	/* bitmap to track qos applicable settings */
 	DECLARE_BITMAP(sde_qos_map, SDE_QOS_MAX);
+	DECLARE_BITMAP(sde_inline_qos_map, SDE_QOS_MAX);
 
 	/* bitmap to track capability settings */
 	DECLARE_BITMAP(sde_caps_map, SDE_CAPS_MAX);
@@ -210,6 +237,11 @@
 	void *sde_rot_hw;
 	int sec_cam_en;
 
+	u32 enable_cdp[SDE_ROT_OP_MAX];
+
+	struct sde_rot_lut_cfg lut_cfg[SDE_ROT_OP_MAX];
+	struct sde_rot_lut_cfg inline_lut_cfg[SDE_ROT_OP_MAX];
+
 	struct ion_client *iclient;
 
 	bool clk_always_on;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
index 051db78..de448a4 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -65,6 +65,8 @@
 #define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF2		0x00C8
 #define MMSS_VBIF_NRT_VBIF_OUT_RD_LIM_CONF0		0x00D0
 #define MMSS_VBIF_NRT_VBIF_OUT_WR_LIM_CONF0		0x00D4
+#define MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000		0x0550
+#define MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000		0x0590
 
 #define SDE_MDP_REG_TRAFFIC_SHAPER_EN			BIT(31)
 #define SDE_MDP_REG_TRAFFIC_SHAPER_RD_CLIENT(num)	(0x030 + (num * 4))
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 980df9f..56cdaa3 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -493,6 +493,12 @@
 		SDE_ROT_REGDUMP_VBIF },
 };
 
+struct sde_rot_cdp_params {
+	bool enable;
+	struct sde_mdp_format_params *fmt;
+	u32 offset;
+};
+
 /* Invalid software timestamp value for initialization */
 #define SDE_REGDMA_SWTS_INVALID	(~0)
 
@@ -741,6 +747,76 @@
 }
 
 /*
+ * sde_hw_rotator_vbif_setting - helper function to set vbif QoS remapper
+ * levels, enable write gather enable and avoid clk gating setting for
+ * debug purpose.
+ *
+ * @rot: Pointer to rotator hw
+ */
+static void sde_hw_rotator_vbif_setting(struct sde_hw_rotator *rot)
+{
+	u32 i, mask, vbif_qos, reg_val = 0;
+	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+
+	/* VBIF_ROT QoS remapper setting */
+	switch (mdata->npriority_lvl) {
+
+	case SDE_MDP_VBIF_4_LEVEL_REMAPPER:
+		for (i = 0; i < mdata->npriority_lvl; i++) {
+			reg_val = SDE_VBIF_READ(mdata,
+					MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
+			mask = 0x3 << (XIN_SSPP * 2);
+			vbif_qos = mdata->vbif_nrt_qos[i];
+			reg_val |= vbif_qos << (XIN_SSPP * 2);
+			/* ensure write is issued after the read operation */
+			mb();
+			SDE_VBIF_WRITE(mdata,
+					MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
+					reg_val);
+		}
+		break;
+
+	case SDE_MDP_VBIF_8_LEVEL_REMAPPER:
+		mask = mdata->npriority_lvl - 1;
+		for (i = 0; i < mdata->npriority_lvl; i++) {
+			/* RD and WR client */
+			reg_val |= (mdata->vbif_nrt_qos[i] & mask)
+							<< (XIN_SSPP * 4);
+			reg_val |= (mdata->vbif_nrt_qos[i] & mask)
+							<< (XIN_WRITEBACK * 4);
+
+			SDE_VBIF_WRITE(mdata,
+				MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 + i*8,
+				reg_val);
+			SDE_VBIF_WRITE(mdata,
+				MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 + i*8,
+				reg_val);
+		}
+		break;
+
+	default:
+		SDEROT_DBG("invalid vbif remapper levels\n");
+	}
+
+	/* Enable write gather for writeback to remove write gaps, which
+	 * may hang AXI/BIMC/SDE.
+	 */
+	SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
+			BIT(XIN_WRITEBACK));
+
+	/*
+	 * For debug purpose, disable clock gating, i.e. Clocks always on
+	 */
+	if (mdata->clk_always_on) {
+		SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3);
+		SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3);
+		SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1,
+				0xFFFF);
+		SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1);
+	}
+}
+
+/*
  * sde_hw_rotator_setup_timestamp_packet - setup timestamp writeback command
  * @ctx: Pointer to rotator context
  * @mask: Bit mask location of the timestamp
@@ -796,6 +872,156 @@
 }
 
 /*
+ * sde_hw_rotator_cdp_configs - configures the CDP registers
+ * @ctx: Pointer to rotator context
+ * @params: Pointer to parameters needed for CDP configs
+ */
+static void sde_hw_rotator_cdp_configs(struct sde_hw_rotator_context *ctx,
+		struct sde_rot_cdp_params *params)
+{
+	int reg_val;
+	u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+	if (!params->enable) {
+		SDE_REGDMA_WRITE(wrptr, params->offset, 0x0);
+		goto end;
+	}
+
+	reg_val = BIT(0); /* enable cdp */
+
+	if (sde_mdp_is_ubwc_format(params->fmt))
+		reg_val |= BIT(1); /* enable UBWC meta cdp */
+
+	if (sde_mdp_is_ubwc_format(params->fmt)
+			|| sde_mdp_is_tilea4x_format(params->fmt)
+			|| sde_mdp_is_tilea5x_format(params->fmt))
+		reg_val |= BIT(2); /* enable tile amortize */
+
+	reg_val |= BIT(3); /* enable preload addr ahead cnt 64 */
+
+	SDE_REGDMA_WRITE(wrptr, params->offset, reg_val);
+
+end:
+	sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
+ * sde_hw_rotator_setup_qos_lut_wr - Set QoS LUT/Danger LUT/Safe LUT configs
+ * for the WRITEBACK rotator for inline and offline rotation.
+ *
+ * @ctx: Pointer to rotator context
+ */
+static void sde_hw_rotator_setup_qos_lut_wr(struct sde_hw_rotator_context *ctx)
+{
+	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+	u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+	/* Offline rotation setting */
+	if (!ctx->sbuf_mode) {
+		/* QOS LUT WR setting */
+		if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) {
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0,
+					mdata->lut_cfg[SDE_ROT_WR].creq_lut_0);
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1,
+					mdata->lut_cfg[SDE_ROT_WR].creq_lut_1);
+		}
+
+		/* Danger LUT WR setting */
+		if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT,
+					mdata->lut_cfg[SDE_ROT_WR].danger_lut);
+
+		/* Safe LUT WR setting */
+		if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT,
+					mdata->lut_cfg[SDE_ROT_WR].safe_lut);
+
+	/* Inline rotation setting */
+	} else {
+		/* QOS LUT WR setting */
+		if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) {
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0,
+				mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0);
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1,
+				mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1);
+		}
+
+		/* Danger LUT WR setting */
+		if (test_bit(SDE_INLINE_QOS_DANGER_LUT,
+					mdata->sde_inline_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT,
+				mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut);
+
+		/* Safe LUT WR setting */
+		if (test_bit(SDE_INLINE_QOS_SAFE_LUT,
+					mdata->sde_inline_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT,
+				mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut);
+	}
+
+	/* Update command queue write ptr */
+	sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
+ * sde_hw_rotator_setup_qos_lut_rd - Set QoS LUT/Danger LUT/Safe LUT configs
+ * for the SSPP rotator for inline and offline rotation.
+ *
+ * @ctx: Pointer to rotator context
+ */
+static void sde_hw_rotator_setup_qos_lut_rd(struct sde_hw_rotator_context *ctx)
+{
+	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+	u32 *wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
+	/* Offline rotation setting */
+	if (!ctx->sbuf_mode) {
+		/* QOS LUT RD setting */
+		if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) {
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0,
+					mdata->lut_cfg[SDE_ROT_RD].creq_lut_0);
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1,
+					mdata->lut_cfg[SDE_ROT_RD].creq_lut_1);
+		}
+
+		/* Danger LUT RD setting */
+		if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT,
+					mdata->lut_cfg[SDE_ROT_RD].danger_lut);
+
+		/* Safe LUT RD setting */
+		if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT,
+					mdata->lut_cfg[SDE_ROT_RD].safe_lut);
+
+	/* inline rotation setting */
+	} else {
+		/* QOS LUT RD setting */
+		if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) {
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0,
+				mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0);
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1,
+				mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1);
+		}
+
+		/* Danger LUT RD setting */
+		if (test_bit(SDE_INLINE_QOS_DANGER_LUT,
+					mdata->sde_inline_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT,
+				mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut);
+
+		/* Safe LUT RD setting */
+		if (test_bit(SDE_INLINE_QOS_SAFE_LUT,
+					mdata->sde_inline_qos_map))
+			SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT,
+				mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut);
+	}
+
+	/* Update command queue write ptr */
+	sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+}
+
+/*
  * sde_hw_rotator_setup_fetchengine - setup fetch engine
  * @ctx: Pointer to rotator context
  * @queue_id: Priority queue identifier
@@ -814,6 +1040,7 @@
 	struct sde_hw_rotator *rot = ctx->rot;
 	struct sde_mdp_format_params *fmt;
 	struct sde_mdp_data *data;
+	struct sde_rot_cdp_params cdp_params = {0};
 	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
 	u32 *wrptr;
 	u32 opmode = 0;
@@ -985,13 +1212,29 @@
 		ctx->is_secure = false;
 	}
 
+	/* Update command queue write ptr */
+	sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+
+	/* CDP register RD setting */
+	cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ?
+					 mdata->enable_cdp[SDE_ROT_RD] : false;
+	cdp_params.fmt = fmt;
+	cdp_params.offset = ROT_SSPP_CDP_CNTL;
+	sde_hw_rotator_cdp_configs(ctx, &cdp_params);
+
+	/* QOS LUT/ Danger LUT/ Safe Lut WR setting */
+	sde_hw_rotator_setup_qos_lut_rd(ctx);
+
+	wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
 	/*
 	 * Determine if traffic shaping is required. Only enable traffic
 	 * shaping when content is 4k@30fps. The actual traffic shaping
 	 * bandwidth calculation is done in output setup.
 	 */
-	if (((cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) &&
-			(cfg->fps <= 30)) {
+	if (((!ctx->sbuf_mode)
+			&& (cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD)
+			&& (cfg->fps <= 30)) {
 		SDEROT_DBG("Enable Traffic Shaper\n");
 		ctx->is_traffic_shaping = true;
 	} else {
@@ -1017,6 +1260,7 @@
 {
 	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
 	struct sde_mdp_format_params *fmt;
+	struct sde_rot_cdp_params cdp_params = {0};
 	u32 *wrptr;
 	u32 pack = 0;
 	u32 dst_format = 0;
@@ -1120,8 +1364,23 @@
 	SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, ctx->op_mode |
 			(flags & SDE_ROT_FLAG_ROT_90 ? BIT(1) : 0) | BIT(0));
 
+	sde_hw_rotator_put_regdma_segment(ctx, wrptr);
+
+	/* CDP register WR setting */
+	cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ?
+					mdata->enable_cdp[SDE_ROT_WR] : false;
+	cdp_params.fmt = fmt;
+	cdp_params.offset = ROT_WB_CDP_CNTL;
+	sde_hw_rotator_cdp_configs(ctx, &cdp_params);
+
+	/* QOS LUT/ Danger LUT/ Safe LUT WR setting */
+	sde_hw_rotator_setup_qos_lut_wr(ctx);
+
+	wrptr = sde_hw_rotator_get_regdma_segment(ctx);
+
 	/* setup traffic shaper for 4k 30fps content or if prefill_bw is set */
-	if (ctx->is_traffic_shaping || cfg->prefill_bw) {
+	if (!ctx->sbuf_mode &&
+			(ctx->is_traffic_shaping || cfg->prefill_bw)) {
 		u32 bw;
 
 		/*
@@ -2136,7 +2395,7 @@
 			item->input.format, item->output.format,
 			entry->perf->config.frame_rate);
 
-	if (mdata->default_ot_rd_limit) {
+	if (!ctx->sbuf_mode && mdata->default_ot_rd_limit) {
 		struct sde_mdp_set_ot_params ot_params;
 
 		memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
@@ -2158,7 +2417,7 @@
 		sde_mdp_set_ot_limit(&ot_params);
 	}
 
-	if (mdata->default_ot_wr_limit) {
+	if (!ctx->sbuf_mode && mdata->default_ot_wr_limit) {
 		struct sde_mdp_set_ot_params ot_params;
 
 		memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
@@ -2189,46 +2448,9 @@
 		SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CREQ_LUT, qos_lut);
 	}
 
-	/* Set CDP control registers to 0 if CDP is disabled */
-	if (!test_bit(SDE_QOS_CDP, mdata->sde_qos_map)) {
-		SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CDP_CNTL, 0x0);
-		SDE_ROTREG_WRITE(rot->mdss_base, ROT_WB_CDP_CNTL, 0x0);
-	}
-
-	if (mdata->npriority_lvl > 0) {
-		u32 mask, reg_val, i, vbif_qos;
-
-		for (i = 0; i < mdata->npriority_lvl; i++) {
-			reg_val = SDE_VBIF_READ(mdata,
-					MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
-			mask = 0x3 << (XIN_SSPP * 2);
-			reg_val &= ~(mask);
-			vbif_qos = mdata->vbif_nrt_qos[i];
-			reg_val |= vbif_qos << (XIN_SSPP * 2);
-			/* ensure write is issued after the read operation */
-			mb();
-			SDE_VBIF_WRITE(mdata,
-					MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
-					reg_val);
-		}
-	}
-
-	/* Enable write gather for writeback to remove write gaps, which
-	 * may hang AXI/BIMC/SDE.
-	 */
-	SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
-			BIT(XIN_WRITEBACK));
-
-	/*
-	 * For debug purpose, disable clock gating, i.e. Clocks always on
-	 */
-	if (mdata->clk_always_on) {
-		SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3);
-		SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3);
-		SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1,
-				0xFFFF);
-		SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1);
-	}
+	/* VBIF QoS and other settings */
+	if (!ctx->sbuf_mode)
+		sde_hw_rotator_vbif_setting(rot);
 
 	return 0;
 
@@ -2337,7 +2559,6 @@
 
 	clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map);
 	set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map);
-	clear_bit(SDE_QOS_CDP, mdata->sde_qos_map);
 	set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map);
 	set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map);
 	clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
index aa762dd..d2b81d5 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
@@ -81,6 +81,8 @@
 #define ROT_SSPP_CREQ_LUT                       (SDE_ROT_SSPP_OFFSET+0x68)
 #define ROT_SSPP_QOS_CTRL                       (SDE_ROT_SSPP_OFFSET+0x6C)
 #define ROT_SSPP_SRC_ADDR_SW_STATUS             (SDE_ROT_SSPP_OFFSET+0x70)
+#define ROT_SSPP_CREQ_LUT_0                     (SDE_ROT_SSPP_OFFSET+0x74)
+#define ROT_SSPP_CREQ_LUT_1                     (SDE_ROT_SSPP_OFFSET+0x78)
 #define ROT_SSPP_CURRENT_SRC0_ADDR              (SDE_ROT_SSPP_OFFSET+0xA4)
 #define ROT_SSPP_CURRENT_SRC1_ADDR              (SDE_ROT_SSPP_OFFSET+0xA8)
 #define ROT_SSPP_CURRENT_SRC2_ADDR              (SDE_ROT_SSPP_OFFSET+0xAC)
@@ -167,6 +169,8 @@
 #define ROT_WB_CREQ_LUT                         (SDE_ROT_WB_OFFSET+0x08C)
 #define ROT_WB_QOS_CTRL                         (SDE_ROT_WB_OFFSET+0x090)
 #define ROT_WB_SYS_CACHE_MODE                   (SDE_ROT_WB_OFFSET+0x094)
+#define ROT_WB_CREQ_LUT_0                       (SDE_ROT_WB_OFFSET+0x098)
+#define ROT_WB_CREQ_LUT_1                       (SDE_ROT_WB_OFFSET+0x09C)
 #define ROT_WB_UBWC_STATIC_CTRL                 (SDE_ROT_WB_OFFSET+0x144)
 #define ROT_WB_SBUF_STATUS_PLANE0               (SDE_ROT_WB_OFFSET+0x148)
 #define ROT_WB_SBUF_STATUS_PLANE1               (SDE_ROT_WB_OFFSET+0x14C)
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index a477340..5970236 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -515,13 +515,13 @@
 		buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
 		break;
 	case HAL_BUFFER_INTERNAL_SCRATCH:
-		buffer = HFI_BUFFER_INTERNAL_SCRATCH;
+		buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH;
 		break;
 	case HAL_BUFFER_INTERNAL_SCRATCH_1:
-		buffer = HFI_BUFFER_INTERNAL_SCRATCH_1;
+		buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1;
 		break;
 	case HAL_BUFFER_INTERNAL_SCRATCH_2:
-		buffer = HFI_BUFFER_INTERNAL_SCRATCH_2;
+		buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2;
 		break;
 	case HAL_BUFFER_INTERNAL_PERSIST:
 		buffer = HFI_BUFFER_INTERNAL_PERSIST;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index b424fbb..89e8356 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1082,19 +1082,19 @@
 			buffreq->buffer[5].buffer_type =
 				HAL_BUFFER_EXTRADATA_OUTPUT2;
 			break;
-		case HFI_BUFFER_INTERNAL_SCRATCH:
+		case HFI_BUFFER_COMMON_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:
+		case HFI_BUFFER_COMMON_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:
+		case HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2:
 			memcpy(&buffreq->buffer[8], hfi_buf_req,
 				sizeof(struct hfi_buffer_requirements));
 			buffreq->buffer[8].buffer_type =
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 48a6f17..5601f1b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -56,13 +56,6 @@
 #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_INTERNAL_RECON (HFI_OX_BASE + 0x9)
 
 #define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3)
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index fc638f0..592f0b8 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -155,6 +155,13 @@
 #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_BUFFER_COMMON_INTERNAL_SCRATCH	(HFI_COMMON_BASE + 0x6)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1	(HFI_COMMON_BASE + 0x7)
+#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2	(HFI_COMMON_BASE + 0x8)
+#define HFI_BUFFER_COMMON_INTERNAL_RECON	(HFI_COMMON_BASE + 0x9)
+#define HFI_BUFFER_EXTRADATA_OUTPUT		(HFI_COMMON_BASE + 0xA)
+#define HFI_BUFFER_EXTRADATA_OUTPUT2		(HFI_COMMON_BASE + 0xB)
+#define HFI_BUFFER_EXTRADATA_INPUT		(HFI_COMMON_BASE + 0xC)
 
 #define  HFI_BITDEPTH_8				(HFI_COMMON_BASE + 0x0)
 #define  HFI_BITDEPTH_9				(HFI_COMMON_BASE + 0x1)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index bf13ac5..04d807f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -3659,7 +3659,6 @@
 	struct ipa_mem_buffer mem_info = {0};
 	static int total_cnt;
 
-	IPADBG("\n");
 	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
 		ipa3_ctx->ep[clnt_hdl].valid == 0) {
 		IPAERR("bad parm 0x%x\n", clnt_hdl);
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index cf7c35d..deb0ce5 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -86,7 +86,7 @@
  */
 #define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT	32
 #define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT	16
-#define CPRH_SDM845_KBSS_FUSE_COMBO_COUNT	16
+#define CPRH_SDM845_KBSS_FUSE_COMBO_COUNT	24
 
 /*
  * Constants which define the name of each fuse corner.
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 119ede3..8aff84c 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -36,6 +36,7 @@
 #include <soc/qcom/boot_stats.h>
 
 #define BUILD_ID_LENGTH 32
+#define CHIP_ID_LENGTH 32
 #define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
 #define SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE 128
 #define SMEM_IMAGE_VERSION_SIZE 4096
@@ -199,6 +200,20 @@
 struct socinfo_v0_13 {
 	struct socinfo_v0_12 v0_12;
 	uint32_t nproduct_id;
+	char chip_name[CHIP_ID_LENGTH];
+};
+
+struct socinfo_v0_14 {
+	struct socinfo_v0_13 v0_13;
+	uint32_t num_clusters;
+	uint32_t ncluster_array_offset;
+	uint32_t num_defective_parts;
+	uint32_t ndefective_parts_array_offset;
+};
+
+struct socinfo_v0_15 {
+	struct socinfo_v0_14 v0_14;
+	uint32_t nmodem_supported;
 };
 
 static union {
@@ -215,10 +230,12 @@
 	struct socinfo_v0_11 v0_11;
 	struct socinfo_v0_12 v0_12;
 	struct socinfo_v0_13 v0_13;
+	struct socinfo_v0_14 v0_14;
+	struct socinfo_v0_15 v0_15;
 } *socinfo;
 
 /* max socinfo format version supported */
-#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 13)
+#define MAX_SOCINFO_FORMAT SOCINFO_VERSION(0, 15)
 
 static struct msm_soc_info cpu_of_id[] = {
 
@@ -705,6 +722,14 @@
 		: 0;
 }
 
+static char *socinfo_get_chip_name(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 13) ?
+			socinfo->v0_13.chip_name : "N/A")
+		: "N/A";
+}
+
 static uint32_t socinfo_get_nproduct_id(void)
 {
 	return socinfo ?
@@ -713,6 +738,46 @@
 		: 0;
 }
 
+static uint32_t socinfo_get_num_clusters(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 14) ?
+			socinfo->v0_14.num_clusters : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_ncluster_array_offset(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 14) ?
+			socinfo->v0_14.ncluster_array_offset : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_num_defective_parts(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 14) ?
+			socinfo->v0_14.num_defective_parts : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_ndefective_parts_array_offset(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 14) ?
+			socinfo->v0_14.ndefective_parts_array_offset : 0)
+		: 0;
+}
+
+static uint32_t socinfo_get_nmodem_supported(void)
+{
+	return socinfo ?
+		(socinfo_format >= SOCINFO_VERSION(0, 15) ?
+			socinfo->v0_15.nmodem_supported : 0)
+		: 0;
+}
+
 enum pmic_model socinfo_get_pmic_model(void)
 {
 	return socinfo ?
@@ -890,6 +955,15 @@
 }
 
 static ssize_t
+msm_get_chip_name(struct device *dev,
+		   struct device_attribute *attr,
+		   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%-.32s\n",
+			socinfo_get_chip_name());
+}
+
+static ssize_t
 msm_get_nproduct_id(struct device *dev,
 			struct device_attribute *attr,
 			char *buf)
@@ -899,6 +973,51 @@
 }
 
 static ssize_t
+msm_get_num_clusters(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_num_clusters());
+}
+
+static ssize_t
+msm_get_ncluster_array_offset(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_ncluster_array_offset());
+}
+
+static ssize_t
+msm_get_num_defective_parts(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_num_defective_parts());
+}
+
+static ssize_t
+msm_get_ndefective_parts_array_offset(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_ndefective_parts_array_offset());
+}
+
+static ssize_t
+msm_get_nmodem_supported(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n",
+		socinfo_get_nmodem_supported());
+}
+
+static ssize_t
 msm_get_pmic_model(struct device *dev,
 			struct device_attribute *attr,
 			char *buf)
@@ -1146,10 +1265,34 @@
 	__ATTR(raw_device_number, S_IRUGO,
 			msm_get_raw_device_number, NULL);
 
+static struct device_attribute msm_soc_attr_chip_name =
+	__ATTR(chip_name, 0444,
+			msm_get_chip_name, NULL);
+
 static struct device_attribute msm_soc_attr_nproduct_id =
 	__ATTR(nproduct_id, 0444,
 			msm_get_nproduct_id, NULL);
 
+static struct device_attribute msm_soc_attr_num_clusters =
+	__ATTR(num_clusters, 0444,
+			msm_get_num_clusters, NULL);
+
+static struct device_attribute msm_soc_attr_ncluster_array_offset =
+	__ATTR(ncluster_array_offset, 0444,
+			msm_get_ncluster_array_offset, NULL);
+
+static struct device_attribute msm_soc_attr_num_defective_parts =
+	__ATTR(num_defective_parts, 0444,
+			msm_get_num_defective_parts, NULL);
+
+static struct device_attribute msm_soc_attr_ndefective_parts_array_offset =
+	__ATTR(ndefective_parts_array_offset, 0444,
+			msm_get_ndefective_parts_array_offset, NULL);
+
+static struct device_attribute msm_soc_attr_nmodem_supported =
+	__ATTR(nmodem_supported, 0444,
+			msm_get_nmodem_supported, NULL);
+
 static struct device_attribute msm_soc_attr_pmic_model =
 	__ATTR(pmic_model, S_IRUGO,
 			msm_get_pmic_model, NULL);
@@ -1280,9 +1423,23 @@
 	device_create_file(msm_soc_device, &images);
 
 	switch (socinfo_format) {
+	case SOCINFO_VERSION(0, 15):
+		device_create_file(msm_soc_device,
+					&msm_soc_attr_nmodem_supported);
+	case SOCINFO_VERSION(0, 14):
+		device_create_file(msm_soc_device,
+					&msm_soc_attr_num_clusters);
+		device_create_file(msm_soc_device,
+					&msm_soc_attr_ncluster_array_offset);
+		device_create_file(msm_soc_device,
+					&msm_soc_attr_num_defective_parts);
+		device_create_file(msm_soc_device,
+				&msm_soc_attr_ndefective_parts_array_offset);
 	case SOCINFO_VERSION(0, 13):
 		 device_create_file(msm_soc_device,
 					&msm_soc_attr_nproduct_id);
+		 device_create_file(msm_soc_device,
+					&msm_soc_attr_chip_name);
 	case SOCINFO_VERSION(0, 12):
 		device_create_file(msm_soc_device,
 					&msm_soc_attr_chip_family);
@@ -1522,6 +1679,53 @@
 			socinfo->v0_13.nproduct_id);
 		break;
 
+	case SOCINFO_VERSION(0, 14):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u serial_number=%u num_pmics=%u chip_family=0x%x raw_device_family=0x%x raw_device_number=0x%x nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype,
+			socinfo->v0_7.pmic_model,
+			socinfo->v0_7.pmic_die_revision,
+			socinfo->v0_9.foundry_id,
+			socinfo->v0_10.serial_number,
+			socinfo->v0_11.num_pmics,
+			socinfo->v0_12.chip_family,
+			socinfo->v0_12.raw_device_family,
+			socinfo->v0_12.raw_device_number,
+			socinfo->v0_13.nproduct_id,
+			socinfo->v0_14.num_clusters,
+			socinfo->v0_14.ncluster_array_offset,
+			socinfo->v0_14.num_defective_parts,
+			socinfo->v0_14.ndefective_parts_array_offset);
+		break;
+
+	case SOCINFO_VERSION(0, 15):
+		pr_info("v%u.%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u foundry_id=%u serial_number=%u num_pmics=%u chip_family=0x%x raw_device_family=0x%x raw_device_number=0x%x nproduct_id=0x%x num_clusters=0x%x ncluster_array_offset=0x%x num_defective_parts=0x%x ndefective_parts_array_offset=0x%x nmodem_supported=0x%x\n",
+			f_maj, f_min, socinfo->v0_1.id, v_maj, v_min,
+			socinfo->v0_2.raw_id, socinfo->v0_2.raw_version,
+			socinfo->v0_3.hw_platform,
+			socinfo->v0_4.platform_version,
+			socinfo->v0_5.accessory_chip,
+			socinfo->v0_6.hw_platform_subtype,
+			socinfo->v0_7.pmic_model,
+			socinfo->v0_7.pmic_die_revision,
+			socinfo->v0_9.foundry_id,
+			socinfo->v0_10.serial_number,
+			socinfo->v0_11.num_pmics,
+			socinfo->v0_12.chip_family,
+			socinfo->v0_12.raw_device_family,
+			socinfo->v0_12.raw_device_number,
+			socinfo->v0_13.nproduct_id,
+			socinfo->v0_14.num_clusters,
+			socinfo->v0_14.ncluster_array_offset,
+			socinfo->v0_14.num_defective_parts,
+			socinfo->v0_14.ndefective_parts_array_offset,
+			socinfo->v0_15.nmodem_supported);
+		break;
+
 	default:
 		pr_err("Unknown format found: v%u.%u\n", f_maj, f_min);
 		break;
diff --git a/include/trace/events/pdc.h b/include/trace/events/pdc.h
new file mode 100644
index 0000000..400e959
--- /dev/null
+++ b/include/trace/events/pdc.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM pdc
+
+#if !defined(_TRACE_PDC_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PDC_H_
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(irq_pin_config,
+
+	TP_PROTO(char *func, u32 pin, u32 hwirq, u32 type, u32 enable),
+
+	TP_ARGS(func, pin, hwirq, type, enable),
+
+	TP_STRUCT__entry(
+		__field(char *, func)
+		__field(u32, pin)
+		__field(u32, hwirq)
+		__field(u32, type)
+		__field(u32, enable)
+	),
+
+	TP_fast_assign(
+		__entry->pin = pin;
+		__entry->func = func;
+		__entry->hwirq = hwirq;
+		__entry->type = type;
+		__entry->enable = enable;
+	),
+
+	TP_printk("%s hwirq:%u pin:%u type:%u enable:%u",
+		__entry->func, __entry->pin, __entry->hwirq, __entry->type,
+		__entry->enable)
+);
+
+#endif
+#define TRACE_INCLUDE_FILE pdc
+#include <trace/define_trace.h>
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index a70b90d..c61c56f 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/debug_locks.h>
 #include <linux/osq_lock.h>
+#include <linux/delay.h>
 
 /*
  * In the DEBUG case we are using the "NULL fastpath" for mutexes,
@@ -378,6 +379,17 @@
 		 * values at the cost of a few extra spins.
 		 */
 		cpu_relax_lowlatency();
+
+		/*
+		 * On arm systems, we must slow down the waiter's repeated
+		 * aquisition of spin_mlock and atomics on the lock count, or
+		 * we risk starving out a thread attempting to release the
+		 * mutex. The mutex slowpath release must take spin lock
+		 * wait_lock. This spin lock can share a monitor with the
+		 * other waiter atomics in the mutex data structure, so must
+		 * take care to rate limit the waiters.
+		 */
+		udelay(1);
 	}
 
 	osq_unlock(&lock->osq);
diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c
index 0b07393..4278e36 100644
--- a/sound/soc/codecs/wcd9330.c
+++ b/sound/soc/codecs/wcd9330.c
@@ -1536,6 +1536,13 @@
 	tomtom_mad_input = ucontrol->value.integer.value[0];
 	micb_4_int_reg = tomtom->resmgr.reg_addr->micb_4_int_rbias;
 
+	if (tomtom_mad_input >= ARRAY_SIZE(tomtom_conn_mad_text)) {
+		dev_err(codec->dev,
+			"%s: tomtom_mad_input = %d out of bounds\n",
+			__func__, tomtom_mad_input);
+		return -EINVAL;
+	}
+
 	pr_debug("%s: tomtom_mad_input = %s\n", __func__,
 			tomtom_conn_mad_text[tomtom_mad_input]);
 
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index d4db55f..36382ba 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -1,5 +1,5 @@
-snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
-			msm-compress-q6-v2.o msm-compr-q6-v2.o \
+snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o \
+			msm-pcm-routing-v2.o msm-compress-q6-v2.o \
 			msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
 			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
 			msm-lsm-client.o msm-pcm-host-voice-v2.o \
diff --git a/sound/soc/msm/qdsp6v2/audio_cal_utils.c b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
index 5d4a0ba..820aa1b 100644
--- a/sound/soc/msm/qdsp6v2/audio_cal_utils.c
+++ b/sound/soc/msm/qdsp6v2/audio_cal_utils.c
@@ -646,7 +646,9 @@
 	return cal_block;
 err:
 	kfree(cal_block->cal_info);
+	cal_block->cal_info = NULL;
 	kfree(cal_block->client_info);
+	cal_block->client_info = NULL;
 	kfree(cal_block);
 	cal_block = NULL;
 	return cal_block;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
deleted file mode 100644
index 449325c..0000000
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ /dev/null
@@ -1,1714 +0,0 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * 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/err.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <sound/q6asm-v2.h>
-#include <sound/pcm_params.h>
-#include <asm/dma.h>
-#include <linux/dma-mapping.h>
-#include <linux/msm_audio_ion.h>
-
-#include <sound/timer.h>
-
-#include "msm-compr-q6-v2.h"
-#include "msm-pcm-routing-v2.h"
-#include <sound/tlv.h>
-
-#define COMPRE_CAPTURE_NUM_PERIODS	16
-/* Allocate the worst case frame size for compressed audio */
-#define COMPRE_CAPTURE_HEADER_SIZE	(sizeof(struct snd_compr_audio_info))
-/* Changing period size to 4032. 4032 will make sure COMPRE_CAPTURE_PERIOD_SIZE
- * is 4096 with meta data size of 64 and MAX_NUM_FRAMES_PER_BUFFER 1
- */
-#define COMPRE_CAPTURE_MAX_FRAME_SIZE	(4032)
-#define COMPRE_CAPTURE_PERIOD_SIZE	((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
-					  COMPRE_CAPTURE_HEADER_SIZE) * \
-					  MAX_NUM_FRAMES_PER_BUFFER)
-#define COMPRE_OUTPUT_METADATA_SIZE	(sizeof(struct output_meta_data_st))
-#define COMPRESSED_LR_VOL_MAX_STEPS	0x20002000
-
-#define MAX_AC3_PARAM_SIZE		(18*2*sizeof(int))
-#define AMR_WB_BAND_MODE 8
-#define AMR_WB_DTX_MODE 0
-
-
-const DECLARE_TLV_DB_LINEAR(compr_rx_vol_gain, 0,
-			    COMPRESSED_LR_VOL_MAX_STEPS);
-
-static struct audio_locks the_locks;
-
-static struct snd_pcm_hardware msm_compr_hardware_capture = {
-	.info =		 (SNDRV_PCM_INFO_MMAP |
-				SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				SNDRV_PCM_INFO_MMAP_VALID |
-				SNDRV_PCM_INFO_INTERLEAVED |
-				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-	.formats =	      SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		SNDRV_PCM_RATE_8000_48000,
-	.rate_min =	     8000,
-	.rate_max =	     48000,
-	.channels_min =	 1,
-	.channels_max =	 8,
-	.buffer_bytes_max =
-		COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS,
-	.period_bytes_min =	COMPRE_CAPTURE_PERIOD_SIZE,
-	.period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
-	.periods_min =	  COMPRE_CAPTURE_NUM_PERIODS,
-	.periods_max =	  COMPRE_CAPTURE_NUM_PERIODS,
-	.fifo_size =	    0,
-};
-
-static struct snd_pcm_hardware msm_compr_hardware_playback = {
-	.info =		 (SNDRV_PCM_INFO_MMAP |
-				SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				SNDRV_PCM_INFO_MMAP_VALID |
-				SNDRV_PCM_INFO_INTERLEAVED |
-				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-	.formats =	      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
-	.rates =		SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
-	.rate_min =	     8000,
-	.rate_max =	     48000,
-	.channels_min =	 1,
-	.channels_max =	 8,
-	.buffer_bytes_max =     1024 * 1024,
-	.period_bytes_min =	128 * 1024,
-	.period_bytes_max =     256 * 1024,
-	.periods_min =	  4,
-	.periods_max =	  8,
-	.fifo_size =	    0,
-};
-
-/* Conventional and unconventional sample rate supported */
-static unsigned int supported_sample_rates[] = {
-	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-};
-
-/* Add supported codecs for compress capture path */
-static uint32_t supported_compr_capture_codecs[] = {
-	SND_AUDIOCODEC_AMRWB
-};
-
-static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
-	.count = ARRAY_SIZE(supported_sample_rates),
-	.list = supported_sample_rates,
-	.mask = 0,
-};
-
-static bool msm_compr_capture_codecs(uint32_t req_codec)
-{
-	int i;
-
-	pr_debug("%s req_codec:%d\n", __func__, req_codec);
-	if (req_codec == 0)
-		return false;
-	for (i = 0; i < ARRAY_SIZE(supported_compr_capture_codecs); i++) {
-		if (req_codec == supported_compr_capture_codecs[i])
-			return true;
-	}
-	return false;
-}
-
-static void compr_event_handler(uint32_t opcode,
-		uint32_t token, uint32_t *payload, void *priv)
-{
-	struct compr_audio *compr = priv;
-	struct msm_audio *prtd = &compr->prtd;
-	struct snd_pcm_substream *substream = prtd->substream;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct audio_aio_write_param param;
-	struct audio_aio_read_param read_param;
-	struct audio_buffer *buf = NULL;
-	phys_addr_t temp;
-	struct output_meta_data_st output_meta_data;
-	uint32_t *ptrmem = (uint32_t *)payload;
-	int i = 0;
-	int time_stamp_flag = 0;
-	int buffer_length = 0;
-	int stop_playback = 0;
-
-	pr_debug("%s opcode =%08x\n", __func__, opcode);
-	switch (opcode) {
-	case ASM_DATA_EVENT_WRITE_DONE_V2: {
-		uint32_t *ptrmem = (uint32_t *)&param;
-
-		pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
-		pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
-		prtd->pcm_irq_pos += prtd->pcm_count;
-		if (atomic_read(&prtd->start))
-			snd_pcm_period_elapsed(substream);
-		else
-			if (substream->timer_running)
-				snd_timer_interrupt(substream->timer, 1);
-		atomic_inc(&prtd->out_count);
-		wake_up(&the_locks.write_wait);
-		if (!atomic_read(&prtd->start)) {
-			atomic_set(&prtd->pending_buffer, 1);
-			break;
-		}
-		atomic_set(&prtd->pending_buffer, 0);
-
-		/*
-		 * check for underrun
-		 */
-		snd_pcm_stream_lock_irq(substream);
-		if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
-			runtime->render_flag |= SNDRV_RENDER_STOPPED;
-			stop_playback = 1;
-		}
-		snd_pcm_stream_unlock_irq(substream);
-
-		if (stop_playback) {
-			pr_err("underrun! render stopped\n");
-			break;
-		}
-
-		buf = prtd->audio_client->port[IN].buf;
-		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
-				__func__, prtd->pcm_count, prtd->out_head);
-		temp = buf[0].phys + (prtd->out_head * prtd->pcm_count);
-		pr_debug("%s:writing buffer[%d] from 0x%pK\n",
-			__func__, prtd->out_head, &temp);
-
-		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
-			time_stamp_flag = SET_TIMESTAMP;
-		else
-			time_stamp_flag = NO_TIMESTAMP;
-		memcpy(&output_meta_data, (char *)(buf->data +
-			prtd->out_head * prtd->pcm_count),
-			COMPRE_OUTPUT_METADATA_SIZE);
-
-		buffer_length = output_meta_data.frame_size;
-		pr_debug("meta_data_length: %d, frame_length: %d\n",
-			 output_meta_data.meta_data_length,
-			 output_meta_data.frame_size);
-		pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
-			 output_meta_data.timestamp_msw,
-			 output_meta_data.timestamp_lsw);
-		if (buffer_length == 0) {
-			pr_debug("Received a zero length buffer-break out");
-			break;
-		}
-		param.paddr = temp + output_meta_data.meta_data_length;
-		param.len = buffer_length;
-		param.msw_ts = output_meta_data.timestamp_msw;
-		param.lsw_ts = output_meta_data.timestamp_lsw;
-		param.flags = time_stamp_flag;
-		param.uid = prtd->session_id;
-		for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
-					i++, ++ptrmem)
-			pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
-		if (q6asm_async_write(prtd->audio_client,
-					&param) < 0)
-			pr_err("%s:q6asm_async_write failed\n",
-				__func__);
-		else
-			prtd->out_head =
-				(prtd->out_head + 1) & (runtime->periods - 1);
-		break;
-	}
-	case ASM_DATA_EVENT_RENDERED_EOS:
-		pr_debug("ASM_DATA_CMDRSP_EOS\n");
-		if (atomic_read(&prtd->eos)) {
-			pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
-			prtd->cmd_ack = 1;
-			wake_up(&the_locks.eos_wait);
-			atomic_set(&prtd->eos, 0);
-		}
-		break;
-	case ASM_DATA_EVENT_READ_DONE_V2: {
-		pr_debug("ASM_DATA_EVENT_READ_DONE\n");
-		pr_debug("buf = %pK, data = 0x%X, *data = %pK,\n"
-			 "prtd->pcm_irq_pos = %d\n",
-				prtd->audio_client->port[OUT].buf,
-			 *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
-				prtd->audio_client->port[OUT].buf->data,
-				prtd->pcm_irq_pos);
-
-		memcpy(prtd->audio_client->port[OUT].buf->data +
-			   prtd->pcm_irq_pos, (ptrmem + READDONE_IDX_SIZE),
-			   COMPRE_CAPTURE_HEADER_SIZE);
-		pr_debug("buf = %pK, updated data = 0x%X, *data = %pK\n",
-				prtd->audio_client->port[OUT].buf,
-			*(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
-				prtd->pcm_irq_pos),
-				prtd->audio_client->port[OUT].buf->data);
-		if (!atomic_read(&prtd->start))
-			break;
-		pr_debug("frame size=%d, buffer = 0x%X\n",
-				ptrmem[READDONE_IDX_SIZE],
-				ptrmem[READDONE_IDX_BUFADD_LSW]);
-		if (ptrmem[READDONE_IDX_SIZE] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
-			pr_err("Frame length exceeded the max length");
-			break;
-		}
-		buf = prtd->audio_client->port[OUT].buf;
-
-		pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%pK\n",
-				prtd->pcm_irq_pos, &buf[0].phys);
-		read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
-		read_param.paddr = buf[0].phys +
-			prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
-		prtd->pcm_irq_pos += prtd->pcm_count;
-
-		if (atomic_read(&prtd->start))
-			snd_pcm_period_elapsed(substream);
-
-		q6asm_async_read(prtd->audio_client, &read_param);
-		break;
-	}
-	case APR_BASIC_RSP_RESULT: {
-		switch (payload[0]) {
-		case ASM_SESSION_CMD_RUN_V2: {
-			if (substream->stream
-				!= SNDRV_PCM_STREAM_PLAYBACK) {
-				atomic_set(&prtd->start, 1);
-				break;
-			}
-			if (!atomic_read(&prtd->pending_buffer))
-				break;
-			pr_debug("%s: writing %d bytes of buffer[%d] to dsp\n",
-				__func__, prtd->pcm_count, prtd->out_head);
-			buf = prtd->audio_client->port[IN].buf;
-			pr_debug("%s: writing buffer[%d] from 0x%pK head %d count %d\n",
-				__func__, prtd->out_head, &buf[0].phys,
-				prtd->pcm_count, prtd->out_head);
-			if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
-				time_stamp_flag = SET_TIMESTAMP;
-			else
-				time_stamp_flag = NO_TIMESTAMP;
-			memcpy(&output_meta_data, (char *)(buf->data +
-				prtd->out_head * prtd->pcm_count),
-				COMPRE_OUTPUT_METADATA_SIZE);
-			buffer_length = output_meta_data.frame_size;
-			pr_debug("meta_data_length: %d, frame_length: %d\n",
-				 output_meta_data.meta_data_length,
-				 output_meta_data.frame_size);
-			pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
-				 output_meta_data.timestamp_msw,
-				 output_meta_data.timestamp_lsw);
-			param.paddr = buf[prtd->out_head].phys
-					+ output_meta_data.meta_data_length;
-			param.len = buffer_length;
-			param.msw_ts = output_meta_data.timestamp_msw;
-			param.lsw_ts = output_meta_data.timestamp_lsw;
-			param.flags = time_stamp_flag;
-			param.uid = prtd->session_id;
-			param.metadata_len = COMPRE_OUTPUT_METADATA_SIZE;
-			if (q6asm_async_write(prtd->audio_client,
-						&param) < 0)
-				pr_err("%s:q6asm_async_write failed\n",
-					__func__);
-			else
-				prtd->out_head =
-					(prtd->out_head + 1)
-					& (runtime->periods - 1);
-			atomic_set(&prtd->pending_buffer, 0);
-		}
-			break;
-		case ASM_STREAM_CMD_FLUSH:
-			pr_debug("ASM_STREAM_CMD_FLUSH\n");
-			prtd->cmd_ack = 1;
-			wake_up(&the_locks.flush_wait);
-			break;
-		default:
-			break;
-		}
-		break;
-	}
-	default:
-		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
-		break;
-	}
-}
-
-static int msm_compr_send_ddp_cfg(struct audio_client *ac,
-					struct snd_dec_ddp *ddp)
-{
-	int i, rc;
-
-	pr_debug("%s\n", __func__);
-
-	if (ddp->params_length / 2 > SND_DEC_DDP_MAX_PARAMS) {
-		pr_err("%s: Invalid number of params %u, max allowed %u\n",
-			__func__, ddp->params_length / 2,
-			SND_DEC_DDP_MAX_PARAMS);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < ddp->params_length/2; i++) {
-		rc = q6asm_ds1_set_endp_params(ac, ddp->params_id[i],
-						ddp->params_value[i]);
-		if (rc) {
-			pr_err("sending params_id: %d failed\n",
-				ddp->params_id[i]);
-			return rc;
-		}
-	}
-	return 0;
-}
-
-static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr = runtime->private_data;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-	struct snd_pcm_hw_params *params;
-	struct asm_aac_cfg aac_cfg;
-	uint16_t bits_per_sample = 16;
-	int ret;
-
-	struct asm_softpause_params softpause = {
-		.enable = SOFT_PAUSE_ENABLE,
-		.period = SOFT_PAUSE_PERIOD,
-		.step = SOFT_PAUSE_STEP,
-		.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
-	};
-	struct asm_softvolume_params softvol = {
-		.period = SOFT_VOLUME_PERIOD,
-		.step = SOFT_VOLUME_STEP,
-		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
-	};
-
-	pr_debug("%s\n", __func__);
-
-	params = &soc_prtd->dpcm[substream->stream].hw_params;
-	if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
-		bits_per_sample = 24;
-
-	ret = q6asm_open_write_v2(prtd->audio_client,
-			compr->codec, bits_per_sample);
-	if (ret < 0) {
-		pr_err("%s: Session out open failed\n",
-				__func__);
-		return -ENOMEM;
-	}
-	msm_pcm_routing_reg_phy_stream(
-			soc_prtd->dai_link->id,
-			prtd->audio_client->perf_mode,
-			prtd->session_id,
-			substream->stream);
-	/*
-	 * the number of channels are required to call volume api
-	 * accoridngly. So, get channels from hw params
-	 */
-	if ((params_channels(params) > 0) &&
-			(params_periods(params) <= runtime->hw.channels_max))
-		prtd->channel_mode = params_channels(params);
-
-	ret = q6asm_set_softpause(prtd->audio_client, &softpause);
-	if (ret < 0)
-		pr_err("%s: Send SoftPause Param failed ret=%d\n",
-				__func__, ret);
-	ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
-	if (ret < 0)
-		pr_err("%s: Send SoftVolume Param failed ret=%d\n",
-				__func__, ret);
-
-	ret = q6asm_set_io_mode(prtd->audio_client,
-			(COMPRESSED_IO | ASYNC_IO_MODE));
-	if (ret < 0) {
-		pr_err("%s: Set IO mode failed\n", __func__);
-		return -ENOMEM;
-	}
-
-	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
-	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
-	prtd->pcm_irq_pos = 0;
-	/* rate and channels are sent to audio driver */
-	prtd->samp_rate = runtime->rate;
-	prtd->channel_mode = runtime->channels;
-	prtd->out_head = 0;
-	atomic_set(&prtd->out_count, runtime->periods);
-
-	if (prtd->enabled)
-		return 0;
-
-	switch (compr->info.codec_param.codec.id) {
-	case SND_AUDIOCODEC_MP3:
-		/* No media format block for mp3 */
-		break;
-	case SND_AUDIOCODEC_AAC:
-		pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
-		memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
-		aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
-		aac_cfg.format = 0x03;
-		aac_cfg.ch_cfg = runtime->channels;
-		aac_cfg.sample_rate =  runtime->rate;
-		ret = q6asm_media_format_block_aac(prtd->audio_client,
-					&aac_cfg);
-		if (ret < 0)
-			pr_err("%s: CMD Format block failed\n", __func__);
-		break;
-	case SND_AUDIOCODEC_AC3: {
-		struct snd_dec_ddp *ddp =
-				&compr->info.codec_param.codec.options.ddp;
-		pr_debug("%s: SND_AUDIOCODEC_AC3\n", __func__);
-		ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
-		if (ret < 0)
-			pr_err("%s: DDP CMD CFG failed\n", __func__);
-		break;
-	}
-	case SND_AUDIOCODEC_EAC3: {
-		struct snd_dec_ddp *ddp =
-				&compr->info.codec_param.codec.options.ddp;
-		pr_debug("%s: SND_AUDIOCODEC_EAC3\n", __func__);
-		ret = msm_compr_send_ddp_cfg(prtd->audio_client, ddp);
-		if (ret < 0)
-			pr_err("%s: DDP CMD CFG failed\n", __func__);
-		break;
-	}
-	default:
-		return -EINVAL;
-	}
-
-	prtd->enabled = 1;
-	prtd->cmd_ack = 0;
-	prtd->cmd_interrupt = 0;
-
-	return 0;
-}
-
-static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-	struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
-	struct snd_codec *codec = &compr->info.codec_param.codec;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
-	struct audio_aio_read_param read_param;
-	uint16_t bits_per_sample = 16;
-	int ret = 0;
-	int i;
-
-	prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
-	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
-	prtd->pcm_irq_pos = 0;
-
-	if (runtime->format == SNDRV_PCM_FORMAT_S24_LE)
-		bits_per_sample = 24;
-
-	if (!msm_compr_capture_codecs(
-				compr->info.codec_param.codec.id)) {
-		/*
-		 * request codec invalid or not supported,
-		 * use default compress format
-		 */
-		compr->info.codec_param.codec.id =
-			SND_AUDIOCODEC_AMRWB;
-	}
-	switch (compr->info.codec_param.codec.id) {
-	case SND_AUDIOCODEC_AMRWB:
-		pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
-		ret = q6asm_open_read(prtd->audio_client,
-				FORMAT_AMRWB);
-		if (ret < 0) {
-			pr_err("%s: compressed Session out open failed\n",
-					__func__);
-			return -ENOMEM;
-		}
-		pr_debug("msm_pcm_routing_reg_phy_stream\n");
-		msm_pcm_routing_reg_phy_stream(
-				soc_prtd->dai_link->id,
-				prtd->audio_client->perf_mode,
-				prtd->session_id, substream->stream);
-		break;
-	default:
-		pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
-		/*
-		 * ret = q6asm_open_read_compressed(prtd->audio_client,
-		 * MAX_NUM_FRAMES_PER_BUFFER,
-		 * COMPRESSED_META_DATA_MODE);
-		 */
-			ret = -EINVAL;
-			break;
-	}
-
-	if (ret < 0) {
-		pr_err("%s: compressed Session out open failed\n",
-				__func__);
-		return -ENOMEM;
-	}
-
-	ret = q6asm_set_io_mode(prtd->audio_client,
-		(COMPRESSED_IO | ASYNC_IO_MODE));
-		if (ret < 0) {
-			pr_err("%s: Set IO mode failed\n", __func__);
-				return -ENOMEM;
-		}
-
-	if (!msm_compr_capture_codecs(codec->id)) {
-		/*
-		 * request codec invalid or not supported,
-		 * use default compress format
-		 */
-		codec->id = SND_AUDIOCODEC_AMRWB;
-	}
-	/* rate and channels are sent to audio driver */
-	prtd->samp_rate = runtime->rate;
-	prtd->channel_mode = runtime->channels;
-
-	if (prtd->enabled)
-		return ret;
-	read_param.len = prtd->pcm_count;
-
-	switch (codec->id) {
-	case SND_AUDIOCODEC_AMRWB:
-		pr_debug("SND_AUDIOCODEC_AMRWB\n");
-		ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
-			MAX_NUM_FRAMES_PER_BUFFER,
-			/*
-			 * use fixed band mode and dtx mode
-			 * band mode - 23.85 kbps
-			 */
-			AMR_WB_BAND_MODE,
-			/* dtx mode - disable */
-			AMR_WB_DTX_MODE);
-		if (ret < 0)
-			pr_err("%s: CMD Format block failed: %d\n",
-				__func__, ret);
-		break;
-	default:
-		pr_debug("No config for codec %d\n", codec->id);
-	}
-	pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
-			 "pcm_count = %d, periods = %d\n",
-			 __func__, prtd->samp_rate, prtd->channel_mode,
-			 prtd->pcm_size, prtd->pcm_count, runtime->periods);
-
-	for (i = 0; i < runtime->periods; i++) {
-		read_param.uid = i;
-		switch (codec->id) {
-		case SND_AUDIOCODEC_AMRWB:
-			read_param.len = prtd->pcm_count
-					- COMPRE_CAPTURE_HEADER_SIZE;
-			read_param.paddr = buf[i].phys
-					+ COMPRE_CAPTURE_HEADER_SIZE;
-			pr_debug("Push buffer [%d] to DSP, paddr: %pK, vaddr: %pK\n",
-					i, &read_param.paddr,
-					buf[i].data);
-			q6asm_async_read(prtd->audio_client, &read_param);
-			break;
-		default:
-			read_param.paddr = buf[i].phys;
-			/* q6asm_async_read_compressed(prtd->audio_client,
-			 * &read_param);
-			 */
-			pr_debug("%s: To add support for read compressed\n",
-								__func__);
-			ret = -EINVAL;
-			break;
-		}
-	}
-	prtd->periods = runtime->periods;
-
-	prtd->enabled = 1;
-
-	return ret;
-}
-
-static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	int ret = 0;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-
-	pr_debug("%s\n", __func__);
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		prtd->pcm_irq_pos = 0;
-
-		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			if (!msm_compr_capture_codecs(
-				compr->info.codec_param.codec.id)) {
-				/*
-				 * request codec invalid or not supported,
-				 * use default compress format
-				 */
-				compr->info.codec_param.codec.id =
-				SND_AUDIOCODEC_AMRWB;
-			}
-			switch (compr->info.codec_param.codec.id) {
-			case SND_AUDIOCODEC_AMRWB:
-				break;
-			default:
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->id,
-					prtd->session_id, substream->stream);
-				break;
-			}
-		}
-		atomic_set(&prtd->pending_buffer, 1);
-		/* fallthrough */
-	case SNDRV_PCM_TRIGGER_RESUME:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		pr_debug("%s: Trigger start\n", __func__);
-		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
-		atomic_set(&prtd->start, 1);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
-		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			switch (compr->info.codec_param.codec.id) {
-			case SND_AUDIOCODEC_AMRWB:
-				break;
-			default:
-				msm_pcm_routing_reg_psthr_stream(
-					soc_prtd->dai_link->id,
-					prtd->session_id, substream->stream);
-				break;
-			}
-		}
-		atomic_set(&prtd->start, 0);
-		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
-		break;
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
-		q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
-		atomic_set(&prtd->start, 0);
-		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static void populate_codec_list(struct compr_audio *compr,
-		struct snd_pcm_runtime *runtime)
-{
-	pr_debug("%s\n", __func__);
-	/* MP3 Block */
-	compr->info.compr_cap.num_codecs = 5;
-	compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
-	compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
-	compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
-	compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
-	compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
-	compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
-	compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
-	compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
-	compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_AMRWB;
-	/* Add new codecs here */
-}
-
-static int msm_compr_open(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr;
-	struct msm_audio *prtd;
-	int ret = 0;
-
-	pr_debug("%s\n", __func__);
-	compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
-	if (compr == NULL) {
-		pr_err("Failed to allocate memory for msm_audio\n");
-		return -ENOMEM;
-	}
-	prtd = &compr->prtd;
-	prtd->substream = substream;
-	runtime->render_flag = SNDRV_DMA_MODE;
-	prtd->audio_client = q6asm_audio_client_alloc(
-				(app_cb)compr_event_handler, compr);
-	if (!prtd->audio_client) {
-		pr_info("%s: Could not allocate memory\n", __func__);
-		kfree(prtd);
-		return -ENOMEM;
-	}
-
-	prtd->audio_client->perf_mode = false;
-	pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
-
-	prtd->session_id = prtd->audio_client->session;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		runtime->hw = msm_compr_hardware_playback;
-		prtd->cmd_ack = 1;
-	} else {
-		runtime->hw = msm_compr_hardware_capture;
-	}
-
-
-	ret = snd_pcm_hw_constraint_list(runtime, 0,
-			SNDRV_PCM_HW_PARAM_RATE,
-			&constraints_sample_rates);
-	if (ret < 0)
-		pr_info("snd_pcm_hw_constraint_list failed\n");
-	/* Ensure that buffer size is a multiple of period size */
-	ret = snd_pcm_hw_constraint_integer(runtime,
-			    SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		pr_info("snd_pcm_hw_constraint_integer failed\n");
-
-	prtd->dsp_cnt = 0;
-	atomic_set(&prtd->pending_buffer, 1);
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		compr->codec = FORMAT_MP3;
-	populate_codec_list(compr, runtime);
-	runtime->private_data = compr;
-	atomic_set(&prtd->eos, 0);
-	return 0;
-}
-
-static int compressed_set_volume(struct msm_audio *prtd, uint32_t volume)
-{
-	int rc = 0;
-	int avg_vol = 0;
-	int lgain = (volume >> 16) & 0xFFFF;
-	int rgain = volume & 0xFFFF;
-
-	if (prtd && prtd->audio_client) {
-		pr_debug("%s: channels %d volume 0x%x\n", __func__,
-			prtd->channel_mode, volume);
-		if ((prtd->channel_mode == 2) &&
-			(lgain != rgain)) {
-			pr_debug("%s: call q6asm_set_lrgain\n", __func__);
-			rc = q6asm_set_lrgain(prtd->audio_client, lgain, rgain);
-		} else {
-			avg_vol = (lgain + rgain)/2;
-			pr_debug("%s: call q6asm_set_volume\n", __func__);
-			rc = q6asm_set_volume(prtd->audio_client, avg_vol);
-		}
-		if (rc < 0) {
-			pr_err("%s: Send Volume command failed rc=%d\n",
-				__func__, rc);
-		}
-	}
-	return rc;
-}
-
-static int msm_compr_playback_close(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-	int dir = 0;
-
-	pr_debug("%s\n", __func__);
-
-	dir = IN;
-	atomic_set(&prtd->pending_buffer, 0);
-
-	prtd->pcm_irq_pos = 0;
-	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
-	q6asm_audio_client_buf_free_contiguous(dir,
-				prtd->audio_client);
-		msm_pcm_routing_dereg_phy_stream(
-			soc_prtd->dai_link->id,
-			SNDRV_PCM_STREAM_PLAYBACK);
-	q6asm_audio_client_free(prtd->audio_client);
-	kfree(prtd);
-	return 0;
-}
-
-static int msm_compr_capture_close(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-	int dir = OUT;
-
-	pr_debug("%s\n", __func__);
-	atomic_set(&prtd->pending_buffer, 0);
-	q6asm_cmd(prtd->audio_client, CMD_CLOSE);
-	q6asm_audio_client_buf_free_contiguous(dir,
-				prtd->audio_client);
-	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
-				SNDRV_PCM_STREAM_CAPTURE);
-	q6asm_audio_client_free(prtd->audio_client);
-	kfree(prtd);
-	return 0;
-}
-
-static int msm_compr_close(struct snd_pcm_substream *substream)
-{
-	int ret = 0;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		ret = msm_compr_playback_close(substream);
-	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		ret = msm_compr_capture_close(substream);
-	return ret;
-}
-
-static int msm_compr_prepare(struct snd_pcm_substream *substream)
-{
-	int ret = 0;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		ret = msm_compr_playback_prepare(substream);
-	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-		ret = msm_compr_capture_prepare(substream);
-	return ret;
-}
-
-static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
-{
-
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-
-	if (prtd->pcm_irq_pos >= prtd->pcm_size)
-		prtd->pcm_irq_pos = 0;
-
-	pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
-			 "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
-			 prtd->pcm_size, runtime->sample_bits,
-			 runtime->frame_bits);
-	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
-}
-
-static int msm_compr_mmap(struct snd_pcm_substream *substream,
-				struct vm_area_struct *vma)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct msm_audio *prtd = runtime->private_data;
-	struct audio_client *ac = prtd->audio_client;
-	struct audio_port_data *apd = ac->port;
-	struct audio_buffer *ab;
-	int dir = -1;
-
-	prtd->mmap_flag = 1;
-	runtime->render_flag = SNDRV_NON_DMA_MODE;
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dir = IN;
-	else
-		dir = OUT;
-	ab = &(apd[dir].buf[0]);
-
-	return msm_audio_ion_mmap(ab, vma);
-}
-
-static int msm_compr_hw_params(struct snd_pcm_substream *substream,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
-	struct audio_buffer *buf;
-	int dir, ret;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dir = IN;
-	else
-		dir = OUT;
-	/* Modifying kernel hardware params based on userspace config */
-	if (params_periods(params) > 0 &&
-		(params_periods(params) != runtime->hw.periods_max)) {
-		runtime->hw.periods_max = params_periods(params);
-	}
-	if (params_period_bytes(params) > 0 &&
-		(params_period_bytes(params) != runtime->hw.period_bytes_min)) {
-		runtime->hw.period_bytes_min = params_period_bytes(params);
-	}
-	runtime->hw.buffer_bytes_max =
-			runtime->hw.period_bytes_min * runtime->hw.periods_max;
-	pr_debug("allocate %zd buffers each of size %d\n",
-		runtime->hw.period_bytes_min,
-		runtime->hw.periods_max);
-	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
-			prtd->audio_client,
-			runtime->hw.period_bytes_min,
-			runtime->hw.periods_max);
-	if (ret < 0) {
-		pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
-						ret);
-		return -ENOMEM;
-	}
-	buf = prtd->audio_client->port[dir].buf;
-
-	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
-	dma_buf->dev.dev = substream->pcm->card->dev;
-	dma_buf->private_data = NULL;
-	dma_buf->area = buf[0].data;
-	dma_buf->addr =  buf[0].phys;
-	dma_buf->bytes = runtime->hw.buffer_bytes_max;
-
-	pr_debug("%s: buf[%pK]dma_buf->area[%pK]dma_buf->addr[%pK]\n"
-		 "dma_buf->bytes[%zd]\n", __func__,
-		 (void *)buf, (void *)dma_buf->area,
-		 &dma_buf->addr, dma_buf->bytes);
-	if (!dma_buf->area)
-		return -ENOMEM;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	return 0;
-}
-
-static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream,
-		unsigned int cmd, void *arg)
-{
-	int rc = 0;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-	uint64_t timestamp;
-	uint64_t temp;
-
-	switch (cmd) {
-	case SNDRV_COMPRESS_TSTAMP: {
-		struct snd_compr_tstamp *tstamp;
-
-		pr_debug("SNDRV_COMPRESS_TSTAMP\n");
-		tstamp = arg;
-		memset(tstamp, 0x0, sizeof(*tstamp));
-		rc = q6asm_get_session_time(prtd->audio_client, &timestamp);
-		if (rc < 0) {
-			pr_err("%s: Get Session Time return value =%lld\n",
-				__func__, timestamp);
-			return -EAGAIN;
-		}
-		temp = (timestamp * 2 * runtime->channels);
-		temp = temp * (runtime->rate/1000);
-		temp = div_u64(temp, 1000);
-		tstamp->sampling_rate = runtime->rate;
-		tstamp->timestamp = timestamp;
-		pr_debug("%s: bytes_consumed:,timestamp = %lld,\n",
-						__func__,
-			tstamp->timestamp);
-		return 0;
-	}
-	case SNDRV_COMPRESS_GET_CAPS: {
-		struct snd_compr_caps *caps;
-
-		caps = arg;
-		memset(caps, 0, sizeof(*caps));
-		pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
-		memcpy(caps, &compr->info.compr_cap, sizeof(*caps));
-		return 0;
-	}
-	case SNDRV_COMPRESS_SET_PARAMS:
-		pr_debug("SNDRV_COMPRESS_SET_PARAMS:\n");
-		memcpy(&compr->info.codec_param, (void *) arg,
-			sizeof(struct snd_compr_params));
-		switch (compr->info.codec_param.codec.id) {
-		case SND_AUDIOCODEC_MP3:
-			/* For MP3 we dont need any other parameter */
-			pr_debug("SND_AUDIOCODEC_MP3\n");
-			compr->codec = FORMAT_MP3;
-			break;
-		case SND_AUDIOCODEC_AAC:
-			pr_debug("SND_AUDIOCODEC_AAC\n");
-			compr->codec = FORMAT_MPEG4_AAC;
-			break;
-		case SND_AUDIOCODEC_AC3: {
-			char params_value[MAX_AC3_PARAM_SIZE];
-			int *params_value_data = (int *)params_value;
-			/* 36 is the max param length for ddp */
-			int i;
-			struct snd_dec_ddp *ddp =
-				&compr->info.codec_param.codec.options.ddp;
-			uint32_t params_length = 0;
-
-			memset(params_value, 0, MAX_AC3_PARAM_SIZE);
-			/* check integer overflow */
-			if (ddp->params_length > UINT_MAX/sizeof(int)) {
-				pr_err("%s: Integer overflow ddp->params_length %d\n",
-				__func__, ddp->params_length);
-				return -EINVAL;
-			}
-			params_length = ddp->params_length*sizeof(int);
-			if (params_length > MAX_AC3_PARAM_SIZE) {
-				/*MAX is 36*sizeof(int) this should not happen*/
-				pr_err("%s: params_length(%d) is greater than %zd\n",
-				__func__, params_length, MAX_AC3_PARAM_SIZE);
-				return -EINVAL;
-			}
-			pr_debug("SND_AUDIOCODEC_AC3\n");
-			compr->codec = FORMAT_AC3;
-			pr_debug("params_length: %d\n", ddp->params_length);
-			for (i = 0; i < params_length/sizeof(int); i++)
-				pr_debug("params_value[%d]: %x\n", i,
-					params_value_data[i]);
-			for (i = 0; i < ddp->params_length/2; i++) {
-				ddp->params_id[i] = params_value_data[2*i];
-				ddp->params_value[i] = params_value_data[2*i+1];
-			}
-			if (atomic_read(&prtd->start)) {
-				rc = msm_compr_send_ddp_cfg(prtd->audio_client,
-								ddp);
-				if (rc < 0)
-					pr_err("%s: DDP CMD CFG failed\n",
-						__func__);
-			}
-			break;
-		}
-		case SND_AUDIOCODEC_EAC3: {
-			char params_value[MAX_AC3_PARAM_SIZE];
-			int *params_value_data = (int *)params_value;
-			/* 36 is the max param length for ddp */
-			int i;
-			struct snd_dec_ddp *ddp =
-				&compr->info.codec_param.codec.options.ddp;
-			uint32_t params_length = 0;
-
-			memset(params_value, 0, MAX_AC3_PARAM_SIZE);
-			/* check integer overflow */
-			if (ddp->params_length > UINT_MAX/sizeof(int)) {
-				pr_err("%s: Integer overflow ddp->params_length %d\n",
-				__func__, ddp->params_length);
-				return -EINVAL;
-			}
-			params_length = ddp->params_length*sizeof(int);
-			if (params_length > MAX_AC3_PARAM_SIZE) {
-				/*MAX is 36*sizeof(int) this should not happen*/
-				pr_err("%s: params_length(%d) is greater than %zd\n",
-				__func__, params_length, MAX_AC3_PARAM_SIZE);
-				return -EINVAL;
-			}
-			pr_debug("SND_AUDIOCODEC_EAC3\n");
-			compr->codec = FORMAT_EAC3;
-			pr_debug("params_length: %d\n", ddp->params_length);
-			for (i = 0; i < ddp->params_length; i++)
-				pr_debug("params_value[%d]: %x\n", i,
-					params_value_data[i]);
-			for (i = 0; i < ddp->params_length/2; i++) {
-				ddp->params_id[i] = params_value_data[2*i];
-				ddp->params_value[i] = params_value_data[2*i+1];
-			}
-			if (atomic_read(&prtd->start)) {
-				rc = msm_compr_send_ddp_cfg(prtd->audio_client,
-								ddp);
-				if (rc < 0)
-					pr_err("%s: DDP CMD CFG failed\n",
-						__func__);
-			}
-			break;
-		}
-		default:
-			pr_debug("FORMAT_LINEAR_PCM\n");
-			compr->codec = FORMAT_LINEAR_PCM;
-			break;
-		}
-		return 0;
-	case SNDRV_PCM_IOCTL1_RESET:
-		pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
-		/* Flush only when session is started during CAPTURE,
-		 * while PLAYBACK has no such restriction.
-		 */
-		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-			  (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
-						atomic_read(&prtd->start))) {
-			if (atomic_read(&prtd->eos)) {
-				prtd->cmd_interrupt = 1;
-				wake_up(&the_locks.eos_wait);
-				atomic_set(&prtd->eos, 0);
-			}
-
-			/* A unlikely race condition possible with FLUSH
-			 * DRAIN if ack is set by flush and reset by drain
-			 */
-			prtd->cmd_ack = 0;
-			rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
-			if (rc < 0) {
-				pr_err("%s: flush cmd failed rc=%d\n",
-					__func__, rc);
-				return rc;
-			}
-			rc = wait_event_timeout(the_locks.flush_wait,
-				prtd->cmd_ack, 5 * HZ);
-			if (!rc)
-				pr_err("Flush cmd timeout\n");
-			prtd->pcm_irq_pos = 0;
-		}
-		break;
-	case SNDRV_COMPRESS_DRAIN:
-		pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
-		if (atomic_read(&prtd->pending_buffer)) {
-			pr_debug("%s: no pending writes, drain would block\n",
-			 __func__);
-			return -EWOULDBLOCK;
-		}
-
-		atomic_set(&prtd->eos, 1);
-		atomic_set(&prtd->pending_buffer, 0);
-		prtd->cmd_ack = 0;
-		q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
-		/* Wait indefinitely for  DRAIN. Flush can also signal this*/
-		rc = wait_event_interruptible(the_locks.eos_wait,
-			(prtd->cmd_ack || prtd->cmd_interrupt));
-
-		if (rc < 0)
-			pr_err("EOS cmd interrupted\n");
-		pr_debug("%s: SNDRV_COMPRESS_DRAIN  out of wait\n", __func__);
-
-		if (prtd->cmd_interrupt)
-			rc = -EINTR;
-
-		prtd->cmd_interrupt = 0;
-		return rc;
-	default:
-		break;
-	}
-	return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-#ifdef CONFIG_COMPAT
-struct snd_enc_wma32 {
-	u32 super_block_align; /* WMA Type-specific data */
-	u32 encodeopt1;
-	u32 encodeopt2;
-};
-
-struct snd_enc_vorbis32 {
-	s32 quality;
-	u32 managed;
-	u32 max_bit_rate;
-	u32 min_bit_rate;
-	u32 downmix;
-};
-
-struct snd_enc_real32 {
-	u32 quant_bits;
-	u32 start_region;
-	u32 num_regions;
-};
-
-struct snd_enc_flac32 {
-	u32 num;
-	u32 gain;
-};
-
-struct snd_enc_generic32 {
-	u32 bw;	/* encoder bandwidth */
-	s32 reserved[15];
-};
-struct snd_dec_ddp32 {
-	u32 params_length;
-	u32 params_id[18];
-	u32 params_value[18];
-};
-
-union snd_codec_options32 {
-	struct snd_enc_wma32 wma;
-	struct snd_enc_vorbis32 vorbis;
-	struct snd_enc_real32 real;
-	struct snd_enc_flac32 flac;
-	struct snd_enc_generic32 generic;
-	struct snd_dec_ddp32 ddp;
-};
-
-struct snd_codec32 {
-	u32 id;
-	u32 ch_in;
-	u32 ch_out;
-	u32 sample_rate;
-	u32 bit_rate;
-	u32 rate_control;
-	u32 profile;
-	u32 level;
-	u32 ch_mode;
-	u32 format;
-	u32 align;
-	union snd_codec_options32 options;
-	u32 reserved[3];
-};
-
-struct snd_compressed_buffer32 {
-	u32 fragment_size;
-	u32 fragments;
-};
-
-struct snd_compr_params32 {
-	struct snd_compressed_buffer32 buffer;
-	struct snd_codec32 codec;
-	u8 no_wake_mode;
-};
-
-struct snd_compr_caps32 {
-	u32 num_codecs;
-	u32 direction;
-	u32 min_fragment_size;
-	u32 max_fragment_size;
-	u32 min_fragments;
-	u32 max_fragments;
-	u32 codecs[MAX_NUM_CODECS];
-	u32 reserved[11];
-};
-struct snd_compr_tstamp32 {
-	u32 byte_offset;
-	u32 copied_total;
-	compat_ulong_t pcm_frames;
-	compat_ulong_t pcm_io_frames;
-	u32 sampling_rate;
-	compat_u64 timestamp;
-};
-enum {
-	SNDRV_COMPRESS_TSTAMP32 = _IOR('C', 0x20, struct snd_compr_tstamp32),
-	SNDRV_COMPRESS_GET_CAPS32 = _IOWR('C', 0x10, struct snd_compr_caps32),
-	SNDRV_COMPRESS_SET_PARAMS32 =
-	_IOW('C', 0x12, struct snd_compr_params32),
-};
-static int msm_compr_compat_ioctl(struct snd_pcm_substream *substream,
-		unsigned int cmd, void *arg)
-{
-	int err = 0;
-
-	switch (cmd) {
-	case SNDRV_COMPRESS_TSTAMP32: {
-		struct snd_compr_tstamp tstamp;
-		struct snd_compr_tstamp32 tstamp32;
-
-		memset(&tstamp, 0, sizeof(tstamp));
-		memset(&tstamp32, 0, sizeof(tstamp32));
-		cmd = SNDRV_COMPRESS_TSTAMP;
-		err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
-		if (err) {
-			pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
-			__func__, err);
-			goto bail_out;
-		}
-		tstamp32.byte_offset = tstamp.byte_offset;
-		tstamp32.copied_total = tstamp.copied_total;
-		tstamp32.pcm_frames = tstamp.pcm_frames;
-		tstamp32.pcm_io_frames = tstamp.pcm_io_frames;
-		tstamp32.sampling_rate = tstamp.sampling_rate;
-		tstamp32.timestamp = tstamp.timestamp;
-		if (copy_to_user(arg, &tstamp32, sizeof(tstamp32))) {
-			pr_err("%s: copytouser failed COMPRESS_TSTAMP32\n",
-			__func__);
-			err = -EFAULT;
-		}
-		break;
-	}
-	case SNDRV_COMPRESS_GET_CAPS32: {
-		struct snd_compr_caps caps;
-		struct snd_compr_caps32 caps32;
-		u32 i;
-
-		memset(&caps, 0, sizeof(caps));
-		memset(&caps32, 0, sizeof(caps32));
-		cmd = SNDRV_COMPRESS_GET_CAPS;
-		err = msm_compr_ioctl_shared(substream, cmd, &caps);
-		if (err) {
-			pr_err("%s: GET_CAPS failed rc %d\n",
-			__func__, err);
-			goto bail_out;
-		}
-		pr_debug("SNDRV_COMPRESS_GET_CAPS_32\n");
-		if (!err && caps.num_codecs >= MAX_NUM_CODECS) {
-			pr_err("%s: Invalid number of codecs\n", __func__);
-			err = -EINVAL;
-			goto bail_out;
-		}
-		caps32.direction = caps.direction;
-		caps32.max_fragment_size = caps.max_fragment_size;
-		caps32.max_fragments = caps.max_fragments;
-		caps32.min_fragment_size = caps.min_fragment_size;
-		caps32.num_codecs = caps.num_codecs;
-		for (i = 0; i < caps.num_codecs; i++)
-			caps32.codecs[i] = caps.codecs[i];
-		if (copy_to_user(arg, &caps32, sizeof(caps32))) {
-			pr_err("%s: copytouser failed COMPRESS_GETCAPS32\n",
-			__func__);
-			err = -EFAULT;
-		}
-		break;
-	}
-	case SNDRV_COMPRESS_SET_PARAMS32: {
-		struct snd_compr_params32 params32;
-		struct snd_compr_params params;
-
-		memset(&params32, 0, sizeof(params32));
-		memset(&params, 0, sizeof(params));
-		cmd = SNDRV_COMPRESS_SET_PARAMS;
-		if (copy_from_user(&params32, arg, sizeof(params32))) {
-			pr_err("%s: copyfromuser failed SET_PARAMS32\n",
-			__func__);
-			err = -EFAULT;
-			goto bail_out;
-		}
-		params.no_wake_mode = params32.no_wake_mode;
-		params.codec.id = params32.codec.id;
-		params.codec.ch_in = params32.codec.ch_in;
-		params.codec.ch_out = params32.codec.ch_out;
-		params.codec.sample_rate = params32.codec.sample_rate;
-		params.codec.bit_rate = params32.codec.bit_rate;
-		params.codec.rate_control = params32.codec.rate_control;
-		params.codec.profile = params32.codec.profile;
-		params.codec.level = params32.codec.level;
-		params.codec.ch_mode = params32.codec.ch_mode;
-		params.codec.format = params32.codec.format;
-		params.codec.align = params32.codec.align;
-
-		switch (params.codec.id) {
-		case SND_AUDIOCODEC_WMA:
-		case SND_AUDIOCODEC_WMA_PRO:
-			params.codec.options.wma.encodeopt1 =
-			params32.codec.options.wma.encodeopt1;
-			params.codec.options.wma.encodeopt2 =
-			params32.codec.options.wma.encodeopt2;
-			params.codec.options.wma.super_block_align =
-			params32.codec.options.wma.super_block_align;
-		break;
-		case SND_AUDIOCODEC_VORBIS:
-			params.codec.options.vorbis.downmix =
-			params32.codec.options.vorbis.downmix;
-			params.codec.options.vorbis.managed =
-			params32.codec.options.vorbis.managed;
-			params.codec.options.vorbis.max_bit_rate =
-			params32.codec.options.vorbis.max_bit_rate;
-			params.codec.options.vorbis.min_bit_rate =
-			params32.codec.options.vorbis.min_bit_rate;
-			params.codec.options.vorbis.quality =
-			params32.codec.options.vorbis.quality;
-		break;
-		case SND_AUDIOCODEC_REAL:
-			params.codec.options.real.num_regions =
-			params32.codec.options.real.num_regions;
-			params.codec.options.real.quant_bits =
-			params32.codec.options.real.quant_bits;
-			params.codec.options.real.start_region =
-			params32.codec.options.real.start_region;
-		break;
-		case SND_AUDIOCODEC_FLAC:
-			params.codec.options.flac.gain =
-			params32.codec.options.flac.gain;
-			params.codec.options.flac.num =
-			params32.codec.options.flac.num;
-		break;
-		case SND_AUDIOCODEC_DTS:
-		case SND_AUDIOCODEC_DTS_PASS_THROUGH:
-		case SND_AUDIOCODEC_DTS_LBR:
-		case SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH:
-		case SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK:
-		break;
-		case SND_AUDIOCODEC_AC3:
-		case SND_AUDIOCODEC_EAC3:
-			params.codec.options.ddp.params_length =
-			params32.codec.options.ddp.params_length;
-			memcpy(params.codec.options.ddp.params_value,
-			params32.codec.options.ddp.params_value,
-			sizeof(params32.codec.options.ddp.params_value));
-			memcpy(params.codec.options.ddp.params_id,
-			params32.codec.options.ddp.params_id,
-			sizeof(params32.codec.options.ddp.params_id));
-		break;
-		default:
-			params.codec.options.generic.bw =
-			params32.codec.options.generic.bw;
-		break;
-		}
-		if (!err)
-			err = msm_compr_ioctl_shared(substream, cmd, &params);
-		break;
-	}
-	default:
-		err = msm_compr_ioctl_shared(substream, cmd, arg);
-	}
-bail_out:
-	return err;
-
-}
-#endif
-static int msm_compr_ioctl(struct snd_pcm_substream *substream,
-		unsigned int cmd, void *arg)
-{
-	int err = 0;
-
-	if (!substream) {
-		pr_err("%s: Invalid params\n", __func__);
-		return -EINVAL;
-	}
-	pr_debug("%s called with cmd = %d\n", __func__, cmd);
-	switch (cmd) {
-	case SNDRV_COMPRESS_TSTAMP: {
-		struct snd_compr_tstamp tstamp;
-
-		if (!arg) {
-			pr_err("%s: Invalid params Tstamp\n", __func__);
-			return -EINVAL;
-		}
-		err = msm_compr_ioctl_shared(substream, cmd, &tstamp);
-		if (err)
-			pr_err("%s: COMPRESS_TSTAMP failed rc %d\n",
-			__func__, err);
-		if (!err && copy_to_user(arg, &tstamp, sizeof(tstamp))) {
-			pr_err("%s: copytouser failed COMPRESS_TSTAMP\n",
-			__func__);
-			err = -EFAULT;
-		}
-		break;
-	}
-	case SNDRV_COMPRESS_GET_CAPS: {
-		struct snd_compr_caps cap;
-
-		if (!arg) {
-			pr_err("%s: Invalid params getcaps\n", __func__);
-			return -EINVAL;
-		}
-		pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
-		err = msm_compr_ioctl_shared(substream, cmd, &cap);
-		if (err)
-			pr_err("%s: GET_CAPS failed rc %d\n",
-			__func__, err);
-		if (!err && copy_to_user(arg, &cap, sizeof(cap))) {
-			pr_err("%s: copytouser failed GET_CAPS\n",
-			__func__);
-			err = -EFAULT;
-		}
-		break;
-	}
-	case SNDRV_COMPRESS_SET_PARAMS: {
-		struct snd_compr_params params;
-
-		if (!arg) {
-			pr_err("%s: Invalid params setparam\n", __func__);
-			return -EINVAL;
-		}
-		if (copy_from_user(&params, arg,
-			sizeof(struct snd_compr_params))) {
-			pr_err("%s: SET_PARAMS\n", __func__);
-			return -EFAULT;
-		}
-		err = msm_compr_ioctl_shared(substream, cmd, &params);
-		if (err)
-			pr_err("%s: SET_PARAMS failed rc %d\n",
-			__func__, err);
-		break;
-	}
-	default:
-		err = msm_compr_ioctl_shared(substream, cmd, arg);
-	}
-	return err;
-}
-
-static int msm_compr_restart(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct compr_audio *compr = runtime->private_data;
-	struct msm_audio *prtd = &compr->prtd;
-	struct audio_aio_write_param param;
-	struct audio_buffer *buf = NULL;
-	struct output_meta_data_st output_meta_data;
-	int time_stamp_flag = 0;
-	int buffer_length = 0;
-
-	pr_debug("%s, trigger restart\n", __func__);
-
-	if (runtime->render_flag & SNDRV_RENDER_STOPPED) {
-		buf = prtd->audio_client->port[IN].buf;
-		pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
-				__func__, prtd->pcm_count, prtd->out_head);
-		pr_debug("%s:writing buffer[%d] from 0x%08x\n",
-				__func__, prtd->out_head,
-				((unsigned int)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count)));
-
-		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
-			time_stamp_flag = SET_TIMESTAMP;
-		else
-			time_stamp_flag = NO_TIMESTAMP;
-		memcpy(&output_meta_data, (char *)(buf->data +
-			prtd->out_head * prtd->pcm_count),
-			COMPRE_OUTPUT_METADATA_SIZE);
-
-		buffer_length = output_meta_data.frame_size;
-		pr_debug("meta_data_length: %d, frame_length: %d\n",
-			 output_meta_data.meta_data_length,
-			 output_meta_data.frame_size);
-		pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
-			 output_meta_data.timestamp_msw,
-			 output_meta_data.timestamp_lsw);
-
-		param.paddr = (unsigned long)buf[0].phys
-				+ (prtd->out_head * prtd->pcm_count)
-				+ output_meta_data.meta_data_length;
-		param.len = buffer_length;
-		param.msw_ts = output_meta_data.timestamp_msw;
-		param.lsw_ts = output_meta_data.timestamp_lsw;
-		param.flags = time_stamp_flag;
-		param.uid = prtd->session_id;
-		if (q6asm_async_write(prtd->audio_client,
-					&param) < 0)
-			pr_err("%s:q6asm_async_write failed\n",
-				__func__);
-		else
-			prtd->out_head =
-				(prtd->out_head + 1) & (runtime->periods - 1);
-
-		runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
-		return 0;
-	}
-	return 0;
-}
-
-static int msm_compr_volume_ctl_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	int rc = 0;
-	struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
-	struct snd_pcm_substream *substream =
-			 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-	struct msm_audio *prtd;
-	int volume = ucontrol->value.integer.value[0];
-
-	pr_debug("%s: volume : %x\n", __func__, volume);
-	if (!substream)
-		return -ENODEV;
-	if (!substream->runtime)
-		return 0;
-	prtd = substream->runtime->private_data;
-	if (prtd)
-		rc = compressed_set_volume(prtd, volume);
-
-	return rc;
-}
-
-static int msm_compr_volume_ctl_get(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
-	struct snd_pcm_substream *substream =
-			 vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-	struct msm_audio *prtd;
-
-	pr_debug("%s\n", __func__);
-	if (!substream)
-		return -ENODEV;
-	if (!substream->runtime)
-		return 0;
-	prtd = substream->runtime->private_data;
-	if (prtd)
-		ucontrol->value.integer.value[0] = prtd->volume;
-	return 0;
-}
-
-static int msm_compr_add_controls(struct snd_soc_pcm_runtime *rtd)
-{
-	int ret = 0;
-	struct snd_pcm *pcm = rtd->pcm;
-	struct snd_pcm_volume *volume_info;
-	struct snd_kcontrol *kctl;
-
-	dev_dbg(rtd->dev, "%s, Volume cntrl add\n", __func__);
-	ret = snd_pcm_add_volume_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-				      NULL, 1, rtd->dai_link->id,
-				      &volume_info);
-	if (ret < 0)
-		return ret;
-	kctl = volume_info->kctl;
-	kctl->put = msm_compr_volume_ctl_put;
-	kctl->get = msm_compr_volume_ctl_get;
-	kctl->tlv.p = compr_rx_vol_gain;
-	return 0;
-}
-
-static const struct snd_pcm_ops msm_compr_ops = {
-	.open	   = msm_compr_open,
-	.hw_params	= msm_compr_hw_params,
-	.close	  = msm_compr_close,
-	.ioctl	  = msm_compr_ioctl,
-	.prepare	= msm_compr_prepare,
-	.trigger	= msm_compr_trigger,
-	.pointer	= msm_compr_pointer,
-	.mmap		= msm_compr_mmap,
-	.restart	= msm_compr_restart,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl   = msm_compr_compat_ioctl,
-#endif
-};
-
-static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	struct snd_card *card = rtd->card->snd_card;
-	int ret = 0;
-
-	if (!card->dev->coherent_dma_mask)
-		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
-	ret = msm_compr_add_controls(rtd);
-	if (ret)
-		pr_err("%s, kctl add failed\n", __func__);
-	return ret;
-}
-
-static struct snd_soc_platform_driver msm_soc_platform = {
-	.ops		= &msm_compr_ops,
-	.pcm_new	= msm_asoc_pcm_new,
-};
-
-static int msm_compr_probe(struct platform_device *pdev)
-{
-
-	dev_info(&pdev->dev, "%s: dev name %s\n",
-			 __func__, dev_name(&pdev->dev));
-
-	return snd_soc_register_platform(&pdev->dev,
-				   &msm_soc_platform);
-}
-
-static int msm_compr_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_platform(&pdev->dev);
-	return 0;
-}
-
-static const struct of_device_id msm_compr_dt_match[] = {
-	{.compatible = "qcom,msm-compr-dsp"},
-	{}
-};
-MODULE_DEVICE_TABLE(of, msm_compr_dt_match);
-
-static struct platform_driver msm_compr_driver = {
-	.driver = {
-		.name = "msm-compr-dsp",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_compr_dt_match,
-	},
-	.probe = msm_compr_probe,
-	.remove = msm_compr_remove,
-};
-
-static int __init msm_soc_platform_init(void)
-{
-	init_waitqueue_head(&the_locks.enable_wait);
-	init_waitqueue_head(&the_locks.eos_wait);
-	init_waitqueue_head(&the_locks.write_wait);
-	init_waitqueue_head(&the_locks.read_wait);
-	init_waitqueue_head(&the_locks.flush_wait);
-
-	return platform_driver_register(&msm_compr_driver);
-}
-module_init(msm_soc_platform_init);
-
-static void __exit msm_soc_platform_exit(void)
-{
-	platform_driver_unregister(&msm_compr_driver);
-}
-module_exit(msm_soc_platform_exit);
-
-MODULE_DESCRIPTION("PCM module platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
deleted file mode 100644
index d6e3ec6..0000000
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This 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_COMPR_H
-#define _MSM_COMPR_H
-#include <sound/apr_audio-v2.h>
-#include <sound/q6asm-v2.h>
-#include <sound/compress_params.h>
-#include <sound/compress_offload.h>
-#include <sound/compress_driver.h>
-
-#include "msm-pcm-q6-v2.h"
-
-struct compr_info {
-	struct snd_compr_caps compr_cap;
-	struct snd_compr_codec_caps codec_caps;
-	struct snd_compr_params codec_param;
-};
-
-struct compr_audio {
-	struct msm_audio prtd;
-	struct compr_info info;
-	uint32_t codec;
-};
-
-#endif /*_MSM_COMPR_H*/