Merge "ARM: dts: msm: Add support for AOP clock for SDM845" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt
index d1f8ce1..eaa7146b 100644
--- a/Documentation/devicetree/bindings/arm/msm/imem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/imem.txt
@@ -57,6 +57,11 @@
 -compatible: "qcom,msm-imem-emergency_download_mode"
 -reg: start address and size of emergency_download_mode region in imem
 
+Kaslr Offset:
+------------------------
+-compatible: "qcom,msm-imem-kaslr_offset"
+-reg: start address and size of kaslr_offset region in imem
+
 USB Diag Cookies:
 -----------------
 Memory region used to store USB PID and serial numbers to be used by
@@ -95,6 +100,12 @@
 			reg = <0x6b0 32>;
 		};
 
+		kaslr_offset@6d0 {
+			compatible = "qcom,msm-imem-kaslr_offset";
+			reg = <0x6d0 12>;
+		};
+
+
 		pil@94c {
 			compatible = "qcom,msm-imem-pil";
 			reg = <0x94c 200>;
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index c6626d1..3ad0986 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -6,8 +6,9 @@
 DSI Controller:
 Required properties:
 - compatible:           Should be "qcom,dsi-ctrl-hw-v<version>". Supported
-			versions include 1.4 and 2.0.
-			eg: qcom,dsi-ctrl-hw-v1.4, qcom,dsi-ctrl-hw-v2.0
+			versions include 1.4, 2.0 and 2.2.
+			eg: qcom,dsi-ctrl-hw-v1.4, qcom,dsi-ctrl-hw-v2.0,
+			qcom,dsi-ctrl-hw-v2.2
 			And for dsi phy driver:
 			qcom,dsi-phy-v0.0-hpm, qcom,dsi-phy-v0.0-lpm,
 			qcom,dsi-phy-v1.0, qcom,dsi-phy-v2.0,
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 95e6f6c..da9a632 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -72,6 +72,11 @@
 						during clock scaling. If this property is not
 						defined, then it falls back to the default HS
 						bus speed mode to maintain backward compatibility.
+	- qcom,sdr104-wa: On Certain chipsets, SDR104 mode might be unstable causing CRC errors
+			  on the interface. So there is a workaround implemented to skip printing
+			  register dumps on CRC errors and also downgrade bus speed mode to
+			  SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable
+			  this workaround.
 
 In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
 	- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
diff --git a/Documentation/devicetree/bindings/prng/msm-rng.txt b/Documentation/devicetree/bindings/prng/msm-rng.txt
new file mode 100644
index 0000000..917c2fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/prng/msm-rng.txt
@@ -0,0 +1,18 @@
+* RNG (Random Number Generator)
+
+Required properties:
+- compatible : Should be "qcom,msm-rng"
+- reg        : Offset and length of the register set for the device
+
+Optional property:
+- qcom,msm-rng-iface-clk : If the device uses iface-clk.
+- qcom,no-qrng-config    : Flag to decide whether the driver do the hardware configuration or not.
+
+Example:
+
+	qcom,msm-rng@f9bff000 {
+		compatible = "qcom,msm-rng";
+		reg = <0xf9bff000 0x200>;
+		qcom,msm-rng-iface-clk;
+		qcom,no-qrng-config;
+	};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index cb7ab27..0afa5a8 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -12,6 +12,7 @@
 
 
 #include "skeleton.dtsi"
+#include <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. SDX POORWILLS";
@@ -135,6 +136,18 @@
 		};
 	};
 
+	clock_gcc: qcom,gcc@100000 {
+		compatible = "qcom,dummycc";
+		clock-output-names = "gcc_clocks";
+		#clock-cells = <1>;
+	};
+
+	clock_cpu: qcom,clock-a7@17810008 {
+		compatible = "qcom,dummycc";
+		clock-output-names = "cpu_clocks";
+		#clock-cells = <1>;
+	};
+
 	blsp1_uart2: serial@831000 {
 		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
 		reg = <0x831000 0x200>;
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index ef75d2f..f4d7965 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -49,5 +49,7 @@
 	select MSM_JTAG_MM if CORESIGHT_ETM
 	select PM_DEVFREQ
 	select COMMON_CLK
+	select COMMON_CLK_QCOM
+	select QCOM_GDSC
 endmenu
 endif
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 2f45c41..522ad95 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -273,12 +273,13 @@
 	};
 
 	mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 {
-		compatible = "qcom,dsi-ctrl-hw-v2.0";
+		compatible = "qcom,dsi-ctrl-hw-v2.2";
 		label = "dsi-ctrl-0";
 		status = "disabled";
 		cell-index = <0>;
-		reg =   <0xae94000 0x400>;
-		reg-names = "dsi_ctrl";
+		reg =   <0xae94000 0x400>,
+			<0xaf08000 0x4>;
+		reg-names = "dsi_ctrl", "disp_cc_base";
 		interrupt-parent = <&mdss_mdp>;
 		interrupts = <4 0>;
 		vdda-1p2-supply = <&pm8998_l26>;
@@ -315,12 +316,13 @@
 	};
 
 	mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 {
-		compatible = "qcom,dsi-ctrl-hw-v2.0";
+		compatible = "qcom,dsi-ctrl-hw-v2.2";
 		label = "dsi-ctrl-1";
 		status = "disabled";
 		cell-index = <1>;
-		reg =   <0xae96000 0x400>;
-		reg-names = "dsi_ctrl";
+		reg =   <0xae96000 0x400>,
+			<0xaf08000 0x4>;
+		reg-names = "dsi_ctrl", "disp_cc_base";
 		interrupt-parent = <&mdss_mdp>;
 		interrupts = <5 0>;
 		vdda-1p2-supply = <&pm8998_l26>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 092acb0..2c48371 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1271,6 +1271,8 @@
 		qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
 			100000000 200000000 4294967295>;
 
+		qcom,sdr104-wa;
+
 		qcom,devfreq,freq-table = <50000000 200000000>;
 		clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
 			<&clock_gcc GCC_SDCC2_APPS_CLK>;
@@ -1580,6 +1582,11 @@
 			compatible = "qcom,msm-imem-pil";
 			reg = <0x94c 200>;
 		};
+
+		kaslr_offset@6d0 {
+			compatible = "qcom,msm-imem-kaslr_offset";
+			reg = <0x6d0 12>;
+		};
 	};
 
 	qcom,venus@aae0000 {
@@ -2064,6 +2071,29 @@
 		qcom,qsee-reentrancy-support = <2>;
 	};
 
+	qcom_rng: qrng@793000 {
+		compatible = "qcom,msm-rng";
+		reg = <0x793000 0x1000>;
+		qcom,msm-rng-iface-clk;
+		qcom,no-qrng-config;
+		qcom,msm-bus,name = "msm-rng-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<1 618 0 0>,    /* No vote */
+			<1 618 0 800>;  /* 100 KHz */
+		clocks = <&clock_gcc GCC_PRNG_AHB_CLK>;
+		clock-names = "iface_clk";
+	};
+
+	qcom_tzlog: tz-log@146bf720 {
+		compatible = "qcom,tz-log";
+		reg = <0x146bf720 0x3000>;
+		qcom,hyplog-enabled;
+		hyplog-address-offset = <0x410>;
+		hyplog-size-offset = <0x414>;
+	};
+
 	qcom,msm_gsi {
 		compatible = "qcom,msm_gsi";
 	};
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 658c871..a2d659e 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -275,6 +275,7 @@
 CONFIG_SERIAL_MSM_GENI=y
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QCOM_GENI=y
@@ -490,6 +491,7 @@
 CONFIG_ARM_GIC_V3_ACL=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 7507c3b..54f9d41 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -282,9 +282,8 @@
 CONFIG_SERIAL_MSM_GENI=y
 CONFIG_SERIAL_MSM_GENI_CONSOLE=y
 CONFIG_DIAG_CHAR=y
-CONFIG_HVC_DCC=y
-CONFIG_HVC_DCC_SERIALIZE_SMP=y
 CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
 CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QCOM_GENI=y
@@ -513,6 +512,7 @@
 CONFIG_PHY_XGENE=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 200dab5..18849f4 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -337,7 +337,6 @@
 config HW_RANDOM_MSM
 	tristate "Qualcomm SoCs Random Number Generator support"
 	depends on HW_RANDOM && ARCH_QCOM
-	default HW_RANDOM
 	---help---
 	  This driver provides kernel-side support for the Random Number
 	  Generator hardware found on Qualcomm SoCs.
@@ -347,6 +346,20 @@
 
 	  If unsure, say Y.
 
+config HW_RANDOM_MSM_LEGACY
+	tristate "QTI MSM Random Number Generator support (LEGACY)"
+	depends on HW_RANDOM && ARCH_QCOM
+	select CRYPTO_AES
+	select CRYPTO_ECB
+	---help---
+	  This driver provides kernel-side support for the Random Number
+	  Generator hardware found on QTI MSM SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called msm_rng.
+
+	  If unsure, say Y.
+
 config HW_RANDOM_ST
 	tristate "ST Microelectronics HW Random Number Generator support"
 	depends on HW_RANDOM && ARCH_STI
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 5f52b1e..637adb5 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -30,6 +30,7 @@
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
 obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
+obj-$(CONFIG_HW_RANDOM_MSM_LEGACY) += msm_rng.o
 obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o
 obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
 obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
new file mode 100644
index 0000000..7641a6a
--- /dev/null
+++ b/drivers/char/hw_random/msm_rng.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2011-2013, 2015, 2017 The Linux Foundation. All rights
+ * reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <soc/qcom/socinfo.h>
+#include <linux/msm-bus.h>
+#include <linux/qrng.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/crypto.h>
+#include <crypto/internal/rng.h>
+
+#include <linux/platform_data/qcom_crypto_device.h>
+
+
+
+#define DRIVER_NAME "msm_rng"
+
+/* Device specific register offsets */
+#define PRNG_DATA_OUT_OFFSET    0x0000
+#define PRNG_STATUS_OFFSET	0x0004
+#define PRNG_LFSR_CFG_OFFSET	0x0100
+#define PRNG_CONFIG_OFFSET	0x0104
+
+/* Device specific register masks and config values */
+#define PRNG_LFSR_CFG_MASK	0xFFFF0000
+#define PRNG_LFSR_CFG_CLOCKS	0x0000DDDD
+#define PRNG_CONFIG_MASK	0xFFFFFFFD
+#define PRNG_HW_ENABLE		0x00000002
+
+#define MAX_HW_FIFO_DEPTH 16                     /* FIFO is 16 words deep */
+#define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4) /* FIFO is 32 bits wide  */
+
+struct msm_rng_device {
+	struct platform_device *pdev;
+	void __iomem *base;
+	struct clk *prng_clk;
+	uint32_t qrng_perf_client;
+	struct mutex rng_lock;
+};
+
+struct msm_rng_device msm_rng_device_info;
+static struct msm_rng_device *msm_rng_dev_cached;
+struct mutex cached_rng_lock;
+static long msm_rng_ioctl(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	long ret = 0;
+
+	switch (cmd) {
+	case QRNG_IOCTL_RESET_BUS_BANDWIDTH:
+		pr_info("calling msm_rng_bus_scale(LOW)\n");
+		ret = msm_bus_scale_client_update_request(
+				msm_rng_device_info.qrng_perf_client, 0);
+		if (ret)
+			pr_err("failed qrng_reset_bus_bw, ret = %ld\n", ret);
+		break;
+	default:
+		pr_err("Unsupported IOCTL call");
+		break;
+	}
+	return ret;
+}
+
+/*
+ *
+ *  This function calls hardware random bit generator directory and retuns it
+ *  back to caller
+ *
+ */
+static int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev,
+					void *data, size_t max)
+{
+	struct platform_device *pdev;
+	void __iomem *base;
+	size_t currsize = 0;
+	u32 val;
+	u32 *retdata = data;
+	int ret;
+	int failed = 0;
+
+	pdev = msm_rng_dev->pdev;
+	base = msm_rng_dev->base;
+
+	/* no room for word data */
+	if (max < 4)
+		return 0;
+
+	mutex_lock(&msm_rng_dev->rng_lock);
+
+	if (msm_rng_dev->qrng_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+				msm_rng_dev->qrng_perf_client, 1);
+		if (ret)
+			pr_err("bus_scale_client_update_req failed!\n");
+	}
+	/* enable PRNG clock */
+	ret = clk_prepare_enable(msm_rng_dev->prng_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to enable clock in callback\n");
+		goto err;
+	}
+	/* read random data from h/w */
+	do {
+		/* check status bit if data is available */
+		while (!(readl_relaxed(base + PRNG_STATUS_OFFSET)
+				& 0x00000001)) {
+			if (failed == 10) {
+				pr_err("Data not available after retry\n");
+				break;
+			}
+			pr_err("msm_rng:Data not available!\n");
+			msleep_interruptible(10);
+			failed++;
+		}
+
+		/* read FIFO */
+		val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
+		if (!val)
+			break;	/* no data to read so just bail */
+
+		/* write data back to callers pointer */
+		*(retdata++) = val;
+		currsize += 4;
+		/* make sure we stay on 32bit boundary */
+		if ((max - currsize) < 4)
+			break;
+
+	} while (currsize < max);
+
+	/* vote to turn off clock */
+	clk_disable_unprepare(msm_rng_dev->prng_clk);
+err:
+	if (msm_rng_dev->qrng_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+				msm_rng_dev->qrng_perf_client, 0);
+		if (ret)
+			pr_err("bus_scale_client_update_req failed!\n");
+	}
+	mutex_unlock(&msm_rng_dev->rng_lock);
+
+	val = 0L;
+	return currsize;
+}
+static int msm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+	struct msm_rng_device *msm_rng_dev;
+	int rv = 0;
+
+	msm_rng_dev = (struct msm_rng_device *)rng->priv;
+	rv = msm_rng_direct_read(msm_rng_dev, data, max);
+
+	return rv;
+}
+
+
+static struct hwrng msm_rng = {
+	.name = DRIVER_NAME,
+	.read = msm_rng_read,
+	.quality = 700,
+};
+
+static int msm_rng_enable_hw(struct msm_rng_device *msm_rng_dev)
+{
+	unsigned long val = 0;
+	unsigned long reg_val = 0;
+	int ret = 0;
+
+	if (msm_rng_dev->qrng_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+				msm_rng_dev->qrng_perf_client, 1);
+		if (ret)
+			pr_err("bus_scale_client_update_req failed!\n");
+	}
+	/* Enable the PRNG CLK */
+	ret = clk_prepare_enable(msm_rng_dev->prng_clk);
+	if (ret) {
+		dev_err(&(msm_rng_dev->pdev)->dev,
+				"failed to enable clock in probe\n");
+		return -EPERM;
+	}
+
+	/* Enable PRNG h/w only if it is NOT ON */
+	val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET) &
+					PRNG_HW_ENABLE;
+	/* PRNG H/W is not ON */
+	if (val != PRNG_HW_ENABLE) {
+		val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
+		val &= PRNG_LFSR_CFG_MASK;
+		val |= PRNG_LFSR_CFG_CLOCKS;
+		writel_relaxed(val, msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
+
+		/* The PRNG CONFIG register should be first written */
+		mb();
+
+		reg_val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET)
+						& PRNG_CONFIG_MASK;
+		reg_val |= PRNG_HW_ENABLE;
+		writel_relaxed(reg_val, msm_rng_dev->base + PRNG_CONFIG_OFFSET);
+
+		/* The PRNG clk should be disabled only after we enable the
+		 * PRNG h/w by writing to the PRNG CONFIG register.
+		 */
+		mb();
+	}
+	clk_disable_unprepare(msm_rng_dev->prng_clk);
+
+	if (msm_rng_dev->qrng_perf_client) {
+		ret = msm_bus_scale_client_update_request(
+				msm_rng_dev->qrng_perf_client, 0);
+		if (ret)
+			pr_err("bus_scale_client_update_req failed!\n");
+	}
+
+	return 0;
+}
+
+static const struct file_operations msm_rng_fops = {
+	.unlocked_ioctl = msm_rng_ioctl,
+};
+static struct class *msm_rng_class;
+static struct cdev msm_rng_cdev;
+
+static int msm_rng_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct msm_rng_device *msm_rng_dev = NULL;
+	void __iomem *base = NULL;
+	bool configure_qrng = true;
+	int error = 0;
+	int ret = 0;
+	struct device *dev;
+
+	struct msm_bus_scale_pdata *qrng_platform_support = NULL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "invalid address\n");
+		error = -EFAULT;
+		goto err_exit;
+	}
+
+	msm_rng_dev = kzalloc(sizeof(struct msm_rng_device), GFP_KERNEL);
+	if (!msm_rng_dev) {
+		error = -ENOMEM;
+		goto err_exit;
+	}
+
+	base = ioremap(res->start, resource_size(res));
+	if (!base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		error = -ENOMEM;
+		goto err_iomap;
+	}
+	msm_rng_dev->base = base;
+
+	/* create a handle for clock control */
+	if ((pdev->dev.of_node) && (of_property_read_bool(pdev->dev.of_node,
+					"qcom,msm-rng-iface-clk")))
+		msm_rng_dev->prng_clk = clk_get(&pdev->dev,
+							"iface_clk");
+	else
+		msm_rng_dev->prng_clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(msm_rng_dev->prng_clk)) {
+		dev_err(&pdev->dev, "failed to register clock source\n");
+		error = -EPERM;
+		goto err_clk_get;
+	}
+
+	/* save away pdev and register driver data */
+	msm_rng_dev->pdev = pdev;
+	platform_set_drvdata(pdev, msm_rng_dev);
+
+	if (pdev->dev.of_node) {
+		/* Register bus client */
+		qrng_platform_support = msm_bus_cl_get_pdata(pdev);
+		msm_rng_dev->qrng_perf_client = msm_bus_scale_register_client(
+						qrng_platform_support);
+		msm_rng_device_info.qrng_perf_client =
+					msm_rng_dev->qrng_perf_client;
+		if (!msm_rng_dev->qrng_perf_client)
+			pr_err("Unable to register bus client\n");
+	}
+
+	/* Enable rng h/w for the targets which can access the entire
+	 * address space of PRNG.
+	 */
+	if ((pdev->dev.of_node) && (of_property_read_bool(pdev->dev.of_node,
+					"qcom,no-qrng-config")))
+		configure_qrng = false;
+	if (configure_qrng) {
+		error = msm_rng_enable_hw(msm_rng_dev);
+		if (error)
+			goto rollback_clk;
+	}
+
+	mutex_init(&msm_rng_dev->rng_lock);
+	mutex_init(&cached_rng_lock);
+
+	/* register with hwrng framework */
+	msm_rng.priv = (unsigned long) msm_rng_dev;
+	error = hwrng_register(&msm_rng);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register hwrng\n");
+		error = -EPERM;
+		goto rollback_clk;
+	}
+	ret = register_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME, &msm_rng_fops);
+
+	msm_rng_class = class_create(THIS_MODULE, "msm-rng");
+	if (IS_ERR(msm_rng_class)) {
+		pr_err("class_create failed\n");
+		return PTR_ERR(msm_rng_class);
+	}
+
+	dev = device_create(msm_rng_class, NULL, MKDEV(QRNG_IOC_MAGIC, 0),
+				NULL, "msm-rng");
+	if (IS_ERR(dev)) {
+		pr_err("Device create failed\n");
+		error = PTR_ERR(dev);
+		goto unregister_chrdev;
+	}
+	cdev_init(&msm_rng_cdev, &msm_rng_fops);
+	msm_rng_dev_cached = msm_rng_dev;
+	return error;
+
+unregister_chrdev:
+	unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
+rollback_clk:
+	clk_put(msm_rng_dev->prng_clk);
+err_clk_get:
+	iounmap(msm_rng_dev->base);
+err_iomap:
+	kzfree(msm_rng_dev);
+err_exit:
+	return error;
+}
+
+static int msm_rng_remove(struct platform_device *pdev)
+{
+	struct msm_rng_device *msm_rng_dev = platform_get_drvdata(pdev);
+
+	unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
+	hwrng_unregister(&msm_rng);
+	clk_put(msm_rng_dev->prng_clk);
+	iounmap(msm_rng_dev->base);
+	platform_set_drvdata(pdev, NULL);
+	if (msm_rng_dev->qrng_perf_client)
+		msm_bus_scale_unregister_client(msm_rng_dev->qrng_perf_client);
+
+	kzfree(msm_rng_dev);
+	msm_rng_dev_cached = NULL;
+	return 0;
+}
+
+static int qrng_get_random(struct crypto_rng *tfm, const u8 *src,
+				unsigned int slen, u8 *rdata,
+				unsigned int dlen)
+{
+	int sizeread = 0;
+	int rv = -EFAULT;
+
+	if (!msm_rng_dev_cached) {
+		pr_err("%s: msm_rng_dev is not initialized.\n", __func__);
+		rv = -ENODEV;
+		goto err_exit;
+	}
+
+	if (!rdata) {
+		pr_err("%s: data buffer is null!\n", __func__);
+		rv = -EINVAL;
+		goto err_exit;
+	}
+
+	if (signal_pending(current) ||
+		mutex_lock_interruptible(&cached_rng_lock)) {
+		pr_err("%s: mutex lock interrupted!\n", __func__);
+		rv = -ERESTARTSYS;
+		goto err_exit;
+	}
+	sizeread = msm_rng_direct_read(msm_rng_dev_cached, rdata, dlen);
+
+	if (sizeread == dlen)
+		rv = 0;
+
+	mutex_unlock(&cached_rng_lock);
+err_exit:
+	return rv;
+
+}
+
+static int qrng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
+{
+	return 0;
+}
+
+static struct rng_alg rng_algs[] = { {
+	.generate	= qrng_get_random,
+	.seed		= qrng_reset,
+	.seedsize	= 0,
+	.base		= {
+		.cra_name		= "qrng",
+		.cra_driver_name	= "fips_hw_qrng",
+		.cra_priority		= 300,
+		.cra_ctxsize		= 0,
+		.cra_module		= THIS_MODULE,
+	}
+} };
+
+static const struct of_device_id qrng_match[] = {
+	{	.compatible = "qcom,msm-rng",
+	},
+	{}
+};
+
+static struct platform_driver rng_driver = {
+	.probe      = msm_rng_probe,
+	.remove     = msm_rng_remove,
+	.driver     = {
+		.name   = DRIVER_NAME,
+		.owner  = THIS_MODULE,
+		.of_match_table = qrng_match,
+	}
+};
+
+static int __init msm_rng_init(void)
+{
+	int ret;
+
+	msm_rng_dev_cached = NULL;
+	ret = platform_driver_register(&rng_driver);
+	if (ret) {
+		pr_err("%s: platform_driver_register error:%d\n",
+			__func__, ret);
+		goto err_exit;
+	}
+	ret = crypto_register_rngs(rng_algs, ARRAY_SIZE(rng_algs));
+	if (ret) {
+		pr_err("%s: crypto_register_algs error:%d\n",
+			__func__, ret);
+		goto err_exit;
+	}
+
+err_exit:
+	return ret;
+}
+
+module_init(msm_rng_init);
+
+static void __exit msm_rng_exit(void)
+{
+	crypto_unregister_rngs(rng_algs, ARRAY_SIZE(rng_algs));
+	platform_driver_unregister(&rng_driver);
+}
+
+module_exit(msm_rng_exit);
+
+MODULE_DESCRIPTION("QTI MSM Random Number Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 6ce0d76..3daefbc 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -40,6 +40,8 @@
 #define PLL_CALIBRATION_SETTINGS		0x030
 #define PLL_BAND_SEL_CAL_SETTINGS_THREE		0x054
 #define PLL_FREQ_DETECT_SETTINGS_ONE		0x064
+#define PLL_PFILT				0x07c
+#define PLL_IFILT				0x080
 #define PLL_OUTDIV				0x094
 #define PLL_CORE_OVERRIDE			0x0a4
 #define PLL_CORE_INPUT_OVERRIDE			0x0a8
@@ -63,6 +65,7 @@
 #define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1	0x164
 #define PLL_PLL_LOCK_OVERRIDE			0x180
 #define PLL_PLL_LOCK_DELAY			0x184
+#define PLL_CLOCK_INVERTERS			0x18c
 #define PLL_COMMON_STATUS_ONE			0x1a0
 
 /* Register Offsets from PHY base address */
@@ -338,7 +341,6 @@
 	MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_THREE, 0x00);
 	MDSS_PLL_REG_W(pll_base, PLL_DSM_DIVIDER, 0x00);
 	MDSS_PLL_REG_W(pll_base, PLL_FEEDBACK_DIVIDER, 0x4e);
