Merge "drm/msm/dp: add support for dp aux" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/msm/board-id.txt b/Documentation/devicetree/bindings/arm/msm/board-id.txt
new file mode 100644
index 0000000..e07a1c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/board-id.txt
@@ -0,0 +1,64 @@
+* BOARD-ID
+
+The qcom,board-id entry specifies the MSM platform and subtype revision.
+It can optionally be an array of these to indicate multiple hardware that use
+the same device tree.  It is expected that the bootloader will use this
+information at boot-up to decide which device tree to use when given multiple
+device trees, some of which may not be compatible with the actual hardware.  It
+is the bootloader's responsibility to pass the correct device tree to the kernel.
+
+Legacy format:
+
+It is expected that the qcom,board-id entry be at the top level of the device
+tree structure.  The format of the entry is:
+
+   qcom,board-id = <platform_id, subtype_id> [, <p2, s2> ...]
+
+where platform_id and subtype_id are the numeric values for the platform and
+subtype of the current hardware.
+
+The "subtype_id" cell is a 32-bit integer whose bit values are defined as follows:
+    bits 31-20 = Reserved bits
+    bits 19-16 = Boot Device Type.
+		 MSM:
+		     0: default (eMMC)
+		     2: EMMC_SDC1
+		     4: BOOT_UFS
+		 MDM:
+		     0: default (NAND)
+		     3: EMMC_SDC1
+    bits 15-8  = DDR Size. For devices with DDR Size as 512MB the value is 0x1, default value as 0x0
+    bits 7-0   = Platform Subtype
+
+In the event that a given device tree is applicable to all hardware versions
+matching a given Platform Type / Subtype ID, the major/minior platform version
+fields in the board_id property shall both be specified as 0xff.
+
+Modern format:
+The cell layout of the qcom,board-id property is as follows:
+
+   qcom,board-id = <board_id, reserved>
+
+where board_id is a 32-bit integer whose bit values are defined as follows:
+    bits 31-24 = Platform Subtype ID
+    bits 23-16 = Platform Version (Major)
+    bits 15-8  = Platform Version (Minor)
+    bits  7-0  = Platform Type ID
+
+and the 'reserved' cell is a 32-bit integer whose bit values are defined as follows:
+    bits 31-13 = Reserved Bits
+    bits 12-11 = Panel Detection. 00 - limit to HD, 01 - limit to 720p,
+		 10 - limit to qHD, 11 - limit to FWVGA
+    bits 10-8  = DDR Size. For devices with DDR Size as 512MB the value is 0x1,
+		 default value as 0x0
+    bits 7-0   = Platform Subtype
+
+In the event that a given device tree is applicable to all hardware versions
+matching a given Platform Type / Subtype ID, the major/minior platform version
+fields in the board_id property shall both be specified as 0xff.
+
+Example:
+   qcom,board-id = <15 0>;
+   qcom,board-id = <0x01040708, 0>;
+   qcom,board-id = <0x01ffff08, 0>;
+   qcom,board-id = <8, 0x100>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-id.txt b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
new file mode 100644
index 0000000..c243154
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-id.txt
@@ -0,0 +1,33 @@
+* MSM-ID
+
+The qcom,msm-id entry specifies the MSM chipset, platform, hardware revision
+and optional manufactured foundry.  It can optionally be an array of these to
+indicate multiple hardware that use the same device tree.  It is expected that
+the bootloader will use this information at boot-up to decide which device tree
+to use when given multiple device trees, some of which may not be compatible
+with the actual hardware.  It is the bootloader's responsibility to pass the
+correct device tree to the kernel.
+
+Format:
+
+It is expected that the qcom,msm-id entry be at the top level of the device
+tree structure.  The format can take one of the two forms below:
+
+   qcom,msm-id = <chipset_foundry_id, platform_id, rev_id> [, <c2, p2, r2> ...]
+   qcom,msm-id = <chipset_foundry_id, rev_id> [, <c2, r2> ...]
+
+If the second format is used one must also define the board-id.
+
+The "chipset_foundry_id" consists of three fields as below:
+
+   bits 0-15  = The unique MSM chipset id.
+   bits 16-23 = The optional foundry id. If bootloader doesn't find a device
+		tree which has exact matching foundry-id with hardware it
+		chooses the device tree with foundry-id = 0.
+   bits 24-31 = Reserved.
+
+Example:
+   qcom,msm-id = <0x1007e 15 0>;
+
+   qcom,board-id= <15 2>;
+   qcom,msm-id = <0x1007e 0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 79ac3b1..7ae63af 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -425,10 +425,44 @@
 					 2003 1675>;
 
 				qcom,cpr-open-loop-voltage-fuse-adjustment =
-					<100000 100000 100000>;
+					/* Speed bin 0 */
+					<100000 100000 100000>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					/* Speed bin 1 */
+					<100000 100000 100000>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>;
 
 				qcom,cpr-closed-loop-voltage-fuse-adjustment =
-					<100000 100000 100000>;
+					/* Speed bin 0 */
+					<100000 100000 100000>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					/* Speed bin 1 */
+					<100000 100000 100000>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>,
+					<     0      0      0>;
 
 				qcom,allow-voltage-interpolation;
 				qcom,allow-quotient-interpolation;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 6818615..5f1b4ee 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1011,6 +1011,35 @@
 		interrupts = <1 5 4>;
 	};
 
