Merge "msmfb: mdss: add mdp3 core driver"
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index de765ea..d09c03a 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,3 +1,6 @@
+mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o
+
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
 mdss-mdp-objs += mdss_mdp_pp.o
 mdss-mdp-objs += mdss_mdp_intf_video.o
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
new file mode 100644
index 0000000..890b00b
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -0,0 +1,917 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/memory_alloc.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+
+#include <mach/board.h>
+#include <mach/clk.h>
+#include <mach/hardware.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_memtypes.h>
+
+#include "mdp3.h"
+#include "mdss_fb.h"
+#include "mdp3_hwio.h"
+#include "mdp3_ctrl.h"
+
+#define MDP_CORE_HW_VERSION	0x03030304
+struct mdp3_hw_resource *mdp3_res;
+
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
+	{						\
+		.src = MSM_BUS_MASTER_MDP_PORT0,	\
+		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
+		.ab = (ab_val),				\
+		.ib = (ib_val),				\
+	}
+
+static struct msm_bus_vectors mdp_bus_vectors[] = {
+	MDP_BUS_VECTOR_ENTRY(0, 0),
+	MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
+	MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
+};
+
+static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+
+static struct msm_bus_scale_pdata mdp_bus_scale_table = {
+	.usecase = mdp_bus_usecases,
+	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+	.name = "mdp3",
+};
+
+struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = {
+	[MDP3_IOMMU_DOMAIN] = {
+		.domain_type = MDP3_IOMMU_DOMAIN,
+		.client_name = "mdp_dma",
+		.partitions = {
+			{
+				.start = SZ_128K,
+				.size = SZ_1G - SZ_128K,
+			},
+		},
+		.npartitions = 1,
+	},
+};
+
+struct mdp3_iommu_ctx_map mdp3_iommu_contexts[MDP3_IOMMU_CTX_MAX] = {
+	[MDP3_IOMMU_CTX_PPP_0] = {
+		.ctx_type = MDP3_IOMMU_CTX_PPP_0,
+		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.ctx_name = "mdpe_0",
+		.attached = 0,
+	},
+	[MDP3_IOMMU_CTX_PPP_1] = {
+		.ctx_type = MDP3_IOMMU_CTX_PPP_1,
+		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.ctx_name = "mdpe_1",
+		.attached = 0,
+	},
+
+	[MDP3_IOMMU_CTX_DMA_0] = {
+		.ctx_type = MDP3_IOMMU_CTX_DMA_0,
+		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.ctx_name = "mdps_0",
+		.attached = 0,
+	},
+
+	[MDP3_IOMMU_CTX_DMA_1] = {
+		.ctx_type = MDP3_IOMMU_CTX_DMA_1,
+		.domain = &mdp3_iommu_domains[MDP3_IOMMU_DOMAIN],
+		.ctx_name = "mdps_1",
+		.attached = 0,
+	},
+};
+
+static irqreturn_t mdp3_irq_handler(int irq, void *ptr)
+{
+	int i = 0;
+	struct mdp3_hw_resource *mdata = (struct mdp3_hw_resource *)ptr;
+	u32 mdp_interrupt = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
+
+	MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_interrupt);
+	pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
+
+	spin_lock(&mdata->irq_lock);
+	mdp_interrupt &= mdata->irqMask;
+
+	while (mdp_interrupt && i < MDP3_MAX_INTR) {
+		if ((mdp_interrupt & 0x1) && mdata->callbacks[i].cb)
+			mdata->callbacks[i].cb(i, mdata->callbacks[i].data);
+		mdp_interrupt = mdp_interrupt >> 1;
+		i++;
+	}
+	spin_unlock(&mdata->irq_lock);
+
+	return IRQ_HANDLED;
+}
+
+void mdp3_irq_enable(int type)
+{
+	unsigned long flag;
+	int irqEnabled = 0;
+
+	pr_debug("mdp3_irq_enable type=%d\n", type);
+	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
+	if (mdp3_res->irqMask & BIT(type)) {
+		pr_debug("interrupt %d already enabled\n", type);
+		spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+		return;
+	}
+	irqEnabled = mdp3_res->irqMask;
+	mdp3_res->irqMask |= BIT(type);
+	MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
+	if (!irqEnabled)
+		enable_irq(mdp3_res->irq);
+	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+}
+
+void mdp3_irq_disable(int type)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
+	if (mdp3_res->irqMask & BIT(type)) {
+		mdp3_res->irqMask &= ~BIT(type);
+		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
+		if (!mdp3_res->irqMask)
+			disable_irq(mdp3_res->irq);
+	} else {
+		pr_debug("interrupt %d not enabled\n", type);
+	}
+	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+}
+
+void mdp3_irq_disable_nosync(int type)
+{
+	if (mdp3_res->irqMask & BIT(type)) {
+		mdp3_res->irqMask &= ~BIT(type);
+		MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask);
+		if (!mdp3_res->irqMask)
+			disable_irq_nosync(mdp3_res->irq);
+	} else {
+		pr_debug("interrupt %d not enabled\n", type);
+	}
+}
+
+int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb)
+{
+	unsigned long flag;
+
+	pr_debug("interrupt %d callback n", type);
+	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
+	if (cb)
+		mdp3_res->callbacks[type] = *cb;
+	else
+		mdp3_res->callbacks[type].cb = NULL;
+
+	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);
+	return 0;
+}
+
+static int mdp3_bus_scale_register(void)
+{
+	if (!mdp3_res->bus_handle) {
+		struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
+		int i;
+
+		for (i = 0; i < bus_pdata->num_usecases; i++) {
+			mdp_bus_usecases[i].num_paths = 1;
+			mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
+		}
+
+		mdp3_res->bus_handle = msm_bus_scale_register_client(bus_pdata);
+		if (!mdp3_res->bus_handle) {
+			pr_err("not able to get bus scale\n");
+			return -ENOMEM;
+		}
+		pr_debug("register bus_hdl=%x\n", mdp3_res->bus_handle);
+	}
+	return 0;
+}
+
+static void mdp3_bus_scale_unregister(void)
+{
+	pr_debug("unregister bus_handle=%x\n", mdp3_res->bus_handle);
+
+	if (mdp3_res->bus_handle)
+		msm_bus_scale_unregister_client(mdp3_res->bus_handle);
+}
+
+int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota)
+{
+	static int current_bus_idx;
+	int bus_idx;
+	int rc;
+
+	if (mdp3_res->bus_handle < 1) {
+		pr_err("invalid bus handle %d\n", mdp3_res->bus_handle);
+		return -EINVAL;
+	}
+
+	if ((ab_quota | ib_quota) == 0) {
+		bus_idx = 0;
+	} else {
+		int num_cases = mdp_bus_scale_table.num_usecases;
+		struct msm_bus_vectors *vect = NULL;
+
+		bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+
+		/* aligning to avoid performing updates for small changes */
+		ab_quota = ALIGN(ab_quota, SZ_64M);
+		ib_quota = ALIGN(ib_quota, SZ_64M);
+
+		vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+		if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+			pr_debug("skip bus scaling, no change in vectors\n");
+			return 0;
+		}
+
+		vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+		vect->ab = ab_quota;
+		vect->ib = ib_quota;
+
+		pr_debug("bus scale idx=%d ab=%llu ib=%llu\n", bus_idx,
+				vect->ab, vect->ib);
+	}
+	current_bus_idx = bus_idx;
+	rc = msm_bus_scale_client_update_request(mdp3_res->bus_handle, bus_idx);
+	return rc;
+}
+
+static int mdp3_clk_update(u32 clk_idx, u32 enable)
+{
+	int ret = -EINVAL;
+	struct clk *clk;
+	int count = 0;
+
+	if (clk_idx >= MDP3_MAX_CLK || !mdp3_res->clocks[clk_idx])
+		return -ENODEV;
+
+	clk = mdp3_res->clocks[clk_idx];
+
+	if (enable)
+		mdp3_res->clock_ref_count[clk_idx]++;
+	else
+		mdp3_res->clock_ref_count[clk_idx]--;
+
+	count = mdp3_res->clock_ref_count[clk_idx];
+	if (count == 1) {
+		pr_debug("clk=%d en=%d\n", clk_idx, enable);
+		ret = clk_prepare_enable(clk);
+	} else if (count == 0) {
+		pr_debug("clk=%d disable\n", clk_idx);
+		clk_disable_unprepare(clk);
+		ret = 0;
+	} else if (count < 0) {
+		pr_err("clk=%d count=%d\n", clk_idx, count);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+int mdp3_vsync_clk_enable(int enable)
+{
+	int ret = 0;
+
+	pr_debug("vsync clk enable=%d\n", enable);
+	mutex_lock(&mdp3_res->res_mutex);
+	mdp3_clk_update(MDP3_CLK_VSYNC, enable);
+	mutex_unlock(&mdp3_res->res_mutex);
+	return ret;
+}
+
+int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate)
+{
+	int ret = 0;
+	unsigned long rounded_rate;
+	struct clk *clk = mdp3_res->clocks[clk_type];
+
+	if (clk) {
+		mutex_lock(&mdp3_res->res_mutex);
+		rounded_rate = clk_round_rate(clk, clk_rate);
+		if (IS_ERR_VALUE(rounded_rate)) {
+			pr_err("unable to round rate err=%ld\n", rounded_rate);
+			mutex_unlock(&mdp3_res->res_mutex);
+			return -EINVAL;
+		}
+		if (rounded_rate != clk_get_rate(clk)) {
+			ret = clk_set_rate(clk, rounded_rate);
+			if (ret)
+				pr_err("clk_set_rate failed ret=%d\n", ret);
+			else
+				pr_debug("mdp clk rate=%lu\n", rounded_rate);
+		}
+		mutex_unlock(&mdp3_res->res_mutex);
+	} else {
+		pr_err("mdp src clk not setup properly\n");
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+unsigned long mdp3_get_clk_rate(u32 clk_idx)
+{
+	unsigned long clk_rate = 0;
+	struct clk *clk;
+
+	if (clk_idx >= MDP3_MAX_CLK)
+		return -ENODEV;
+
+	clk = mdp3_res->clocks[clk_idx];
+
+	if (clk) {
+		mutex_lock(&mdp3_res->res_mutex);
+		clk_rate = clk_get_rate(clk);
+		mutex_unlock(&mdp3_res->res_mutex);
+	}
+	return clk_rate;
+}
+
+static int mdp3_clk_register(char *clk_name, int clk_idx)
+{
+	struct clk *tmp;
+
+	if (clk_idx >= MDP3_MAX_CLK) {
+		pr_err("invalid clk index %d\n", clk_idx);
+		return -EINVAL;
+	}
+
+	tmp = devm_clk_get(&mdp3_res->pdev->dev, clk_name);
+	if (IS_ERR(tmp)) {
+		pr_err("unable to get clk: %s\n", clk_name);
+		return PTR_ERR(tmp);
+	}
+
+	mdp3_res->clocks[clk_idx] = tmp;
+
+	return 0;
+}
+
+static int mdp3_clk_setup(void)
+{
+	int rc;
+
+	rc = mdp3_clk_register("iface_clk", MDP3_CLK_AHB);
+	if (rc)
+		return rc;
+
+	rc = mdp3_clk_register("core_clk", MDP3_CLK_CORE);
+	if (rc)
+		return rc;
+
+	rc = mdp3_clk_register("vsync_clk", MDP3_CLK_VSYNC);
+	if (rc)
+		return rc;
+
+	rc = mdp3_clk_register("lcdc_clk", MDP3_CLK_LCDC);
+	if (rc)
+		return rc;
+
+	return rc;
+}
+
+static void mdp3_clk_remove(void)
+{
+	clk_put(mdp3_res->clocks[MDP3_CLK_AHB]);
+	clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
+	clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+	clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
+}
+
+int mdp3_clk_enable(int enable)
+{
+	int rc;
+
+	pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
+
+	mutex_lock(&mdp3_res->res_mutex);
+	rc = mdp3_clk_update(MDP3_CLK_AHB, enable);
+	rc |= mdp3_clk_update(MDP3_CLK_CORE, enable);
+	rc |= mdp3_clk_update(MDP3_CLK_VSYNC, enable);
+	mutex_unlock(&mdp3_res->res_mutex);
+	return rc;
+}
+
+static int mdp3_irq_setup(void)
+{
+	int ret;
+
+	ret = devm_request_irq(&mdp3_res->pdev->dev,
+				mdp3_res->irq,
+				mdp3_irq_handler,
+				IRQF_DISABLED, "MDP", mdp3_res);
+	if (ret) {
+		pr_err("mdp request_irq() failed!\n");
+		return ret;
+	}
+	disable_irq(mdp3_res->irq);
+	return 0;
+}
+
+static int mdp3_iommu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags, void *token)
+{
+	pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
+	return 0;
+}
+
+int mdp3_iommu_attach(int context)
+{
+	struct mdp3_iommu_ctx_map *context_map;
+	struct mdp3_iommu_domain_map *domain_map;
+
+	if (context >= MDP3_IOMMU_CTX_MAX)
+		return -EINVAL;
+
+	context_map = mdp3_res->iommu_contexts + context;
+	if (context_map->attached) {
+		pr_warn("mdp iommu already attached\n");
+		return 0;
+	}
+
+	domain_map = context_map->domain;
+
+	iommu_attach_device(domain_map->domain, context_map->ctx);
+
+	context_map->attached = true;
+	return 0;
+}
+
+int mdp3_iommu_dettach(int context)
+{
+	struct mdp3_iommu_ctx_map *context_map;
+	struct mdp3_iommu_domain_map *domain_map;
+
+	if (context >= MDP3_IOMMU_CTX_MAX)
+		return -EINVAL;
+
+	context_map = mdp3_res->iommu_contexts + context;
+	if (!context_map->attached) {
+		pr_warn("mdp iommu not attached\n");
+		return 0;
+	}
+
+	domain_map = context_map->domain;
+	iommu_detach_device(domain_map->domain, context_map->ctx);
+	context_map->attached = false;
+
+	return 0;
+}
+
+int mdp3_iommu_domain_init(void)
+{
+	struct msm_iova_layout layout;
+	int i;
+
+	if (mdp3_res->domains) {
+		pr_warn("iommu domain already initialized\n");
+		return 0;
+	}
+
+	for (i = 0; i < MDP3_IOMMU_DOMAIN_MAX; i++) {
+		int domain_idx;
+		layout.client_name = mdp3_iommu_domains[i].client_name;
+		layout.partitions = mdp3_iommu_domains[i].partitions;
+		layout.npartitions = mdp3_iommu_domains[i].npartitions;
+		layout.is_secure = false;
+
+		domain_idx = msm_register_domain(&layout);
+		if (IS_ERR_VALUE(domain_idx))
+			return -EINVAL;
+
+		mdp3_iommu_domains[i].domain_idx = domain_idx;
+		mdp3_iommu_domains[i].domain = msm_get_iommu_domain(domain_idx);
+		if (!mdp3_iommu_domains[i].domain) {
+			pr_err("unable to get iommu domain(%d)\n",
+				domain_idx);
+			return -EINVAL;
+		}
+		iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
+					mdp3_iommu_fault_handler,
+					NULL);
+	}
+
+	mdp3_res->domains = mdp3_iommu_domains;
+
+	return 0;
+}
+
+int mdp3_iommu_context_init(void)
+{
+	int i;
+
+	if (mdp3_res->iommu_contexts) {
+		pr_warn("iommu context already initialized\n");
+		return 0;
+	}
+
+	for (i = 0; i < MDP3_IOMMU_CTX_MAX; i++) {
+		mdp3_iommu_contexts[i].ctx =
+			msm_iommu_get_ctx(mdp3_iommu_contexts[i].ctx_name);
+
+		if (!mdp3_iommu_contexts[i].ctx) {
+			pr_warn("unable to get iommu ctx(%s)\n",
+				mdp3_iommu_contexts[i].ctx_name);
+			return -EINVAL;
+		}
+	}
+
+	mdp3_res->iommu_contexts = mdp3_iommu_contexts;
+
+	return 0;
+}
+
+int mdp3_iommu_init(void)
+{
+	int ret;
+
+	ret = mdp3_iommu_domain_init();
+	if (ret) {
+		pr_err("mdp3 iommu domain init fails\n");
+		return ret;
+	}
+
+	ret = mdp3_iommu_context_init();
+	if (ret) {
+		pr_err("mdp3 iommu context init fails\n");
+		return ret;
+	}
+	return ret;
+}
+
+static int mdp3_check_version(void)
+{
+	int rc;
+
+	rc = mdp3_clk_update(MDP3_CLK_AHB, 1);
+	if (rc)
+		return rc;
+
+	mdp3_res->mdp_rev = MDP3_REG_READ(MDP3_REG_HW_VERSION);
+
+	rc = mdp3_clk_update(MDP3_CLK_AHB, 0);
+	if (rc)
+		pr_err("fail to turn off the MDP3_CLK_AHB clk\n");
+
+	if (mdp3_res->mdp_rev != MDP_CORE_HW_VERSION) {
+		pr_err("mdp_hw_revision=%x mismatch\n", mdp3_res->mdp_rev);
+		rc = -ENODEV;
+	}
+	return rc;
+}
+
+static int mdp3_hw_init(void)
+{
+	int i;
+
+	for (i = MDP3_DMA_P; i < MDP3_DMA_MAX; i++) {
+		mdp3_res->dma[i].dma_sel = i;
+		mdp3_res->dma[i].capability = MDP3_DMA_CAP_ALL;
+		mdp3_res->dma[i].in_use = 0;
+		mdp3_res->dma[i].available = 1;
+	}
+	mdp3_res->dma[MDP3_DMA_S].capability = MDP3_DMA_CAP_DITHER;
+	mdp3_res->dma[MDP3_DMA_E].available = 0;
+
+	for (i = MDP3_DMA_OUTPUT_SEL_AHB; i < MDP3_DMA_OUTPUT_SEL_MAX; i++) {
+		mdp3_res->intf[i].cfg.type = i;
+		mdp3_res->intf[i].active = 0;
+		mdp3_res->intf[i].in_use = 0;
+		mdp3_res->intf[i].available = 1;
+	}
+	mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_AHB].available = 0;
+	mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_LCDC].available = 0;
+
+	return 0;
+}
+
+static int mdp3_res_init(void)
+{
+	int rc = 0;
+
+	rc = mdp3_irq_setup();
+	if (rc)
+		return rc;
+
+	rc = mdp3_clk_setup();
+	if (rc)
+		return rc;
+
+	mdp3_res->ion_client = msm_ion_client_create(-1, mdp3_res->pdev->name);
+	if (IS_ERR_OR_NULL(mdp3_res->ion_client)) {
+		pr_err("msm_ion_client_create() return error (%p)\n",
+				mdp3_res->ion_client);
+		mdp3_res->ion_client = NULL;
+		return -EINVAL;
+	}
+
+	rc = mdp3_iommu_init();
+	if (rc)
+		return rc;
+
+	rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_DMA_0);
+	if (rc) {
+		pr_err("fail to attach DMA-P context 0\n");
+		return rc;
+	}
+	rc = mdp3_bus_scale_register();
+	if (rc) {
+		pr_err("unable to register bus scaling\n");
+		return rc;
+	}
+
+	rc = mdp3_hw_init();
+
+	return rc;
+}
+
+static int mdp3_parse_dt(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
+	if (!res) {
+		pr_err("unable to get MDP base address\n");
+		return -EINVAL;
+	}
+
+	mdp3_res->mdp_reg_size = resource_size(res);
+	mdp3_res->mdp_base = devm_ioremap(&pdev->dev, res->start,
+					mdp3_res->mdp_reg_size);
+	if (unlikely(!mdp3_res->mdp_base)) {
+		pr_err("unable to map MDP base\n");
+		return -ENOMEM;
+	}
+
+	pr_debug("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+		(int) res->start,
+		(int) mdp3_res->mdp_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		pr_err("unable to get MDSS irq\n");
+		return -EINVAL;
+	}
+	mdp3_res->irq = res->start;
+
+	return 0;
+}
+
+static int mdp3_init(struct msm_fb_data_type *mfd)
+{
+	return mdp3_ctrl_init(mfd);
+}
+
+u32 mdp3_fb_stride(u32 fb_index, u32 xres, int bpp)
+{
+	/*
+	 * The adreno GPU hardware requires that the pitch be aligned to
+	 * 32 pixels for color buffers, so for the cases where the GPU
+	 * is writing directly to fb0, the framebuffer pitch
+	 * also needs to be 32 pixel aligned
+	 */
+
+	if (fb_index == 0)
+		return ALIGN(xres, 32) * bpp;
+	else
+		return xres * bpp;
+}
+
+/*
+ * physical contiguous memory should be allocated in mdss_fb, and SMMU
+ * virtual address mapping can be done in the MDP h/w specific code.   It
+ * should have a reference count, if none is current mapped, the SMMU context
+ * can bedetached, thus allowing power saving in SMMU.
+ */
+static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
+{
+	int dom;
+	void *virt = NULL;
+	unsigned long phys = 0;
+	size_t size;
+	u32 yres = mfd->fbi->var.yres_virtual;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
+
+	if (mfd->index == 0) {
+		virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+		if (!virt) {
+			pr_err("unable to alloc fbmem size=%u\n", size);
+			return -ENOMEM;
+		}
+		phys = memory_pool_node_paddr(virt);
+		dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
+		msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+					&mfd->iova);
+
+		pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
+			size, virt, phys, mfd->index);
+	} else {
+		size = 0;
+	}
+
+	mfd->fbi->screen_base = virt;
+	mfd->fbi->fix.smem_start = phys;
+	mfd->fbi->fix.smem_len = size;
+	return 0;
+}
+
+struct mdp3_dma *mdp3_get_dma_pipe(int capability)
+{
+	int i;
+
+	for (i = MDP3_DMA_P; i < MDP3_DMA_MAX; i++) {
+		if (!mdp3_res->dma[i].in_use && mdp3_res->dma[i].available &&
+			mdp3_res->dma[i].capability & capability) {
+			mdp3_res->dma[i].in_use = true;
+			return &mdp3_res->dma[i];
+		}
+	}
+	return NULL;
+}
+
+struct mdp3_intf *mdp3_get_display_intf(int type)
+{
+	int i;
+
+	for (i = MDP3_DMA_OUTPUT_SEL_AHB; i < MDP3_DMA_OUTPUT_SEL_MAX; i++) {
+		if (!mdp3_res->intf[i].in_use && mdp3_res->intf[i].available &&
+			mdp3_res->intf[i].cfg.type == type) {
+			mdp3_res->intf[i].in_use = true;
+			return &mdp3_res->intf[i];
+		}
+	}
+	return NULL;
+}
+
+static int mdp3_probe(struct platform_device *pdev)
+{
+	int rc;
+	static struct msm_mdp_interface mdp3_interface = {
+	.init_fnc = mdp3_init,
+	.fb_mem_alloc_fnc = mdp3_fbmem_alloc,
+	.fb_stride = mdp3_fb_stride,
+	};
+
+	if (!pdev->dev.of_node) {
+		pr_err("MDP driver only supports device tree probe\n");
+		return -ENOTSUPP;
+	}
+
+	if (mdp3_res) {
+		pr_err("MDP already initialized\n");
+		return -EINVAL;
+	}
+
+	mdp3_res = devm_kzalloc(&pdev->dev, sizeof(struct mdp3_hw_resource),
+				GFP_KERNEL);
+	if (mdp3_res == NULL)
+		return -ENOMEM;
+
+	pdev->id = 0;
+	mdp3_res->pdev = pdev;
+	mutex_init(&mdp3_res->res_mutex);
+	spin_lock_init(&mdp3_res->irq_lock);
+	platform_set_drvdata(pdev, mdp3_res);
+
+	rc = mdp3_parse_dt(pdev);
+	if (rc)
+		goto probe_done;
+
+	rc = mdp3_res_init();
+	if (rc) {
+		pr_err("unable to initialize mdp3 resources\n");
+		goto probe_done;
+	}
+
+	rc = mdp3_check_version();
+	if (rc) {
+		pr_err("mdp3 check version failed\n");
+		goto probe_done;
+	}
+
+	rc = mdss_fb_register_mdp_instance(&mdp3_interface);
+	if (rc)
+		pr_err("unable to register mdp instance\n");
+
+probe_done:
+	if (IS_ERR_VALUE(rc)) {
+		devm_kfree(&pdev->dev, mdp3_res);
+		mdp3_res = NULL;
+	}
+
+	return rc;
+}
+
+static  int mdp3_suspend_sub(struct mdp3_hw_resource *mdata)
+{
+	return 0;
+}
+
+static  int mdp3_resume_sub(struct mdp3_hw_resource *mdata)
+{
+	return 0;
+}
+
+static int mdp3_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev);
+
+	if (!mdata)
+		return -ENODEV;
+
+	pr_debug("display suspend\n");
+
+	return mdp3_suspend_sub(mdata);
+}
+
+static int mdp3_resume(struct platform_device *pdev)
+{
+	struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev);
+
+	if (!mdata)
+		return -ENODEV;
+
+	pr_debug("display resume\n");
+
+	return mdp3_resume_sub(mdata);
+}
+
+static int mdp3_remove(struct platform_device *pdev)
+{
+	struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev);
+
+	if (!mdata)
+		return -ENODEV;
+	pm_runtime_disable(&pdev->dev);
+	mdp3_bus_scale_unregister();
+	mdp3_clk_remove();
+	return 0;
+}
+
+static const struct of_device_id mdp3_dt_match[] = {
+	{ .compatible = "qcom,mdss_mdp3",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, mdp3_dt_match);
+EXPORT_COMPAT("qcom,mdss_mdp3");
+
+static struct platform_driver mdp3_driver = {
+	.probe = mdp3_probe,
+	.remove = mdp3_remove,
+	.suspend = mdp3_suspend,
+	.resume = mdp3_resume,
+	.shutdown = NULL,
+	.driver = {
+		.name = "mdp3",
+		.of_match_table = mdp3_dt_match,
+	},
+};
+
+static int __init mdp3_driver_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&mdp3_driver);
+	if (ret) {
+		pr_err("register mdp3 driver failed!\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+module_init(mdp3_driver_init);
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
new file mode 100644
index 0000000..c853664
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This 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 MDP3_H
+#define MDP3_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/earlysuspend.h>
+
+#include <mach/iommu_domains.h>
+
+#include "mdp3_dma.h"
+
+enum  {
+	MDP3_CLK_AHB,
+	MDP3_CLK_CORE,
+	MDP3_CLK_VSYNC,
+	MDP3_CLK_LCDC,
+	MDP3_MAX_CLK
+};
+
+enum {
+	MDP3_IOMMU_DOMAIN,
+	MDP3_IOMMU_DOMAIN_MAX
+};
+
+enum {
+	MDP3_IOMMU_CTX_PPP_0,
+	MDP3_IOMMU_CTX_PPP_1,
+	MDP3_IOMMU_CTX_DMA_0,
+	MDP3_IOMMU_CTX_DMA_1,
+	MDP3_IOMMU_CTX_MAX
+};
+
+enum {
+	MDP3_BW_CLIENT_DMA_P,
+	MDP3_BW_CLIENT_DMA_S,
+	MDP3_BW_CLIENT_DMA_E,
+	MDP3_BW_CLIENT_PPP,
+};
+
+struct mdp3_iommu_domain_map {
+	u32 domain_type;
+	char *client_name;
+	struct msm_iova_partition partitions[1];
+	int npartitions;
+	int domain_idx;
+	struct iommu_domain *domain;
+};
+
+struct mdp3_iommu_ctx_map {
+	u32 ctx_type;
+	struct mdp3_iommu_domain_map *domain;
+	char *ctx_name;
+	struct device *ctx;
+	int attached;
+};
+
+#define MDP3_MAX_INTR 28
+
+struct mdp3_intr_cb {
+	void (*cb)(int type, void *);
+	void *data;
+};
+
+struct mdp3_hw_resource {
+	struct platform_device *pdev;
+	u32 mdp_rev;
+
+	struct mutex res_mutex;
+
+	struct clk *clocks[MDP3_MAX_CLK];
+	int clock_ref_count[MDP3_MAX_CLK];
+
+	char __iomem *mdp_base;
+	size_t mdp_reg_size;
+
+	u32 irq;
+	u32 bus_handle;
+
+	struct ion_client *ion_client;
+	struct mdp3_iommu_domain_map *domains;
+	struct mdp3_iommu_ctx_map *iommu_contexts;
+
+	struct mdp3_dma dma[MDP3_DMA_MAX];
+	struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
+
+	spinlock_t irq_lock;
+	u32 irqMask;
+	struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
+
+	struct early_suspend suspend_handler;
+};
+
+extern struct mdp3_hw_resource *mdp3_res;
+
+struct mdp3_dma *mdp3_get_dma_pipe(int capability);
+struct mdp3_intf *mdp3_get_display_intf(int type);
+void mdp3_irq_enable(int type);
+void mdp3_irq_disable(int type);
+void mdp3_irq_disable_nosync(int type);
+int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb);
+int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate);
+int mdp3_clk_enable(int enable);
+int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
+
+#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
+#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
+
+#endif /* MDP3_H */
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
new file mode 100644
index 0000000..e07c0a4
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -0,0 +1,511 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "mdp3_ctrl.h"
+#include "mdp3.h"
+
+#define MDP_VSYNC_CLK_RATE	19200000
+#define VSYNC_PERIOD 16
+
+void vsync_notify_handler(void *arg)
+{
+	struct mdp3_session_data *session = (struct mdp3_session_data *)session;
+	complete(&session->vsync_comp);
+}
+
+static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
+{
+	struct mdp3_session_data *mdp3_session;
+	struct mdp3_vsync_notification vsync_client;
+
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
+		!mdp3_session->intf)
+		return -ENODEV;
+
+	vsync_client.handler = vsync_notify_handler;
+	vsync_client.arg = mdp3_session;
+
+	mutex_lock(&mdp3_session->lock);
+	if (!mdp3_session->status) {
+		pr_debug("fb%d is not on yet", mfd->index);
+		mutex_unlock(&mdp3_session->lock);
+		return -EINVAL;
+	}
+
+	mdp3_session->dma->vsync_enable(mdp3_session->dma, &vsync_client);
+	mutex_unlock(&mdp3_session->lock);
+	return 0;
+}
+
+static ssize_t mdp3_vsync_show_event(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdp3_session_data *mdp3_session = NULL;
+	u64 vsync_ticks;
+	ktime_t vsync_time;
+	int rc;
+
+	if (!mfd || !mfd->mdp.private1)
+		return 0;
+
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+
+	rc = wait_for_completion_interruptible_timeout(
+				&mdp3_session->vsync_comp,
+				msecs_to_jiffies(VSYNC_PERIOD * 5));
+	if (rc <= 0) {
+		pr_warn("vsync wait on fb%d interrupted (%d)\n",
+			mfd->index, rc);
+		return -EBUSY;
+	}
+
+	vsync_time = mdp3_session->dma->get_vsync_time(mdp3_session->dma);
+	vsync_ticks = ktime_to_ns(vsync_time);
+
+	pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks);
+	rc = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks);
+	return rc;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, mdp3_vsync_show_event, NULL);
+
+static struct attribute *vsync_fs_attrs[] = {
+	&dev_attr_vsync_event.attr,
+	NULL,
+};
+
+static struct attribute_group vsync_fs_attr_group = {
+	.attrs = vsync_fs_attrs,
+};
+
+static int mdp3_ctrl_res_req_dma(struct msm_fb_data_type *mfd, int status)
+{
+	int rc = 0;
+	if (status) {
+		struct mdss_panel_info *panel_info = mfd->panel_info;
+		int ab = 0;
+		int ib = 0;
+		unsigned long core_clk = 0;
+		int vtotal = 0;
+		ab = panel_info->xres * panel_info->yres * 4;
+		ab *= panel_info->mipi.frame_rate;
+		ib = (ab * 3) / 2;
+		vtotal = panel_info->lcdc.v_back_porch +
+			panel_info->lcdc.v_front_porch +
+			panel_info->lcdc.v_pulse_width +
+			panel_info->yres;
+		core_clk = panel_info->xres * panel_info->yres;
+		core_clk *= panel_info->mipi.frame_rate;
+		core_clk = (core_clk / panel_info->yres) * vtotal;
+		mdp3_clk_set_rate(MDP3_CLK_CORE, core_clk);
+		mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE);
+
+		rc = mdp3_clk_enable(true);
+		if (rc)
+			return rc;
+
+		mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, ab, ib);
+	} else {
+		rc = mdp3_clk_enable(false);
+		rc |= mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, 0, 0);
+	}
+	return rc;
+}
+
+static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd)
+{
+	int type;
+	switch (mfd->panel.type) {
+	case MIPI_VIDEO_PANEL:
+		type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
+		break;
+	case MIPI_CMD_PANEL:
+		type = MDP3_DMA_OUTPUT_SEL_DSI_CMD;
+		break;
+	case LCDC_PANEL:
+		type = MDP3_DMA_OUTPUT_SEL_LCDC;
+		break;
+	default:
+		type = MDP3_DMA_OUTPUT_SEL_MAX;
+	}
+	return type;
+}
+
+static int mdp3_ctrl_get_source_format(struct msm_fb_data_type *mfd)
+{
+	int format;
+	switch (mfd->fb_imgType) {
+	case MDP_RGB_565:
+		format = MDP3_DMA_IBUF_FORMAT_RGB565;
+		break;
+	case MDP_RGB_888:
+		format = MDP3_DMA_IBUF_FORMAT_RGB888;
+		break;
+	case MDP_ARGB_8888:
+	case MDP_RGBA_8888:
+		format = MDP3_DMA_IBUF_FORMAT_XRGB8888;
+		break;
+	default:
+		format = MDP3_DMA_IBUF_FORMAT_UNDEFINED;
+	}
+	return format;
+}
+
+static int mdp3_ctrl_get_pack_pattern(struct msm_fb_data_type *mfd)
+{
+	int packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_RGB;
+	if (mfd->fb_imgType == MDP_RGBA_8888)
+		packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_BGR;
+	return packPattern;
+}
+
+static int mdp3_ctrl_intf_init(struct msm_fb_data_type *mfd,
+				struct mdp3_intf *intf)
+{
+	int rc;
+	struct mdp3_intf_cfg cfg;
+	struct mdp3_video_intf_cfg *video = &cfg.video;
+	struct mdss_panel_info *p = mfd->panel_info;
+	int h_back_porch = p->lcdc.h_back_porch;
+	int h_front_porch = p->lcdc.h_front_porch;
+	int w = p->xres;
+	int v_back_porch = p->lcdc.v_back_porch;
+	int v_front_porch = p->lcdc.v_front_porch;
+	int h = p->yres;
+	int h_sync_skew = p->lcdc.hsync_skew;
+	int h_pulse_width = p->lcdc.h_pulse_width;
+	int v_pulse_width = p->lcdc.v_pulse_width;
+	int hsync_period = h_front_porch + h_back_porch + w + h_pulse_width;
+	int vsync_period = v_front_porch + v_back_porch + h + v_pulse_width;
+	vsync_period *= hsync_period;
+
+	cfg.type = mdp3_ctrl_get_intf_type(mfd);
+	if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
+		cfg.type == MDP3_DMA_OUTPUT_SEL_LCDC) {
+		video->hsync_period = hsync_period;
+		video->hsync_pulse_width = h_pulse_width;
+		video->vsync_period = vsync_period;
+		video->vsync_pulse_width = v_pulse_width * hsync_period;
+		video->display_start_x = h_back_porch + h_pulse_width;
+		video->display_end_x = hsync_period - h_front_porch - 1;
+		video->display_start_y =
+			(v_back_porch + v_pulse_width) * hsync_period;
+		video->display_end_y =
+			vsync_period - v_front_porch * hsync_period - 1;
+		video->active_start_x = video->display_start_x;
+		video->active_end_x = video->display_end_x;
+		video->active_h_enable = true;
+		video->active_start_y = video->display_start_y;
+		video->active_end_y = video->display_end_y;
+		video->active_v_enable = true;
+		video->hsync_skew = h_sync_skew;
+		video->hsync_polarity = 1;
+		video->vsync_polarity = 1;
+		video->de_polarity = 1;
+	} else if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		cfg.dsi_cmd.primary_dsi_cmd_id = 0;
+		cfg.dsi_cmd.secondary_dsi_cmd_id = 1;
+		cfg.dsi_cmd.dsi_cmd_tg_intf_sel = 0;
+	} else
+		return -EINVAL;
+	rc = mdp3_intf_init(intf, &cfg);
+	return rc;
+}
+
+static int mdp3_ctrl_dma_init(struct msm_fb_data_type *mfd,
+				struct mdp3_dma *dma)
+{
+	int rc;
+	struct mdss_panel_info *panel_info = mfd->panel_info;
+	struct fb_info *fbi = mfd->fbi;
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	struct mdp3_dma_output_config outputConfig;
+	struct mdp3_dma_source sourceConfig;
+
+	fix = &fbi->fix;
+	var = &fbi->var;
+
+	sourceConfig.format = mdp3_ctrl_get_source_format(mfd);
+	sourceConfig.width = panel_info->xres;
+	sourceConfig.height = panel_info->yres;
+	sourceConfig.x = 0;
+	sourceConfig.y = 0;
+	sourceConfig.stride = fix->line_length;
+	sourceConfig.buf = (void *)mfd->iova;
+
+	outputConfig.dither_en = 0;
+	outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd);
+	outputConfig.bit_mask_polarity = 0;
+	outputConfig.color_components_flip = 0;
+	outputConfig.pack_pattern = mdp3_ctrl_get_pack_pattern(mfd);
+	outputConfig.pack_align = MDP3_DMA_OUTPUT_PACK_ALIGN_LSB;
+	outputConfig.color_comp_out_bits = (MDP3_DMA_OUTPUT_COMP_BITS_8 << 4) |
+					(MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)|
+					MDP3_DMA_OUTPUT_COMP_BITS_8;
+
+	rc = mdp3_dma_init(dma, &sourceConfig, &outputConfig);
+	return rc;
+}
+
+static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session;
+	struct mdss_panel_data *panel;
+
+	pr_debug("mdp3_ctrl_on\n");
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
+		!mdp3_session->intf) {
+		pr_err("mdp3_ctrl_on no device");
+		return -ENODEV;
+	}
+	mutex_lock(&mdp3_session->lock);
+	if (mdp3_session->status) {
+		pr_info("fb%d is on already", mfd->index);
+		goto on_error;
+	}
+
+	rc = mdp3_ctrl_res_req_dma(mfd, 1);
+	if (rc) {
+		pr_err("resource request for dma on failed\n");
+		goto on_error;
+	}
+
+	rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma);
+	if (rc) {
+		pr_err("dma init failed\n");
+		goto on_error;
+	}
+
+	rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
+	if (rc) {
+		pr_err("display interface init failed\n");
+		goto on_error;
+	}
+
+	panel = mdp3_session->panel;
+
+	if (panel->event_handler)
+		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL);
+
+	if (rc) {
+		pr_err("fail to turn on the panel\n");
+		goto on_error;
+	}
+
+	rc = mdp3_session->dma->start(mdp3_session->dma, mdp3_session->intf);
+	if (rc) {
+		pr_err("fail to start the MDP display interface\n");
+		goto on_error;
+	}
+
+on_error:
+	if (!rc)
+		mdp3_session->status = 1;
+
+	mutex_unlock(&mdp3_session->lock);
+	return rc;
+}
+
+static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
+{
+	int rc = 0;
+	struct mdp3_session_data *mdp3_session;
+	struct mdss_panel_data *panel;
+
+	pr_debug("mdp3_ctrl_off\n");
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
+		!mdp3_session->intf) {
+		pr_err("mdp3_ctrl_on no device");
+		return -ENODEV;
+	}
+
+	mutex_lock(&mdp3_session->lock);
+
+	if (!mdp3_session->status) {
+		pr_info("fb%d is off already", mfd->index);
+		goto off_error;
+	}
+
+	panel = mdp3_session->panel;
+	if (panel->event_handler)
+		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
+
+	if (rc)
+		pr_err("fail to turn off the panel\n");
+
+	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+
+	if (rc)
+		pr_err("fail to stop the MDP3 dma\n");
+
+	rc = mdp3_ctrl_res_req_dma(mfd, 0);
+	if (rc)
+		pr_err("resource release  for dma on failed\n");
+
+off_error:
+	mdp3_session->status = 0;
+
+	mutex_unlock(&mdp3_session->lock);
+	return 0;
+}
+
+static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
+{
+	struct fb_info *fbi;
+	struct mdp3_session_data *mdp3_session;
+	u32 offset;
+	int bpp;
+
+	pr_debug("mdp3_ctrl_pan_display\n");
+	if (!mfd || !mfd->mdp.private1)
+		return;
+
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session || !mdp3_session->dma)
+		return;
+
+	if (!mdp3_session->status) {
+		pr_err("mdp3_ctrl_pan_display, display off!\n");
+		return;
+	}
+
+	mutex_lock(&mdp3_session->lock);
+	fbi = mfd->fbi;
+
+	bpp = fbi->var.bits_per_pixel / 8;
+	offset = fbi->var.xoffset * bpp +
+		 fbi->var.yoffset * fbi->fix.line_length;
+
+	if (offset > fbi->fix.smem_len) {
+		pr_err("invalid fb offset=%u total length=%u\n",
+			offset, fbi->fix.smem_len);
+		goto pan_error;
+	}
+
+	mdp3_session->dma->update(mdp3_session->dma,
+				(void *)mfd->iova + offset);
+pan_error:
+	mutex_unlock(&mdp3_session->lock);
+}
+
+static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
+					u32 cmd, void __user *argp)
+{
+	int rc = -EINVAL;
+	struct mdp3_session_data *mdp3_session;
+	int val;
+
+	pr_debug("mdp3_ctrl_ioctl_handler\n");
+
+	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
+	if (!mdp3_session)
+		return -ENODEV;
+
+	if (!mdp3_session->status) {
+		pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case MSMFB_VSYNC_CTRL:
+	case MSMFB_OVERLAY_VSYNC_CTRL:
+		if (!copy_from_user(&val, argp, sizeof(val))) {
+			rc = mdp3_ctrl_vsync_enable(mfd, val);
+			if (!val)
+				init_completion(&mdp3_session->vsync_comp);
+		} else {
+			pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
+			rc = -EFAULT;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
+{
+	struct device *dev = mfd->fbi->dev;
+	struct msm_mdp_interface *mdp3_interface = &mfd->mdp;
+	struct mdp3_session_data *mdp3_session = NULL;
+	u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
+	int rc;
+
+	pr_debug("mdp3_ctrl_init\n");
+	mdp3_interface->on_fnc = mdp3_ctrl_on;
+	mdp3_interface->off_fnc = mdp3_ctrl_off;
+	mdp3_interface->do_histogram = NULL;
+	mdp3_interface->cursor_update = NULL;
+	mdp3_interface->dma_fnc = mdp3_ctrl_pan_display;
+	mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
+	mdp3_interface->kickoff_fnc = NULL;
+
+	mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
+	if (!mdp3_session) {
+		pr_err("fail to allocate mdp3 private data structure");
+		return -ENOMEM;
+	}
+	memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
+	mutex_init(&mdp3_session->lock);
+	init_completion(&mdp3_session->vsync_comp);
+	mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
+	if (!mdp3_session->dma) {
+		rc = -ENODEV;
+		goto init_done;
+	}
+
+	intf_type = mdp3_ctrl_get_intf_type(mfd);
+	mdp3_session->intf = mdp3_get_display_intf(intf_type);
+	if (!mdp3_session->intf) {
+		rc = -ENODEV;
+		goto init_done;
+	}
+
+	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
+	mdp3_session->status = 0;
+
+	mfd->mdp.private1 = mdp3_session;
+
+	rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group);
+	if (rc) {
+		pr_err("vsync sysfs group creation failed, ret=%d\n", rc);
+		goto init_done;
+	}
+
+	kobject_uevent(&dev->kobj, KOBJ_ADD);
+	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
+
+init_done:
+	if (IS_ERR_VALUE(rc))
+		kfree(mdp3_session);
+
+	return rc;
+}
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
new file mode 100644
index 0000000..d42ece7
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This 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 MDP3_CTRL_H
+#define MDP3_CTRL_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+
+#include "mdp3_dma.h"
+#include "mdss_fb.h"
+#include "mdss_panel.h"
+
+struct mdp3_session_data {
+	struct mutex lock;
+	int status;
+	struct mdp3_dma *dma;
+	struct mdss_panel_data *panel;
+	struct mdp3_intf *intf;
+	struct msm_fb_data_type *mfd;
+	struct completion vsync_comp;
+};
+
+int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
+
+#endif /* MDP3_CTRL_H */
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
new file mode 100644
index 0000000..69e3d7e
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -0,0 +1,914 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
+
+#include "mdp3.h"
+#include "mdp3_dma.h"
+#include "mdp3_hwio.h"
+
+#define DMA_STOP_POLL_SLEEP_US 1000
+#define DMA_STOP_POLL_TIMEOUT_US 16000
+
+static ktime_t mdp3_get_vsync_time(struct mdp3_dma *dma)
+{
+	unsigned long flag;
+	ktime_t time;
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	time = dma->vsync_time;
+	spin_unlock_irqrestore(&dma->dma_lock, flag);
+	return time;
+}
+
+static void mdp3_vsync_intr_handler(int type, void *arg)
+{
+	struct mdp3_dma *dma = (struct mdp3_dma *)arg;
+	struct mdp3_vsync_notification vsync_client;
+
+	pr_debug("mdp3_vsync_intr_handler\n");
+	spin_lock(&dma->dma_lock);
+	vsync_client = dma->vsync_client;
+	if (!vsync_client.handler)
+		dma->cb_type &= ~MDP3_DMA_CALLBACK_TYPE_VSYNC;
+	dma->vsync_time = ktime_get();
+	complete(&dma->vsync_comp);
+	if (vsync_client.handler)
+		vsync_client.handler(vsync_client.arg);
+	spin_unlock(&dma->dma_lock);
+
+	if (!vsync_client.handler)
+		mdp3_irq_disable_nosync(type);
+}
+
+static void mdp3_dma_done_intr_handler(int type, void *arg)
+{
+	struct mdp3_dma *dma = (struct mdp3_dma *)arg;
+
+	pr_debug("mdp3_dma_done_intr_handler\n");
+	spin_lock(&dma->dma_lock);
+	dma->busy = false;
+	dma->cb_type &= ~MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+	spin_unlock(&dma->dma_lock);
+	complete(&dma->dma_comp);
+	mdp3_irq_disable_nosync(type);
+}
+
+void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type)
+{
+	int irq_bit;
+	unsigned long flag;
+
+	pr_debug("mdp3_dma_callback_enable type=%d\n", type);
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	if (dma->cb_type & type) {
+		spin_unlock_irqrestore(&dma->dma_lock, flag);
+		return;
+	} else {
+		dma->cb_type |= type;
+		spin_unlock_irqrestore(&dma->dma_lock, flag);
+	}
+
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
+		dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) {
+		if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC)
+			mdp3_irq_enable(MDP3_INTR_LCDC_START_OF_FRAME);
+	} else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) {
+			irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE;
+			irq_bit += dma->dma_sel;
+			mdp3_irq_enable(irq_bit);
+		}
+
+		if (type & MDP3_DMA_CALLBACK_TYPE_DMA_DONE) {
+			irq_bit = MDP3_INTR_DMA_P_DONE;
+			if (dma->dma_sel == MDP3_DMA_S)
+				irq_bit = MDP3_INTR_DMA_S_DONE;
+			mdp3_irq_enable(irq_bit);
+		}
+	} else {
+		pr_err("mdp3_dma_callback_enable not supported interface\n");
+	}
+}
+
+void mdp3_dma_callback_disable(struct mdp3_dma *dma, int type)
+{
+	int irq_bit;
+	unsigned long flag;
+
+	pr_debug("mdp3_dma_callback_disable type=%d\n", type);
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	if ((dma->cb_type & type) == 0) {
+		spin_unlock_irqrestore(&dma->dma_lock, flag);
+		return;
+	} else {
+		dma->cb_type &= ~type;
+		spin_unlock_irqrestore(&dma->dma_lock, flag);
+	}
+
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
+		dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) {
+		if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC)
+			mdp3_irq_disable(MDP3_INTR_LCDC_START_OF_FRAME);
+	} else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) {
+			irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE;
+			irq_bit += dma->dma_sel;
+			mdp3_irq_disable(irq_bit);
+		}
+
+		if (type & MDP3_DMA_CALLBACK_TYPE_DMA_DONE) {
+			irq_bit = MDP3_INTR_DMA_P_DONE;
+			if (dma->dma_sel == MDP3_DMA_S)
+				irq_bit = MDP3_INTR_DMA_S_DONE;
+			mdp3_irq_disable(irq_bit);
+		}
+	}
+}
+
+static int mdp3_dma_callback_setup(struct mdp3_dma *dma)
+{
+	int rc;
+	struct mdp3_intr_cb vsync_cb = {
+		.cb = mdp3_vsync_intr_handler,
+		.data = dma,
+	};
+
+	struct mdp3_intr_cb dma_cb = {
+		.cb = mdp3_dma_done_intr_handler,
+		.data = dma,
+	};
+
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO ||
+		dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC)
+		rc = mdp3_set_intr_callback(MDP3_INTR_LCDC_START_OF_FRAME,
+					&vsync_cb);
+	else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		int irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE;
+		irq_bit += dma->dma_sel;
+		rc = mdp3_set_intr_callback(irq_bit, &vsync_cb);
+		irq_bit = MDP3_INTR_DMA_P_DONE;
+		if (dma->dma_sel == MDP3_DMA_S)
+			irq_bit = MDP3_INTR_DMA_S_DONE;
+		rc |= mdp3_set_intr_callback(irq_bit, &dma_cb);
+	} else {
+		pr_err("mdp3_dma_callback_setup not suppported interface\n");
+		rc = -ENODEV;
+	}
+	return rc;
+}
+
+static void mdp3_dma_vsync_enable(struct mdp3_dma *dma,
+				struct mdp3_vsync_notification *vsync_client)
+{
+	unsigned long flag;
+	int updated = 0;
+	int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+
+	pr_debug("mdp3_dma_vsync_enable\n");
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	if (vsync_client) {
+		if (dma->vsync_client.handler != vsync_client->handler) {
+			dma->vsync_client = *vsync_client;
+			updated = 1;
+		}
+	} else {
+		if (!dma->vsync_client.handler) {
+			dma->vsync_client.handler = NULL;
+			dma->vsync_client.arg = NULL;
+			updated = 1;
+		}
+	}
+	spin_unlock_irqrestore(&dma->dma_lock, flag);
+
+	if (updated) {
+		if (vsync_client && vsync_client->handler)
+			mdp3_dma_callback_enable(dma, cb_type);
+		else
+			mdp3_dma_callback_disable(dma, cb_type);
+	}
+}
+
+static int mdp3_dmap_config(struct mdp3_dma *dma,
+			struct mdp3_dma_source *source_config,
+			struct mdp3_dma_output_config *output_config)
+{
+	u32 dma_p_cfg_reg, dma_p_size, dma_p_out_xy;
+
+	dma_p_cfg_reg = source_config->format << 25;
+	if (output_config->dither_en)
+		dma_p_cfg_reg |= BIT(24);
+	dma_p_cfg_reg |= output_config->out_sel << 19;
+	dma_p_cfg_reg |= output_config->bit_mask_polarity << 18;
+	dma_p_cfg_reg |= output_config->color_components_flip << 14;
+	dma_p_cfg_reg |= output_config->pack_pattern << 8;
+	dma_p_cfg_reg |= output_config->pack_align << 7;
+	dma_p_cfg_reg |= output_config->color_comp_out_bits;
+
+	dma_p_size = source_config->width | (source_config->height << 16);
+	dma_p_out_xy = source_config->x | (source_config->y << 16);
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CONFIG, dma_p_cfg_reg);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_SIZE, dma_p_size);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)source_config->buf);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_OUT_XY, dma_p_out_xy);
+
+	/*
+	 * NOTE: MDP_DMA_P_FETCH_CFG: max_burst_size need to use value 4, not
+	 * the default 16 for MDP hang issue workaround
+	 */
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x10);
+	MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
+
+	dma->source_config = *source_config;
+	dma->output_config = *output_config;
+
+	mdp3_dma_callback_setup(dma);
+	return 0;
+}
+
+static int mdp3_dmas_config(struct mdp3_dma *dma,
+			struct mdp3_dma_source *source_config,
+			struct mdp3_dma_output_config *output_config)
+{
+	u32 dma_s_cfg_reg, dma_s_size, dma_s_out_xy;
+
+	dma_s_cfg_reg = source_config->format << 25;
+	if (output_config->dither_en)
+		dma_s_cfg_reg |= BIT(24);
+	dma_s_cfg_reg |= output_config->out_sel << 19;
+	dma_s_cfg_reg |= output_config->bit_mask_polarity << 18;
+	dma_s_cfg_reg |= output_config->color_components_flip << 14;
+	dma_s_cfg_reg |= output_config->pack_pattern << 8;
+	dma_s_cfg_reg |= output_config->pack_align << 7;
+	dma_s_cfg_reg |= output_config->color_comp_out_bits;
+
+	dma_s_size = source_config->width | (source_config->height << 16);
+	dma_s_out_xy = source_config->x | (source_config->y << 16);
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_CONFIG, dma_s_cfg_reg);
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_SIZE, dma_s_size);
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_ADDR, (u32)source_config->buf);
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_Y_STRIDE, source_config->stride);
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_OUT_XY, dma_s_out_xy);
+
+	MDP3_REG_WRITE(MDP3_REG_SECONDARY_RD_PTR_IRQ, 0x10);
+
+	dma->source_config = *source_config;
+	dma->output_config = *output_config;
+
+	mdp3_dma_callback_setup(dma);
+	return 0;
+}
+
+static int mdp3_dmap_cursor_config(struct mdp3_dma *dma,
+				struct mdp3_dma_cursor *cursor)
+{
+	u32 cursor_size, cursor_pos, blend_param, trans_mask;
+
+	cursor_size = cursor->width | (cursor->height << 16);
+	cursor_pos = cursor->x | (cursor->y << 16);
+	trans_mask = 0;
+	if (cursor->blend_config.mode == MDP3_DMA_CURSOR_BLEND_CONSTANT_ALPHA) {
+		blend_param = cursor->blend_config.constant_alpha << 24;
+	} else if (cursor->blend_config.mode ==
+			MDP3_DMA_CURSOR_BLEND_COLOR_KEYING) {
+		blend_param = cursor->blend_config.transparent_color;
+		trans_mask = cursor->blend_config.transparency_mask;
+	} else {
+		blend_param = 0;
+	}
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_FORMAT, cursor->format);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_SIZE, cursor_size);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BUF_ADDR, (u32)cursor->buf);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_POS, cursor_pos);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BLEND_CONFIG,
+			cursor->blend_config.mode);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BLEND_PARAM, blend_param);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BLEND_TRANS_MASK, trans_mask);
+	dma->cursor = *cursor;
+	return 0;
+}
+
+static int mdp3_dmap_ccs_config(struct mdp3_dma *dma,
+			struct mdp3_dma_color_correct_config *config,
+			struct mdp3_dma_ccs *ccs,
+			struct mdp3_dma_lut *lut)
+{
+	int i;
+	u32 addr, cc_config, color;
+
+	cc_config = config->lut_enable;
+	if (config->ccs_enable)
+		cc_config |= BIT(3);
+	cc_config |= config->lut_position << 4;
+	cc_config |= config->ccs_sel << 5;
+	cc_config |= config->pre_bias_sel << 6;
+	cc_config |= config->post_bias_sel << 7;
+	cc_config |= config->pre_limit_sel << 8;
+	cc_config |= config->post_limit_sel << 9;
+	cc_config |= config->lut_sel << 10;
+
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config);
+
+	if (config->ccs_enable && ccs) {
+		if (ccs->mv1) {
+			addr = MDP3_REG_DMA_P_CSC_MV1;
+			for (i = 0; i < 9; i++) {
+				MDP3_REG_WRITE(addr, ccs->mv1[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->mv2) {
+			addr = MDP3_REG_DMA_P_CSC_MV2;
+			for (i = 0; i < 9; i++) {
+				MDP3_REG_WRITE(addr, ccs->mv2[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->pre_bv1) {
+			addr = MDP3_REG_DMA_P_CSC_PRE_BV1;
+			for (i = 0; i < 3; i++) {
+				MDP3_REG_WRITE(addr, ccs->pre_bv1[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->pre_bv2) {
+			addr = MDP3_REG_DMA_P_CSC_PRE_BV2;
+			for (i = 0; i < 3; i++) {
+				MDP3_REG_WRITE(addr, ccs->pre_bv2[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->post_bv1) {
+			addr = MDP3_REG_DMA_P_CSC_POST_BV1;
+			for (i = 0; i < 3; i++) {
+				MDP3_REG_WRITE(addr, ccs->post_bv1[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->post_bv2) {
+			addr = MDP3_REG_DMA_P_CSC_POST_BV2;
+			for (i = 0; i < 3; i++) {
+				MDP3_REG_WRITE(addr, ccs->post_bv2[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->pre_lv1) {
+			addr = MDP3_REG_DMA_P_CSC_PRE_LV1;
+			for (i = 0; i < 6; i++) {
+				MDP3_REG_WRITE(addr, ccs->pre_lv1[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->pre_lv2) {
+			addr = MDP3_REG_DMA_P_CSC_PRE_LV2;
+			for (i = 0; i < 6; i++) {
+				MDP3_REG_WRITE(addr, ccs->pre_lv2[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->post_lv1) {
+			addr = MDP3_REG_DMA_P_CSC_POST_LV1;
+			for (i = 0; i < 6; i++) {
+				MDP3_REG_WRITE(addr, ccs->post_lv1[i]);
+				addr += 4;
+			}
+		}
+
+		if (ccs->post_lv2) {
+			addr = MDP3_REG_DMA_P_CSC_POST_LV2;
+			for (i = 0; i < 6; i++) {
+				MDP3_REG_WRITE(addr, ccs->post_lv2[i]);
+				addr += 4;
+			}
+		}
+	}
+
+	if (config->lut_enable && lut) {
+		if (lut->color0_lut1 && lut->color1_lut1 && lut->color2_lut1) {
+			addr = MDP3_REG_DMA_P_CSC_LUT1;
+			for (i = 0; i < 256; i++) {
+				color = lut->color0_lut1[i];
+				color |= lut->color1_lut1[i] << 8;
+				color |= lut->color2_lut1[i] << 16;
+				MDP3_REG_WRITE(addr, color);
+				addr += 4;
+			}
+		}
+
+		if (lut->color0_lut2 && lut->color1_lut2 && lut->color2_lut2) {
+			addr = MDP3_REG_DMA_P_CSC_LUT2;
+			for (i = 0; i < 256; i++) {
+				color = lut->color0_lut2[i];
+				color |= lut->color1_lut2[i] << 8;
+				color |= lut->color2_lut2[i] << 16;
+				MDP3_REG_WRITE(addr, color);
+				addr += 4;
+			}
+		}
+	}
+
+	dma->ccs_config = *config;
+	return 0;
+}
+
+static int mdp3_dmap_histo_config(struct mdp3_dma *dma,
+			struct mdp3_dma_histogram_config *histo_config)
+{
+	u32 hist_bit_mask, hist_control;
+
+	if (histo_config->bit_mask_polarity)
+		hist_bit_mask = BIT(31);
+	hist_bit_mask |= histo_config->bit_mask;
+
+	if (histo_config->auto_clear_en)
+		hist_control = BIT(0);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_FRAME_CNT,
+			histo_config->frame_count);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_BIT_MASK, hist_bit_mask);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CONTROL, hist_control);
+	return 0;
+}
+
+static int mdp3_dmap_update(struct mdp3_dma *dma, void *buf)
+{
+	int wait_for_dma_done = 0;
+	unsigned long flag;
+	int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+
+	pr_debug("mdp3_dmap_update\n");
+
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+		spin_lock_irqsave(&dma->dma_lock, flag);
+		if (dma->busy)
+			wait_for_dma_done = 1;
+		spin_unlock_irqrestore(&dma->dma_lock, flag);
+
+		if (wait_for_dma_done)
+			wait_for_completion_killable(&dma->dma_comp);
+	}
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf);
+	dma->source_config.buf = buf;
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 1);
+		dma->busy = true;
+	}
+	wmb();
+	init_completion(&dma->vsync_comp);
+	spin_unlock_irqrestore(&dma->dma_lock, flag);
+
+	mdp3_dma_callback_enable(dma, cb_type);
+	pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
+	wait_for_completion_killable(&dma->vsync_comp);
+	pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
+	return 0;
+}
+
+static int mdp3_dmas_update(struct mdp3_dma *dma, void *buf)
+{
+	int wait_for_dma_done = 0;
+	unsigned long flag;
+	int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+		spin_lock_irqsave(&dma->dma_lock, flag);
+		if (dma->busy)
+			wait_for_dma_done = 1;
+		spin_unlock_irqrestore(&dma->dma_lock, flag);
+
+		if (wait_for_dma_done)
+			wait_for_completion_killable(&dma->dma_comp);
+	}
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_ADDR, (u32)buf);
+	dma->source_config.buf = buf;
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		MDP3_REG_WRITE(MDP3_REG_DMA_S_START, 1);
+		dma->busy = true;
+	}
+	wmb();
+	init_completion(&dma->vsync_comp);
+	spin_unlock_irqrestore(&dma->dma_lock, flag);
+
+	mdp3_dma_callback_enable(dma, cb_type);
+	wait_for_completion_killable(&dma->vsync_comp);
+	return 0;
+}
+
+static int mdp3_dmap_cursor_update(struct mdp3_dma *dma, int x, int y)
+{
+	u32 cursor_pos;
+
+	cursor_pos = x | (y << 16);
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_POS, cursor_pos);
+	dma->cursor.x = x;
+	dma->cursor.y = y;
+	return 0;
+}
+
+static int mdp3_dmap_histo_get(struct mdp3_dma *dma,
+			struct mdp3_dma_histogram_data *data)
+{
+	int i;
+	u32 addr, extra;
+
+	addr = MDP3_REG_DMA_P_HIST_R_DATA;
+	for (i = 0; i < 32; i++) {
+		data->r_data[i] = MDP3_REG_READ(addr);
+		addr += 4;
+	}
+
+	addr = MDP3_REG_DMA_P_HIST_G_DATA;
+	for (i = 0; i < 32; i++) {
+		data->g_data[i] = MDP3_REG_READ(addr);
+		addr += 4;
+	}
+
+	addr = MDP3_REG_DMA_P_HIST_B_DATA;
+	for (i = 0; i < 32; i++) {
+		data->b_data[i] = MDP3_REG_READ(addr);
+		addr += 4;
+	}
+
+	extra = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_0);
+	data->r_min_value = (extra & 0x1F0000) >> 16;
+	data->r_max_value = (extra & 0x1F000000) >> 24;
+	extra = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_1);
+	data->g_min_value = extra & 0x1F;
+	data->g_max_value = (extra & 0x1F00) >> 8;
+	data->b_min_value = (extra & 0x1F0000) >> 16;
+	data->b_max_value = (extra & 0x1F000000) >> 24;
+	return 0;
+}
+
+static int mdp3_dmap_histo_op(struct mdp3_dma *dma, u32 op)
+{
+	switch (op) {
+	case MDP3_DMA_HISTO_OP_START:
+		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1);
+		break;
+	case MDP3_DMA_HISTO_OP_STOP:
+		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_STOP_REQ, 1);
+		break;
+	case MDP3_DMA_HISTO_OP_CANCEL:
+		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CANCEL_REQ, 1);
+		break;
+	case MDP3_DMA_HISTO_OP_RESET:
+		MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_RESET_SEQ_START, 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mdp3_dmap_histo_intr_status(struct mdp3_dma *dma, int *status)
+{
+	*status = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_STATUS);
+	return 0;
+}
+
+static int mdp3_dmap_histo_intr_enable(struct mdp3_dma *dma, u32 mask)
+{
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, mask);
+	return 0;
+}
+
+static int mdp3_dmap_histo_intr_clear(struct mdp3_dma *dma, u32 mask)
+{
+	MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_CLEAR, mask);
+	return 0;
+}
+
+static int mdp3_dma_start(struct mdp3_dma *dma, struct mdp3_intf *intf)
+{
+	unsigned long flag;
+	int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
+	u32 dma_start_offset = MDP3_REG_DMA_P_START;
+
+	if (dma->dma_sel == MDP3_DMA_P)
+		dma_start_offset = MDP3_REG_DMA_P_START;
+	else if (dma->dma_sel == MDP3_DMA_S)
+		dma_start_offset = MDP3_REG_DMA_S_START;
+	else
+		return -EINVAL;
+
+	spin_lock_irqsave(&dma->dma_lock, flag);
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
+		cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+		MDP3_REG_WRITE(dma_start_offset, 1);
+		dma->busy = true;
+	}
+
+	intf->start(intf);
+	wmb();
+	init_completion(&dma->vsync_comp);
+	spin_unlock_irqrestore(&dma->dma_lock, flag);
+
+	mdp3_dma_callback_enable(dma, cb_type);
+	pr_debug("mdp3_dma_start wait for vsync_comp in\n");
+	wait_for_completion_killable(&dma->vsync_comp);
+	pr_debug("mdp3_dma_start wait for vsync_comp out\n");
+	return 0;
+}
+
+static int mdp3_dma_stop(struct mdp3_dma *dma, struct mdp3_intf *intf)
+{
+	int ret = 0;
+	u32 status, display_status_bit;
+
+	if (dma->dma_sel == MDP3_DMA_P)
+		display_status_bit = BIT(6);
+	else if (dma->dma_sel == MDP3_DMA_S)
+		display_status_bit = BIT(7);
+	else
+		return -EINVAL;
+
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+		display_status_bit |= BIT(11);
+
+	intf->stop(intf);
+	ret = readl_poll_timeout((mdp3_res->mdp_base + MDP3_REG_DISPLAY_STATUS),
+				status,
+				((status & display_status_bit) == 0),
+				DMA_STOP_POLL_SLEEP_US,
+				DMA_STOP_POLL_TIMEOUT_US);
+
+	mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_VSYNC |
+					MDP3_DMA_CALLBACK_TYPE_DMA_DONE);
+
+	dma->busy = false;
+	return ret;
+}
+
+int mdp3_dma_init(struct mdp3_dma *dma,
+		struct mdp3_dma_source *source_config,
+		struct mdp3_dma_output_config *output_config)
+{
+	int ret = 0;
+
+	pr_debug("mdp3_dma_init\n");
+	switch (dma->dma_sel) {
+	case MDP3_DMA_P:
+		dma->busy = 0;
+
+		ret = mdp3_dmap_config(dma, source_config, output_config);
+		if (ret < 0)
+			return ret;
+
+		dma->config_cursor = mdp3_dmap_cursor_config;
+		dma->config_ccs = mdp3_dmap_ccs_config;
+		dma->config_histo = mdp3_dmap_histo_config;
+		dma->update = mdp3_dmap_update;
+		dma->update_cursor = mdp3_dmap_cursor_update;
+		dma->get_histo = mdp3_dmap_histo_get;
+		dma->histo_op = mdp3_dmap_histo_op;
+		dma->histo_intr_status = mdp3_dmap_histo_intr_status;
+		dma->histo_intr_enable = mdp3_dmap_histo_intr_enable;
+		dma->histo_intr_clear = mdp3_dmap_histo_intr_clear;
+		dma->vsync_enable = mdp3_dma_vsync_enable;
+		dma->get_vsync_time = mdp3_get_vsync_time;
+		dma->start = mdp3_dma_start;
+		dma->stop = mdp3_dma_stop;
+		break;
+	case MDP3_DMA_S:
+		dma->busy = 0;
+		ret = mdp3_dmas_config(dma, source_config, output_config);
+		if (ret < 0)
+			return ret;
+
+		dma->config_cursor = NULL;
+		dma->config_ccs = NULL;
+		dma->config_histo = NULL;
+		dma->update = mdp3_dmas_update;
+		dma->update_cursor = NULL;
+		dma->get_histo = NULL;
+		dma->histo_op = NULL;
+		dma->histo_intr_status = NULL;
+		dma->histo_intr_enable = NULL;
+		dma->histo_intr_clear = NULL;
+		dma->vsync_enable = mdp3_dma_vsync_enable;
+		dma->get_vsync_time = mdp3_get_vsync_time;
+		dma->start = mdp3_dma_start;
+		dma->stop = mdp3_dma_stop;
+		break;
+	case MDP3_DMA_E:
+	default:
+		ret = -ENODEV;
+		break;
+	}
+
+	spin_lock_init(&dma->dma_lock);
+	init_completion(&dma->vsync_comp);
+	init_completion(&dma->dma_comp);
+	dma->cb_type = 0;
+	dma->vsync_client.handler = NULL;
+	dma->vsync_client.arg = NULL;
+
+	memset(&dma->cursor, 0, sizeof(dma->cursor));
+	memset(&dma->ccs_config, 0, sizeof(dma->ccs_config));
+	memset(&dma->histogram_config, 0, sizeof(dma->histogram_config));
+
+	return ret;
+}
+
+int lcdc_config(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg)
+{
+	u32 temp;
+	struct mdp3_video_intf_cfg *v = &cfg->video;
+	temp = v->hsync_pulse_width | (v->hsync_period << 16);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_HSYNC_CTL, temp);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_VSYNC_PERIOD, v->vsync_period);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_VSYNC_PULSE_WIDTH, v->vsync_pulse_width);
+	temp = v->display_start_x | (v->display_end_x << 16);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_DISPLAY_HCTL, temp);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_DISPLAY_V_START, v->display_start_y);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_DISPLAY_V_END, v->display_end_y);
+	temp = v->active_start_x | (v->active_end_x);
+	if (v->active_h_enable)
+		temp |= BIT(31);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_ACTIVE_HCTL, temp);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_ACTIVE_V_START, v->active_start_y);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_ACTIVE_V_END, v->active_end_y);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_HSYNC_SKEW, v->hsync_skew);
+	temp = 0;
+	if (!v->hsync_polarity)
+		temp = BIT(0);
+	if (!v->vsync_polarity)
+		temp = BIT(1);
+	if (!v->de_polarity)
+		temp = BIT(2);
+	MDP3_REG_WRITE(MDP3_REG_LCDC_CTL_POLARITY, temp);
+
+	return 0;
+}
+
+int lcdc_start(struct mdp3_intf *intf)
+{
+	MDP3_REG_WRITE(MDP3_REG_LCDC_EN, BIT(0));
+	wmb();
+	intf->active = true;
+	return 0;
+}
+
+int lcdc_stop(struct mdp3_intf *intf)
+{
+	MDP3_REG_WRITE(MDP3_REG_LCDC_EN, 0);
+	wmb();
+	intf->active = false;
+	return 0;
+}
+
+int dsi_video_config(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg)
+{
+	u32 temp;
+	struct mdp3_video_intf_cfg *v = &cfg->video;
+
+	pr_debug("dsi_video_config\n");
+
+	temp = v->hsync_pulse_width | (v->hsync_period << 16);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_HSYNC_CTL, temp);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_VSYNC_PERIOD, v->vsync_period);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_VSYNC_PULSE_WIDTH,
+			v->vsync_pulse_width);
+	temp = v->display_start_x | (v->display_end_x << 16);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_DISPLAY_HCTL, temp);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_DISPLAY_V_START, v->display_start_y);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_DISPLAY_V_END, v->display_end_y);
+	temp = v->active_start_x | (v->active_end_x << 16);
+	if (v->active_h_enable)
+		temp |= BIT(31);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_ACTIVE_HCTL, temp);
+
+	temp = v->active_start_y;
+	if (v->active_v_enable)
+		temp |= BIT(31);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_ACTIVE_V_START, temp);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_ACTIVE_V_END, v->active_end_y);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_HSYNC_SKEW, v->hsync_skew);
+	temp = 0;
+	if (!v->hsync_polarity)
+		temp |= BIT(0);
+	if (!v->vsync_polarity)
+		temp |= BIT(1);
+	if (!v->de_polarity)
+		temp |= BIT(2);
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_CTL_POLARITY, temp);
+
+	return 0;
+}
+
+int dsi_video_start(struct mdp3_intf *intf)
+{
+	pr_debug("dsi_video_start\n");
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, BIT(0));
+	wmb();
+	intf->active = true;
+	return 0;
+}
+
+int dsi_video_stop(struct mdp3_intf *intf)
+{
+	pr_debug("dsi_video_stop\n");
+	MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 0);
+	wmb();
+	intf->active = false;
+	return 0;
+}
+
+int dsi_cmd_config(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg)
+{
+	u32 id_map = 0;
+	u32 trigger_en = 0;
+
+	if (cfg->dsi_cmd.primary_dsi_cmd_id)
+		id_map = BIT(0);
+	if (cfg->dsi_cmd.secondary_dsi_cmd_id)
+		id_map = BIT(4);
+
+	if (cfg->dsi_cmd.dsi_cmd_tg_intf_sel)
+		trigger_en = BIT(4);
+
+	MDP3_REG_WRITE(MDP3_REG_DSI_CMD_MODE_ID_MAP, id_map);
+	MDP3_REG_WRITE(MDP3_REG_DSI_CMD_MODE_TRIGGER_EN, trigger_en);
+
+	return 0;
+}
+
+int dsi_cmd_start(struct mdp3_intf *intf)
+{
+	intf->active = true;
+	return 0;
+}
+
+int dsi_cmd_stop(struct mdp3_intf *intf)
+{
+	intf->active = false;
+	return 0;
+}
+
+int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg)
+{
+	int ret = 0;
+	switch (cfg->type) {
+	case MDP3_DMA_OUTPUT_SEL_LCDC:
+		intf->config = lcdc_config;
+		intf->start = lcdc_start;
+		intf->stop = lcdc_stop;
+		break;
+	case MDP3_DMA_OUTPUT_SEL_DSI_VIDEO:
+		intf->config = dsi_video_config;
+		intf->start = dsi_video_start;
+		intf->stop = dsi_video_stop;
+		break;
+	case MDP3_DMA_OUTPUT_SEL_DSI_CMD:
+		intf->config = dsi_cmd_config;
+		intf->start = dsi_cmd_start;
+		intf->stop = dsi_cmd_stop;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	intf->active = false;
+	if (intf->config)
+		ret = intf->config(intf, cfg);
+
+	if (ret) {
+		pr_err("MDP interface initialization failed\n");
+		return ret;
+	}
+
+	intf->cfg = *cfg;
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
new file mode 100644
index 0000000..2fb8427
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -0,0 +1,336 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This 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 MDP3_DMA_H
+#define MDP3_DMA_H
+
+#include <linux/sched.h>
+
+enum {
+	MDP3_DMA_P,
+	MDP3_DMA_S,
+	MDP3_DMA_E,
+	MDP3_DMA_MAX
+};
+
+enum {
+	MDP3_DMA_CAP_CURSOR = 0x1,
+	MDP3_DMA_CAP_COLOR_CORRECTION = 0x2,
+	MDP3_DMA_CAP_HISTOGRAM = 0x4,
+	MDP3_DMA_CAP_GAMMA_CORRECTION = 0x8,
+	MDP3_DMA_CAP_DITHER = 0x10,
+	MDP3_DMA_CAP_ALL = 0x1F
+};
+
+enum {
+	MDP3_DMA_OUTPUT_SEL_AHB,
+	MDP3_DMA_OUTPUT_SEL_DSI_CMD,
+	MDP3_DMA_OUTPUT_SEL_LCDC,
+	MDP3_DMA_OUTPUT_SEL_DSI_VIDEO,
+	MDP3_DMA_OUTPUT_SEL_MAX
+};
+
+enum {
+	MDP3_DMA_IBUF_FORMAT_RGB888,
+	MDP3_DMA_IBUF_FORMAT_RGB565,
+	MDP3_DMA_IBUF_FORMAT_XRGB8888,
+	MDP3_DMA_IBUF_FORMAT_UNDEFINED
+};
+
+enum {
+	MDP3_DMA_OUTPUT_PACK_PATTERN_RGB = 0x21,
+	MDP3_DMA_OUTPUT_PACK_PATTERN_RBG = 0x24,
+	MDP3_DMA_OUTPUT_PACK_PATTERN_BGR = 0x12,
+	MDP3_DMA_OUTPUT_PACK_PATTERN_BRG = 0x18,
+	MDP3_DMA_OUTPUT_PACK_PATTERN_GBR = 0x06,
+	MDP3_DMA_OUTPUT_PACK_PATTERN_GRB = 0x09,
+};
+
+enum {
+	MDP3_DMA_OUTPUT_PACK_ALIGN_LSB,
+	MDP3_DMA_OUTPUT_PACK_ALIGN_MSB
+};
+
+enum {
+	MDP3_DMA_OUTPUT_COMP_BITS_4, /*4 bits per color component*/
+	MDP3_DMA_OUTPUT_COMP_BITS_5,
+	MDP3_DMA_OUTPUT_COMP_BITS_6,
+	MDP3_DMA_OUTPUT_COMP_BITS_8,
+};
+
+enum {
+	MDP3_DMA_CURSOR_FORMAT_ARGB888,
+};
+
+enum {
+	MDP3_DMA_COLOR_CORRECT_SET_1,
+	MDP3_DMA_COLOR_CORRECT_SET_2
+};
+
+enum {
+	MDP3_DMA_LUT_POSITION_PRE,
+	MDP3_DMA_LUT_POSITION_POST
+};
+
+enum {
+	MDP3_DMA_LUT_DISABLE = 0x0,
+	MDP3_DMA_LUT_ENABLE_C0 = 0x01,
+	MDP3_DMA_LUT_ENABLE_C1 = 0x02,
+	MDP3_DMA_LUT_ENABLE_C2 = 0x04,
+	MDP3_DMA_LUT_ENABLE_ALL = 0x07,
+};
+
+enum {
+	MDP3_DMA_HISTOGRAM_BIT_MASK_NONE = 0X0,
+	MDP3_DMA_HISTOGRAM_BIT_MASK_ONE_MSB = 0x1,
+	MDP3_DMA_HISTOGRAM_BIT_MASK_TWO_MSB = 0x2,
+	MDP3_DMA_HISTOGRAM_BIT_MASK_THREE_MSB = 0x3
+};
+
+enum {
+	MDP3_DMA_COLOR_FLIP_NONE,
+	MDP3_DMA_COLOR_FLIP_COMP1 = 0x1,
+	MDP3_DMA_COLOR_FLIP_COMP2 = 0x2,
+	MDP3_DMA_COLOR_FLIP_COMP3 = 0x4,
+};
+
+enum {
+	MDP3_DMA_CURSOR_BLEND_NONE = 0x0,
+	MDP3_DMA_CURSOR_BLEND_PER_PIXEL_ALPHA =  0x3,
+	MDP3_DMA_CURSOR_BLEND_CONSTANT_ALPHA = 0x5,
+	MDP3_DMA_CURSOR_BLEND_COLOR_KEYING = 0x9
+};
+
+enum {
+	MDP3_DMA_HISTO_OP_START,
+	MDP3_DMA_HISTO_OP_STOP,
+	MDP3_DMA_HISTO_OP_CANCEL,
+	MDP3_DMA_HISTO_OP_RESET
+};
+
+enum {
+	MDP3_DMA_CALLBACK_TYPE_VSYNC = 0x01,
+	MDP3_DMA_CALLBACK_TYPE_DMA_DONE = 0x02,
+};
+
+struct mdp3_dma_source {
+	u32 format;
+	int width;
+	int height;
+	int x;
+	int y;
+	void *buf;
+	int stride;
+};
+
+struct mdp3_dma_output_config {
+	int dither_en;
+	u32 out_sel;
+	u32 bit_mask_polarity;
+	u32 color_components_flip;
+	u32 pack_pattern;
+	u32 pack_align;
+	u32 color_comp_out_bits;
+};
+
+struct mdp3_dma_cursor_blend_config {
+	u32 mode;
+	u32 transparent_color; /*color keying*/
+	u32 transparency_mask;
+	u32 constant_alpha;
+};
+
+struct mdp3_dma_cursor {
+	int enable; /* enable cursor or not*/
+	u32 format;
+	int width;
+	int height;
+	int x;
+	int y;
+	void *buf;
+	struct mdp3_dma_cursor_blend_config blend_config;
+};
+
+struct mdp3_dma_ccs {
+	u32 *mv1; /*set1 matrix vector, 3x3 */
+	u32 *mv2;
+	u32 *pre_bv1; /*pre-bias vector for set1, 1x3*/
+	u32 *pre_bv2;
+	u32 *post_bv1; /*post-bias vecotr for set1,  */
+	u32 *post_bv2;
+	u32 *pre_lv1; /*pre-limit vector for set 1, 1x6*/
+	u32 *pre_lv2;
+	u32 *post_lv1;
+	u32 *post_lv2;
+};
+
+struct mdp3_dma_lut {
+	uint8_t *color0_lut1;
+	uint8_t *color1_lut1;
+	uint8_t *color2_lut1;
+	uint8_t *color0_lut2;
+	uint8_t *color1_lut2;
+	uint8_t *color2_lut2;
+};
+
+struct mdp3_dma_color_correct_config {
+	int ccs_enable;
+	int lut_enable;
+	u32 lut_sel;
+	u32 post_limit_sel;
+	u32 pre_limit_sel;
+	u32 post_bias_sel;
+	u32 pre_bias_sel;
+	u32 ccs_sel;
+	u32 lut_position;
+};
+
+struct mdp3_dma_histogram_config {
+	int frame_count;
+	u32 bit_mask_polarity;
+	u32 bit_mask;
+	int auto_clear_en;
+};
+
+struct mdp3_dma_histogram_data {
+	uint8_t r_max_value;
+	uint8_t r_min_value;
+	uint8_t b_max_value;
+	uint8_t b_min_value;
+	uint8_t g_max_value;
+	uint8_t g_min_value;
+	uint8_t r_data[32];
+	uint8_t g_data[32];
+	uint8_t b_data[32];
+};
+
+struct mdp3_vsync_notification {
+	void (*handler)(void *arg);
+	void *arg;
+};
+
+struct mdp3_intf;
+
+struct mdp3_dma {
+	u32 dma_sel;
+	u32 capability;
+	int in_use;
+	int available;
+	int busy;
+
+	spinlock_t dma_lock;
+	struct completion vsync_comp;
+	struct completion dma_comp;
+	ktime_t vsync_time;
+	struct mdp3_vsync_notification vsync_client;
+	u32 cb_type;
+
+	struct mdp3_dma_output_config output_config;
+	struct mdp3_dma_source source_config;
+
+	struct mdp3_dma_cursor cursor;
+	struct mdp3_dma_color_correct_config ccs_config;
+	struct mdp3_dma_histogram_config histogram_config;
+
+	int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf);
+
+	int (*stop)(struct mdp3_dma *dma, struct mdp3_intf *intf);
+
+	int (*config_cursor)(struct mdp3_dma *dma,
+				struct mdp3_dma_cursor *cursor);
+
+	int (*config_ccs)(struct mdp3_dma *dma,
+			struct mdp3_dma_color_correct_config *config,
+			struct mdp3_dma_ccs *ccs,
+			struct mdp3_dma_lut *lut);
+
+	int (*update)(struct mdp3_dma *dma, void *buf);
+
+	int (*update_cursor)(struct mdp3_dma *dma, int x, int y);
+
+	int (*get_histo)(struct mdp3_dma *dma,
+				struct mdp3_dma_histogram_data *data);
+
+	int (*config_histo)(struct mdp3_dma *dma,
+				struct mdp3_dma_histogram_config *histo_config);
+
+	int (*histo_op)(struct mdp3_dma *dma,
+				u32 op);
+
+	int (*histo_intr_status)(struct mdp3_dma *dma, int *status);
+
+	int (*histo_intr_enable)(struct mdp3_dma *dma, u32 mask);
+
+	int (*histo_intr_clear)(struct mdp3_dma *dma, u32 mask);
+
+	void (*vsync_enable)(struct mdp3_dma *dma,
+			struct mdp3_vsync_notification *vsync_client);
+
+	ktime_t (*get_vsync_time)(struct mdp3_dma *dma);
+
+};
+
+struct mdp3_video_intf_cfg {
+	int hsync_period;
+	int hsync_pulse_width;
+	int vsync_period;
+	int vsync_pulse_width;
+	int display_start_x;
+	int display_end_x;
+	int display_start_y;
+	int display_end_y;
+	int active_start_x;
+	int active_end_x;
+	int active_h_enable;
+	int active_start_y;
+	int active_end_y;
+	int active_v_enable;
+	int hsync_skew;
+	int hsync_polarity;
+	int vsync_polarity;
+	int de_polarity;
+};
+
+struct mdp3_dsi_cmd_intf_cfg {
+	int primary_dsi_cmd_id;
+	int secondary_dsi_cmd_id;
+	int dsi_cmd_tg_intf_sel;
+};
+
+struct mdp3_intf_cfg {
+	u32 type;
+	struct mdp3_video_intf_cfg video;
+	struct mdp3_dsi_cmd_intf_cfg dsi_cmd;
+};
+
+struct mdp3_intf {
+	struct mdp3_intf_cfg cfg;
+	int active;
+	int available;
+	int in_use;
+	int (*config)(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg);
+	int (*start)(struct mdp3_intf *intf);
+	int (*stop)(struct mdp3_intf *intf);
+};
+
+int mdp3_dma_init(struct mdp3_dma *dma,
+		struct mdp3_dma_source *source_config,
+		struct mdp3_dma_output_config *output_config);
+
+int mdp3_intf_init(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg);
+
+void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type);
+
+void mdp3_dma_callback_disable(struct mdp3_dma *dma, int type);
+
+#endif /* MDP3_DMA_H */
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
new file mode 100644
index 0000000..2763f46
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -0,0 +1,216 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This 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 MDP3_HWIO_H
+#define MDP3_HWIO_H
+
+#include <linux/bitops.h>
+
+/*synchronization*/
+#define MDP3_REG_SYNC_CONFIG_0				0x0300
+#define MDP3_REG_SYNC_CONFIG_1				0x0304
+#define MDP3_REG_SYNC_CONFIG_2				0x0308
+#define MDP3_REG_SYNC_STATUS_0				0x030c
+#define MDP3_REG_SYNC_STATUS_1				0x0310
+#define MDP3_REG_SYNC_STATUS_2				0x0314
+#define MDP3_REG_PRIMARY_VSYNC_OUT_CTRL			0x0318
+#define MDP3_REG_SECONDARY_VSYNC_OUT_CTRL		0x031c
+#define MDP3_REG_EXTERNAL_VSYNC_OUT_CTRL		0x0320
+#define MDP3_REG_VSYNC_SEL				0x0324
+
+/*interrupt*/
+#define MDP3_REG_INTR_ENABLE				0x0020
+#define MDP3_REG_INTR_STATUS				0x0024
+#define MDP3_REG_INTR_CLEAR				0x0028
+
+#define MDP3_REG_PRIMARY_RD_PTR_IRQ			0x021C
+#define MDP3_REG_SECONDARY_RD_PTR_IRQ			0x0220
+
+/*operation control*/
+#define MDP3_REG_DMA_P_START				0x0044
+#define MDP3_REG_DMA_S_START				0x0048
+#define MDP3_REG_DMA_E_START				0x004c
+
+#define MDP3_REG_DISPLAY_STATUS				0x0038
+
+#define MDP3_REG_HW_VERSION				0x0070
+#define MDP3_REG_SW_RESET				0x0074
+
+/*EBI*/
+#define MDP3_REG_EBI2_LCD0				0x003c
+#define MDP3_REG_EBI2_LCD0_YSTRIDE			0x0050
+
+/*DMA_P*/
+#define MDP3_REG_DMA_P_CONFIG				0x90000
+#define MDP3_REG_DMA_P_SIZE				0x90004
+#define MDP3_REG_DMA_P_IBUF_ADDR			0x90008
+#define MDP3_REG_DMA_P_IBUF_Y_STRIDE			0x9000C
+#define MDP3_REG_DMA_P_PROFILE_EN			0x90020
+#define MDP3_REG_DMA_P_OUT_XY				0x90010
+#define MDP3_REG_DMA_P_CURSOR_FORMAT			0x90040
+#define MDP3_REG_DMA_P_CURSOR_SIZE			0x90044
+#define MDP3_REG_DMA_P_CURSOR_BUF_ADDR			0x90048
+#define MDP3_REG_DMA_P_CURSOR_POS			0x9004c
+#define MDP3_REG_DMA_P_CURSOR_BLEND_CONFIG		0x90060
+#define MDP3_REG_DMA_P_CURSOR_BLEND_PARAM		0x90064
+#define MDP3_REG_DMA_P_CURSOR_BLEND_TRANS_MASK		0x90068
+#define MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG		0x90070
+#define MDP3_REG_DMA_P_CSC_BYPASS			0X93004
+#define MDP3_REG_DMA_P_CSC_MV1				0x93400
+#define MDP3_REG_DMA_P_CSC_MV2				0x93440
+#define MDP3_REG_DMA_P_CSC_PRE_BV1			0x93500
+#define MDP3_REG_DMA_P_CSC_PRE_BV2			0x93540
+#define MDP3_REG_DMA_P_CSC_POST_BV1			0x93580
+#define MDP3_REG_DMA_P_CSC_POST_BV2			0x935c0
+#define MDP3_REG_DMA_P_CSC_PRE_LV1			0x93600
+#define MDP3_REG_DMA_P_CSC_PRE_LV2			0x93640
+#define MDP3_REG_DMA_P_CSC_POST_LV1			0x93680
+#define MDP3_REG_DMA_P_CSC_POST_LV2			0x936c0
+#define MDP3_REG_DMA_P_CSC_LUT1				0x93800
+#define MDP3_REG_DMA_P_CSC_LUT2				0x93c00
+#define MDP3_REG_DMA_P_HIST_START			0x94000
+#define MDP3_REG_DMA_P_HIST_FRAME_CNT			0x94004
+#define MDP3_REG_DMA_P_HIST_BIT_MASK			0x94008
+#define MDP3_REG_DMA_P_HIST_RESET_SEQ_START		0x9400c
+#define MDP3_REG_DMA_P_HIST_CONTROL			0x94010
+#define MDP3_REG_DMA_P_HIST_INTR_STATUS			0x94014
+#define MDP3_REG_DMA_P_HIST_INTR_CLEAR			0x94018
+#define MDP3_REG_DMA_P_HIST_INTR_ENABLE			0x9401c
+#define MDP3_REG_DMA_P_HIST_STOP_REQ			0x94020
+#define MDP3_REG_DMA_P_HIST_CANCEL_REQ			0x94024
+#define MDP3_REG_DMA_P_HIST_EXTRA_INFO_0		0x94028
+#define MDP3_REG_DMA_P_HIST_EXTRA_INFO_1		0x9402c
+#define MDP3_REG_DMA_P_HIST_R_DATA			0x94100
+#define MDP3_REG_DMA_P_HIST_G_DATA			0x94200
+#define MDP3_REG_DMA_P_HIST_B_DATA			0x94300
+#define MDP3_REG_DMA_P_FETCH_CFG			0x90074
+#define MDP3_REG_DMA_P_DCVS_CTRL			0x90080
+#define MDP3_REG_DMA_P_DCVS_STATUS			0x90084
+
+/*DMA_S*/
+#define MDP3_REG_DMA_S_CONFIG				0x90000
+#define MDP3_REG_DMA_S_SIZE				0x90004
+#define MDP3_REG_DMA_S_IBUF_ADDR			0x90008
+#define MDP3_REG_DMA_S_IBUF_Y_STRIDE			0x9000C
+#define MDP3_REG_DMA_S_OUT_XY				0x90010
+
+/*interface*/
+#define MDP3_REG_LCDC_EN				0xE0000
+#define MDP3_REG_LCDC_HSYNC_CTL				0xE0004
+#define MDP3_REG_LCDC_VSYNC_PERIOD			0xE0008
+#define MDP3_REG_LCDC_VSYNC_PULSE_WIDTH			0xE000C
+#define MDP3_REG_LCDC_DISPLAY_HCTL			0xE0010
+#define MDP3_REG_LCDC_DISPLAY_V_START			0xE0014
+#define MDP3_REG_LCDC_DISPLAY_V_END			0xE0018
+#define MDP3_REG_LCDC_ACTIVE_HCTL			0xE001C
+#define MDP3_REG_LCDC_ACTIVE_V_START			0xE0020
+#define MDP3_REG_LCDC_ACTIVE_V_END			0xE0024
+#define MDP3_REG_LCDC_BORDER_COLOR			0xE0028
+#define MDP3_REG_LCDC_UNDERFLOW_CTL			0xE002C
+#define MDP3_REG_LCDC_HSYNC_SKEW			0xE0030
+#define MDP3_REG_LCDC_TEST_CTL				0xE0034
+#define MDP3_REG_LCDC_CTL_POLARITY			0xE0038
+#define MDP3_REG_LCDC_TEST_COL_VAR1			0xE003C
+#define MDP3_REG_LCDC_TEST_COL_VAR2			0xE0040
+#define MDP3_REG_LCDC_UFLOW_HIDING_CTL			0xE0044
+#define MDP3_REG_LCDC_LOST_PIXEL_CNT_VALUE		0xE0048
+
+#define MDP3_REG_DSI_VIDEO_EN				0xF0000
+#define MDP3_REG_DSI_VIDEO_HSYNC_CTL			0xF0004
+#define MDP3_REG_DSI_VIDEO_VSYNC_PERIOD			0xF0008
+#define MDP3_REG_DSI_VIDEO_VSYNC_PULSE_WIDTH		0xF000C
+#define MDP3_REG_DSI_VIDEO_DISPLAY_HCTL			0xF0010
+#define MDP3_REG_DSI_VIDEO_DISPLAY_V_START		0xF0014
+#define MDP3_REG_DSI_VIDEO_DISPLAY_V_END		0xF0018
+#define MDP3_REG_DSI_VIDEO_ACTIVE_HCTL			0xF001C
+#define MDP3_REG_DSI_VIDEO_ACTIVE_V_START		0xF0020
+#define MDP3_REG_DSI_VIDEO_ACTIVE_V_END			0xF0024
+#define MDP3_REG_DSI_VIDEO_BORDER_COLOR			0xF0028
+#define MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL		0xF002C
+#define MDP3_REG_DSI_VIDEO_HSYNC_SKEW			0xF0030
+#define MDP3_REG_DSI_VIDEO_TEST_CTL			0xF0034
+#define MDP3_REG_DSI_VIDEO_CTL_POLARITY			0xF0038
+#define MDP3_REG_DSI_VIDEO_TEST_COL_VAR1		0xF003C
+#define MDP3_REG_DSI_VIDEO_TEST_COL_VAR2		0xF0040
+#define MDP3_REG_DSI_VIDEO_UFLOW_HIDING_CTL		0xF0044
+#define MDP3_REG_DSI_VIDEO_LOST_PIXEL_CNT_VALUE		0xF0048
+
+#define MDP3_REG_DSI_CMD_MODE_ID_MAP			0xF1000
+#define MDP3_REG_DSI_CMD_MODE_TRIGGER_EN		0xF1004
+
+/*interrupt mask*/
+
+#define MDP3_INTR_DP0_ROI_DONE_BIT			BIT(0)
+#define MDP3_INTR_DP1_ROI_DONE_BIT			BIT(1)
+#define MDP3_INTR_DMA_S_DONE_BIT			BIT(2)
+#define MDP3_INTR_DMA_E_DONE_BIT			BIT(3)
+#define MDP3_INTR_DP0_TERMINAL_FRAME_DONE_BIT		BIT(4)
+#define MDP3_INTR_DP1_TERMINAL_FRAME_DONE_BIT		BIT(5)
+#define MDP3_INTR_DMA_TV_DONE_BIT			BIT(6)
+#define MDP3_INTR_TV_ENCODER_UNDER_RUN_BIT		BIT(7)
+#define MDP3_INTR_SYNC_PRIMARY_LINE_BIT			BIT(8)
+#define MDP3_INTR_SYNC_SECONDARY_LINE_BIT		BIT(9)
+#define MDP3_INTR_SYNC_EXTERNAL_LINE_BIT		BIT(10)
+#define MDP3_INTR_DP0_FETCH_DONE_BIT			BIT(11)
+#define MDP3_INTR_DP1_FETCH_DONE_BIT			BIT(12)
+#define MDP3_INTR_TV_OUT_FRAME_START_BIT		BIT(13)
+#define MDP3_INTR_DMA_P_DONE_BIT			BIT(14)
+#define MDP3_INTR_LCDC_START_OF_FRAME_BIT		BIT(15)
+#define MDP3_INTR_LCDC_UNDERFLOW_BIT			BIT(16)
+#define MDP3_INTR_DMA_P_LINE_BIT			BIT(17)
+#define MDP3_INTR_DMA_S_LINE_BIT			BIT(18)
+#define MDP3_INTR_DMA_E_LINE_BIT			BIT(19)
+#define MDP3_INTR_DMA_P_HISTO_BIT			BIT(20)
+#define MDP3_INTR_DTV_OUT_DONE_BIT			BIT(21)
+#define MDP3_INTR_DTV_OUT_START_OF_FRAME_BIT		BIT(22)
+#define MDP3_INTR_DTV_OUT_UNDERFLOW_BIT			BIT(23)
+#define MDP3_INTR_DTV_OUT_LINE_BIT			BIT(24)
+#define MDP3_INTR_DMA_P_AUTO_FREFRESH_START_BIT		BIT(25)
+#define MDP3_INTR_DMA_S_AUTO_FREFRESH_START_BIT		BIT(26)
+#define MDP3_INTR_QPIC_EOF_ENABLE_BIT			BIT(27)
+
+enum {
+	MDP3_INTR_DP0_ROI_DONE,
+	MDP3_INTR_DP1_ROI_DONE,
+	MDP3_INTR_DMA_S_DONE,
+	MDP3_INTR_DMA_E_DONE,
+	MDP3_INTR_DP0_TERMINAL_FRAME_DONE,
+	MDP3_INTR_DP1_TERMINAL_FRAME_DONE,
+	MDP3_INTR_DMA_TV_DONE,
+	MDP3_INTR_TV_ENCODER_UNDER_RUN,
+	MDP3_INTR_SYNC_PRIMARY_LINE,
+	MDP3_INTR_SYNC_SECONDARY_LINE,
+	MDP3_INTR_SYNC_EXTERNAL_LINE,
+	MDP3_INTR_DP0_FETCH_DONE,
+	MDP3_INTR_DP1_FETCH_DONE,
+	MDP3_INTR_TV_OUT_FRAME_START,
+	MDP3_INTR_DMA_P_DONE,
+	MDP3_INTR_LCDC_START_OF_FRAME,
+	MDP3_INTR_LCDC_UNDERFLOW,
+	MDP3_INTR_DMA_P_LINE,
+	MDP3_INTR_DMA_S_LINE,
+	MDP3_INTR_DMA_E_LINE,
+	MDP3_INTR_DMA_P_HISTO,
+	MDP3_INTR_DTV_OUT_DONE,
+	MDP3_INTR_DTV_OUT_START_OF_FRAME,
+	MDP3_INTR_DTV_OUT_UNDERFLOW,
+	MDP3_INTR_DTV_OUT_LINE,
+	MDP3_INTR_DMA_P_AUTO_FREFRESH_START,
+	MDP3_INTR_DMA_S_AUTO_FREFRESH_START,
+	MDP3_INTR_QPIC_EOF_ENABLE,
+};
+
+#define MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT		BIT(0)
+#define MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT		BIT(1)
+
+#endif /* MDP3_HWIO_H */