-	MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x00);
 	MDSS_PLL_REG_W(pll_base, PLL_CALIBRATION_SETTINGS, 0x40);
 	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba);
 	MDSS_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
@@ -347,9 +349,11 @@
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x08);
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_BAND_SET_RATE_1, 0xc0);
-	MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x82);
+	MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa);
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c);
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x80);
+	MDSS_PLL_REG_W(pll_base, PLL_PFILT, 0x29);
+	MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f);
 }
 
 static void dsi_pll_commit(struct dsi_pll_10nm *pll,
@@ -367,9 +371,11 @@
 		       reg->frac_div_start_mid);
 	MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1,
 		       reg->frac_div_start_high);
-	MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0xc8);
+	MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40);
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
-	MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x0a);
+	MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06);
+	MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10);
+	MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, 0x0);
 
 }
 
@@ -450,8 +456,8 @@
 {
 	u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0);
 
-	MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5));
 	MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0);
+	MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5));
 	ndelay(250);
 }
 
@@ -464,6 +470,22 @@
 	ndelay(250);
 }
 
+static void dsi_pll_disable_global_clk(struct mdss_pll_resources *rsc)
+{
+	u32 data;
+
+	data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+	MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data & ~BIT(5)));
+}
+
+static void dsi_pll_enable_global_clk(struct mdss_pll_resources *rsc)
+{
+	u32 data;
+
+	data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+	MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data | BIT(5)));
+}
+
 static int dsi_pll_enable(struct dsi_pll_vco_clk *vco)
 {
 	int rc;
@@ -490,6 +512,11 @@
 	}
 
 	rsc->pll_on = true;
+
+	dsi_pll_enable_global_clk(rsc);
+	if (rsc->slave)
+		dsi_pll_enable_global_clk(rsc->slave);
+
 	MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0x01);
 	if (rsc->slave)
 		MDSS_PLL_REG_W(rsc->slave->phy_base, PHY_CMN_RBUF_CTRL, 0x01);
@@ -500,8 +527,9 @@
 
 static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc)
 {
-	dsi_pll_disable_pll_bias(rsc);
+	dsi_pll_disable_global_clk(rsc);
 	MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0);
+	dsi_pll_disable_pll_bias(rsc);
 }
 
 static void dsi_pll_disable(struct dsi_pll_vco_clk *vco)
@@ -613,6 +641,9 @@
 	u32 outdiv;
 	u64 pll_freq, tmp64;
 
+	if (!vco->priv)
+		pr_err("vco priv is null\n");
+
 	rc = mdss_pll_resource_enable(pll, true);
 	if (rc) {
 		pr_err("failed to enable pll(%d) resource, rc=%d\n",
@@ -671,9 +702,11 @@
 	reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
 	*div = (reg_val & 0xF0) >> 4;
 
-	if (*div == 0)
-		*div = 1;
-	else
+	/**
+	 * Common clock framework the divider value is interpreted as one less
+	 * hence we return one less for all dividers except when zero
+	 */
+	if (*div != 0)
 		*div -= 1;
 
 	(void)mdss_pll_resource_enable(pll, false);
@@ -701,13 +734,15 @@
 		pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
 		return rc;
 	}
-	/* In common clock framework the divider value provided is one less */
+	/**
+	 * In common clock framework the divider value provided is one less and
+	 * and hence adjusting the divider value by one prior to writing it to
+	 * hardware
+	 */
 	div++;
-
 	pixel_clk_set_div_sub(pll, div);
 	if (pll->slave)
 		pixel_clk_set_div_sub(pll->slave, div);
-
 	(void)mdss_pll_resource_enable(pll, false);
 
 	return 0;
@@ -728,12 +763,12 @@
 	reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
 	*div = (reg_val & 0x0F);
 
-	/* Common clock framework will add one to divider value sent */
-	if (*div == 0)
-		*div = 1;
-	else
+	/**
+	 *Common clock framework the divider value is interpreted as one less
+	 * hence we return one less for all dividers except when zero
+	 */
+	if (*div != 0)
 		*div -= 1;
-
 	(void)mdss_pll_resource_enable(pll, false);
 
 	return rc;
@@ -771,6 +806,12 @@
 		pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
 		return rc;
 	}
+
+	/**
+	 * In common clock framework the divider value provided is one less and
+	 * and hence adjusting the divider value by one prior to writing it to
+	 * hardware
+	 */
 	div++;
 
 	bit_clk_set_div_sub(rsc, div);
@@ -806,9 +847,11 @@
 	else
 		*div = 1;
 
-	if (*div == 0)
-		*div = 1;
-	else
+	/**
+	 *Common clock framework the divider value is interpreted as one less
+	 * hence we return one less for all dividers except when zero
+	 */
+	if (*div != 0)
 		*div -= 1;
 
 	(void)mdss_pll_resource_enable(pll, false);
@@ -851,8 +894,12 @@
 		return rc;
 	}
 
+	/**
+	 * In common clock framework the divider value provided is one less and
+	 * and hence adjusting the divider value by one prior to writing it to
+	 * hardware
+	 */
 	div++;
-
 	rc = post_vco_clk_set_div_sub(pll, div);
 	if (!rc && pll->slave)
 		rc = post_vco_clk_set_div_sub(pll->slave, div);
@@ -885,9 +932,11 @@
 	else
 		*div = 1;
 
-	if (*div == 0)
-		*div = 1;
-	else
+	/**
+	 *Common clock framework the divider value is interpreted as one less
+	 * hence we return one less for all dividers except when zero
+	 */
+	if (*div != 0)
 		*div -= 1;
 
 	(void)mdss_pll_resource_enable(pll, false);
@@ -930,8 +979,12 @@
 		return rc;
 	}
 
+	/**
+	 * In common clock framework the divider value provided is one less and
+	 * and hence adjusting the divider value by one prior to writing it to
+	 * hardware
+	 */
 	div++;
-
 	rc = post_bit_clk_set_div_sub(pll, div);
 	if (!rc && pll->slave)
 		rc = post_bit_clk_set_div_sub(pll->slave, div);
@@ -1057,7 +1110,6 @@
 };
 
 static struct clk_regmap_div dsi0pll_bitclk_src = {
-	.reg = 0x48,
 	.shift = 0,
 	.width = 4,
 	.clkr = {
@@ -1072,7 +1124,6 @@
 };
 
 static struct clk_regmap_div dsi1pll_bitclk_src = {
-	.reg = 0x48,
 	.shift = 0,
 	.width = 4,
 	.clkr = {
@@ -1087,9 +1138,8 @@
 };
 
 static struct clk_regmap_div dsi0pll_post_vco_div = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 2,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi0pll_post_vco_div",
@@ -1102,9 +1152,8 @@
 };
 
 static struct clk_regmap_div dsi1pll_post_vco_div = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 2,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi1pll_post_vco_div",
@@ -1141,9 +1190,8 @@
 };
 
 static struct clk_regmap_div dsi0pll_post_bit_div = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi0pll_post_bit_div",
@@ -1156,9 +1204,8 @@
 };
 
 static struct clk_regmap_div dsi1pll_post_bit_div = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi1pll_post_bit_div",
@@ -1171,12 +1218,11 @@
 };
 
 static struct clk_regmap_mux dsi0pll_byteclk_mux = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 0,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
-			.name = "dsi0pll_byteclk_mux",
+			.name = "dsi0_phy_pll_out_byteclk",
 			.parent_names = (const char *[]){"dsi0pll_byteclk_src"},
 			.num_parents = 1,
 			.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1186,12 +1232,11 @@
 };
 
 static struct clk_regmap_mux dsi1pll_byteclk_mux = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 0,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
-			.name = "dsi1pll_byteclk_mux",
+			.name = "dsi1_phy_pll_out_byteclk",
 			.parent_names = (const char *[]){"dsi1pll_byteclk_src"},
 			.num_parents = 1,
 			.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1201,15 +1246,14 @@
 };
 
 static struct clk_regmap_mux dsi0pll_pclk_src_mux = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 0,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi0pll_pclk_src_mux",
 			.parent_names = (const char *[]){"dsi0pll_post_bit_div",
-						"dsi0pll_post_bit_div"},
-			.num_parents = 1,
+						"dsi0pll_post_vco_div"},
+			.num_parents = 2,
 			.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
 			.ops = &clk_regmap_mux_closest_ops,
 		},
@@ -1217,15 +1261,14 @@
 };
 
 static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 0,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi1pll_pclk_src_mux",
 			.parent_names = (const char *[]){"dsi1pll_post_bit_div",
-						"dsi1pll_post_bit_div"},
-			.num_parents = 1,
+						"dsi1pll_post_vco_div"},
+			.num_parents = 2,
 			.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
 			.ops = &clk_regmap_mux_closest_ops,
 		},
@@ -1233,7 +1276,6 @@
 };
 
 static struct clk_regmap_div dsi0pll_pclk_src = {
-	.reg = 0x48,
 	.shift = 0,
 	.width = 4,
 	.clkr = {
@@ -1249,7 +1291,6 @@
 };
 
 static struct clk_regmap_div dsi1pll_pclk_src = {
-	.reg = 0x48,
 	.shift = 0,
 	.width = 4,
 	.clkr = {
@@ -1265,12 +1306,11 @@
 };
 
 static struct clk_regmap_mux dsi0pll_pclk_mux = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 0,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
-			.name = "dsi0pll_pclk_mux",
+			.name = "dsi0_phy_pll_out_dsiclk",
 			.parent_names = (const char *[]){"dsi0pll_pclk_src"},
 			.num_parents = 1,
 			.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1280,12 +1320,11 @@
 };
 
 static struct clk_regmap_mux dsi1pll_pclk_mux = {
-	.reg = 0x48,
 	.shift = 0,
-	.width = 4,
+	.width = 0,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
-			.name = "dsi1pll_pclk_mux",
+			.name = "dsi1_phy_pll_out_dsiclk",
 			.parent_names = (const char *[]){"dsi1pll_pclk_src"},
 			.num_parents = 1,
 			.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1339,8 +1378,8 @@
 	}
 
 	pll_rsc_db[ndx] = pll_res;
-	pll_res->priv = &plls[ndx];
 	plls[ndx].rsc = pll_res;
+	pll_res->priv = &plls[ndx];
 	pll_res->vco_delay = VCO_DELAY_USEC;
 
 	clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
@@ -1386,6 +1425,7 @@
 				pll_res, &dsi_pll_10nm_config);
 		dsi0pll_byteclk_mux.clkr.regmap = rmap;
 
+		dsi0pll_vco_clk.priv = pll_res;
 		for (i = VCO_CLK_0; i <= PCLK_MUX_0_CLK; i++) {
 			clk = devm_clk_register(&pdev->dev,
 						mdss_dsi_pllcc_10nm[i]);
@@ -1431,6 +1471,7 @@
 		rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
 				pll_res, &dsi_pll_10nm_config);
 		dsi1pll_byteclk_mux.clkr.regmap = rmap;
+		dsi1pll_vco_clk.priv = pll_res;
 
 		for (i = VCO_CLK_1; i <= PCLK_MUX_1_CLK; i++) {
 			clk = devm_clk_register(&pdev->dev,
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 0a0d303..7f82fda 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -150,6 +150,7 @@
 	switch (pll_res->pll_interface_type) {
 	case MDSS_DSI_PLL_10NM:
 		rc = dsi_pll_clock_register_10nm(pdev, pll_res);
+		break;
 	case MDSS_UNKNOWN_PLL:
 	default:
 		rc = -EINVAL;
@@ -370,7 +371,7 @@
 
 	return rc;
 }
-subsys_initcall(mdss_pll_driver_init);
+fs_initcall(mdss_pll_driver_init);
 
 static void __exit mdss_pll_driver_deinit(void)
 {
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 28b7ca6..eccfcea 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -194,9 +194,7 @@
 		WARN(1, "gdsc_base register is not defined\n");
 		return true;
 	}
-
-	return ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) &&
-		(!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true;
+	return readl_relaxed(pll_res->gdsc_base) & BIT(31) ? false : true;
 }
 
 static inline int mdss_pll_div_prepare(struct clk_hw *hw)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 5b85b8d..8f582f6 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -70,6 +70,29 @@
 }
 
 /**
+ * devfreq_set_freq_limits() - Set min and max frequency from freq_table
+ * @devfreq:	the devfreq instance
+ */
+static void devfreq_set_freq_limits(struct devfreq *devfreq)
+{
+	int idx;
+	unsigned long min = ~0, max = 0;
+
+	if (!devfreq->profile->freq_table)
+		return;
+
+	for (idx = 0; idx < devfreq->profile->max_state; idx++) {
+		if (min > devfreq->profile->freq_table[idx])
+			min = devfreq->profile->freq_table[idx];
+		if (max < devfreq->profile->freq_table[idx])
+			max = devfreq->profile->freq_table[idx];
+	}
+
+	devfreq->min_freq = min;
+	devfreq->max_freq = max;
+}
+
+/**
  * devfreq_get_freq_level() - Lookup freq_table for the frequency
  * @devfreq:	the devfreq instance
  * @freq:	the target frequency
@@ -569,6 +592,7 @@
 		devfreq_set_freq_table(devfreq);
 		mutex_lock(&devfreq->lock);
 	}
+	devfreq_set_freq_limits(devfreq);
 
 	dev_set_name(&devfreq->dev, "%s", dev_name(dev));
 	err = device_register(&devfreq->dev);
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b5d78b1..4112bef 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -109,6 +109,7 @@
 				dsi-staging/dsi_ctrl_hw_cmn.o \
 				dsi-staging/dsi_ctrl_hw_1_4.o \
 				dsi-staging/dsi_ctrl_hw_2_0.o \
+				dsi-staging/dsi_ctrl_hw_2_2.o \
 				dsi-staging/dsi_ctrl.o \
 				dsi-staging/dsi_catalog.o \
 				dsi-staging/dsi_drm.o \
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 976be99..1434eac 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -83,6 +83,19 @@
 		ctrl->ops.clamp_enable = NULL;
 		ctrl->ops.clamp_disable = NULL;
 		break;
+	case DSI_CTRL_VERSION_2_2:
+		ctrl->ops.phy_reset_config = dsi_ctrl_hw_22_phy_reset_config;
+		ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
+		ctrl->ops.wait_for_lane_idle =
+			dsi_ctrl_hw_20_wait_for_lane_idle;
+		ctrl->ops.reg_dump_to_buffer =
+			dsi_ctrl_hw_20_reg_dump_to_buffer;
+		ctrl->ops.ulps_ops.ulps_request = NULL;
+		ctrl->ops.ulps_ops.ulps_exit = NULL;
+		ctrl->ops.ulps_ops.get_lanes_in_ulps = NULL;
+		ctrl->ops.clamp_enable = NULL;
+		ctrl->ops.clamp_disable = NULL;
+		break;
 	default:
 		break;
 	}
@@ -121,6 +134,7 @@
 	switch (version) {
 	case DSI_CTRL_VERSION_1_4:
 	case DSI_CTRL_VERSION_2_0:
+	case DSI_CTRL_VERSION_2_2:
 		dsi_catalog_cmn_init(ctrl, version);
 		break;
 	default:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 4a6a934..160cd32 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -157,6 +157,8 @@
 void dsi_ctrl_hw_dln0_phy_err(struct dsi_ctrl_hw *ctrl);
 void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl,
 			bool enable);
+void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
+			bool enable);
 
 /* Definitions specific to 1.4 DSI controller hardware */
 int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 5df48c3..9a71ea0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -62,6 +62,7 @@
 
 static const enum dsi_ctrl_version dsi_ctrl_v1_4 = DSI_CTRL_VERSION_1_4;
 static const enum dsi_ctrl_version dsi_ctrl_v2_0 = DSI_CTRL_VERSION_2_0;