+	mincpubw: qcom,mincpubw {
+		compatible = "qcom,devbw";
+		governor = "powersave";
+		qcom,src-dst-ports = <1 512>;
+		qcom,active-only;
+		qcom,bw-tbl =
+			<  762 /*  200 MHz */ >,
+			< 1144 /*  300 MHz */ >,
+			< 1720 /*  451 MHz */ >,
+			< 2086 /*  547 MHz */ >,
+			< 2597 /*  681 MHz */ >,
+			< 2929 /*  768 MHz */ >,
+			< 3879 /* 1017 MHz */ >,
+			< 4943 /* 1296 MHz */ >,
+			< 5931 /* 1555 MHz */ >,
+			< 6881 /* 1804 MHz */ >;
+	};
+
+	devfreq-cpufreq {
+		mincpubw-cpufreq {
+			target-dev = <&mincpubw>;
+			cpu-to-dev-map-0 =
+				< 1708800  762 >;
+			cpu-to-dev-map-4 =
+				< 2035200  762 >,
+				< 2092800 2597 >;
+		};
+	};
+
 	clock_rpmh: qcom,rpmhclk {
 		compatible = "qcom,rpmh-clk-sdm845";
 		#clock-cells = <1>;
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 3a38d37..7f56fb6 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -174,6 +174,7 @@
 	struct clk_regmap	clkr;
 	u8			flags;
 #define FORCE_ENABLE_RCG	BIT(0)
+#define DFS_ENABLE_RCG		BIT(1)
 };
 
 #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)
@@ -187,4 +188,6 @@
 extern const struct clk_ops clk_gfx3d_ops;
 extern const struct clk_ops clk_dp_ops;
 
+extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk,
+				struct device *dev, u8 rcg_flags);
 #endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 3d101ac..6bdea53 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -18,6 +18,7 @@
 #include <linux/export.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/regmap.h>
 #include <linux/rational.h>
 #include <linux/math64.h>
@@ -50,6 +51,14 @@
 #define N_REG			0xc
 #define D_REG			0x10
 
+/* Dynamic Frequency Scaling */
+#define MAX_PERF_LEVEL		16
+#define SE_CMD_DFSR_OFFSET	0x14
+#define SE_CMD_DFS_EN		BIT(0)
+#define SE_PERF_DFSR(level)	(0x1c + 0x4 * (level))
+#define SE_PERF_M_DFSR(level)	(0x5c + 0x4 * (level))
+#define SE_PERF_N_DFSR(level)	(0x9c + 0x4 * (level))
+
 static struct freq_tbl cxo_f = {
 	.freq = 19200000,
 	.src = 0,
@@ -127,6 +136,9 @@
 	int ret;
 	u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
 
+	if (rcg->flags & DFS_ENABLE_RCG)
+		return 0;
+
 	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
 				 CFG_SRC_SEL_MASK, cfg);
 	if (ret)
@@ -236,6 +248,9 @@
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
 	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask;
 
+	if (rcg->flags & DFS_ENABLE_RCG)
+		return rcg->current_freq;
+
 	if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) {
 		if (!rcg->current_freq)
 			rcg->current_freq = cxo_f.freq;
@@ -333,6 +348,9 @@
 	struct clk_hw *hw = &rcg->clkr.hw;
 	int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
 
+	if (rcg->flags & DFS_ENABLE_RCG)
+		return -EPERM;
+
 	if (index < 0)
 		return index;
 
@@ -461,7 +479,7 @@
 	}
 
 	ret = clk_rcg2_configure(rcg, f);
-	if (ret)
+	if (ret && ret != -EPERM)
 		return ret;
 
 	if (rcg->flags & FORCE_ENABLE_RCG) {
@@ -1170,3 +1188,167 @@
 	.list_registers = clk_rcg2_list_registers,
 };
 EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
+
+/* Common APIs to be used for DFS based RCGR */
+static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset,
+		u32 *mode, u32 *pre_div)
+{
+	struct clk_rcg2 *rcg;
+	int num_parents = clk_hw_get_num_parents(hw);
+	u32 cfg, mask;
+	int i, ret;
+
+	if (!hw)
+		return -EINVAL;
+
+	rcg = to_clk_rcg2(hw);
+
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg);
+	if (ret)
+		goto err;
+
+	mask = BIT(rcg->hid_width) - 1;
+	*pre_div = cfg & mask ? (cfg & mask) : 1;
+
+	*mode = cfg & CFG_MODE_MASK;
+	*mode >>= CFG_MODE_SHIFT;
+
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == rcg->parent_map[i].cfg)
+			return i;
+err:
+	pr_debug("%s: Clock %s has invalid parent, using default.\n",
+		 __func__, clk_hw_get_name(hw));
+	return 0;
+}
+
+static int calculate_m_and_n(struct clk_hw *hw, u32 m_offset, u32 n_offset,
+		u32 mode, u32 *m, u32 *n)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	u32 val, mask;
+	int ret = 0;
+
+	if (!hw)
+		return -EINVAL;
+
+	*m = *n = 0;
+
+	if (mode) {
+		/* Calculate M & N values */
+		mask = BIT(rcg->mnd_width) - 1;
+		ret =  regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_offset,
+					&val);
+		if (ret) {
+			pr_err("Failed to read M offset register\n");
+			goto err;
+		}
+
+		val &= mask;
+		*m  = val;
+
+		ret =  regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_offset,
+					&val);
+		if (ret) {
+			pr_err("Failed to read N offset register\n");
+			goto err;
+		}
+
+		/* val ~(N-M) */
+		val = ~val;
+		val &= mask;
+		val += *m;
+		*n = val;
+	}
+err:
+	return ret;
+}
+
+int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk, struct device *dev,
+						u8 rcg_flags)
+{
+	int i, j, index, ret = 0;
+	unsigned long calc_freq, prate;
+	u32 val, pre_div = 0, mode = 0, m = 0, n = 0;
+	struct freq_tbl *dfs_freq_tbl;
+	struct clk_hw *phw;
+
+	if (!clk)
+		return -EINVAL;
+
+	/* Check for DFS_EN */
+	ret = regmap_read(clk->clkr.regmap, clk->cmd_rcgr + SE_CMD_DFSR_OFFSET,
+						&val);
+	if (ret) {
+		dev_err(dev, "Failed to read DFS enable register\n");
+		return -EINVAL;
+	}
+
+	if (!(val & SE_CMD_DFS_EN))
+		return ret;
+
+	dfs_freq_tbl = devm_kzalloc(dev, MAX_PERF_LEVEL *
+				sizeof(struct freq_tbl), GFP_KERNEL);
+	if (!dfs_freq_tbl)
+		return -ENOMEM;
+
+	/* Populate the Perf Level */
+	for (i = 0; i < MAX_PERF_LEVEL; i++) {
+		/* Get parent index and mode */
+		index = clk_parent_index_pre_div_and_mode(&clk->clkr.hw,
+							SE_PERF_DFSR(i), &mode,
+							&pre_div);
+		if (index < 0) {
+			pr_err("Failed to get parent index & mode %d\n", index);
+			return index;
+		}
+
+		/* clock pre_div */
+		dfs_freq_tbl[i].pre_div = pre_div;
+
+		/* Fill the parent src */
+		dfs_freq_tbl[i].src = clk->parent_map[index].src;
+
+		/* Get the parent clock and parent rate */
+		phw = clk_hw_get_parent_by_index(&clk->clkr.hw, index);
+		prate = clk_hw_get_rate(phw);
+
+		ret = calculate_m_and_n(&clk->clkr.hw, SE_PERF_M_DFSR(i),
+					SE_PERF_N_DFSR(i), mode, &m, &n);
+		if (ret)
+			goto err;
+
+		dfs_freq_tbl[i].m = m;
+		dfs_freq_tbl[i].n = n;
+
+		/* calculate the final frequency */
+		calc_freq = calc_rate(prate, dfs_freq_tbl[i].m,
+						dfs_freq_tbl[i].n, mode,
+						dfs_freq_tbl[i].pre_div);
+
+		/* Check for duplicate frequencies */
+		for (j = 0; j  < i; j++) {
+			if (dfs_freq_tbl[j].freq == calc_freq)
+				goto done;
+		}
+
+		dfs_freq_tbl[i].freq = calc_freq;
+	}
+done:
+	j = i;
+
+	for (i = 0; i < j; i++)
+		pr_debug("Index[%d]\tfreq_table.freq %ld\tfreq_table.src %d\t"
+		"freq_table.pre_div %d\tfreq_table.m %d\tfreq_table.n %d\t"
+		"RCG flags %x\n", i, dfs_freq_tbl[i].freq, dfs_freq_tbl[i].src,
+				dfs_freq_tbl[i].pre_div, dfs_freq_tbl[i].m,
+				dfs_freq_tbl[i].n, rcg_flags);
+
+	clk->flags |= rcg_flags;
+	clk->freq_tbl = dfs_freq_tbl;
+err:
+	return ret;
+}
diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c
index fffcbaf..b2ff04a 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -275,4 +275,26 @@
 }
 EXPORT_SYMBOL_GPL(qcom_cc_probe);
 