+static const enum dsi_ctrl_version dsi_ctrl_v2_2 = DSI_CTRL_VERSION_2_2;
 
 static const struct of_device_id msm_dsi_of_match[] = {
 	{
@@ -72,6 +73,10 @@
 		.compatible = "qcom,dsi-ctrl-hw-v2.0",
 		.data = &dsi_ctrl_v2_0,
 	},
+	{
+		.compatible = "qcom,dsi-ctrl-hw-v2.2",
+		.data = &dsi_ctrl_v2_2,
+	},
 	{}
 };
 
@@ -428,15 +433,34 @@
 	pr_debug("[%s] map dsi_ctrl registers to %p\n", ctrl->name,
 		 ctrl->hw.base);
 
-	ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name);
-	if (IS_ERR(ptr)) {
-		rc = PTR_ERR(ptr);
-		return rc;
+	switch (ctrl->version) {
+	case DSI_CTRL_VERSION_1_4:
+	case DSI_CTRL_VERSION_2_0:
+		ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name);
+		if (IS_ERR(ptr)) {
+			pr_err("mmss_misc base address not found for [%s]\n",
+					ctrl->name);
+			rc = PTR_ERR(ptr);
+			return rc;
+		}
+		ctrl->hw.mmss_misc_base = ptr;
+		ctrl->hw.disp_cc_base = NULL;
+		break;
+	case DSI_CTRL_VERSION_2_2:
+		ptr = msm_ioremap(pdev, "disp_cc_base", ctrl->name);
+		if (IS_ERR(ptr)) {
+			pr_err("disp_cc base address not found for [%s]\n",
+					ctrl->name);
+			rc = PTR_ERR(ptr);
+			return rc;
+		}
+		ctrl->hw.disp_cc_base = ptr;
+		ctrl->hw.mmss_misc_base = NULL;
+		break;
+	default:
+		break;
 	}
 
-	ctrl->hw.mmss_misc_base = ptr;
-	pr_debug("[%s] map mmss_misc registers to %p\n", ctrl->name,
-		 ctrl->hw.mmss_misc_base);
 	return rc;
 }
 
@@ -532,7 +556,7 @@
 		goto fail;
 	}
 
-	link->esc_clk = devm_clk_get(&pdev->dev, "core_clk");
+	link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
 	if (IS_ERR(link->esc_clk)) {
 		rc = PTR_ERR(link->esc_clk);
 		pr_err("failed to get esc_clk, rc=%d\n", rc);
@@ -613,10 +637,8 @@
 	rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
 					  &ctrl->pwr_info.digital,
 					  "qcom,core-supply-entries");
-	if (rc) {
-		pr_err("failed to get digital supply, rc = %d\n", rc);
-		goto error;
-	}
+	if (rc)
+		pr_debug("failed to get digital supply, rc = %d\n", rc);
 
 	rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
 					  &ctrl->pwr_info.host_pwr,
@@ -663,10 +685,10 @@
 	ctrl->pwr_info.host_pwr.vregs = NULL;
 	ctrl->pwr_info.host_pwr.count = 0;
 error_digital:
-	devm_kfree(&pdev->dev, ctrl->pwr_info.digital.vregs);
+	if (ctrl->pwr_info.digital.vregs)
+		devm_kfree(&pdev->dev, ctrl->pwr_info.digital.vregs);
 	ctrl->pwr_info.digital.vregs = NULL;
 	ctrl->pwr_info.digital.count = 0;
-error:
 	return rc;
 }
 
@@ -1204,6 +1226,7 @@
 	}
 
 	dsi_ctrl->cell_index = index;
+	dsi_ctrl->version = version;
 
 	dsi_ctrl->name = of_get_property(pdev->dev.of_node, "label", NULL);
 	if (!dsi_ctrl->name)
@@ -1227,7 +1250,6 @@
 		goto fail_clks;
 	}
 
-	dsi_ctrl->version = version;
 	rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version,
 				    dsi_ctrl->cell_index);
 	if (rc) {
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 161024a..859d707 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -41,6 +41,7 @@
 	DSI_CTRL_VERSION_UNKNOWN,
 	DSI_CTRL_VERSION_1_4,
 	DSI_CTRL_VERSION_2_0,
+	DSI_CTRL_VERSION_2_2,
 	DSI_CTRL_VERSION_MAX
 };
 
@@ -575,18 +576,26 @@
 
 /*
  * struct dsi_ctrl_hw - DSI controller hardware object specific to an instance
- * @base:           VA for the DSI controller base address.
- * @length:         Length of the DSI controller register map.
- * @index:          Instance ID of the controller.
- * @feature_map:    Features supported by the DSI controller.
- * @ops:            Function pointers to the operations supported by the
- *                  controller.
+ * @base:                   VA for the DSI controller base address.
+ * @length:                 Length of the DSI controller register map.
+ * @mmss_misc_base:         Base address of mmss_misc register map.
+ * @mmss_misc_length:       Length of mmss_misc register map.
+ * @disp_cc_base:           Base address of disp_cc register map.
+ * @disp_cc_length:         Length of disp_cc register map.
+ * @index:                  Instance ID of the controller.
+ * @feature_map:            Features supported by the DSI controller.
+ * @ops:                    Function pointers to the operations supported by the
+ *                          controller.
+ * @supported_interrupts:   Number of supported interrupts.
+ * @supported_errors:       Number of supported errors.
  */
 struct dsi_ctrl_hw {
 	void __iomem *base;
 	u32 length;
 	void __iomem *mmss_misc_base;
 	u32 mmss_misc_length;
+	void __iomem *disp_cc_base;
+	u32 disp_cc_length;
 	u32 index;
 
 	/* features */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c
new file mode 100644
index 0000000..1b1e811
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "dsi-hw:" fmt
+
+#include "dsi_ctrl_hw.h"
+#include "dsi_ctrl_reg.h"
+#include "dsi_hw.h"
+
+/* Equivalent to register DISP_CC_MISC_CMD */
+#define DISP_CC_CLAMP_REG_OFF 0x00
+
+/**
+ * dsi_ctrl_hw_22_phy_reset_config() - to configure clamp control during ulps
+ * @ctrl:          Pointer to the controller host hardware.
+ * @enable:      boolean to specify enable/disable.
+ */
+void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
+		bool enable)
+{
+	u32 reg = 0;
+
+	reg = DSI_DISP_CC_R32(ctrl, DISP_CC_CLAMP_REG_OFF);
+
+	/* Mask/unmask disable PHY reset bit */
+	if (enable)
+		reg &= ~BIT(ctrl->index);
+	else
+		reg |= BIT(ctrl->index);
+	DSI_DISP_CC_W32(ctrl, DISP_CC_CLAMP_REG_OFF, reg);
+}
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 8605338..122a63d 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
@@ -320,8 +320,8 @@
 	reg |= (common_cfg->bit_swap_green ? BIT(4) : 0);
 	reg |= (common_cfg->bit_swap_blue ? BIT(8) : 0);
 	DSI_W32(ctrl, DSI_VIDEO_MODE_DATA_CTRL, reg);
-	/* Enable Timing double buffering */
-	DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1);
+	/* Disable Timing double buffering */
+	DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x0);
 
 
 	pr_debug("[DSI_%d] Video engine setup done\n", ctrl->index);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
index 447f613..8250da3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
@@ -33,6 +33,15 @@
 		writel_relaxed((val), (dsi_hw)->mmss_misc_base + (off)); \
 	} while (0)
 
+#define DSI_DISP_CC_R32(dsi_hw, off) \
+	readl_relaxed((dsi_hw)->disp_cc_base + (off))
+#define DSI_DISP_CC_W32(dsi_hw, off, val) \
+	do {\
+		pr_err("[DSI_%d][%s] - [0x%08x]\n", \
+			(dsi_hw)->index, #off, val); \
+		writel_relaxed((val), (dsi_hw)->disp_cc_base + (off)); \
+	} while (0)
+
 #define DSI_R64(dsi_hw, off) readq_relaxed((dsi_hw)->base + (off))
 #define DSI_W64(dsi_hw, off, val) writeq_relaxed((val), (dsi_hw)->base + (off))
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 96a98bd..cdc1ff6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -388,7 +388,7 @@
 	/** TODO: initialize debugfs */
 	dsi_phy->pdev = pdev;
 	platform_set_drvdata(pdev, dsi_phy);
-	pr_debug("Probe successful for %s\n", dsi_phy->name);
+	pr_info("Probe successful for %s\n", dsi_phy->name);
 	return 0;
 
 fail_supplies:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
index 96f5c19..6a3dad8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
@@ -159,7 +159,7 @@
 			    struct dsi_phy_cfg *cfg)
 {
 	int i;
-	u8 tx_dctrl[] = {0x00, 0x00, 0x00, 0x02, 0x01};
+	u8 tx_dctrl[] = {0x00, 0x00, 0x00, 0x04, 0x01};
 
 	/* Strength ctrl settings */
 	for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
@@ -186,6 +186,10 @@
 		DSI_W32(phy, DSIPHY_LNX_OFFSET_BOT_CTRL(i), 0x0);
 		DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]);
 	}
+
+	/* Toggle BIT 0 to release freeze I/0 */
+	DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x05);
+	DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x04);
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 4b263d3..4471d0b 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -138,6 +138,7 @@
 	CRTC_PROP_MEM_IB,
 	CRTC_PROP_ROT_PREFILL_BW,
 	CRTC_PROP_ROT_CLK,
+	CRTC_PROP_ROI_V1,
 
 	/* total # of properties */
 	CRTC_PROP_COUNT
@@ -158,6 +159,7 @@
 	CONNECTOR_PROP_DST_Y,
 	CONNECTOR_PROP_DST_W,
 	CONNECTOR_PROP_DST_H,
+	CONNECTOR_PROP_ROI_V1,
 
 	/* enum/bitmask properties */
 	CONNECTOR_PROP_TOPOLOGY_NAME,
@@ -200,6 +202,38 @@
 };
 
 /**
+ * struct msm_roi_alignment - region of interest alignment restrictions
+ * @xstart_pix_align: left x offset alignment restriction
+ * @width_pix_align: width alignment restriction
+ * @ystart_pix_align: top y offset alignment restriction
+ * @height_pix_align: height alignment restriction
+ * @min_width: minimum width restriction
+ * @min_height: minimum height restriction
+ */
+struct msm_roi_alignment {
+	uint32_t xstart_pix_align;
+	uint32_t width_pix_align;
+	uint32_t ystart_pix_align;
+	uint32_t height_pix_align;
+	uint32_t min_width;
+	uint32_t min_height;
+};
+
+/**
+ * struct msm_roi_caps - display's region of interest capabilities
+ * @enabled: true if some region of interest is supported
+ * @merge_rois: merge rois before sending to display
+ * @num_roi: maximum number of rois supported
+ * @align: roi alignment restrictions
+ */
+struct msm_roi_caps {
+	bool enabled;
+	bool merge_rois;
+	uint32_t num_roi;
+	struct msm_roi_alignment align;
+};
+
+/**
  * struct msm_display_dsc_info - defines dsc configuration
  * @version:                 DSC version.
  * @scr_rev:                 DSC revision.
@@ -338,6 +372,7 @@
  * @vtotal:		display vertical total
  * @jitter:		display jitter configuration
  * @comp_info:          Compression supported by the display
+ * @roi_caps:           Region of interest capability info
  */
 struct msm_display_info {
 	int intf_type;
@@ -361,21 +396,19 @@
 	uint32_t jitter;
 
 	struct msm_compression_info comp_info;
+	struct msm_roi_caps roi_caps;
 };
 
 #define MSM_MAX_ROI	4
 
 /**
- * struct msm_roi_mapping - Regions of interest structure for mapping CRTC to
- *	Connector output
- * @num_rects: number of valid rectangles in src and dst arrays
- * @src: source roi rectangle
- * @dst: destination roi rectangle
+ * struct msm_roi_list - list of regions of interest for a drm object
+ * @num_rects: number of valid rectangles in the roi array
+ * @roi: list of roi rectangles
  */