+int qcom_cc_register_rcg_dfs(struct platform_device *pdev,
+			 const struct qcom_cc_dfs_desc *desc)
+{
+	struct clk_dfs *clks = desc->clks;
+	size_t num_clks = desc->num_clks;
+	int i, ret = 0;
+
+	for (i = 0; i < num_clks; i++) {
+		ret = clk_rcg2_get_dfs_clock_rate(clks[i].rcg, &pdev->dev,
+						clks[i].rcg_flags);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed calculating DFS frequencies for %s\n",
+				clk_hw_get_name(&(clks[i].rcg)->clkr.hw));
+			break;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(qcom_cc_register_rcg_dfs);
+
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index e728dec..5e26763 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -14,6 +14,7 @@
 #define __QCOM_CLK_COMMON_H__
 
 #include <linux/reset-controller.h>
+#include "clk-rcg.h"
 
 struct platform_device;
 struct regmap_config;
@@ -40,6 +41,16 @@
 	unsigned long rrate;
 };
 
+struct clk_dfs {
+	struct clk_rcg2 *rcg;
+	u8 rcg_flags;
+};
+
+struct qcom_cc_dfs_desc {
+	struct clk_dfs *clks;
+	size_t num_clks;
+};
+
 extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
 					     unsigned long rate);
 extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
@@ -56,6 +67,10 @@
 				struct regmap *regmap);
 extern int qcom_cc_probe(struct platform_device *pdev,
 			 const struct qcom_cc_desc *desc);
+
+extern int qcom_cc_register_rcg_dfs(struct platform_device *pdev,
+			 const struct qcom_cc_dfs_desc *desc);
+
 extern struct clk_ops clk_dummy_ops;
 
 #define BM(msb, lsb)	(((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 228f716..b38bfb0 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -3509,6 +3509,31 @@
 	[GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
 };
 
+/* List of RCG clocks and corresponding flags requested for DFS Mode */
+static struct clk_dfs gcc_dfs_clocks[] = {
+	{ &gcc_qupv3_wrap0_s0_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap0_s1_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap0_s2_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap0_s3_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap0_s4_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap0_s5_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap0_s6_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap0_s7_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s0_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s1_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s2_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s3_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s4_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s5_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s6_clk_src, DFS_ENABLE_RCG },
+	{ &gcc_qupv3_wrap1_s7_clk_src, DFS_ENABLE_RCG },
+};
+
+static const struct qcom_cc_dfs_desc gcc_sdm845_dfs_desc = {
+	.clks = gcc_dfs_clocks,
+	.num_clks = ARRAY_SIZE(gcc_dfs_clocks),
+};
+
 static const struct regmap_config gcc_sdm845_regmap_config = {
 	.reg_bits	= 32,
 	.reg_stride	= 4,
@@ -3599,10 +3624,10 @@
 	clk_prepare_enable(gcc_camera_ahb_clk.clkr.hw.clk);
 	clk_prepare_enable(gcc_video_ahb_clk.clkr.hw.clk);
 
-	/*
-	 * TODO:
-	 * 1. QUPv3 support
-	 */
+	/* DFS clock registration */
+	ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to register with DFS!\n");
 
 	dev_info(&pdev->dev, "Registered GCC clocks\n");
 	return ret;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index dcf3c08..a3a3d28 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -3054,6 +3054,11 @@
 			state->crtc_h);
 		seq_printf(s, "\tmultirect: mode: %d index: %d\n",
 			pstate->multirect_mode, pstate->multirect_index);