-struct msm_roi_mapping {
+struct msm_roi_list {
 	uint32_t num_rects;
-	struct drm_clip_rect src[MSM_MAX_ROI];
-	struct drm_clip_rect dst[MSM_MAX_ROI];
+	struct drm_clip_rect roi[MSM_MAX_ROI];
 };
 
 /**
@@ -383,7 +416,7 @@
  * @rois: Regions of interest structure for mapping CRTC to Connector output
  */
 struct msm_display_kickoff_params {
-	struct msm_roi_mapping *rois;
+	struct msm_roi_list *rois;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 6c2d643..e3f8261 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -21,6 +21,12 @@
 
 #define BL_NODE_NAME_SIZE 32
 
+#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
+		(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
+
+#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
+		(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
+
 static const struct drm_prop_enum_list e_topology_name[] = {
 	{SDE_RM_TOPOLOGY_UNKNOWN,	"sde_unknown"},
 	{SDE_RM_TOPOLOGY_SINGLEPIPE,	"sde_singlepipe"},
@@ -248,6 +254,25 @@
 	return rc;
 }
 
+void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
+{
+	struct sde_connector *c_conn;
+	struct dsi_display *display;
+	u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
+
+	if (!connector) {
+		SDE_ERROR("invalid connector\n");
+		return;
+	}
+
+	c_conn = to_sde_connector(connector);
+	display = (struct dsi_display *) c_conn->display;
+
+	if (display && c_conn->ops.clk_ctrl)
+		c_conn->ops.clk_ctrl(display->mdp_clk_handle,
+				DSI_ALL_CLKS, state);
+}
+
 static void sde_connector_destroy(struct drm_connector *connector)
 {
 	struct sde_connector *c_conn;
@@ -397,6 +422,122 @@
 	return &c_state->base;
 }
 
+static int _sde_connector_roi_v1_check_roi(
+		struct sde_connector *c_conn,
+		struct drm_clip_rect *roi_conn,
+		const struct msm_roi_caps *caps)
+{
+	const struct msm_roi_alignment *align = &caps->align;
+	int w = roi_conn->x2 - roi_conn->x1;
+	int h = roi_conn->y2 - roi_conn->y1;
+
+	if (w <= 0 || h <= 0) {
+		SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", w, h);
+		return -EINVAL;
+	}
+
+	if (w < align->min_width || w % align->width_pix_align) {
+		SDE_ERROR_CONN(c_conn,
+				"invalid conn roi width %d min %d align %d\n",
+				w, align->min_width, align->width_pix_align);
+		return -EINVAL;
+	}
+
+	if (h < align->min_height || h % align->height_pix_align) {
+		SDE_ERROR_CONN(c_conn,
+				"invalid conn roi height %d min %d align %d\n",
+				h, align->min_height, align->height_pix_align);
+		return -EINVAL;
+	}
+
+	if (roi_conn->x1 % align->xstart_pix_align) {
+		SDE_ERROR_CONN(c_conn, "invalid conn roi x1 %d align %d\n",
+				roi_conn->x1, align->xstart_pix_align);
+		return -EINVAL;
+	}
+
+	if (roi_conn->y1 % align->ystart_pix_align) {
+		SDE_ERROR_CONN(c_conn, "invalid conn roi y1 %d align %d\n",
+				roi_conn->y1, align->ystart_pix_align);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int _sde_connector_set_roi_v1(
+		struct sde_connector *c_conn,
+		struct sde_connector_state *c_state,
+		void *usr_ptr)
+{
+	struct sde_drm_roi_v1 roi_v1;
+	struct msm_display_info display_info;
+	struct msm_roi_caps *caps;
+	int i, rc;
+
+	if (!c_conn || !c_state) {
+		SDE_ERROR("invalid args\n");
+		return -EINVAL;
+	}
+
+	rc = sde_connector_get_info(&c_conn->base, &display_info);
+	if (rc) {
+		SDE_ERROR_CONN(c_conn, "display get info error: %d\n", rc);
+		return rc;
+	}
+
+	caps = &display_info.roi_caps;
+	if (!caps->enabled) {
+		SDE_ERROR_CONN(c_conn, "display roi capability is disabled\n");
+		return -ENOTSUPP;
+	}
+
+	memset(&c_state->rois, 0, sizeof(c_state->rois));
+
+	if (!usr_ptr) {
+		SDE_DEBUG_CONN(c_conn, "rois cleared\n");
+		return 0;
+	}
+
+	if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
+		SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
+		return -EINVAL;
+	}
+
+	SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
+
+	if (roi_v1.num_rects == 0) {
+		SDE_DEBUG_CONN(c_conn, "rois cleared\n");
+		return 0;
+	}
+
+	if (roi_v1.num_rects > SDE_MAX_ROI_V1 ||
+			roi_v1.num_rects > caps->num_roi) {
+		SDE_ERROR_CONN(c_conn, "too many rects specified: %d\n",
+				roi_v1.num_rects);
+		return -EINVAL;
+	}
+
+	c_state->rois.num_rects = roi_v1.num_rects;
+	for (i = 0; i < roi_v1.num_rects; ++i) {
+		int rc;
+
+		rc = _sde_connector_roi_v1_check_roi(c_conn, &roi_v1.roi[i],
+				caps);
+		if (rc)
+			return rc;
+
+		c_state->rois.roi[i] = roi_v1.roi[i];
+		SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
+				c_state->rois.roi[i].x1,
+				c_state->rois.roi[i].y1,
+				c_state->rois.roi[i].x2,
+				c_state->rois.roi[i].y2);
+	}
+
+	return 0;
+}
+
 static int sde_connector_atomic_set_property(struct drm_connector *connector,
 		struct drm_connector_state *state,
 		struct drm_property *property,
@@ -462,6 +603,12 @@
 			SDE_ERROR("invalid topology_control: 0x%llX\n", val);
 	}
 
+	if (idx == CONNECTOR_PROP_ROI_V1) {
+		rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
+		if (rc)
+			SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
+	}
+
 	/* check for custom property handling */
 	if (!rc && c_conn->ops.set_property) {
 		rc = c_conn->ops.set_property(connector,
@@ -511,13 +658,7 @@
 
 	idx = msm_property_index(&c_conn->property_info, property);
 	if (idx == CONNECTOR_PROP_RETIRE_FENCE)
-		/*
-		 * Set a fence offset if not a virtual connector, so that the
-		 * fence signals after one additional commit rather than at the
-		 * end of the current one.
-		 */
-		rc = sde_fence_create(&c_conn->retire_fence, val,
-			c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
+		rc = sde_fence_create(&c_conn->retire_fence, val, 0);
 	else
 		/* get cached property value */
 		rc = msm_property_atomic_get(&c_conn->property_info,
@@ -706,6 +847,7 @@
 	struct sde_kms_info *info;
 	struct sde_connector *c_conn = NULL;
 	struct dsi_display *dsi_display;
+	struct msm_display_info display_info;
 	int rc;
 
 	if (!dev || !dev->dev_private || !encoder) {
@@ -838,6 +980,13 @@
 		}
 	}
 
+	rc = sde_connector_get_info(&c_conn->base, &display_info);
+	if (!rc && display_info.roi_caps.enabled) {
+		msm_property_install_volatile_range(
+				&c_conn->property_info, "sde_drm_roi_v1", 0x0,
+				0, ~0, 0, CONNECTOR_PROP_ROI_V1);
+	}
+
 	msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
 			0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 70d4952..601299e 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -150,6 +150,14 @@
 	int (*pre_kickoff)(struct drm_connector *connector,
 			void *display,
 			struct msm_display_kickoff_params *params);
+
+	/**
+	 * clk_ctrl - perform clk enable/disable on the connector
+	 * @handle: Pointer to clk handle
+	 * @type: Type of clks
+	 * @enable: State of clks
+	 */
+	int (*clk_ctrl)(void *handle, u32 type, u32 state);
 };
 
 /**
@@ -273,7 +281,7 @@
 	int mmu_id;
 	uint64_t property_values[CONNECTOR_PROP_COUNT];
 
-	struct msm_roi_mapping rois;
+	struct msm_roi_list rois;
 };
 
 /**
@@ -366,6 +374,13 @@
 		struct msm_display_info *info);
 
 /**
+ * sde_connector_clk_ctrl - enables/disables the connector clks
+ * @connector: Pointer to drm connector object
+ * @enable: true/false to enable/disable
+ */
+void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable);
+
+/**
  * sde_connector_trigger_event - indicate that an event has occurred
  *	Any callbacks that have been registered against this event will
  *	be called from the same thread context.
@@ -425,5 +440,22 @@
  */
 int sde_connector_pre_kickoff(struct drm_connector *connector);
 
+/**
+ * sde_connector_needs_offset - adjust the output fence offset based on
+ *                              display type
+ * @connector: Pointer to drm connector object
+ * Returns: true if offset is required, false for all other cases.
+ */
+static inline bool sde_connector_needs_offset(struct drm_connector *connector)
+{
+	struct sde_connector *c_conn;
+
+	if (!connector)
+		return false;
+
+	c_conn = to_sde_connector(connector);
+	return (c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
+}
+
 #endif /* _SDE_CONNECTOR_H_ */
 
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index a44dd68..6bae083 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -656,21 +656,344 @@
 	}
 }
 
+void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
+		const struct sde_rect **crtc_roi)
+{
+	struct sde_crtc_state *crtc_state;
+
+	if (!state || !crtc_roi)
+		return;
+
+	crtc_state = to_sde_crtc_state(state);
+	*crtc_roi = &crtc_state->crtc_roi;
+}
+
+static int _sde_crtc_set_roi_v1(struct drm_crtc_state *state,
+		void *usr_ptr)
+{
+	struct drm_crtc *crtc;
+	struct sde_crtc_state *cstate;
+	struct sde_drm_roi_v1 roi_v1;
+	int i;
+
+	if (!state) {
+		SDE_ERROR("invalid args\n");
+		return -EINVAL;
+	}
+
+	cstate = to_sde_crtc_state(state);
+	crtc = cstate->base.crtc;
+
+	memset(&cstate->user_roi_list, 0, sizeof(cstate->user_roi_list));
+
+	if (!usr_ptr) {
+		SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc));
+		return 0;
+	}
+
+	if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
+		SDE_ERROR("crtc%d: failed to copy roi_v1 data\n", DRMID(crtc));
+		return -EINVAL;
+	}
+
+	SDE_DEBUG("crtc%d: num_rects %d\n", DRMID(crtc), roi_v1.num_rects);
+
+	if (roi_v1.num_rects == 0) {
+		SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc));
+		return 0;
+	}
+
+	if (roi_v1.num_rects > SDE_MAX_ROI_V1) {
+		SDE_ERROR("crtc%d: too many rects specified: %d\n", DRMID(crtc),
+				roi_v1.num_rects);
+		return -EINVAL;
+	}
+
+	cstate->user_roi_list.num_rects = roi_v1.num_rects;
+	for (i = 0; i < roi_v1.num_rects; ++i) {
+		cstate->user_roi_list.roi[i] = roi_v1.roi[i];
+		SDE_DEBUG("crtc%d: roi%d: roi (%d,%d) (%d,%d)\n",
+				DRMID(crtc), i,
+				cstate->user_roi_list.roi[i].x1,
+				cstate->user_roi_list.roi[i].y1,
+				cstate->user_roi_list.roi[i].x2,
+				cstate->user_roi_list.roi[i].y2);
+	}
+
+	return 0;
+}
+
+static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct drm_connector *conn;
+	struct drm_connector_state *conn_state;
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *crtc_state;
+	struct sde_rect *crtc_roi;
+	struct drm_clip_rect crtc_clip, *user_rect;
+	int i, num_attached_conns = 0;
+
+	if (!crtc || !state)
+		return -EINVAL;
+
+	sde_crtc = to_sde_crtc(crtc);
+	crtc_state = to_sde_crtc_state(state);
+	crtc_roi = &crtc_state->crtc_roi;
+
+	/* init to invalid range maxes */
+	crtc_clip.x1 = ~0;
+	crtc_clip.y1 = ~0;
+	crtc_clip.x2 = 0;
+	crtc_clip.y2 = 0;
+
+	for_each_connector_in_state(state->state, conn, conn_state, i) {
+		struct sde_connector_state *sde_conn_state;
+
+		if (!conn_state || conn_state->crtc != crtc)
+			continue;
+
+		if (num_attached_conns) {
+			SDE_ERROR(
+				"crtc%d: unsupported: roi on crtc w/ >1 connectors\n",
+					DRMID(crtc));
+			return -EINVAL;
+		}
+		++num_attached_conns;
+
+		sde_conn_state = to_sde_connector_state(conn_state);
+
+		if (memcmp(&sde_conn_state->rois, &crtc_state->user_roi_list,
+				sizeof(crtc_state->user_roi_list))) {
+			SDE_ERROR("%s: crtc -> conn roi scaling unsupported\n",
+					sde_crtc->name);
+			return -EINVAL;
+		}
+	}
+
+	/* aggregate all clipping rectangles together for overall crtc roi */
+	for (i = 0; i < crtc_state->user_roi_list.num_rects; i++) {
+		user_rect = &crtc_state->user_roi_list.roi[i];
+
+		crtc_clip.x1 = min(crtc_clip.x1, user_rect->x1);
+		crtc_clip.y1 = min(crtc_clip.y1, user_rect->y1);
+		crtc_clip.x2 = max(crtc_clip.x2, user_rect->x2);
+		crtc_clip.y2 = max(crtc_clip.y2, user_rect->y2);
+
+		SDE_DEBUG(
+			"%s: conn%d roi%d (%d,%d),(%d,%d) -> crtc (%d,%d),(%d,%d)\n",
+				sde_crtc->name, DRMID(crtc), i,
+				user_rect->x1, user_rect->y1,
+				user_rect->x2, user_rect->y2,
+				crtc_clip.x1, crtc_clip.y1,
+				crtc_clip.x2, crtc_clip.y2);
+
+	}
+
+	if (crtc_clip.x2  && crtc_clip.y2) {
+		crtc_roi->x = crtc_clip.x1;
+		crtc_roi->y = crtc_clip.y1;
+		crtc_roi->w = crtc_clip.x2 - crtc_clip.x1;
+		crtc_roi->h = crtc_clip.y2 - crtc_clip.y1;
+	} else {
+		crtc_roi->x = 0;
+		crtc_roi->y = 0;
+		crtc_roi->w = 0;
+		crtc_roi->h = 0;
+	}
+
+	SDE_DEBUG("%s: crtc roi (%d,%d,%d,%d)\n", sde_crtc->name,
+			crtc_roi->x, crtc_roi->y, crtc_roi->w, crtc_roi->h);
+
+	return 0;
+}
+
+static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
+		struct drm_crtc_state *state, int lm_idx)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *crtc_state;
+	const struct sde_rect *crtc_roi;
+	const struct sde_rect *lm_bounds;
+	struct sde_rect *lm_roi;
+
+	if (!crtc || !state || lm_idx >= ARRAY_SIZE(crtc_state->lm_bounds))
+		return -EINVAL;
+
+	sde_crtc = to_sde_crtc(crtc);
+	crtc_state = to_sde_crtc_state(state);
+	crtc_roi = &crtc_state->crtc_roi;
+	lm_bounds = &crtc_state->lm_bounds[lm_idx];
+	lm_roi = &crtc_state->lm_roi[lm_idx];
+
+	if (!sde_kms_rect_is_null(crtc_roi)) {
+		sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi);
+		if (sde_kms_rect_is_null(lm_roi)) {
+			SDE_ERROR("unsupported R/L only partial update\n");
+			return -EINVAL;
+		}
+	} else {
+		memcpy(lm_roi, lm_bounds, sizeof(*lm_roi));
+	}
+
+	SDE_DEBUG("%s: lm%d roi (%d,%d,%d,%d)\n", sde_crtc->name, lm_idx,
+			lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h);
+
+	return 0;
+}
+
+static int _sde_crtc_check_rois_centered_and_symmetric(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *crtc_state;
+	const struct sde_rect *roi_prv, *roi_cur;
+	int lm_idx;
+
+	if (!crtc || !state)
+		return -EINVAL;
+
+	/*
+	 * On certain HW, ROIs must be centered on the split between LMs,
+	 * and be of equal width.
+	 */
+
+	sde_crtc = to_sde_crtc(crtc);
+	crtc_state = to_sde_crtc_state(state);
+
+	roi_prv = &crtc_state->lm_roi[0];
+	for (lm_idx = 1; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+		roi_cur = &crtc_state->lm_roi[lm_idx];
+
+		/* check lm rois are equal width & first roi ends at 2nd roi */
+		if (((roi_prv->x + roi_prv->w) != roi_cur->x) ||
+				(roi_prv->w != roi_cur->w)) {
+			SDE_ERROR("%s: roi lm%d x %d w %d lm%d x %d w %d\n",
+					sde_crtc->name,
+					lm_idx-1, roi_prv->x, roi_prv->w,
+					lm_idx, roi_cur->x, roi_cur->w);
+			return -EINVAL;
+		}
+		roi_prv = roi_cur;
+	}
+
+	return 0;
+}
+
+static int _sde_crtc_check_planes_within_crtc_roi(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *crtc_state;
+	const struct sde_rect *crtc_roi;
+	struct drm_plane_state *pstate;
+	struct drm_plane *plane;
+
+	if (!crtc || !state)
+		return -EINVAL;
+
+	/*
+	 * Reject commit if a Plane CRTC destination coordinates fall outside
+	 * the partial CRTC ROI. LM output is determined via connector ROIs,
+	 * if they are specified, not Plane CRTC ROIs.
+	 */
+
+	sde_crtc = to_sde_crtc(crtc);
+	crtc_state = to_sde_crtc_state(state);
+	crtc_roi = &crtc_state->crtc_roi;
+
+	if (sde_kms_rect_is_null(crtc_roi))
+		return 0;
+
+	drm_atomic_crtc_state_for_each_plane(plane, state) {
+		struct sde_rect plane_roi, intersection;
+
+		pstate = drm_atomic_get_plane_state(state->state, plane);
+		if (IS_ERR_OR_NULL(pstate)) {
+			int rc = PTR_ERR(pstate);
+
+			SDE_ERROR("%s: failed to get plane%d state, %d\n",
+					sde_crtc->name, plane->base.id, rc);
+			return rc;
+		}
+
+		plane_roi.x = pstate->crtc_x;
+		plane_roi.y = pstate->crtc_y;
+		plane_roi.w = pstate->crtc_w;
+		plane_roi.h = pstate->crtc_h;
+		sde_kms_rect_intersect(crtc_roi, &plane_roi, &intersection);
+		if (!sde_kms_rect_is_equal(&plane_roi, &intersection)) {
+			SDE_ERROR(
+				"%s: plane%d crtc roi (%d,%d,%d,%d) outside crtc roi (%d,%d,%d,%d)\n",
+					sde_crtc->name, plane->base.id,
+					plane_roi.x, plane_roi.y,
+					plane_roi.w, plane_roi.h,
+					crtc_roi->x, crtc_roi->y,
+					crtc_roi->w, crtc_roi->h);
+			return -E2BIG;
+		}
+	}
+
+	return 0;
+}
+
+static int _sde_crtc_check_rois(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct sde_crtc *sde_crtc;
+	int lm_idx;
+	int rc;
+
+	if (!crtc || !state)
+		return -EINVAL;
+
+	sde_crtc = to_sde_crtc(crtc);
+
+	rc = _sde_crtc_set_crtc_roi(crtc, state);
+	if (rc)
+		return rc;
+
+	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+		rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
+		if (rc)
+			return rc;
+	}
+
+	rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state);
+	if (rc)
+		return rc;
+
+	rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
 static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc)
 {
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *crtc_state;
+	const struct sde_rect *lm_roi;
+	struct sde_hw_mixer *hw_lm;
 	int lm_idx, lm_horiz_position;
 
+	if (!crtc)
+		return;
+
 	sde_crtc = to_sde_crtc(crtc);
 	crtc_state = to_sde_crtc_state(crtc->state);
 
 	lm_horiz_position = 0;
 	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
-		const struct sde_rect *lm_roi = &crtc_state->lm_bounds[lm_idx];
-		struct sde_hw_mixer *hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
 		struct sde_hw_mixer_cfg cfg;
 
+		lm_roi = &crtc_state->lm_roi[lm_idx];
+		hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
+
+		SDE_EVT32(DRMID(crtc_state->base.crtc), lm_idx,
+			lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h);
+
 		if (sde_kms_rect_is_null(lm_roi))
 			continue;
 
@@ -742,9 +1065,12 @@
 
 		format = to_sde_format(msm_framebuffer_format(pstate->base.fb));
 
-		SDE_EVT32(DRMID(plane), state->src_x, state->src_y,
-			state->src_w >> 16, state->src_h >> 16, state->crtc_x,
-			state->crtc_y, state->crtc_w, state->crtc_h);
+		SDE_EVT32(DRMID(crtc), DRMID(plane),
+				state->fb ? state->fb->base.id : -1,
+				state->src_x >> 16, state->src_y >> 16,
+				state->src_w >> 16, state->src_h >> 16,
+				state->crtc_x, state->crtc_y,
+				state->crtc_w, state->crtc_h);
 
 		for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
 			struct sde_rect intersect;
@@ -877,6 +1203,8 @@
 		ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx,
 			&sde_crtc->stage_cfg, i);
 	}
+
+	_sde_crtc_program_lm_output_roi(crtc);
 }
 
 void sde_crtc_prepare_commit(struct drm_crtc *crtc,
@@ -1329,14 +1657,18 @@
 	crtc_split_width = sde_crtc_mixer_width(sde_crtc, adj_mode);
 
 	for (i = 0; i < sde_crtc->num_mixers; i++) {
-		struct sde_rect *lm_bound = &cstate->lm_bounds[i];
-
-		lm_bound->x = crtc_split_width * i;
-		lm_bound->y = 0;
-		lm_bound->w = crtc_split_width;
-		lm_bound->h = adj_mode->vdisplay;
-		SDE_EVT32(DRMID(crtc), i, lm_bound->x, lm_bound->y,
-				lm_bound->w, lm_bound->h);
+		cstate->lm_bounds[i].x = crtc_split_width * i;
+		cstate->lm_bounds[i].y = 0;
+		cstate->lm_bounds[i].w = crtc_split_width;
+		cstate->lm_bounds[i].h = adj_mode->vdisplay;
+		memcpy(&cstate->lm_roi[i], &cstate->lm_bounds[i],
+				sizeof(cstate->lm_roi[i]));
+		SDE_EVT32(DRMID(crtc), i,
+				cstate->lm_bounds[i].x, cstate->lm_bounds[i].y,
+				cstate->lm_bounds[i].w, cstate->lm_bounds[i].h);
+		SDE_DEBUG("%s: lm%d bnd&roi (%d,%d,%d,%d)\n", sde_crtc->name, i,
+				cstate->lm_roi[i].x, cstate->lm_roi[i].y,
+				cstate->lm_roi[i].w, cstate->lm_roi[i].h);
 	}
 
 	drm_mode_debug_printmodeline(adj_mode);
@@ -1366,10 +1698,10 @@
 	sde_crtc = to_sde_crtc(crtc);
 	dev = crtc->dev;
 
-	if (!sde_crtc->num_mixers)
+	if (!sde_crtc->num_mixers) {
 		_sde_crtc_setup_mixers(crtc);
-
-	_sde_crtc_setup_lm_bounds(crtc, crtc->state);
+		_sde_crtc_setup_lm_bounds(crtc, crtc->state);
+	}
 
 	if (sde_crtc->event) {
 		WARN_ON(sde_crtc->event);
@@ -2117,6 +2449,11 @@
 		}
 	}
 
+	rc = _sde_crtc_check_rois(crtc, state);
+	if (rc) {
+		SDE_ERROR("crtc%d failed roi check %d\n", crtc->base.id, rc);
+		goto end;
+	}
 
 end:
 	_sde_crtc_rp_free_unused(&cstate->rp);
@@ -2243,6 +2580,9 @@
 			"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);
 
 	sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion);
@@ -2315,6 +2655,9 @@
 			case CRTC_PROP_DIM_LAYER_V1:
 				_sde_crtc_set_dim_layer_v1(cstate, (void *)val);
 				break;
+			case CRTC_PROP_ROI_V1:
+				ret = _sde_crtc_set_roi_v1(state, (void *)val);
+				break;
 			default:
 				/* nothing to do */
 				break;
@@ -2364,19 +2707,28 @@
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *cstate;
 	int i, ret = -EINVAL;
+	bool conn_offset = 0;
 
 	if (!crtc || !state) {
 		SDE_ERROR("invalid argument(s)\n");
 	} else {
 		sde_crtc = to_sde_crtc(crtc);
 		cstate = to_sde_crtc_state(state);
+
+		for (i = 0; i < cstate->num_connectors; ++i) {
+			conn_offset = sde_connector_needs_offset(
+						cstate->connectors[i]);
+			if (conn_offset)
+				break;
+		}
+
 		i = msm_property_index(&sde_crtc->property_info, property);
 		if (i == CRTC_PROP_OUTPUT_FENCE) {
 			uint32_t offset = sde_crtc_get_property(cstate,
 					CRTC_PROP_OUTPUT_FENCE_OFFSET);
 
-			ret = sde_fence_create(
-					&sde_crtc->output_fence, val, offset);
+			ret = sde_fence_create(&sde_crtc->output_fence, val,
+							offset + conn_offset);
 			if (ret)
 				SDE_ERROR("fence create failed\n");
 		} else {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 36231d4..7ad0955 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -250,6 +250,11 @@
  * @rsc_client    : sde rsc client when mode is valid
  * @lm_bounds     : LM boundaries based on current mode full resolution, no ROI.
  *                  Origin top left of CRTC.
+ * @crtc_roi      : Current CRTC ROI. Possibly sub-rectangle of mode.
+ *                  Origin top left of CRTC.
+ * @lm_roi        : Current LM ROI, possibly sub-rectangle of mode.
+ *                  Origin top left of CRTC.
+ * @user_roi_list : List of user's requested ROIs as from set property
  * @property_values: Current crtc property values
  * @input_fence_timeout_ns : Cached input fence timeout, in ns
  * @property_blobs: Reference pointers for blob properties
@@ -270,6 +275,9 @@
 	bool rsc_update;
 
 	struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
+	struct sde_rect crtc_roi;
+	struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
+	struct msm_roi_list user_roi_list;
 
 	uint64_t property_values[CRTC_PROP_COUNT];
 	uint64_t input_fence_timeout_ns;
@@ -433,4 +441,14 @@
  */
 void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag);
 
+/**
+ * sde_crtc_get_crtc_roi - retrieve the crtc_roi from the given state object
+ *	used to allow the planes to adjust their final lm out_xy value in the
+ *	case of partial update
+ * @crtc_state: Pointer to crtc state
+ * @crtc_roi: Output pointer to crtc roi in the given state
+ */
+void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
+		const struct sde_rect **crtc_roi);
+
 #endif /* _SDE_CRTC_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 11cca1f..cfa3b5e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -490,8 +490,8 @@
 		return 0;
 
 	for (i = 0, cur_pos = dst_list_pos;
-		(cur_pos < (dst_list_size - 1)) && src_list[i].fourcc_format
-		&& (i < src_list_size); ++i, ++cur_pos)
+		(cur_pos < (dst_list_size - 1)) && (i < src_list_size)
+		&& src_list[i].fourcc_format; ++i, ++cur_pos)
 		dst_list[cur_pos] = src_list[i];
 
 	dst_list[cur_pos].fourcc_format = 0;
@@ -565,7 +565,7 @@
 				rc = -EINVAL;
 			}
 			*off_count = 0;
-			memset(prop_count, 0, sizeof(int *) * prop_size);
+			memset(prop_count, 0, sizeof(int) * prop_size);
 			return rc;
 		}
 	}
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 2393e61..4a5479d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -566,7 +566,8 @@
 		.get_info =   dsi_display_get_info,
 		.set_backlight = dsi_display_set_backlight,
 		.soft_reset   = dsi_display_soft_reset,
-		.pre_kickoff  = dsi_conn_pre_kickoff
+		.pre_kickoff  = dsi_conn_pre_kickoff,
+		.clk_ctrl = dsi_display_clk_ctrl
 	};
 	static const struct sde_connector_ops wb_ops = {
 		.post_init =    sde_wb_connector_post_init,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index bd6b302..8662207 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2204,6 +2204,7 @@
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb;
 	struct sde_rect src, dst;
+	const struct sde_rect *crtc_roi;
 	bool q16_data = true;
 	int idx;
 
@@ -2283,6 +2284,11 @@
 		}
 	}
 
+	/* re-program the output rects always in the case of partial update */
+	sde_crtc_get_crtc_roi(crtc->state, &crtc_roi);
+	if (!sde_kms_rect_is_null(crtc_roi))
+		pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
+
 	if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
 		memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
 
@@ -2320,6 +2326,13 @@
 			src.y &= ~0x1;
 		}
 
+		/*
+		 * adjust layer mixer position of the sspp in the presence
+		 * of a partial update to the active lm origin
+		 */
+		dst.x -= crtc_roi->x;
+		dst.y -= crtc_roi->y;
+
 		psde->pipe_cfg.src_rect = src;
 		psde->pipe_cfg.dst_rect = dst;
 
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 62efe8e..9a68dbe 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -25,10 +25,44 @@
 #include <linux/msm-bus.h>
 #include <linux/msm-bus-board.h>
 #include <linux/sde_io_util.h>
+#include <linux/sde_rsc.h>
 
 #include "sde_power_handle.h"
 #include "sde_trace.h"
 
+static void sde_power_event_trigger_locked(struct sde_power_handle *phandle,
+		u32 event_type)
+{
+	struct sde_power_event *event;
+
+	list_for_each_entry(event, &phandle->event_list, list) {
+		if (event->event_type & event_type)
+			event->cb_fnc(event_type, event->usr);
+	}
+}
+
+static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable)
+{
+	u32 rsc_state;
+
+	/* creates the rsc client on the first enable */
+	if (!phandle->rsc_client_init) {
+		phandle->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX,
+				"sde_power_handle", false);
+		if (IS_ERR_OR_NULL(phandle->rsc_client)) {
+			pr_debug("sde rsc client create failed :%ld\n",
+						PTR_ERR(phandle->rsc_client));
+			phandle->rsc_client = NULL;
+		}
+		phandle->rsc_client_init = true;
+	}
+
+	rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
+
+	return sde_rsc_client_state_update(phandle->rsc_client,
+			rsc_state, NULL, -1);
+}
+
 struct sde_power_client *sde_power_client_create(
 	struct sde_power_handle *phandle, char *client_name)
 {
@@ -48,6 +82,7 @@
 	strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
 	client->usecase_ndx = VOTE_INDEX_DISABLE;
 	client->id = id;
+	client->active = true;
 	pr_debug("client %s created:%pK id :%d\n", client_name,
 		client, id);
 	id++;
@@ -62,6 +97,9 @@
 {
 	if (!client  || !phandle) {
 		pr_err("reg bus vote: invalid client handle\n");
+	} else if (!client->active) {
+		pr_err("sde power deinit already done\n");
+		kfree(client);
 	} else {
 		pr_debug("bus vote client %s destroyed:%pK id:%u\n",
 			client->name, client, client->id);
@@ -661,6 +699,11 @@
 	}
 
 	INIT_LIST_HEAD(&phandle->power_client_clist);
+	INIT_LIST_HEAD(&phandle->event_list);
+
+	phandle->rsc_client = NULL;
+	phandle->rsc_client_init = false;
+
 	mutex_init(&phandle->phandle_lock);
 
 	return rc;
@@ -672,10 +715,12 @@
 clk_err:
 	msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
 vreg_err:
-	devm_kfree(&pdev->dev, mp->vreg_config);
+	if (mp->vreg_config)
+		devm_kfree(&pdev->dev, mp->vreg_config);
 	mp->num_vreg = 0;
 parse_vreg_err:
-	devm_kfree(&pdev->dev, mp->clk_config);
+	if (mp->clk_config)
+		devm_kfree(&pdev->dev, mp->clk_config);
 	mp->num_clk = 0;
 end:
 	return rc;
@@ -685,6 +730,8 @@
 	struct sde_power_handle *phandle)
 {
 	struct dss_module_power *mp;
+	struct sde_power_client *curr_client, *next_client;
+	struct sde_power_event *curr_event, *next_event;
 
 	if (!phandle || !pdev) {
 		pr_err("invalid input param\n");
@@ -692,6 +739,26 @@
 	}
 	mp = &phandle->mp;
 
+	mutex_lock(&phandle->phandle_lock);
+	list_for_each_entry_safe(curr_client, next_client,
+			&phandle->power_client_clist, list) {
+		pr_err("cliend:%s-%d still registered with refcount:%d\n",
+				curr_client->name, curr_client->id,
+				curr_client->refcount);
+		curr_client->active = false;
+		list_del(&curr_client->list);
+	}
+
+	list_for_each_entry_safe(curr_event, next_event,
+			&phandle->event_list, list) {
+		pr_err("event:%d, client:%s still registered\n",
+				curr_event->event_type,
+				curr_event->client_name);
+		curr_event->active = false;
+		list_del(&curr_event->list);
+	}
+	mutex_unlock(&phandle->phandle_lock);
+
 	sde_power_data_bus_unregister(&phandle->data_bus_handle);
 
 	sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
@@ -708,6 +775,9 @@
 
 	mp->num_vreg = 0;
 	mp->num_clk = 0;
+
+	if (phandle->rsc_client)
+		sde_rsc_client_destroy(phandle->rsc_client);
 }
 
 int sde_power_resource_enable(struct sde_power_handle *phandle,
@@ -757,6 +827,9 @@
 		goto end;
 
 	if (enable) {
+		sde_power_event_trigger_locked(phandle,
+				SDE_POWER_EVENT_PRE_ENABLE);
+
 		rc = sde_power_data_bus_update(&phandle->data_bus_handle,
 									enable);
 		if (rc) {
@@ -764,10 +837,13 @@
 			goto data_bus_hdl_err;
 		}
 
-		rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
-		if (rc) {
-			pr_err("failed to enable vregs rc=%d\n", rc);
-			goto vreg_err;
+		if (!phandle->rsc_client_init) {
+			rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
+									enable);
+			if (rc) {
+				pr_err("failed to enable vregs rc=%d\n", rc);
+				goto vreg_err;
+			}
 		}
 
 		rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
@@ -777,20 +853,39 @@
 			goto reg_bus_hdl_err;
 		}
 
+		rc = sde_power_rsc_update(phandle, true);
+		if (rc) {
+			pr_err("failed to update rsc\n");
+			goto rsc_err;
+		}
+
 		rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
 		if (rc) {
 			pr_err("clock enable failed rc:%d\n", rc);
 			goto clk_err;
 		}
+
+		sde_power_event_trigger_locked(phandle,
+				SDE_POWER_EVENT_POST_ENABLE);
+
 	} else {
+		sde_power_event_trigger_locked(phandle,
+				SDE_POWER_EVENT_PRE_DISABLE);
+
 		msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
 
+		sde_power_rsc_update(phandle, false);
+
 		sde_power_reg_bus_update(phandle->reg_bus_hdl,
 							max_usecase_ndx);
 
-		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
-
+		if (!phandle->rsc_client_init)
+			msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
+									enable);
 		sde_power_data_bus_update(&phandle->data_bus_handle, enable);
+
+		sde_power_event_trigger_locked(phandle,
+				SDE_POWER_EVENT_POST_DISABLE);
 	}
 
 end:
@@ -798,9 +893,12 @@
 	return rc;
 
 clk_err:
+	sde_power_rsc_update(phandle, false);
+rsc_err:
 	sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
 reg_bus_hdl_err:
-	msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
+	if (!phandle->rsc_client_init)
+		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
 vreg_err:
 	sde_power_data_bus_update(&phandle->data_bus_handle, 0);
 data_bus_hdl_err:
@@ -903,3 +1001,52 @@
 
 	return clk;
 }
+
+struct sde_power_event *sde_power_handle_register_event(
+		struct sde_power_handle *phandle,
+		u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
+		void *usr, char *client_name)
+{
+	struct sde_power_event *event;
+
+	if (!phandle) {
+		pr_err("invalid power handle\n");
+		return ERR_PTR(-EINVAL);
+	} else if (!cb_fnc || !event_type) {
+		pr_err("no callback fnc or event type\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	event = kzalloc(sizeof(struct sde_power_event), GFP_KERNEL);
+	if (!event)
+		return ERR_PTR(-ENOMEM);
+
+	event->event_type = event_type;
+	event->cb_fnc = cb_fnc;
+	event->usr = usr;
+	strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN);
+	event->active = true;
+
+	mutex_lock(&phandle->phandle_lock);
+	list_add(&event->list, &phandle->event_list);
+	mutex_unlock(&phandle->phandle_lock);
+
+	return event;
+}
+
+void sde_power_handle_unregister_event(
+		struct sde_power_handle *phandle,
+		struct sde_power_event *event)
+{
+	if (!phandle || !event) {
+		pr_err("invalid phandle or event\n");
+	} else if (!event->active) {
+		pr_err("power handle deinit already done\n");
+		kfree(event);
+	} else {
+		mutex_lock(&phandle->phandle_lock);
+		list_del_init(&event->list);
+		mutex_unlock(&phandle->phandle_lock);
+		kfree(event);
+	}
+}
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index 4e262a3..b26ef9f 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -23,6 +23,18 @@
 
 #include <linux/sde_io_util.h>
 
+/* event will be triggered before power handler disable */
+#define SDE_POWER_EVENT_PRE_DISABLE	0x1
+
+/* event will be triggered after power handler disable */
+#define SDE_POWER_EVENT_POST_DISABLE	0x2
+
+/* event will be triggered before power handler enable */
+#define SDE_POWER_EVENT_PRE_ENABLE	0x4
+
+/* event will be triggered after power handler enable */
+#define SDE_POWER_EVENT_POST_ENABLE	0x8
+
 /**
  * mdss_bus_vote_type: register bus vote type
  * VOTE_INDEX_DISABLE: removes the client vote
@@ -59,6 +71,7 @@
  * @list:	list to attach power handle master list
  * @ab:         arbitrated bandwidth for each bus client
  * @ib:         instantaneous bandwidth for each bus client
+ * @active:	inidcates the state of sde power handle
  */
 struct sde_power_client {
 	char name[MAX_CLIENT_NAME_LEN];
@@ -68,6 +81,7 @@
 	struct list_head list;
 	u64 ab[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX];
 	u64 ib[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX];
+	bool active;
 };
 
 /**
@@ -90,6 +104,24 @@
 	u32 ao_bw_uc_idx;
 };
 
+/*
+ * struct sde_power_event - local event registration structure
+ * @client_name: name of the client registering
+ * @cb_fnc: pointer to desired callback function
+ * @usr: user pointer to pass to callback event trigger
+ * @event: refer to SDE_POWER_HANDLE_EVENT_*
+ * @list: list to attach event master list
+ * @active: indicates the state of sde power handle
+ */
+struct sde_power_event {
+	char client_name[MAX_CLIENT_NAME_LEN];
+	void (*cb_fnc)(u32 event_type, void *usr);
+	void *usr;
+	u32 event_type;
+	struct list_head list;
+	bool active;
+};
+
 /**
  * struct sde_power_handle: power handle main struct
  * @mp:		module power for clock and regulator
@@ -99,6 +131,9 @@
  * @usecase_ndx: current usecase index
  * @reg_bus_hdl: current register bus handle
  * @data_bus_handle: context structure for data bus control
+ * @event_list: current power handle event list
+ * @rsc_client: sde rsc client pointer
+ * @rsc_client_init: boolean to control rsc client create
  */
 struct sde_power_handle {
 	struct dss_module_power mp;
@@ -108,6 +143,9 @@
 	u32 current_usecase_ndx;
 	u32 reg_bus_hdl;
 	struct sde_power_data_bus_handle data_bus_handle;
+	struct list_head event_list;
+	struct sde_rsc_client *rsc_client;
+	bool rsc_client_init;
 };
 
 /**
@@ -226,4 +264,28 @@
 void sde_power_data_bus_bandwidth_ctrl(struct sde_power_handle *phandle,
 		struct sde_power_client *pclient, int enable);
 
+/**
+ * sde_power_handle_register_event - register a callback function for an event.
+ *	Clients can register for multiple events with a single register.
+ *	Any block with access to phandle can register for the event
+ *	notification.
+ * @phandle:	power handle containing the resources
+ * @event_type:	event type to register; refer SDE_POWER_HANDLE_EVENT_*
+ * @cb_fnc:	pointer to desired callback function
+ * @usr:	user pointer to pass to callback on event trigger
+ *
+ * Return:	event pointer if success, or error code otherwise
+ */
+struct sde_power_event *sde_power_handle_register_event(
+		struct sde_power_handle *phandle,
+		u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
+		void *usr, char *client_name);
+/**
+ * sde_power_handle_unregister_event - unregister callback for event(s)
+ * @phandle:	power handle containing the resources
+ * @event:	event pointer returned after power handle register
+ */
+void sde_power_handle_unregister_event(struct sde_power_handle *phandle,
+		struct sde_power_event *event);
+
 #endif /* _SDE_POWER_HANDLE_H_ */
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index a9ddf0f..96b4472 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -15,6 +15,7 @@
 
 #include <linux/atomic.h>
 #include <linux/bitmap.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
@@ -86,6 +87,7 @@
 #define TCS_TYPE_NR			4
 #define TCS_MBOX_TOUT_MS		2000
 #define MAX_POOL_SIZE			(MAX_TCS_PER_TYPE * TCS_TYPE_NR)
+#define TCS_M_INIT			0xFFFF
 
 struct tcs_drv;
 
@@ -97,10 +99,12 @@
 	struct tasklet_struct tasklet;
 	struct delayed_work dwork;
 	int err;
+	int idx;
+	bool in_use;
 };
 
 struct tcs_response_pool {
-	struct tcs_response *resp;
+	struct tcs_response resp[MAX_POOL_SIZE];
 	spinlock_t lock;
 	DECLARE_BITMAP(avail, MAX_POOL_SIZE);
 };
@@ -116,8 +120,6 @@
 	int ncpt; /* num cmds per tcs */
 	DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
 	spinlock_t tcs_lock; /* TCS type lock */
-	spinlock_t tcs_m_lock[MAX_TCS_PER_TYPE];
-	struct tcs_response *resp[MAX_TCS_PER_TYPE];
 };
 
 /* One per MBOX controller */