+
+		seq_printf(s, "\texcl_rect: x:%4d y:%4d w:%4d h:%4d\n",
+			pstate->excl_rect.x, pstate->excl_rect.y,
+			pstate->excl_rect.w, pstate->excl_rect.h);
+
 		seq_puts(s, "\n");
 	}
 
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 3a6de75..ad207d6 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2447,7 +2447,7 @@
 		   pstate->excl_rect.h != old_pstate->excl_rect.h ||
 		   pstate->excl_rect.x != old_pstate->excl_rect.x ||
 		   pstate->excl_rect.y != old_pstate->excl_rect.y) {
-		SDE_DEBUG_PLANE(psde, "excl rect updated\n");
+		SDE_DEBUG_PLANE(psde, "excl_rect updated\n");
 		pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
 	}
 
@@ -2660,6 +2660,9 @@
 				(char *)&fmt->base.pixel_format);
 			ret = -EINVAL;
 		}
+		SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
+				pstate->excl_rect.x, pstate->excl_rect.y,
+				pstate->excl_rect.w, pstate->excl_rect.h);
 	}
 
 modeset_update:
@@ -3480,20 +3483,24 @@
 	}
 
 	if (!usr_ptr) {
-		SDE_DEBUG_PLANE(psde, "excl rect data removed\n");
+		SDE_DEBUG_PLANE(psde, "invalid  excl_rect user data\n");
 		return;
 	}
 
 	if (copy_from_user(&excl_rect_v1, usr_ptr, sizeof(excl_rect_v1))) {
-		SDE_ERROR_PLANE(psde, "failed to copy excl rect data\n");
+		SDE_ERROR_PLANE(psde, "failed to copy excl_rect data\n");
 		return;
 	}
 
 	/* populate from user space */
 	pstate->excl_rect.x = excl_rect_v1.x1;
 	pstate->excl_rect.y = excl_rect_v1.y1;
-	pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1 + 1;
-	pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1 + 1;
+	pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1;
+	pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1;
+
+	SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
+			pstate->excl_rect.x, pstate->excl_rect.y,
+			pstate->excl_rect.w, pstate->excl_rect.h);
 }
 
 static int sde_plane_atomic_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index bf3a91a..2e92335 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1509,8 +1509,7 @@
 			PERFCOUNTER_FLAG_KERNEL);
 
 		if (ret) {
-			KGSL_DRV_ERR(device,
-				"Unable to get the perf counters for DCVS\n");
+			WARN_ONCE(1, "Unable to get perf counters for DCVS\n");
 			adreno_dev->perfctr_pwr_lo = 0;
 		}
 	}
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 24b5faa..e157e7b 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -813,12 +813,12 @@
 
 	t = jiffies + msecs_to_jiffies(timeout);
 
-	while (!time_after(jiffies, t)) {
+	do {
 		kgsl_gmu_regread(device, offset, &value);
 		if ((value & mask) == expected_ret)
 			return 0;
 		cpu_relax();
-	}
+	} while (!time_after(jiffies, t));
 
 	return -EINVAL;
 }
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 54659fc..8de1a7e 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1438,7 +1438,7 @@
 
 	if (hfi->hfi_interrupt_num) {
 		devm_free_irq(&gmu->pdev->dev,
-				hfi->hfi_interrupt_num, gmu);
+				hfi->hfi_interrupt_num, hfi);
 		hfi->hfi_interrupt_num = 0;
 	}
 
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 8906027..14eb3ab 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -86,7 +86,6 @@
 };
 
 static const char *const hevc_tier_level[] = {
-	"Level unknown"
 	"Main Tier Level 1",
 	"Main Tier Level 2",
 	"Main Tier Level 2.1",
@@ -113,6 +112,7 @@
 	"High Tier Level 6",
 	"High Tier Level 6.1",
 	"High Tier Level 6.2",
+	"Level unknown",
 };
 
 static const char *const hevc_profile[] = {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 2289b23..05d6d63 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1267,10 +1267,9 @@
 			return -EINVAL;
 		}
 		if (*num_buffers < bufreq->buffer_count_min_host) {
-			dprintk(VIDC_ERR,
-				"Invalid parameters : Req = %d Act = %d\n",
+			dprintk(VIDC_DBG,
+				"Client passed num buffers %d less than the min_host count %d\n",
 				*num_buffers, bufreq->buffer_count_min_host);
-			return -EINVAL;
 		}
 		*num_planes = inst->bufq[OUTPUT_PORT].num_planes;
 		if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
@@ -1299,11 +1298,10 @@
 		if (inst->session_type != MSM_VIDC_DECODER &&
 			inst->state > MSM_VIDC_LOAD_RESOURCES_DONE) {
 			if (*num_buffers < bufreq->buffer_count_min_host) {
-				dprintk(VIDC_ERR,
-					"Invalid parameters : Req = %d Act = %d\n",
+				dprintk(VIDC_DBG,
+					"Client passed num buffers %d less than the min_host count %d\n",
 						*num_buffers,
 						bufreq->buffer_count_min_host);
-				return -EINVAL;
 			}
 		}
 		*num_planes = inst->bufq[CAPTURE_PORT].num_planes;
@@ -1890,16 +1888,30 @@
 	switch (ctrl->id) {
 
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
-	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+		ctrl->val = msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+			inst->profile);
+		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
-		ctrl->val = inst->profile;
+		ctrl->val = msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+			inst->profile);
 		break;
 
 	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		ctrl->val = msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+			inst->level);
+		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
-	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+		ctrl->val = msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+			inst->level);
+		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
-		ctrl->val = inst->level;
+		ctrl->val = msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+			inst->level);
 		break;
 
 	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index c0bbfbb..058af0e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -199,6 +199,8 @@
 			return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
 		case HAL_H264_LEVEL_51:
 			return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+		case HAL_H264_LEVEL_52:
+			return V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
 		default:
 			goto unknown_value;
 		}
@@ -212,7 +214,91 @@
 		default:
 			goto unknown_value;
 		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
+		switch (value) {
+		case HAL_HEVC_PROFILE_MAIN:
+			return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN;
+		case HAL_HEVC_PROFILE_MAIN10:
+			return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10;
+		case HAL_HEVC_PROFILE_MAIN_STILL_PIC:
+			return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
+	switch (value) {
+	case HAL_HEVC_MAIN_TIER_LEVEL_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1;
+	case HAL_HEVC_MAIN_TIER_LEVEL_2:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2;
+	case HAL_HEVC_MAIN_TIER_LEVEL_2_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1;
+	case HAL_HEVC_MAIN_TIER_LEVEL_3:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3;
+	case HAL_HEVC_MAIN_TIER_LEVEL_3_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1;
+	case HAL_HEVC_MAIN_TIER_LEVEL_4:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4;
+	case HAL_HEVC_MAIN_TIER_LEVEL_4_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1;
+	case HAL_HEVC_MAIN_TIER_LEVEL_5:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5;
+	case HAL_HEVC_MAIN_TIER_LEVEL_5_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1;
+	case HAL_HEVC_MAIN_TIER_LEVEL_5_2:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2;
+	case HAL_HEVC_MAIN_TIER_LEVEL_6:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6;
+	case HAL_HEVC_MAIN_TIER_LEVEL_6_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1;
+	case HAL_HEVC_MAIN_TIER_LEVEL_6_2:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2;
+	case HAL_HEVC_HIGH_TIER_LEVEL_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1;
+	case HAL_HEVC_HIGH_TIER_LEVEL_2:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2;
+	case HAL_HEVC_HIGH_TIER_LEVEL_2_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1;
+	case HAL_HEVC_HIGH_TIER_LEVEL_3:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3;
+	case HAL_HEVC_HIGH_TIER_LEVEL_3_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1;
+	case HAL_HEVC_HIGH_TIER_LEVEL_4:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4;
+	case HAL_HEVC_HIGH_TIER_LEVEL_4_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1;
+	case HAL_HEVC_HIGH_TIER_LEVEL_5:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5;
+	case HAL_HEVC_HIGH_TIER_LEVEL_5_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1;
+	case HAL_HEVC_HIGH_TIER_LEVEL_5_2:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2;
+	case HAL_HEVC_HIGH_TIER_LEVEL_6:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6;
+	case HAL_HEVC_HIGH_TIER_LEVEL_6_1:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1;
+	case HAL_HEVC_HIGH_TIER_LEVEL_6_2:
+		return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2;
+	case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN:
+		return HAL_HEVC_TIER_LEVEL_UNKNOWN;
+	default:
+		goto unknown_value;
+	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+		switch (value) {
+		case HAL_VPX_LEVEL_VERSION_0:
+			return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0;
+		case HAL_VPX_LEVEL_VERSION_1:
+			return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1;
+		case HAL_VPX_LEVEL_VERSION_2:
+			return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2;
+		case HAL_VPX_LEVEL_VERSION_3:
+			return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3;
+		case HAL_VPX_LEVEL_UNUSED:
+			return V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED;
+		default:
+			goto unknown_value;
+		}
 	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
 	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
 		/*
@@ -396,6 +482,8 @@
 			return HAL_HEVC_HIGH_TIER_LEVEL_6;
 		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1:
 			return HAL_HEVC_HIGH_TIER_LEVEL_6_1;
+		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2:
+			return HAL_HEVC_HIGH_TIER_LEVEL_6_2;
 		case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN:
 			return HAL_HEVC_TIER_LEVEL_UNKNOWN;
 		default:
@@ -1463,15 +1551,9 @@
 	* ptr[4] = colour space
 	*/
 
-	inst->entropy_mode = msm_comm_hal_to_v4l2(
-		V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
-			event_notify->entropy_mode);
-	inst->profile = msm_comm_hal_to_v4l2(
-		V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-			event_notify->profile);
-	inst->level = msm_comm_hal_to_v4l2(
-		V4L2_CID_MPEG_VIDEO_H264_LEVEL,
-			event_notify->level);
+	inst->entropy_mode = event_notify->entropy_mode;
+	inst->profile = event_notify->profile;
+	inst->level = event_notify->level;
 
 	ptr = (u32 *)seq_changed_event.u.data;
 	ptr[0] = event_notify->height;
@@ -2342,7 +2424,7 @@
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
 			vbuf->flags |= V4L2_QCOM_BUF_FLAG_EOS;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
-			vbuf->flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
+			vbuf->flags |= V4L2_QCOM_BUF_FLAG_CODECCONFIG;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
 			vbuf->flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
 		if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index bcc29c0..da18377 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -377,11 +377,11 @@
 };
 
 enum hal_vpx_level {
+	HAL_VPX_LEVEL_UNUSED = 0x00000000,
 	HAL_VPX_LEVEL_VERSION_0 = 0x00000001,
 	HAL_VPX_LEVEL_VERSION_1 = 0x00000002,
 	HAL_VPX_LEVEL_VERSION_2 = 0x00000004,
 	HAL_VPX_LEVEL_VERSION_3 = 0x00000008,
-	HAL_VPX_LEVEL_UNUSED = 0x10000000,
 };
 
 struct hal_frame_rate {
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index 4d2f54d..a9b78d5 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -74,6 +74,12 @@
 #define DCC_RD_MOD_WR_DESCRIPTOR	(BIT(31))
 #define DCC_LINK_DESCRIPTOR		(BIT(31) | BIT(30))
 
+#define DCC_READ_IND			0x00
+#define DCC_WRITE_IND			(BIT(28))
+
+#define DCC_AHB_IND			0x00
+#define DCC_APB_IND			BIT(29)
+
 #define DCC_MAX_LINK_LIST		5
 #define DCC_INVALID_LINK_LIST		0xFF
 
@@ -92,6 +98,13 @@
 	DCC_DATA_SINK_ATB
 };
 
+enum dcc_descriptor_type {
+	DCC_ADDR_TYPE,
+	DCC_LOOP_TYPE,
+	DCC_READ_WRITE_TYPE,
+	DCC_WRITE_TYPE
+};
+
 static const char * const str_dcc_data_sink[] = {
 	[DCC_DATA_SINK_SRAM]		= "sram",
 	[DCC_DATA_SINK_ATB]		= "atb",
@@ -103,15 +116,16 @@
 };
 
 struct dcc_config_entry {
-	uint32_t		base;
-	uint32_t		offset;
-	uint32_t		len;
-	uint32_t		index;
-	uint32_t		loop_cnt;
-	uint32_t		rd_mod_wr;
-	uint32_t		mask;
-	bool			rd_wr_entry;
-	struct list_head	list;
+	uint32_t			base;
+	uint32_t			offset;
+	uint32_t			len;
+	uint32_t			index;
+	uint32_t			loop_cnt;
+	uint32_t			write_val;
+	uint32_t			mask;
+	bool				apb_bus;
+	enum dcc_descriptor_type	desc_type;
+	struct list_head		list;
 };
 
 struct dcc_drvdata {
@@ -189,7 +203,7 @@
 	mutex_lock(&drvdata->mutex);
 
 	if (!dcc_ready(drvdata)) {
-		dev_err(drvdata->dev, "DCC is not ready!\n");
+		dev_err(drvdata->dev, "DCC is not ready\n");
 		ret = -EBUSY;
 		goto err;
 	}
@@ -224,7 +238,7 @@
 	uint32_t loop_off = 0;
 	uint32_t link;
 	uint32_t pos, total_len = 0, loop_len = 0;
-	uint32_t loop, loop_cnt;
+	uint32_t loop, loop_cnt = 0;
 	bool loop_start = false;
 	struct dcc_config_entry *entry;
 
@@ -233,7 +247,9 @@
 	link = 0;
 
 	list_for_each_entry(entry, &drvdata->cfg_head[curr_list], list) {
-		if (entry->rd_wr_entry) {
+		switch (entry->desc_type) {
+		case DCC_READ_WRITE_TYPE:
+		{
 			if (link) {
 				/* write new offset = 1 to continue
 				 * processing the list
@@ -255,12 +271,14 @@
 			dcc_sram_writel(drvdata, entry->mask, sram_offset);
 				sram_offset += 4;
 
-			dcc_sram_writel(drvdata, entry->rd_mod_wr, sram_offset);
+			dcc_sram_writel(drvdata, entry->write_val, sram_offset);
 				sram_offset += 4;
-			continue;
+			addr = 0;
+			break;
 		}
 
-		if (entry->loop_cnt) {
+		case DCC_LOOP_TYPE:
+		{
 			/* Check if we need to write link of prev entry */
 			if (link) {
 				dcc_sram_writel(drvdata, link, sram_offset);
@@ -292,73 +310,130 @@
 			prev_off = 0;
 			prev_addr = addr;
 
-			continue;
+			break;
 		}
 
-		/* Address type */
-		addr = (entry->base >> 4) & BM(0, 27);
-		addr |= DCC_ADDR_DESCRIPTOR;
-		off = entry->offset/4;
-		total_len += entry->len * 4;
-
-		if (!prev_addr || prev_addr != addr || prev_off > off) {
-			/* Check if we need to write link of prev entry */
+		case DCC_WRITE_TYPE:
+		{
 			if (link) {
+				/* write new offset = 1 to continue
+				 * processing the list
+				 */
+				link |= ((0x1 << 8) & BM(8, 14));
 				dcc_sram_writel(drvdata, link, sram_offset);
 				sram_offset += 4;
+				/* Reset link and prev_off */
+				addr = 0x00;
+				prev_off = 0;
+				prev_addr = addr;
 			}
-			dev_err(drvdata->dev,
-				"DCC: sram address.%d\n", sram_offset);
 
-			/* Write address */
+			off = entry->offset/4;
+			/* write new offset-length pair to correct position */
+			link |= ((off & BM(0, 7)) | BIT(15) |
+				 ((entry->len << 8) & BM(8, 14)));
+			link |= DCC_LINK_DESCRIPTOR;
+
+			/* Address type */
+			addr = (entry->base >> 4) & BM(0, 27);
+			if (entry->apb_bus)
+				addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND
+					| DCC_APB_IND;
+			else
+				addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND
+					| DCC_AHB_IND;
+
 			dcc_sram_writel(drvdata, addr, sram_offset);
-			sram_offset += 4;
+				sram_offset += 4;
 
-			/* Reset link and prev_off */
-			link = 0;
-			prev_off = 0;
-		}
-
-		if ((off - prev_off) > 0xFF || entry->len > MAX_DCC_LEN) {
-			dev_err(drvdata->dev,
-				"DCC: Progamming error! Base: 0x%x, offset 0x%x.\n",
-				entry->base, entry->offset);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		if (link) {
-			/*
-			 * link already has one offset-length so new
-			 * offset-length needs to be placed at bits [29:15]
-			 */
-			pos = 15;
-
-			/* Clear bits [31:16] */
-			link &= BM(0, 14);
-		} else {
-			/*
-			 * link is empty, so new offset-length needs to be
-			 * placed at bits [15:0]
-			 */
-			pos = 0;
-			link = 1 << 15;
-		}
-
-		/* write new offset-length pair to correct position */
-		link |= (((off-prev_off) & BM(0, 7)) |
-			 ((entry->len << 8) & BM(8, 14))) << pos;
-
-		link |= DCC_LINK_DESCRIPTOR;
-
-		if (pos) {
 			dcc_sram_writel(drvdata, link, sram_offset);
-			sram_offset += 4;
+				sram_offset += 4;
+
+			dcc_sram_writel(drvdata, entry->write_val, sram_offset);
+				sram_offset += 4;
+			addr = 0x00;
 			link = 0;
+			break;
 		}
 
-		prev_off  = off;
-		prev_addr = addr;
+		default:
+		{
+			/* Address type */
+			addr = (entry->base >> 4) & BM(0, 27);
+			if (entry->apb_bus)
+				addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND
+					| DCC_APB_IND;
+			else
+				addr |= DCC_ADDR_DESCRIPTOR | DCC_READ_IND
+					| DCC_AHB_IND;
+
+			off = entry->offset/4;
+			total_len += entry->len * 4;
+
+			if (!prev_addr || prev_addr != addr || prev_off > off) {
+				/* Check if we need to write prev link entry */
+				if (link) {
+					dcc_sram_writel(drvdata,
+							link, sram_offset);
+					sram_offset += 4;
+				}
+				dev_dbg(drvdata->dev,
+					"DCC: sram address 0x%x\n",
+					sram_offset);
+
+				/* Write address */
+				dcc_sram_writel(drvdata, addr, sram_offset);
+				sram_offset += 4;
+
+				/* Reset link and prev_off */
+				link = 0;
+				prev_off = 0;
+			}
+
+			if ((off - prev_off) > 0xFF ||
+			    entry->len > MAX_DCC_LEN) {
+				dev_err(drvdata->dev,
+					"DCC: Progamming error Base: 0x%x, offset 0x%x\n",
+					entry->base, entry->offset);
+				ret = -EINVAL;
+				goto err;
+			}
+
+			if (link) {
+				/*
+				 * link already has one offset-length so new
+				 * offset-length needs to be placed at
+				 * bits [29:15]
+				 */
+				pos = 15;
+
+				/* Clear bits [31:16] */
+				link &= BM(0, 14);
+			} else {
+				/*
+				 * link is empty, so new offset-length needs
+				 * to be placed at bits [15:0]
+				 */
+				pos = 0;
+				link = 1 << 15;
+			}
+
+			/* write new offset-length pair to correct position */
+			link |= (((off-prev_off) & BM(0, 7)) |
+				 ((entry->len << 8) & BM(8, 14))) << pos;
+
+			link |= DCC_LINK_DESCRIPTOR;
+
+			if (pos) {
+				dcc_sram_writel(drvdata, link, sram_offset);
+				sram_offset += 4;
+				link = 0;
+			}
+
+			prev_off  = off;
+			prev_addr = addr;
+			}
+		}
 	}
 
 	if (link) {
@@ -368,7 +443,7 @@
 
 	if (loop_start) {
 		dev_err(drvdata->dev,
-			"DCC: Progamming error! Loop unterminated.\n");
+			"DCC: Progamming error: Loop unterminated\n");
 		ret = -EINVAL;
 		goto err;
 	}
@@ -457,7 +532,7 @@
 	 */
 	for (i = 0; i < 2; i++) {
 		if (!dcc_ready(drvdata))
-			dev_err(drvdata->dev, "DCC is not ready!\n");
+			dev_err(drvdata->dev, "DCC is not ready\n");
 
 		dcc_writel(drvdata, 1,
 			   DCC_LL_SW_TRIGGER(drvdata->curr_list));
@@ -476,13 +551,13 @@
 		return -EINVAL;
 
 	if (drvdata->enable[curr_list]) {
-		dev_err(drvdata->dev, "DCC is already enabled!\n");
+		dev_err(drvdata->dev, "DCC is already enabled\n");
 		return -EINVAL;
 	}
 
 	lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(curr_list));
 	if (lock_reg & 0x1) {
-		dev_err(drvdata->dev, "DCC is already enabled!\n");
+		dev_err(drvdata->dev, "DCC is already enabled\n");
 		return -EINVAL;
 	}
 
@@ -565,7 +640,7 @@
 	mutex_lock(&drvdata->mutex);
 
 	if (!dcc_ready(drvdata))
-		dev_err(drvdata->dev, "DCC is not ready! Disabling DCC...\n");
+		dev_err(drvdata->dev, "DCC is not ready Disabling DCC...\n");
 
 	for (curr_list = 0; curr_list < DCC_MAX_LINK_LIST; curr_list++) {
 		if (!drvdata->enable[curr_list])
@@ -600,7 +675,7 @@
 	mutex_lock(&drvdata->mutex);
 	lock_reg = dcc_readl(drvdata, DCC_LL_LOCK(val));
 	if (lock_reg & 0x1) {
-		dev_err(drvdata->dev, "DCC linked list is already configured!\n");
+		dev_err(drvdata->dev, "DCC linked list is already configured\n");
 		mutex_unlock(&drvdata->mutex);
 		return -EINVAL;
 	}
@@ -783,25 +858,36 @@
 	mutex_lock(&drvdata->mutex);
 	list_for_each_entry(entry,
 			    &drvdata->cfg_head[drvdata->curr_list], list) {
-		if (entry->rd_wr_entry)
+		switch (entry->desc_type) {
+		case DCC_READ_WRITE_TYPE:
 			len = snprintf(local_buf, 64,
 				       "Index: 0x%x, mask: 0x%x, val: 0x%x\n",
 				       entry->index, entry->mask,
-				       entry->rd_mod_wr);
-		else if (entry->loop_cnt)
+				       entry->write_val);
+			break;
+		case DCC_LOOP_TYPE:
 			len = snprintf(local_buf, 64, "Index: 0x%x, Loop: %d\n",
 				       entry->index, entry->loop_cnt);
-		else
-			len = snprintf(local_buf, 64,
-				       "Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x\n",
-				       entry->index, entry->base,
-				       entry->offset, entry->len);
-
-		if ((count + len) > PAGE_SIZE) {
-			dev_err(dev, "DCC: Couldn't write complete config!\n");
 			break;
+		case DCC_WRITE_TYPE:
+			len = snprintf(local_buf, 64,
+				       "Write Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+				       entry->index, entry->base,
+				       entry->offset, entry->len,
+				       entry->apb_bus);
+			break;
+		default:
+			len = snprintf(local_buf, 64,
+				       "Read Index: 0x%x, Base: 0x%x, Offset: 0x%x, len: 0x%x APB: %d\n",
+				       entry->index, entry->base,
+				       entry->offset, entry->len,
+				       entry->apb_bus);
 		}
 
+		if ((count + len) > PAGE_SIZE) {
+			dev_err(dev, "DCC: Couldn't write complete config\n");
+			break;
+		}
 		strlcat(buf, local_buf, PAGE_SIZE);
 		count += len;
 	}
@@ -812,7 +898,7 @@
 }
 
 static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr,
-			  unsigned int len)
+			  unsigned int len, int apb_bus)
 {
 	int ret;
 	struct dcc_config_entry *entry, *pentry;
@@ -821,7 +907,7 @@
 	mutex_lock(&drvdata->mutex);
 
 	if (!len) {
-		dev_err(drvdata->dev, "DCC: Invalid length!\n");
+		dev_err(drvdata->dev, "DCC: Invalid length\n");
 		ret = -EINVAL;
 		goto err;
 	}
@@ -883,6 +969,8 @@
 		entry->offset = offset;
 		entry->len = min_t(uint32_t, len, MAX_DCC_LEN);
 		entry->index = drvdata->nr_config[drvdata->curr_list]++;
+		entry->desc_type = DCC_ADDR_TYPE;
+		entry->apb_bus = apb_bus;
 		INIT_LIST_HEAD(&entry->list);
 		list_add_tail(&entry->list,
 			      &drvdata->cfg_head[drvdata->curr_list]);
@@ -902,24 +990,30 @@
 				struct device_attribute *attr,
 				const char *buf, size_t size)
 {
-	int ret, len;
+	int ret, len, apb_bus;
 	unsigned int base;
 	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
 	int nval;
 
-	nval = sscanf(buf, "%x %i", &base, &len);
-	if (nval <= 0 || nval > 2)
+	nval = sscanf(buf, "%x %i %d", &base, &len, &apb_bus);
+	if (nval <= 0 || nval > 3)
 		return -EINVAL;
 
-	if (nval == 1)
-		len = 1;
-
 	if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
 		dev_err(dev, "Select link list to program using curr_list\n");
 		return -EINVAL;
 	}
 
-	ret = dcc_config_add(drvdata, base, len);
+	if (nval == 1) {
+		len = 1;
+		apb_bus = 0;
+	} else if (nval == 2) {
+		apb_bus = 0;
+	} else {
+		apb_bus = 1;
+	}
+
+	ret = dcc_config_add(drvdata, base, len, apb_bus);
 	if (ret)
 		return ret;
 
@@ -1087,7 +1181,7 @@
 	}
 
 	if (list_empty(&drvdata->cfg_head[drvdata->curr_list])) {
-		dev_err(drvdata->dev, "DCC: No read address programmed!\n");
+		dev_err(drvdata->dev, "DCC: No read address programmed\n");
 		ret = -EPERM;
 		goto err;
 	}
@@ -1098,9 +1192,9 @@
 		goto err;
 	}
 
-	entry->rd_wr_entry = true;
+	entry->desc_type = DCC_READ_WRITE_TYPE;
 	entry->mask = mask;
-	entry->rd_mod_wr = val;
+	entry->write_val = val;
 	entry->index = drvdata->nr_config[drvdata->curr_list]++;
 	INIT_LIST_HEAD(&entry->list);
 	list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
@@ -1110,6 +1204,54 @@
 }
 static DEVICE_ATTR(rd_mod_wr, 0200, NULL, dcc_rd_mod_wr);
 
+static ssize_t dcc_write(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t size)
+{
+	int ret = size;
+	int nval;
+	unsigned int addr, write_val;
+	int apb_bus;
+	struct dcc_drvdata *drvdata = dev_get_drvdata(dev);
+	struct dcc_config_entry *entry;
+
+	mutex_lock(&drvdata->mutex);
+
+	nval = sscanf(buf, "%x %x %d", &addr, &write_val, &apb_bus);
+
+	if (drvdata->curr_list >= DCC_MAX_LINK_LIST) {
+		dev_err(dev, "Select link list to program using curr_list\n");
+		return -EINVAL;
+	}
+
+	if (nval <= 1 || nval > 3) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	entry = devm_kzalloc(drvdata->dev, sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	if (nval == 3)
+		entry->apb_bus = true;
+
+	entry->desc_type = DCC_WRITE_TYPE;
+	entry->base = addr & BM(4, 31);
+	entry->offset = addr - entry->base;
+	entry->write_val = write_val;
+	entry->index = drvdata->nr_config[drvdata->curr_list]++;
+	entry->len = 1;
+	INIT_LIST_HEAD(&entry->list);
+	list_add_tail(&entry->list, &drvdata->cfg_head[drvdata->curr_list]);
+err:
+	mutex_unlock(&drvdata->mutex);
+	return ret;
+}
+static DEVICE_ATTR(config_write, 0200, NULL, dcc_write);
+
 static const struct device_attribute *dcc_attrs[] = {
 	&dev_attr_func_type,
 	&dev_attr_data_sink,
@@ -1123,6 +1265,7 @@
 	&dev_attr_loop,
 	&dev_attr_rd_mod_wr,
 	&dev_attr_curr_list,
+	&dev_attr_config_write,
 	NULL,
 };
 
@@ -1134,7 +1277,7 @@
 	for (i = 0; attrs[i] != NULL; i++) {
 		ret = device_create_file(dev, attrs[i]);
 		if (ret) {
-			dev_err(dev, "DCC: Couldn't create sysfs attribute: %s!\n",
+			dev_err(dev, "DCC: Couldn't create sysfs attribute: %s\n",
 				attrs[i]->attr.name);
 			break;
 		}
@@ -1173,7 +1316,7 @@
 
 	if (copy_to_user(data, buf, len)) {
 		dev_err(drvdata->dev,
-			"DCC: Couldn't copy all data to user!\n");
+			"DCC: Couldn't copy all data to user\n");
 		kfree(buf);
 		return -EFAULT;
 	}
@@ -1372,7 +1515,7 @@
 			}
 
 		if (i == ARRAY_SIZE(str_dcc_data_sink)) {
-			dev_err(dev, "Unknown sink type for DCC! Using '%s' as data sink\n",
+			dev_err(dev, "Unknown sink type for DCC Using '%s' as data sink\n",
 				str_dcc_data_sink[drvdata->data_sink]);
 		}
 	}