@@ -148,16 +150,13 @@
 	if (!pool)
 		return -ENOMEM;
 
-	pool->resp = devm_kzalloc(&drv->pdev->dev, sizeof(*pool->resp) *
-				MAX_POOL_SIZE, GFP_KERNEL);
-	if (!pool->resp)
-		return -ENOMEM;
-
 	for (i = 0; i < MAX_POOL_SIZE; i++) {
 		tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done,
 						(unsigned long) &pool->resp[i]);
-		INIT_DELAYED_WORK(&pool->resp[i].dwork,
-						tcs_notify_timeout);
+		INIT_DELAYED_WORK(&pool->resp[i].dwork, tcs_notify_timeout);
+		pool->resp[i].drv = drv;
+		pool->resp[i].idx = i;
+		pool->resp[i].m = TCS_M_INIT;
 	}
 
 	spin_lock_init(&pool->lock);
@@ -166,39 +165,59 @@
 	return 0;
 }
 
-static struct tcs_response *get_response_from_pool(struct tcs_drv *drv)
+static struct tcs_response *setup_response(struct tcs_drv *drv,
+		struct tcs_mbox_msg *msg, struct mbox_chan *chan,
+		u32 m, int err)
 {
 	struct tcs_response_pool *pool = drv->resp_pool;
 	struct tcs_response *resp = ERR_PTR(-ENOMEM);
-	unsigned long flags;
 	int pos;
 
-	spin_lock_irqsave(&pool->lock, flags);
+	spin_lock(&pool->lock);
 	pos = find_first_zero_bit(pool->avail, MAX_POOL_SIZE);
 	if (pos != MAX_POOL_SIZE) {
 		bitmap_set(pool->avail, pos, 1);
 		resp = &pool->resp[pos];
-		memset(resp, 0, sizeof(*resp));
-		tasklet_init(&resp->tasklet, tcs_notify_tx_done,
-						(unsigned long) resp);
-		INIT_DELAYED_WORK(&resp->dwork, tcs_notify_timeout);
-		resp->drv = drv;
+		resp->chan = chan;
+		resp->msg = msg;
+		resp->m = m;
+		resp->err = err;
+		resp->in_use = false;
 	}
-	spin_unlock_irqrestore(&pool->lock, flags);
+	spin_unlock(&pool->lock);
 
 	return resp;
 }
 
-static void free_response_to_pool(struct tcs_response *resp)
+static void free_response(struct tcs_response *resp)
 {
 	struct tcs_response_pool *pool = resp->drv->resp_pool;
-	unsigned long flags;
-	int i;
 
-	spin_lock_irqsave(&pool->lock, flags);
-	i = resp - pool->resp;
-	bitmap_clear(pool->avail, i, 1);
-	spin_unlock_irqrestore(&pool->lock, flags);
+	spin_lock(&pool->lock);
+	resp->err = -EINVAL;
+	bitmap_clear(pool->avail, resp->idx, 1);
+	spin_unlock(&pool->lock);
+}
+
+static inline struct tcs_response *get_response(struct tcs_drv *drv, u32 m)
+{
+	struct tcs_response_pool *pool = drv->resp_pool;
+	struct tcs_response *resp = NULL;
+	int pos = 0;
+
+	do {
+		pos = find_next_bit(pool->avail, MAX_POOL_SIZE, pos);
+		if (pos == MAX_POOL_SIZE)
+			break;
+		resp = &pool->resp[pos];
+		if (resp->m == m && !resp->in_use) {
+			resp->in_use = true;
+			break;
+		}
+		pos++;
+	} while (1);
+
+	return resp;
 }
 
 static inline u32 read_drv_config(void __iomem *base)
@@ -226,7 +245,7 @@
 		write_tcs_reg(base, reg, m, n, data);
 		if (data == read_tcs_reg(base, reg, m, n))
 			break;
-		cpu_relax();
+		udelay(1);
 	} while (1);
 }
 
@@ -311,13 +330,6 @@
 	return get_tcs_of_type(drv, type);
 }
 
-static inline struct tcs_response *get_tcs_response(struct tcs_drv *drv, int m)
-{
-	struct tcs_mbox *tcs = get_tcs_from_index(drv, m);
-
-	return tcs ? tcs->resp[m - tcs->tcs_offset] : NULL;
-}
-
 static inline void send_tcs_response(struct tcs_response *resp)
 {
 	tasklet_schedule(&resp->tasklet);
@@ -340,7 +352,6 @@
 	struct tcs_mbox *tcs;
 	struct tcs_response *resp;
 	struct tcs_cmd *cmd;
-	u32 irq_clear = 0;
 	u32 data;
 
 	/* Know which TCSes were triggered */
@@ -350,8 +361,7 @@
 		if (!(irq_status & BIT(m)))
 			continue;
 
-		/* Find the TCS that triggered */
-		resp = get_tcs_response(drv, m);
+		resp = get_response(drv, m);
 		if (!resp) {
 			pr_err("No resp request for TCS-%d\n", m);
 			continue;
@@ -397,18 +407,13 @@
 			write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
 		}
 
-		/* Notify the client that this request is completed. */
+		/* Clear the TCS IRQ status */
+		write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m));
+
+		/* Clean up response object and notify mbox in tasklet */
 		send_tcs_response(resp);
-		irq_clear |= BIT(m);
-	}
 
-	/* Clear the TCS IRQ status */
-	write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, irq_clear);
-
-	/* Mark the TCS as free */
-	for (m = 0; irq_status >= BIT(m); m++) {
-		if (!(irq_status & BIT(m)))
-			continue;
+		/* Notify the client that this request is completed. */
 		atomic_set(&drv->tcs_in_use[m], 0);
 	}
 
@@ -435,8 +440,8 @@
 	int err = resp->err;
 	int m = resp->m;
 
-	free_response_to_pool(resp);
 	mbox_notify_tx_done(chan, msg, m, err);
+	free_response(resp);
 }
 
 /**
@@ -468,7 +473,7 @@
 			cmd = &msg->payload[i];
 			addr = read_tcs_reg(drv->reg_base, TCS_DRV_CMD_ADDR,
 						m, i);
-			pending = (cmd->addr == addr);
+			pending |= (cmd->addr == addr);
 		}
 		if (pending) {
 			pr_err("TCS-%d blocked waiting for RPMH to respond.\n",
@@ -481,8 +486,8 @@
 		}
 	}
 
-	free_response_to_pool(resp);
 	mbox_notify_tx_done(chan, msg, -1, -ETIMEDOUT);
+	free_response(resp);
 }
 
 static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
@@ -525,8 +530,6 @@
 	write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, cmd_enable);
 
 	if (trigger) {
-		/* Mark the TCS as busy */
-		atomic_set(&drv->tcs_in_use[m], 1);
 		/* HW req: Clear the DRV_CONTROL and enable TCS again */
 		write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, 0);
 		write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
@@ -590,13 +593,14 @@
 		}
 retry:
 		if (!is_free)
-			cpu_relax();
+			udelay(1);
 	} while (!is_free);
 }
 
 static int find_free_tcs(struct tcs_mbox *tcs)
 {
 	int slot, m = 0;
+	u32 irq_status;
 
 	/* Loop until we find a free AMC */
 	do {
@@ -604,9 +608,14 @@
 			slot = m * tcs->ncpt;
 			break;
 		}
-		if (++m >= tcs->num_tcs)
+		if (++m >= tcs->num_tcs) {
 			m = 0;
-		cpu_relax();
+			irq_status = read_tcs_reg(tcs->drv->reg_base,
+						TCS_DRV_IRQ_STATUS, 0, 0);
+			WARN((irq_status & tcs->tcs_mask && in_irq()),
+				"TCS busy. Request should not be made from hard IRQ context.");
+			udelay(10);
+		}
 	} while (1);
 
 	return slot;
@@ -663,26 +672,6 @@
 	return (slot != MAX_TCS_SLOTS) ? slot : -ENOMEM;
 }
 
-static struct tcs_response *setup_response(struct tcs_mbox *tcs,
-		struct mbox_chan *chan, struct tcs_mbox_msg *msg, int m)
-{
-	struct tcs_response *resp = get_response_from_pool(tcs->drv);
-
-	if (IS_ERR(resp))
-		return resp;
-
-	if (m < tcs->tcs_offset)
-		return ERR_PTR(-EINVAL);
-
-	tcs->resp[m - tcs->tcs_offset] = resp;
-	resp->msg = msg;
-	resp->chan = chan;
-	resp->m = m;
-	resp->err = 0;
-
-	return resp;
-}
-
 static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
 				bool trigger)
 {
@@ -697,14 +686,20 @@
 	if (IS_ERR(tcs))
 		return PTR_ERR(tcs);
 
+	if (trigger)
+		resp = setup_response(drv, msg, chan, TCS_M_INIT, 0);
+
 	/* Identify the sequential slots that we can write to */
 	spin_lock(&tcs->tcs_lock);
 	slot = find_slots(tcs, msg);
 	if (slot < 0) {
 		dev_err(dev, "No TCS slot found.\n");
 		spin_unlock(&tcs->tcs_lock);
+		if (resp)
+			free_response(resp);
 		return slot;
 	}
+
 	/* Mark the slots as in-use, before we unlock */
 	if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
 		bitmap_set(tcs->slots, slot, msg->num_payload);
@@ -713,27 +708,16 @@
 	for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
 		tcs->cmd_addr[slot + i] = msg->payload[i].addr;
 
-	if (trigger)
-		resp = setup_response(tcs, chan, msg,
-				slot / tcs->ncpt + tcs->tcs_offset);
-
-	spin_unlock(&tcs->tcs_lock);
-
-	/*
-	 * Find the TCS corresponding to the slot and start writing.
-	 * Break down 'slot' into a 'n' position in the 'm'th TCS.
-	 */
 	offset = slot / tcs->ncpt;
 	m = offset + tcs->tcs_offset;
 	n = slot % tcs->ncpt;
 
-	spin_lock(&tcs->tcs_m_lock[offset]);
+	/* Block, if we have an address from the msg in flight */
 	if (trigger) {
-		/* Block, if we have an address from the msg in flight */
+		resp->m = m;
+		/* Mark the TCS as busy */
+		atomic_set(&drv->tcs_in_use[m], 1);
 		wait_for_req_inflight(drv, tcs, msg);
-		/* If the TCS is busy there is nothing to do but spin wait */
-		while (!tcs_is_free(drv, m))
-			cpu_relax();
 	}
 
 	/* Write to the TCS or AMC */
@@ -743,7 +727,7 @@
 	if (trigger)
 		schedule_tcs_err_response(resp);
 
-	spin_unlock(&tcs->tcs_m_lock[offset]);
+	spin_unlock(&tcs->tcs_lock);
 
 	return 0;
 }
@@ -769,11 +753,9 @@
 		spin_lock(&tcs->tcs_lock);
 		for (i = 0; i < tcs->num_tcs; i++) {
 			m = i + tcs->tcs_offset;
-			spin_lock(&tcs->tcs_m_lock[i]);
 			while (!tcs_is_free(drv, m))
-				cpu_relax();
+				udelay(1);
 			__tcs_buffer_invalidate(drv->reg_base, m);
-			spin_unlock(&tcs->tcs_m_lock[i]);
 		}
 		/* Mark the TCS as free */
 		bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
@@ -840,12 +822,9 @@
 tx_fail:
 	if (ret) {
 		struct tcs_drv *drv = container_of(chan->mbox,
-							struct tcs_drv, mbox);
-		struct tcs_response *resp = get_response_from_pool(drv);
-
-		resp->chan = chan;
-		resp->msg = msg;
-		resp->err = ret;
+					struct tcs_drv, mbox);
+		struct tcs_response *resp = setup_response(
+				drv, msg, chan, TCS_M_INIT, ret);
 
 		dev_err(dev, "Error sending RPMH message %d\n", ret);
 		send_tcs_response(resp);
@@ -1040,8 +1019,6 @@
 		tcs->ncpt = (tcs->type == CONTROL_TCS) ? TCS_HIDDEN_MAX_SLOTS
 							: ncpt;
 		spin_lock_init(&tcs->tcs_lock);
-		for (j = 0; j < ARRAY_SIZE(tcs->tcs_m_lock); j++)
-			spin_lock_init(&tcs->tcs_m_lock[j]);
 
 		if (tcs->num_tcs <= 0 || tcs->type == CONTROL_TCS)
 			continue;
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 a0b53bb..3bf6ce0 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -140,6 +140,18 @@
 	int domain;
 };
 
+/*
+ * struct sde_rot_debug_bus: rotator debugbus header structure
+ * @wr_addr: write address for debugbus controller
+ * @block_id: rotator debugbus block id
+ * @test_id: rotator debugbus test id
+ */
+struct sde_rot_debug_bus {
+	u32 wr_addr;
+	u32 block_id;
+	u32 test_id;
+};
+
 struct sde_rot_vbif_debug_bus {
 	u32 disable_bus_addr;
 	u32 block_bus_addr;
@@ -191,6 +203,8 @@
 
 	struct sde_rot_vbif_debug_bus *nrt_vbif_dbg_bus;
 	u32 nrt_vbif_dbg_bus_size;
+	struct sde_rot_debug_bus *rot_dbg_bus;
+	u32 rot_dbg_bus_size;
 
 	struct sde_rot_regdump *regdump;
 	u32 regdump_size;
@@ -199,6 +213,8 @@
 	int sec_cam_en;
 
 	struct ion_client *iclient;
+
+	bool clk_always_on;
 };
 
 int sde_rotator_base_init(struct sde_rot_data_type **pmdata,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index e56c70a..e9ff67c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -30,6 +30,7 @@
 #define SDE_EVTLOG_DEFAULT_PANIC 1
 #define SDE_EVTLOG_DEFAULT_REGDUMP SDE_ROT_DBG_DUMP_IN_MEM
 #define SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM
+#define SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM
 
 /*
  * evtlog will print this number of entries when it is called through
@@ -53,6 +54,8 @@
 #define GROUP_BYTES 4
 #define ROW_BYTES 16
 
+#define SDE_ROT_TEST_MASK(id, tp)	((id << 4) | (tp << 1) | BIT(0))
+
 static DEFINE_SPINLOCK(sde_rot_xlock);
 
 /*
@@ -86,11 +89,14 @@
  * @panic_on_err - boolean indicates issue panic after EVTLOG dump
  * @enable_reg_dump - control in-log/memory dump for rotator registers
  * @enable_vbif_dbgbus_dump - control in-log/memory dump for VBIF debug bus
+ * @enable_rot_dbgbus_dump - control in-log/memroy dump for rotator debug bus
  * @evtlog_dump_work - schedule work strucutre for timeout handler
  * @work_dump_reg - storage for register dump control in schedule work
  * @work_panic - storage for panic control in schedule work
  * @work_vbif_dbgbus - storage for VBIF debug bus control in schedule work
+ * @work_rot_dbgbus - storage for rotator debug bus control in schedule work
  * @nrt_vbif_dbgbus_dump - memory buffer for VBIF debug bus dumping
+ * @rot_dbgbus_dump - memory buffer for rotator debug bus dumping
  * @reg_dump_array - memory buffer for rotator registers dumping
  */
 struct sde_rot_dbg_evtlog {
@@ -103,14 +109,88 @@
 	u32 panic_on_err;
 	u32 enable_reg_dump;
 	u32 enable_vbif_dbgbus_dump;
+	u32 enable_rot_dbgbus_dump;
 	struct work_struct evtlog_dump_work;
 	bool work_dump_reg;
 	bool work_panic;
 	bool work_vbif_dbgbus;
+	bool work_rot_dbgbus;
 	u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */
+	u32 *rot_dbgbus_dump;
 	u32 *reg_dump_array[SDE_ROT_DEBUG_BASE_MAX];
 } sde_rot_dbg_evtlog;
 
+static void sde_rot_dump_debug_bus(u32 bus_dump_flag, u32 **dump_mem)
+{
+	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+	bool in_log, in_mem;
+	u32 *dump_addr = NULL;
+	u32 status = 0;
+	struct sde_rot_debug_bus *head;
+	phys_addr_t phys = 0;
+	int i;
+	u32 offset;
+	void __iomem *base;
+
+	in_log = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG);
+	in_mem = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM);
+	base = mdata->sde_io.base;
+
+	if (!base || !mdata->rot_dbg_bus || !mdata->rot_dbg_bus_size)
+		return;
+
+	pr_info("======== SDE Rotator Debug bus DUMP =========\n");
+
+	if (in_mem) {
+		if (!(*dump_mem))
+			*dump_mem = dma_alloc_coherent(&mdata->pdev->dev,
+				mdata->rot_dbg_bus_size * 4 * sizeof(u32),
+				&phys, GFP_KERNEL);
+
+		if (*dump_mem) {
+			dump_addr = *dump_mem;
+			pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n",
+				__func__, dump_addr,
+				dump_addr + (u32)mdata->rot_dbg_bus_size * 16);
+		} else {
+			in_mem = false;
+			pr_err("dump_mem: allocation fails\n");
+		}
+	}
+
+	sde_smmu_ctrl(1);
+
+	for (i = 0; i < mdata->rot_dbg_bus_size; i++) {
+		head = mdata->rot_dbg_bus + i;
+		writel_relaxed(SDE_ROT_TEST_MASK(head->block_id, head->test_id),
+				base + head->wr_addr);
+		wmb(); /* make sure test bits were written */
+
+		offset = head->wr_addr + 0x4;
+
+		status = readl_relaxed(base + offset);
+
+		if (in_log)
+			pr_err("waddr=0x%x blk=%d tst=%d val=0x%x\n",
+				head->wr_addr, head->block_id, head->test_id,
+				status);
+
+		if (dump_addr && in_mem) {
+			dump_addr[i*4]     = head->wr_addr;
+			dump_addr[i*4 + 1] = head->block_id;
+			dump_addr[i*4 + 2] = head->test_id;
+			dump_addr[i*4 + 3] = status;
+		}
+
+		/* Disable debug bus once we are done */
+		writel_relaxed(0, base + head->wr_addr);
+	}
+
+	sde_smmu_ctrl(0);
+
+	pr_info("========End Debug bus=========\n");
+}
+
 /*
  * sde_rot_evtlog_is_enabled - helper function for checking EVTLOG
  *                             enable/disable
@@ -518,18 +598,26 @@
  * @dump_vbif_debug_bus: boolean indicates VBIF debug bus dump
  */
 static void sde_rot_evtlog_dump_helper(bool dead, const char *panic_name,
-	bool dump_rot, bool dump_vbif_debug_bus)
+	bool dump_rot, bool dump_vbif_debug_bus, bool dump_rot_debug_bus)
 {
 	sde_rot_evtlog_dump_all();
 
-	if (dump_rot)
-		sde_rot_dump_reg_all();
+	if (dump_rot_debug_bus)
+		sde_rot_dump_debug_bus(
+				sde_rot_dbg_evtlog.enable_rot_dbgbus_dump,
+				&sde_rot_dbg_evtlog.rot_dbgbus_dump);
 
 	if (dump_vbif_debug_bus)
 		sde_rot_dump_vbif_debug_bus(
 				sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump,
 				&sde_rot_dbg_evtlog.nrt_vbif_dbgbus_dump);
 
+	/*
+	 * Rotator registers always dump last
+	 */
+	if (dump_rot)
+		sde_rot_dump_reg_all();
+
 	if (dead)
 		panic(panic_name);
 }
@@ -544,7 +632,8 @@
 		sde_rot_dbg_evtlog.work_panic,
 		"evtlog_workitem",
 		sde_rot_dbg_evtlog.work_dump_reg,
-		sde_rot_dbg_evtlog.work_vbif_dbgbus);
+		sde_rot_dbg_evtlog.work_vbif_dbgbus,
+		sde_rot_dbg_evtlog.work_rot_dbgbus);
 }
 
 /*
@@ -569,6 +658,7 @@
 	bool dead = false;
 	bool dump_rot = false;
 	bool dump_vbif_dbgbus = false;
+	bool dump_rot_dbgbus = false;
 	char *blk_name = NULL;
 	va_list args;
 
@@ -590,6 +680,9 @@
 		if (!strcmp(blk_name, "vbif_dbg_bus"))
 			dump_vbif_dbgbus = true;
 
+		if (!strcmp(blk_name, "rot_dbg_bus"))
+			dump_rot_dbgbus = true;
+
 		if (!strcmp(blk_name, "panic"))
 			dead = true;
 	}
@@ -600,10 +693,11 @@
 		sde_rot_dbg_evtlog.work_panic = dead;
 		sde_rot_dbg_evtlog.work_dump_reg = dump_rot;
 		sde_rot_dbg_evtlog.work_vbif_dbgbus = dump_vbif_dbgbus;
+		sde_rot_dbg_evtlog.work_rot_dbgbus = dump_rot_dbgbus;
 		schedule_work(&sde_rot_dbg_evtlog.evtlog_dump_work);
 	} else {
 		sde_rot_evtlog_dump_helper(dead, name, dump_rot,
-			dump_vbif_dbgbus);
+			dump_vbif_dbgbus, dump_rot_dbgbus);
 	}
 }
 
@@ -836,6 +930,13 @@
 		return -EINVAL;
 	}
 
+	mdata->clk_always_on = false;
+	if (!debugfs_create_bool("clk_always_on", 0644,
+			debugfs_root, &mdata->clk_always_on)) {
+		SDEROT_WARN("failed to create debugfs clk_always_on\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -919,12 +1020,16 @@
 			    &sde_rot_dbg_evtlog.enable_reg_dump);
 	debugfs_create_u32("vbif_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog,
 			    &sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump);
+	debugfs_create_u32("rot_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog,
+			    &sde_rot_dbg_evtlog.enable_rot_dbgbus_dump);
 
 	sde_rot_dbg_evtlog.evtlog_enable = SDE_EVTLOG_DEFAULT_ENABLE;
 	sde_rot_dbg_evtlog.panic_on_err = SDE_EVTLOG_DEFAULT_PANIC;
 	sde_rot_dbg_evtlog.enable_reg_dump = SDE_EVTLOG_DEFAULT_REGDUMP;
 	sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump =
 		SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP;
+	sde_rot_dbg_evtlog.enable_rot_dbgbus_dump =
+		SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP;
 
 	pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n",
 			sde_rot_dbg_evtlog.evtlog_enable,
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 a152573..8f2746d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -385,11 +385,95 @@
 };
 
 static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = {
-	{0x214, 0x21c, 16, 1, 0x10}, /* arb clients */
+	{0x214, 0x21c, 16, 1, 0x200}, /* arb clients main */
 	{0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */
 	{0x21c, 0x214, 0, 12, 0xc}, /* xin blocks - clock side */
 };
 
+static struct sde_rot_debug_bus rot_dbgbus_r3[] = {
+	/*
+	 * rottop - 0xA8850
+	 */
+	/* REGDMA */
+	{ 0XA8850, 0, 0 },
+	{ 0XA8850, 0, 1 },
+	{ 0XA8850, 0, 2 },
+	{ 0XA8850, 0, 3 },
+	{ 0XA8850, 0, 4 },
+
+	/* ROT_WB */
+	{ 0XA8850, 1, 0 },
+	{ 0XA8850, 1, 1 },
+	{ 0XA8850, 1, 2 },
+	{ 0XA8850, 1, 3 },
+	{ 0XA8850, 1, 4 },
+	{ 0XA8850, 1, 5 },
+	{ 0XA8850, 1, 6 },
+	{ 0XA8850, 1, 7 },
+
+	/* UBWC_DEC */
+	{ 0XA8850, 2, 0 },
+
+	/* UBWC_ENC */
+	{ 0XA8850, 3, 0 },
+
+	/* ROT_FETCH_0 */
+	{ 0XA8850, 4, 0 },
+	{ 0XA8850, 4, 1 },
+	{ 0XA8850, 4, 2 },
+	{ 0XA8850, 4, 3 },
+	{ 0XA8850, 4, 4 },
+	{ 0XA8850, 4, 5 },
+	{ 0XA8850, 4, 6 },
+	{ 0XA8850, 4, 7 },
+
+	/* ROT_FETCH_1 */
+	{ 0XA8850, 5, 0 },
+	{ 0XA8850, 5, 1 },
+	{ 0XA8850, 5, 2 },
+	{ 0XA8850, 5, 3 },
+	{ 0XA8850, 5, 4 },
+	{ 0XA8850, 5, 5 },
+	{ 0XA8850, 5, 6 },
+	{ 0XA8850, 5, 7 },
+
+	/* ROT_FETCH_2 */
+	{ 0XA8850, 6, 0 },
+	{ 0XA8850, 6, 1 },
+	{ 0XA8850, 6, 2 },
+	{ 0XA8850, 6, 3 },
+	{ 0XA8850, 6, 4 },
+	{ 0XA8850, 6, 5 },
+	{ 0XA8850, 6, 6 },
+	{ 0XA8850, 6, 7 },
+
+	/* ROT_FETCH_3 */
+	{ 0XA8850, 7, 0 },
+	{ 0XA8850, 7, 1 },
+	{ 0XA8850, 7, 2 },
+	{ 0XA8850, 7, 3 },
+	{ 0XA8850, 7, 4 },
+	{ 0XA8850, 7, 5 },
+	{ 0XA8850, 7, 6 },
+	{ 0XA8850, 7, 7 },
+
+	/* ROT_FETCH_4 */
+	{ 0XA8850, 8, 0 },
+	{ 0XA8850, 8, 1 },
+	{ 0XA8850, 8, 2 },
+	{ 0XA8850, 8, 3 },
+	{ 0XA8850, 8, 4 },
+	{ 0XA8850, 8, 5 },
+	{ 0XA8850, 8, 6 },
+	{ 0XA8850, 8, 7 },
+
+	/* ROT_UNPACK_0*/
+	{ 0XA8850, 9, 0 },
+	{ 0XA8850, 9, 1 },
+	{ 0XA8850, 9, 2 },
+	{ 0XA8850, 9, 3 },
+};
+
 static struct sde_rot_regdump sde_rot_r3_regdump[] = {
 	{ "SDEROT_ROTTOP", SDE_ROT_ROTTOP_OFFSET, 0x100, SDE_ROT_REGDUMP_READ },
 	{ "SDEROT_SSPP", SDE_ROT_SSPP_OFFSET, 0x200, SDE_ROT_REGDUMP_READ },
@@ -1430,7 +1514,8 @@
 	sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
 
 	if (status & ROT_ERROR_BIT)
-		SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus", "panic");
+		SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus",
+				"vbif_dbg_bus", "panic");
 
 	return sts;
 }
@@ -1614,8 +1699,8 @@
 			SDEROT_ERR(
 				"Mismatch SWTS with HWTS: swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
 				swts, hwts, regdmasts, rotsts);
-			SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus",
-					"panic");
+			SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus",
+					"vbif_dbg_bus", "panic");
 		}
 
 		/* Turn off rotator clock after checking rotator registers */
@@ -2134,6 +2219,17 @@
 	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);
+	}
+
 	return 0;
 
 error:
@@ -2260,6 +2356,9 @@
 	mdata->nrt_vbif_dbg_bus_size =
 			ARRAY_SIZE(nrt_vbif_dbg_bus_r3);
 
+	mdata->rot_dbg_bus = rot_dbgbus_r3;
+	mdata->rot_dbg_bus_size = ARRAY_SIZE(rot_dbgbus_r3);
+
 	mdata->regdump = sde_rot_r3_regdump;
 	mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump);
 	SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index c042a4a..1a1078d 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1965,6 +1965,8 @@
 	if (device->res->pm_qos_latency_us &&
 		pm_qos_request_active(&device->qos))
 		pm_qos_remove_request(&device->qos);
+
+	__resume(device);
 	__set_state(device, VENUS_STATE_DEINIT);
 	__unload_fw(device);
 
@@ -4054,6 +4056,8 @@
 	__venus_power_off(device);
 	device->resources.fw.cookie = NULL;
 	__deinit_resources(device);
+
+	dprintk(VIDC_PROF, "Firmware unloaded successfully\n");
 }
 
 static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info)
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index bcc296b..d8e9599 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2200,6 +2200,17 @@
 	int need_retune = card->host->need_retune;
 	int ecc_err = 0, gen_err = 0;
 
+	if (card->host->sdr104_wa && mmc_card_sd(card) &&
+	    (card->host->ios.timing == MMC_TIMING_UHS_SDR104) &&
+	    !card->sdr104_blocked &&
+	    (brq->data.error == -EILSEQ ||
+	     brq->data.error == -EIO ||
+	     brq->data.error == -ETIMEDOUT ||
+	     brq->cmd.error == -EILSEQ ||
+	     brq->cmd.error == -EIO ||
+	     brq->cmd.error == -ETIMEDOUT))
+		card->err_in_sdr104 = true;
+
 	/*
 	 * sbc.error indicates a problem with the set block count
 	 * command.  No data will have been transferred.
@@ -3640,6 +3651,7 @@
 	struct mmc_async_req *areq;
 	const u8 packed_nr = 2;
 	u8 reqs = 0;
+	bool reset = false;
 #ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
 	unsigned long waitfor = jiffies;
 #endif
@@ -3685,6 +3697,26 @@
 		type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
 		mmc_queue_bounce_post(mq_rq);
 
+		if (card->err_in_sdr104) {
+			/*
+			 * Data CRC/timeout errors will manifest as CMD/DATA
+			 * ERR. But we'd like to retry these too.
+			 * Moreover, no harm done if this fails too for multiple
+			 * times, we anyway reduce the bus-speed and retry the
+			 * same request.
+			 * If that fails too, we don't override this status.
+			 */
+			if (status == MMC_BLK_ABORT ||
+			    status == MMC_BLK_CMD_ERR ||
+			    status == MMC_BLK_DATA_ERR ||
+			    status == MMC_BLK_RETRY)
+				/* reset on all of these errors and retry */
+				reset = true;
+
+			status = MMC_BLK_RETRY;
+			card->err_in_sdr104 = false;
+		}
+
 		switch (status) {
 		case MMC_BLK_SUCCESS:
 		case MMC_BLK_PARTIAL:
@@ -3725,8 +3757,32 @@
 			break;
 		case MMC_BLK_RETRY:
 			retune_retry_done = brq->retune_retry_done;
-			if (retry++ < MMC_BLK_MAX_RETRIES)
+			if (retry++ < MMC_BLK_MAX_RETRIES) {
 				break;
+			} else if (reset) {
+				reset = false;
+				/*
+				 * If we exhaust all the retries due to
+				 * CRC/timeout errors in SDR140 mode with UHS SD
+				 * cards, re-configure the card in SDR50
+				 * bus-speed mode.
+				 * All subsequent re-init of this card will be
+				 * in SDR50 mode, unless it is removed and
+				 * re-inserted. When new UHS SD cards are
+				 * inserted, it may start at SDR104 mode if
+				 * supported by the card.
+				 */
+				pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n",
+					req->rq_disk->disk_name);
+				mmc_host_clear_sdr104(card->host);
+				mmc_suspend_clk_scaling(card->host);
+				mmc_blk_reset(md, card->host, type);
+				/* SDR104 mode is blocked from now on */
+				card->sdr104_blocked = true;
+				/* retry 5 times again */
+				retry = 0;
+				break;
+			}
 			/* Fall through */
 		case MMC_BLK_ABORT:
 			if (!mmc_blk_reset(md, card->host, type) &&
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9987859..220ba6d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -4175,6 +4175,10 @@
 
 	if (ret) {
 		mmc_card_set_removed(host->card);
+		if (host->card->sdr104_blocked) {
+			mmc_host_set_sdr104(host);
+			host->card->sdr104_blocked = false;
+		}
 		pr_debug("%s: card remove detected\n", mmc_hostname(host));
 	}
 
@@ -4281,7 +4285,7 @@
 		mmc_release_host(host);
 		goto out;
 	}
-+	mmc_rescan_try_freq(host, host->f_min);
+	mmc_rescan_try_freq(host, host->f_min);
 	mmc_release_host(host);
 
  out:
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 3f39058..2adf42c 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -80,7 +80,6 @@
 
 extern bool mmc_can_scale_clk(struct mmc_host *host);
 extern int mmc_init_clk_scaling(struct mmc_host *host);
-extern int mmc_suspend_clk_scaling(struct mmc_host *host);
 extern int mmc_resume_clk_scaling(struct mmc_host *host);
 extern int mmc_exit_clk_scaling(struct mmc_host *host);
 extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 7f66ad3..7112f9f 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -432,26 +432,26 @@
 	if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
 	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) &&
 	    (card->host->f_max > UHS_SDR104_MIN_DTR)) {
-			card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
-	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
-		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
-		    (card->host->f_max > UHS_DDR50_MIN_DTR)) {
-			card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
+		card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
 		    SD_MODE_UHS_SDR50) &&
 		    (card->host->f_max > UHS_SDR50_MIN_DTR)) {
-			card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
+		card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
+	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
+		    (card->host->f_max > UHS_DDR50_MIN_DTR)) {
+		card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
 		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) &&
 		 (card->host->f_max > UHS_SDR25_MIN_DTR)) {
-			card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
+		card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
 	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
 		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
 		    MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
 		    SD_MODE_UHS_SDR12)) {
-			card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
+		card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
 	}
 }
 
@@ -1313,6 +1313,8 @@
 #endif
 	mmc_card_clr_suspended(host->card);
 
+	if (host->card->sdr104_blocked)
+		goto out;
 	err = mmc_resume_clk_scaling(host);
 	if (err) {
 		pr_err("%s: %s: fail to resume clock scaling (%d)\n",
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 9650085..fe62b69 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1939,6 +1939,8 @@
 	if (of_get_property(np, "qcom,core_3_0v_support", NULL))
 		pdata->core_3_0v_support = true;
 
+	pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa");
+
 	return pdata;
 out:
 	return NULL;
@@ -4422,6 +4424,8 @@
 	if (msm_host->pdata->nonhotplug)
 		msm_host->mmc->caps2 |= MMC_CAP2_NONHOTPLUG;
 
+	msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa;
+
 	init_completion(&msm_host->pwr_irq_completion);
 
 	if (gpio_is_valid(msm_host->pdata->status_gpio)) {
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index 533b241..53b1953 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -151,6 +151,7 @@
 	unsigned char sup_ice_clk_cnt;
 	struct sdhci_msm_pm_qos_data pm_qos_data;
 	bool core_3_0v_support;
+	bool sdr104_wa;
 };
 
 struct sdhci_msm_bus_vote {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 744e520..53a6ae8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3096,7 +3096,10 @@
 			       mmc_hostname(host->mmc), intmask,
 			       host->data->error, ktime_to_ms(ktime_sub(
 			       ktime_get(), host->data_start_time)));
-			sdhci_dumpregs(host);
+
+			if (!host->mmc->sdr104_wa ||
+			    (host->mmc->ios.timing != MMC_TIMING_UHS_SDR104))
+				sdhci_dumpregs(host);
 		}
 		sdhci_finish_data(host);
 	} else {
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index efcc4e8..9f04957 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -28,6 +28,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/system_misc.h>
+#include <asm/memory.h>
 
 #include <soc/qcom/scm.h>
 #include <soc/qcom/restart.h>
@@ -57,11 +58,17 @@
 #ifdef CONFIG_QCOM_DLOAD_MODE
 #define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode"
 #define DL_MODE_PROP "qcom,msm-imem-download_mode"
+#ifdef CONFIG_RANDOMIZE_BASE
+#define KASLR_OFFSET_PROP "qcom,msm-imem-kaslr_offset"
+#endif
 
 static int in_panic;
 static void *dload_mode_addr;
 static bool dload_mode_enabled;
 static void *emergency_dload_mode_addr;
+#ifdef CONFIG_RANDOMIZE_BASE
+static void *kaslr_imem_addr;
+#endif
 static bool scm_dload_supported;
 
 static int dload_set(const char *val, struct kernel_param *kp);
@@ -420,6 +427,27 @@
 			pr_err("unable to map imem EDLOAD mode offset\n");
 	}
 
+#ifdef CONFIG_RANDOMIZE_BASE
+#define KASLR_OFFSET_BIT_MASK	0x00000000FFFFFFFF
+	np = of_find_compatible_node(NULL, NULL, KASLR_OFFSET_PROP);
+	if (!np) {
+		pr_err("unable to find DT imem KASLR_OFFSET node\n");
+	} else {
+		kaslr_imem_addr = of_iomap(np, 0);
+		if (!kaslr_imem_addr)
+			pr_err("unable to map imem KASLR offset\n");
+	}
+
+	if (kaslr_imem_addr && scm_is_secure_device()) {
+		__raw_writel(0xdead4ead, kaslr_imem_addr);
+		__raw_writel(KASLR_OFFSET_BIT_MASK &
+		(kimage_vaddr - KIMAGE_VADDR), kaslr_imem_addr + 4);
+		__raw_writel(KASLR_OFFSET_BIT_MASK &
+			((kimage_vaddr - KIMAGE_VADDR) >> 32),
+			kaslr_imem_addr + 8);
+		iounmap(kaslr_imem_addr);
+	}
+#endif
 #endif
 	np = of_find_compatible_node(NULL, NULL,
 				"qcom,msm-imem-restart_reason");
@@ -484,4 +512,4 @@
 {
 	return platform_driver_register(&msm_restart_driver);
 }
-device_initcall(msm_restart_init);
+pure_initcall(msm_restart_init);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 1635bab..b3c1150 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -108,7 +108,7 @@
 	struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);
 
 	atomic_dec(rpm_msg->wait_count);
-	wake_up_interruptible(rpm_msg->waitq);
+	wake_up(rpm_msg->waitq);
 }
 
 static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
@@ -151,7 +151,7 @@
 	/* Signal the blocking thread we are done */
 	if (waitq) {
 		atomic_dec(wc);
-		wake_up_interruptible(waitq);
+		wake_up(waitq);
 	}
 }
 
@@ -329,9 +329,7 @@
 	if (ret < 0)
 		return ret;
 
-	ret = wait_event_interruptible(waitq, atomic_read(&wait_count) == 0);
-	if (ret)
-		return ret;
+	wait_event(waitq, atomic_read(&wait_count) == 0);
 
 	return rpm_msg.err;
 }
@@ -423,13 +421,11 @@
 	rpm_msg.msg.num_payload = n;
 
 	ret = __rpmh_write(rc, state, &rpm_msg);
-	if (ret < 0)
-		return ret;
-
-	ret = wait_event_interruptible(waitq, atomic_read(&wait_count) == 0);
 	if (ret)
 		return ret;
 
+	wait_event(waitq, atomic_read(&wait_count) == 0);
+
 	return rpm_msg.err;
 }
 EXPORT_SYMBOL(rpmh_write);
@@ -494,8 +490,6 @@
 		rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]);
 		if (IS_ERR_OR_NULL(rpm_msg[i]))
 			return PTR_ERR(rpm_msg[i]);
-		rpm_msg[i]->waitq = &waitq;
-		rpm_msg[i]->wait_count = &wait_count;
 		cmd += n[i];
 	}
 
@@ -504,16 +498,18 @@
 		might_sleep();
 		atomic_set(&wait_count, count);
 		for (i = 0; i < count; i++) {
+			rpm_msg[i]->waitq = &waitq;
+			rpm_msg[i]->wait_count = &wait_count;
 			/* Bypass caching and write to mailbox directly */
 			ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg);
 			if (ret < 0)
 				return ret;
 		}
-		return wait_event_interruptible(waitq,
-					atomic_read(&wait_count) == 0);
+		wait_event(waitq, atomic_read(&wait_count) == 0);
 	} else {
 		/* Send Sleep requests to the controller, expect no response */
 		for (i = 0; i < count; i++) {
+			rpm_msg[i]->waitq = NULL;
 			ret = mbox_send_controller_data(rc->chan,
 						&rpm_msg[i]->msg);
 			/* Clean up our call by spoofing tx_done */
@@ -521,6 +517,8 @@
 		}
 		return 0;
 	}
+
+	return 0;
 }
 EXPORT_SYMBOL(rpmh_write_passthru);
 
@@ -623,9 +621,7 @@
 		return ret;
 
 	/* Wait until the response is received from RPMH */
-	ret = wait_event_interruptible(waitq, atomic_read(&wait_count) == 0);
-	if (ret)
-		return ret;
+	wait_event(waitq, atomic_read(&wait_count) == 0);
 
 	/* Read the data back from the tcs_mbox_msg structrure */
 	*resp = rpm_msg.cmd[0].data;
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index f3d6209..7a784aa 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -30,6 +30,7 @@
 #include <soc/qcom/scm.h>
 #include <soc/qcom/memory_dump.h>
 #include <soc/qcom/watchdog.h>
+#include <linux/dma-mapping.h>
 
 #define MODULE_NAME "msm_watchdog"
 #define WDT0_ACCSCSSNBARK_INT 0
@@ -49,6 +50,7 @@
 #define SCM_SET_REGSAVE_CMD	0x2
 #define SCM_SVC_SEC_WDOG_DIS	0x7
 #define MAX_CPU_CTX_SIZE	2048
+#define MAX_CPU_SCANDUMP_SIZE	0x10000
 
 static struct msm_watchdog_data *wdog_data;
 
@@ -557,6 +559,49 @@
 	return;
 }
 
+static void configure_scandump(struct msm_watchdog_data *wdog_dd)
+{
+	int ret;
+	struct msm_dump_entry dump_entry;
+	struct msm_dump_data *cpu_data;
+	int cpu;
+	static dma_addr_t dump_addr;
+	static void *dump_vaddr;
+
+	for_each_cpu(cpu, cpu_present_mask) {
+		cpu_data = devm_kzalloc(wdog_dd->dev,
+					sizeof(struct msm_dump_data),
+					GFP_KERNEL);
+		if (!cpu_data)
+			continue;
+
+		dump_vaddr = (void *) dma_alloc_coherent(wdog_dd->dev,
+							 MAX_CPU_SCANDUMP_SIZE,
+							 &dump_addr,
+							 GFP_KERNEL);
+		if (!dump_vaddr) {
+			dev_err(wdog_dd->dev, "Couldn't get memory for dump\n");
+			continue;
+		}
+		memset(dump_vaddr, 0x0, MAX_CPU_SCANDUMP_SIZE);
+
+		cpu_data->addr = dump_addr;
+		cpu_data->len = MAX_CPU_SCANDUMP_SIZE;
+		dump_entry.id = MSM_DUMP_DATA_SCANDUMP_PER_CPU + cpu;
+		dump_entry.addr = virt_to_phys(cpu_data);
+		ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
+					     &dump_entry);
+		if (ret) {
+			dev_err(wdog_dd->dev, "Dump setup failed, id = %d\n",
+				MSM_DUMP_DATA_SCANDUMP_PER_CPU + cpu);
+			dma_free_coherent(wdog_dd->dev, MAX_CPU_SCANDUMP_SIZE,
+					  dump_vaddr,
+					  dump_addr);
+			devm_kfree(wdog_dd->dev, cpu_data);
+		}
+	}
+}
+
 static int init_watchdog_sysfs(struct msm_watchdog_data *wdog_dd)
 {
 	int error = 0;
@@ -617,6 +662,7 @@
 	delay_time = msecs_to_jiffies(wdog_dd->pet_time);
 	wdog_dd->min_slack_ticks = UINT_MAX;
 	wdog_dd->min_slack_ns = ULLONG_MAX;
+	configure_scandump(wdog_dd);
 	configure_bark_dump(wdog_dd);
 	timeout = (wdog_dd->bark_time * WDT_HZ)/1000;
 	__raw_writel(timeout, wdog_dd->base + WDT0_BARK_TIME);
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
new file mode 100644
index 0000000..6243588
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MSM_GCC_SDX24_H
+#define _DT_BINDINGS_CLK_MSM_GCC_SDX24_H
+
+/* GCC clock registers */
+#define GCC_BLSP1_AHB_CLK					0
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK				1
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC				2
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK				3
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC				4
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK				5
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC				6
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK				7
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC				8
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK				9
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC				10
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK				11
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC				12
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK				13
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC				14
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK				15
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC				16
+#define GCC_BLSP1_SLEEP_CLK					17
+#define GCC_BLSP1_UART1_APPS_CLK				18
+#define GCC_BLSP1_UART1_APPS_CLK_SRC				19
+#define GCC_BLSP1_UART2_APPS_CLK				20
+#define GCC_BLSP1_UART2_APPS_CLK_SRC				21
+#define GCC_BLSP1_UART3_APPS_CLK				22
+#define GCC_BLSP1_UART3_APPS_CLK_SRC				23
+#define GCC_BLSP1_UART4_APPS_CLK				24
+#define GCC_BLSP1_UART4_APPS_CLK_SRC				25
+#define GCC_BOOT_ROM_AHB_CLK					26
+#define GCC_CE1_AHB_CLK						27
+#define GCC_CE1_AXI_CLK						28
+#define GCC_CE1_CLK						29
+#define GCC_CPUSS_AHB_CLK					30
+#define GCC_CPUSS_AHB_CLK_SRC					31
+#define GCC_CPUSS_GNOC_CLK					32
+#define GCC_CPUSS_GPLL0_CLK_SRC					33
+#define GCC_CPUSS_RBCPR_CLK					34
+#define GCC_CPUSS_RBCPR_CLK_SRC					35
+#define GCC_GP1_CLK						36
+#define GCC_GP1_CLK_SRC						37
+#define GCC_GP2_CLK						38
+#define GCC_GP2_CLK_SRC						39
+#define GCC_GP3_CLK						40
+#define GCC_GP3_CLK_SRC						41
+#define GCC_MSS_CFG_AHB_CLK					42
+#define GCC_MSS_GPLL0_DIV_CLK_SRC				43
+#define GCC_MSS_SNOC_AXI_CLK					44
+#define GCC_PCIE_AUX_CLK					45
+#define GCC_PCIE_AUX_PHY_CLK_SRC				46
+#define GCC_PCIE_CFG_AHB_CLK					47
+#define GCC_PCIE_MSTR_AXI_CLK					48
+#define GCC_PCIE_PHY_REFGEN_CLK					49
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC				50
+#define GCC_PCIE_PIPE_CLK					51
+#define GCC_PCIE_SLEEP_CLK					52
+#define GCC_PCIE_SLV_AXI_CLK					53
+#define GCC_PCIE_SLV_Q2A_AXI_CLK				54
+#define GCC_PDM2_CLK						55
+#define GCC_PDM2_CLK_SRC					56
+#define GCC_PDM_AHB_CLK						57
+#define GCC_PDM_XO4_CLK						58
+#define GCC_PRNG_AHB_CLK					59
+#define GCC_SDCC1_AHB_CLK					60
+#define GCC_SDCC1_APPS_CLK					61
+#define GCC_SDCC1_APPS_CLK_SRC					62
+#define GCC_SPMI_FETCHER_AHB_CLK				63
+#define GCC_SPMI_FETCHER_CLK					64
+#define GCC_SPMI_FETCHER_CLK_SRC				65
+#define GCC_SYS_NOC_CPUSS_AHB_CLK				66
+#define GCC_USB30_MASTER_CLK					67
+#define GCC_USB30_MASTER_CLK_SRC				68
+#define GCC_USB30_MOCK_UTMI_CLK					69
+#define GCC_USB30_MOCK_UTMI_CLK_SRC				70
+#define GCC_USB30_SLEEP_CLK					71
+#define GCC_USB3_PHY_AUX_CLK					72
+#define GCC_USB3_PHY_AUX_CLK_SRC				73
+#define GCC_USB3_PHY_PIPE_CLK					74
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK				75
+#define GCC_XO_DIV4_CLK						76
+#define GPLL0							77
+#define GPLL0_OUT_EVEN						78
+
+/* GDSCs */
+#define PCIE_GDSC						0
+#define USB30_GDSC						1
+
+/* CPU clocks */
+#define CLOCK_A7SS						0
+
+/* GCC reset clocks */
+#define GCC_BLSP1_QUP1_BCR					0
+#define GCC_BLSP1_QUP2_BCR					1
+#define GCC_BLSP1_QUP3_BCR					2
+#define GCC_BLSP1_QUP4_BCR					3
+#define GCC_BLSP1_UART2_BCR					4
+#define GCC_BLSP1_UART3_BCR					5
+#define GCC_BLSP1_UART4_BCR					6
+#define GCC_CE1_BCR						7
+#define GCC_PCIE_BCR						8
+#define GCC_PCIE_PHY_BCR					9
+#define GCC_PDM_BCR						10
+#define GCC_PRNG_BCR						11
+#define GCC_SDCC1_BCR						12
+#define GCC_SPMI_FETCHER_BCR					13
+#define GCC_USB30_BCR						14
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR				15
+
+#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d0ec667..72dd7ba 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -439,6 +439,8 @@
 	u8 *cached_ext_csd;
 	bool cmdq_init;
 	struct mmc_bkops_info bkops;
+	bool err_in_sdr104;
+	bool sdr104_blocked;
 };
 
 /*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 5d5aff1..959414b 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -179,6 +179,7 @@
 extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
 extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable);
+extern int mmc_suspend_clk_scaling(struct mmc_host *host);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ba1e826..ecfc173 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -587,6 +587,8 @@
 	struct io_latency_state io_lat_s;
 #endif
 
+	bool sdr104_wa;
+
 	/*
 	 * Set to 1 to just stop the SDCLK to the card without
 	 * actually disabling the clock from it's source.
@@ -751,6 +753,16 @@
 		 MMC_CAP_UHS_DDR50);
 }
 
+static inline void mmc_host_clear_sdr104(struct mmc_host *host)
+{
+	host->caps &= ~MMC_CAP_UHS_SDR104;
+}
+
+static inline void mmc_host_set_sdr104(struct mmc_host *host)
+{
+	host->caps |= MMC_CAP_UHS_SDR104;
+}
+
 static inline int mmc_host_packed_wr(struct mmc_host *host)
 {
 	return host->caps2 & MMC_CAP2_PACKED_WR;
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 8ec7c30..931b494 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -260,27 +260,6 @@
 #define SCSI_INQ_PQ_NOT_CON     0x01
 #define SCSI_INQ_PQ_NOT_CAP     0x03
 
-
-/*
- * Here are some scsi specific ioctl commands which are sometimes useful.
- *
- * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
- */
-
-/* Used to obtain PUN and LUN info.  Conflicts with CDROMAUDIOBUFSIZ */
-#define SCSI_IOCTL_GET_IDLUN		0x5382
-
-/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */
-
-/* Used to obtain the host number of a device. */
-#define SCSI_IOCTL_PROBE_HOST		0x5385
-
-/* Used to obtain the bus number for a device */
-#define SCSI_IOCTL_GET_BUS_NUMBER	0x5386
-
-/* Used to obtain the PCI location of a device */
-#define SCSI_IOCTL_GET_PCI		0x5387
-
 /* Pull a u32 out of a SCSI message (using BE SCSI conventions) */
 static inline __u32 scsi_to_u32(__u8 *ptr)
 {
diff --git a/include/soc/qcom/memory_dump.h b/include/soc/qcom/memory_dump.h
index a7b87aa..dbae8e8 100644
--- a/include/soc/qcom/memory_dump.h
+++ b/include/soc/qcom/memory_dump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -62,7 +62,7 @@
 #define MSM_DUMP_MINOR(val)		(val & 0xFFFFF)
 
 
-#define MAX_NUM_ENTRIES		0x120
+#define MAX_NUM_ENTRIES		0x140
 
 enum msm_dump_data_ids {
 	MSM_DUMP_DATA_CPU_CTX = 0x00,
@@ -82,10 +82,12 @@
 	MSM_DUMP_DATA_VSENSE = 0xE9,
 	MSM_DUMP_DATA_RPM = 0xEA,
 	MSM_DUMP_DATA_SCANDUMP = 0xEB,
+	MSM_DUMP_DATA_RPMH = 0xEC,
 	MSM_DUMP_DATA_TMC_ETF = 0xF0,
 	MSM_DUMP_DATA_TMC_REG = 0x100,
 	MSM_DUMP_DATA_LOG_BUF = 0x110,
 	MSM_DUMP_DATA_LOG_BUF_FIRST_IDX = 0x111,
+	MSM_DUMP_DATA_SCANDUMP_PER_CPU = 0x130,
 	MSM_DUMP_DATA_MAX = MAX_NUM_ENTRIES,
 };
 
diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h
index b1bf6aa..74034c6 100644
--- a/include/uapi/drm/sde_drm.h
+++ b/include/uapi/drm/sde_drm.h
@@ -344,4 +344,16 @@
 	uint64_t modes;
 };
 
+#define SDE_MAX_ROI_V1	4
+
+/**
+ * struct sde_drm_roi_v1 - list of regions of interest for a drm object
+ * @num_rects: number of valid rectangles in the roi array
+ * @roi: list of roi rectangles
+ */
+struct sde_drm_roi_v1 {
+	uint32_t num_rects;
+	struct drm_clip_rect roi[SDE_MAX_ROI_V1];
+};
+
 #endif /* _SDE_DRM_H_ */
diff --git a/include/uapi/scsi/scsi_ioctl.h b/include/uapi/scsi/scsi_ioctl.h
index 516c581a..d9ce5cc 100644
--- a/include/uapi/scsi/scsi_ioctl.h
+++ b/include/uapi/scsi/scsi_ioctl.h
@@ -17,9 +17,25 @@
 #define	SCSI_REMOVAL_PREVENT	1
 #define	SCSI_REMOVAL_ALLOW	0
 
-#ifdef __KERNEL__
+/*
+ * Here are some scsi specific ioctl commands which are sometimes useful.
+ *
+ * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
+ */
 
-struct scsi_device;
+/* Used to obtain PUN and LUN info.  Conflicts with CDROMAUDIOBUFSIZ */
+#define SCSI_IOCTL_GET_IDLUN		0x5382
+
+/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */
+
+/* Used to obtain the host number of a device. */
+#define SCSI_IOCTL_PROBE_HOST		0x5385
+
+/* Used to obtain the bus number for a device */
+#define SCSI_IOCTL_GET_BUS_NUMBER	0x5386
+
+/* Used to obtain the PCI location of a device */
+#define SCSI_IOCTL_GET_PCI		0x5387
 
 /*
  * Structures used for scsi_ioctl et al.
@@ -42,9 +58,11 @@
 	unsigned char host_wwn[8]; // include NULL term.
 } Scsi_FCTargAddress;
 
+#ifdef __KERNEL__
+struct scsi_device;
+
 int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev,
 		int cmd, bool ndelay);
 extern int scsi_ioctl(struct scsi_device *, int, void __user *);
-
 #endif /* __KERNEL__ */
 #endif /* _SCSI_IOCTL_H */
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 826f566..654806e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -153,27 +153,27 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct msm_voice *voice;
 
-	if (!strcmp("VoLTE", substream->pcm->id)) {
+	if (!strncmp("VoLTE", substream->pcm->id, 5)) {
 		voice = &voice_info[VOLTE_SESSION_INDEX];
 		pr_debug("%s: Open VoLTE Substream Id=%s\n",
 			 __func__, substream->pcm->id);
-	} else if (!strcmp("Voice2", substream->pcm->id)) {
+	} else if (!strncmp("Voice2", substream->pcm->id, 6)) {
 		voice = &voice_info[VOICE2_SESSION_INDEX];
 		pr_debug("%s: Open Voice2 Substream Id=%s\n",
 			 __func__, substream->pcm->id);
-	} else if (!strcmp("QCHAT", substream->pcm->id)) {
+	} else if (!strncmp("QCHAT", substream->pcm->id, 5)) {
 		voice = &voice_info[QCHAT_SESSION_INDEX];
 		pr_debug("%s: Open QCHAT Substream Id=%s\n",
 			 __func__, substream->pcm->id);
-	} else if (!strcmp("VoWLAN", substream->pcm->id)) {
+	} else if (!strncmp("VoWLAN", substream->pcm->id, 6)) {
 		voice = &voice_info[VOWLAN_SESSION_INDEX];
 		pr_debug("%s: Open VoWLAN Substream Id=%s\n",
 			 __func__, substream->pcm->id);
-	} else if (!strcmp("VoiceMMode1", substream->pcm->id)) {
+	} else if (!strncmp("VoiceMMode1", substream->pcm->id, 11)) {
 		voice = &voice_info[VOICEMMODE1_INDEX];
 		pr_debug("%s: Open VoiceMMode1 Substream Id=%s\n",
 			 __func__, substream->pcm->id);
-	} else if (!strcmp("VoiceMMode2", substream->pcm->id)) {
+	} else if (!strncmp("VoiceMMode2", substream->pcm->id, 11)) {
 		voice = &voice_info[VOICEMMODE2_INDEX];
 		pr_debug("%s: Open VoiceMMode2 Substream Id=%s\n",
 			 __func__, substream->pcm->id);