mdss: display: Add Mobile Display SubSystem driver

- Implements Linux frame buffer interface to interact with userspace
  libraries and applications, based on msm_fb frame buffer.
- Implement MDP driver which handles MDP core data path setup and
  hardware blocks programming.
- Support for UI through Linux frame buffer FBIOPAN_DISPLAY ioctl.

Change-Id: Ib98677b8d81d74283b27dea08a9f1a705c101bce
Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 7777154..4e1c807 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -84,6 +84,16 @@
 	  Support for MSM MDP HW revision 4.0
 	  Say Y here if this is msm7x30 variant platform.
 
+config FB_MSM_MDSS
+	bool "MDSS HW"
+	---help---
+	The Mobile Display Sub System (MDSS) driver supports devices which
+	contain MDSS hardware block.
+
+	The MDSS driver implements frame buffer interface to provide access to
+	the display hardware and provide a way for users to display graphics
+	on connected display panels.
+
 config FB_MSM_MDP_NONE
 	bool "MDP HW None"
 	---help---
@@ -936,4 +946,5 @@
 	default n
 	---help---
 	  Support for EBI2 panel auto detect
+
 endif
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index e4a0948..a0f9e02 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -1,10 +1,12 @@
+ifeq ($(CONFIG_FB_MSM_MDSS),y)
+obj-y += mdss/
+else
 obj-y := msm_fb.o
 
 obj-$(CONFIG_FB_MSM_LOGO) += logo.o
 obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
 
 ifeq ($(CONFIG_FB_MSM_MDP_HW),y)
-
 # MDP
 obj-y += mdp.o
 
@@ -182,15 +184,15 @@
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback.o
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_overlay_writeback.o
-
-obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
-obj-$(CONFIG_MSM_VIDC_720P) += vidc/
 else
 obj-$(CONFIG_FB_MSM_EBI2) += ebi2_host.o
 obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
 obj-y += msm_fb_panel.o
 obj-$(CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL) += ebi2_epson_s1d_qvga.o
 endif
+endif
 
+obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
+obj-$(CONFIG_MSM_VIDC_720P) += vidc/
 clean:
 	rm *.o .*cmd
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
new file mode 100644
index 0000000..fa4843c
--- /dev/null
+++ b/drivers/video/msm/mdss/Makefile
@@ -0,0 +1,4 @@
+mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
+mdss-mdp-objs += mdss_mdp_overlay.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
new file mode 100644
index 0000000..aaf6690
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_H
+#define MDSS_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_reg_base + addr)
+#define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
+
+extern unsigned char *mdss_reg_base;
+
+struct mdss_res_type {
+	u32 rev;
+	u32 mdp_rev;
+	struct clk *mdp_clk;
+	struct clk *mdp_pclk;
+	struct clk *mdp_lut_clk;
+	struct clk *vsync_clk;
+	struct regulator *fs;
+
+	struct workqueue_struct *clk_ctrl_wq;
+	struct delayed_work clk_ctrl_worker;
+
+	u32 irq;
+	u32 irq_mask;
+	u32 irq_ena;
+	u32 irq_buzy;
+
+	u32 clk_ena;
+	u32 suspend;
+	u32 timeout;
+
+	u32 fs_ena;
+	u32 vsync_ena;
+
+	u32 intf;
+	u32 eintf_ena;
+	u32 prim_ptype;
+	u32 res_init;
+	u32 pdev_lcnt;
+	u32 bus_hdl;
+
+	u32 smp_mb_cnt;
+	u32 smp_mb_size;
+	u32 *pipe_type_map;
+	u32 *mixer_type_map;
+};
+extern struct mdss_res_type *mdss_res;
+#endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
new file mode 100644
index 0000000..cec9cb8
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -0,0 +1,1228 @@
+/*
+ * Core MDSS framebuffer driver.
+ *
+ * Copyright (C) 2007 Google Incorporated
+ * Copyright (c) 2008-2012, Code Aurora Forum. 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
+ * 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/android_pmem.h>
+#include <linux/bootmem.h>
+#include <linux/console.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/memory.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/msm_mdp.h>
+#include <linux/proc_fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+
+#include <mach/board.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MDSS_FB_NUM 3
+#else
+#define MDSS_FB_NUM 2
+#endif
+
+#define MAX_FBI_LIST 32
+static struct fb_info *fbi_list[MAX_FBI_LIST];
+static int fbi_list_index;
+
+static u32 mdss_fb_pseudo_palette[16] = {
+	0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd);
+static int mdss_fb_open(struct fb_info *info, int user);
+static int mdss_fb_release(struct fb_info *info, int user);
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static int mdss_fb_set_par(struct fb_info *info);
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+			     int op_enable);
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
+static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg);
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+
+#define MAX_BACKLIGHT_BRIGHTNESS 255
+static int lcd_backlight_registered;
+
+static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
+				      enum led_brightness value)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
+	int bl_lvl;
+
+	if (value > MAX_BACKLIGHT_BRIGHTNESS)
+		value = MAX_BACKLIGHT_BRIGHTNESS;
+
+	/* This maps android backlight level 0 to 255 into
+	   driver backlight level 0 to bl_max with rounding */
+	bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
+		 /(2 * MAX_BACKLIGHT_BRIGHTNESS);
+
+	if (!bl_lvl && value)
+		bl_lvl = 1;
+
+	mdss_fb_set_backlight(mfd, bl_lvl);
+}
+
+static struct led_classdev backlight_led = {
+	.name           = "lcd-backlight",
+	.brightness     = MAX_BACKLIGHT_BRIGHTNESS,
+	.brightness_set = mdss_fb_set_bl_brightness,
+};
+
+static ssize_t mdss_fb_get_type(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+
+	switch (mfd->panel_info.type) {
+	case NO_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "no panel\n");
+		break;
+	case HDMI_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n");
+		break;
+	case LVDS_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "lvds panel\n");
+		break;
+	case DTV_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "dtv panel\n");
+		break;
+	case MIPI_VIDEO_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "mipi dsi video panel\n");
+		break;
+	case MIPI_CMD_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n");
+		break;
+	case WRITEBACK_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "writeback panel\n");
+		break;
+	default:
+		ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
+		break;
+	}
+
+	return ret;
+}
+
+static DEVICE_ATTR(mdss_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
+static struct attribute *mdss_fb_attrs[] = {
+	&dev_attr_mdss_fb_type.attr,
+	NULL,
+};
+
+static struct attribute_group mdss_fb_attr_group = {
+	.attrs = mdss_fb_attrs,
+};
+
+static int mdss_fb_create_sysfs(struct msm_fb_data_type *mfd)
+{
+	int rc;
+
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
+	if (rc)
+		pr_err("sysfs group creation failed, rc=%d\n", rc);
+	return rc;
+}
+
+static void mdss_fb_remove_sysfs(struct msm_fb_data_type *mfd)
+{
+	sysfs_remove_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
+}
+
+static int mdss_fb_probe(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd = NULL;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi;
+	int rc;
+
+	if (fbi_list_index >= MAX_FBI_LIST)
+		return -ENOMEM;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata)
+		return -ENODEV;
+
+	/*
+	 * alloc framebuffer info + par data
+	 */
+	fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), &pdev->dev);
+	if (fbi == NULL) {
+		pr_err("can't allocate framebuffer info data!\n");
+		return -ENOMEM;
+	}
+
+	mfd = (struct msm_fb_data_type *)fbi->par;
+	mfd->key = MFD_KEY;
+	mfd->fbi = fbi;
+	mfd->panel_info = pdata->panel_info;
+	mfd->panel.type = pdata->panel_info.type;
+	mfd->panel.id = mfd->index;
+	mfd->fb_page = MDSS_FB_NUM;
+	mfd->index = fbi_list_index;
+	mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
+	mfd->panel_info.frame_count = 0;
+	mfd->bl_level = 0;
+	mfd->fb_imgType = MDP_RGBA_8888;
+	mfd->iclient = msm_ion_client_create(-1, pdev->name);
+	if (IS_ERR(mfd->iclient))
+		mfd->iclient = NULL;
+
+	mfd->pdev = pdev;
+
+	mutex_init(&mfd->lock);
+
+	fbi_list[fbi_list_index++] = fbi;
+
+	platform_set_drvdata(pdev, mfd);
+
+	rc = mdss_fb_register(mfd);
+	if (rc)
+		return rc;
+
+	rc = pm_runtime_set_active(mfd->fbi->dev);
+	if (rc < 0)
+		pr_err("pm_runtime: fail to set active.\n");
+	pm_runtime_enable(mfd->fbi->dev);
+
+	/* android supports only one lcd-backlight/lcd for now */
+	if (!lcd_backlight_registered) {
+		if (led_classdev_register(&pdev->dev, &backlight_led))
+			pr_err("led_classdev_register failed\n");
+		else
+			lcd_backlight_registered = 1;
+	}
+
+	mdss_fb_create_sysfs(mfd);
+
+	return 0;
+}
+
+static int mdss_fb_remove(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+	mdss_fb_remove_sysfs(mfd);
+
+	pm_runtime_disable(mfd->fbi->dev);
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (mdss_fb_suspend_sub(mfd))
+		pr_err("msm_fb_remove: can't stop the device %d\n",
+			    mfd->index);
+
+	/* remove /dev/fb* */
+	unregister_framebuffer(mfd->fbi);
+
+	if (lcd_backlight_registered) {
+		lcd_backlight_registered = 0;
+		led_classdev_unregister(&backlight_led);
+	}
+
+	return 0;
+}
+
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	/*
+	 * suspend this channel
+	 */
+	mfd->suspend.op_enable = mfd->op_enable;
+	mfd->suspend.panel_power_on = mfd->panel_power_on;
+
+	if (mfd->op_enable) {
+		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+				mfd->suspend.op_enable);
+		if (ret) {
+			pr_warn("can't turn off display!\n");
+			return ret;
+		}
+		mfd->op_enable = false;
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_PM)
+static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	/* resume state var recover */
+	mfd->op_enable = mfd->suspend.op_enable;
+
+	if (mfd->suspend.panel_power_on) {
+		ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+					mfd->op_enable);
+		if (ret)
+			pr_warn("can't turn on display!\n");
+	}
+
+	return ret;
+}
+
+static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct msm_fb_data_type *mfd;
+	int ret = 0;
+
+	pr_debug("mdss_fb_suspend\n");
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	console_lock();
+	fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
+
+	ret = mdss_fb_suspend_sub(mfd);
+	if (ret != 0) {
+		pr_err("failed to suspend! %d\n", ret);
+		fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
+	} else {
+		pdev->dev.power.power_state = state;
+	}
+
+	console_unlock();
+	return ret;
+}
+
+static int mdss_fb_resume(struct platform_device *pdev)
+{
+	/* This resume function is called when interrupt is enabled.
+	 */
+	int ret = 0;
+	struct msm_fb_data_type *mfd;
+
+	pr_debug("mdss_fb_resume\n");
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	console_lock();
+	ret = mdss_fb_resume_sub(mfd);
+	pdev->dev.power.power_state = PMSG_ON;
+	fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
+	console_unlock();
+
+	return ret;
+}
+#else
+#define mdss_fb_suspend NULL
+#define mdss_fb_resume NULL
+#endif
+
+#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
+static int mdss_fb_ext_suspend(struct device *dev)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	if (mfd->panel_info.type == HDMI_PANEL ||
+	    mfd->panel_info.type == DTV_PANEL)
+		ret = mdss_fb_suspend_sub(mfd);
+
+	return ret;
+}
+
+static int mdss_fb_ext_resume(struct device *dev)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	if (mfd->panel_info.type == HDMI_PANEL ||
+	    mfd->panel_info.type == DTV_PANEL)
+		ret = mdss_fb_resume_sub(mfd);
+
+	return ret;
+}
+#else
+#define mdss_fb_ext_suspend NULL
+#define mdss_fb_ext_resume NULL
+#endif
+
+static const struct dev_pm_ops mdss_fb_dev_pm_ops = {
+	.suspend = mdss_fb_ext_suspend,
+	.resume = mdss_fb_ext_resume,
+};
+
+static struct platform_driver mdss_fb_driver = {
+	.probe = mdss_fb_probe,
+	.remove = mdss_fb_remove,
+	.suspend = mdss_fb_suspend,
+	.resume = mdss_fb_resume,
+	.shutdown = NULL,
+	.driver = {
+		.name = "mdss_fb",
+		.pm = &mdss_fb_dev_pm_ops,
+	},
+};
+
+static int unset_bl_level, bl_updated;
+static int bl_level_old;
+
+void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
+{
+	struct mdss_panel_data *pdata;
+
+	if (!mfd->panel_power_on || !bl_updated) {
+		unset_bl_level = bkl_lvl;
+		return;
+	} else {
+		unset_bl_level = 0;
+	}
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+
+	if ((pdata) && (pdata->set_backlight)) {
+		mutex_lock(&mfd->lock);
+		if (bl_level_old == bkl_lvl) {
+			mutex_unlock(&mfd->lock);
+			return;
+		}
+		mfd->bl_level = bkl_lvl;
+		pdata->set_backlight(mfd->bl_level);
+		bl_level_old = mfd->bl_level;
+		mutex_unlock(&mfd->lock);
+	}
+}
+
+void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
+{
+	struct mdss_panel_data *pdata;
+
+	if (unset_bl_level && !bl_updated) {
+		pdata = dev_get_platdata(&mfd->pdev->dev);
+		if ((pdata) && (pdata->set_backlight)) {
+			mutex_lock(&mfd->lock);
+			mfd->bl_level = unset_bl_level;
+			pdata->set_backlight(mfd->bl_level);
+			bl_level_old = unset_bl_level;
+			mutex_unlock(&mfd->lock);
+			bl_updated = 1;
+		}
+	}
+}
+
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+			     int op_enable)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int ret = 0;
+
+	if (!op_enable)
+		return -EPERM;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		if (!mfd->panel_power_on) {
+			msleep(20);
+			ret = mfd->on_fnc(mfd);
+			if (ret == 0)
+				mfd->panel_power_on = true;
+		}
+		break;
+
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_POWERDOWN:
+	default:
+		if (mfd->panel_power_on) {
+			int curr_pwr_state;
+
+			mfd->op_enable = false;
+			curr_pwr_state = mfd->panel_power_on;
+			mfd->panel_power_on = false;
+			bl_updated = 0;
+
+			msleep(20);
+			ret = mfd->off_fnc(mfd);
+			if (ret)
+				mfd->panel_power_on = curr_pwr_state;
+
+			mfd->op_enable = true;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static int mdss_fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
+}
+
+/*
+ * Custom Framebuffer mmap() function for MSM driver.
+ * Differs from standard mmap() function by allowing for customized
+ * page-protection.
+ */
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	/* Get frame buffer memory range. */
+	unsigned long start = info->fix.smem_start;
+	u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	if (off >= len) {
+		/* memory mapped io */
+		off -= len;
+		if (info->var.accel_flags) {
+			mutex_unlock(&info->lock);
+			return -EINVAL;
+		}
+		start = info->fix.mmio_start;
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+	}
+
+	/* Set VM flags. */
+	start &= PAGE_MASK;
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	/* Set VM page protection */
+	if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	else if (mfd->mdp_fb_page_protection ==
+		 MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
+		vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+	else if (mfd->mdp_fb_page_protection ==
+		 MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
+		vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+	else if (mfd->mdp_fb_page_protection ==
+		 MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
+		vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
+	else
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	/* Remap the frame buffer I/O range */
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static struct fb_ops mdss_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = mdss_fb_open,
+	.fb_release = mdss_fb_release,
+	.fb_check_var = mdss_fb_check_var,	/* vinfo check */
+	.fb_set_par = mdss_fb_set_par,	/* set the video mode */
+	.fb_blank = mdss_fb_blank,	/* blank display */
+	.fb_pan_display = mdss_fb_pan_display,	/* pan display */
+	.fb_ioctl = mdss_fb_ioctl,	/* perform fb specific ioctl */
+	.fb_mmap = mdss_fb_mmap,
+};
+
+static u32 mdss_fb_line_length(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;
+}
+
+static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
+{
+	void *virt = NULL;
+	unsigned long phys = 0;
+	size_t size;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * mfd->panel_info.yres);
+	size *= mfd->fb_page;
+
+	if (mfd->index == 0) {
+		virt = dma_alloc_coherent(NULL, size, (dma_addr_t *) &phys,
+				GFP_KERNEL);
+		if (!virt) {
+			pr_err("unable to alloc fb memory size=%u\n", size);
+			return -ENOMEM;
+		}
+
+		pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+			size, virt, phys, mfd->index);
+	} else {
+		pr_debug("no memory allocated for fb%d\n", mfd->index);
+		size = 0;
+	}
+
+	mfd->fbi->screen_base = virt;
+	mfd->fbi->fix.smem_start = phys;
+	mfd->fbi->fix.smem_len = size;
+
+	return 0;
+}
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd)
+{
+	int ret = -ENODEV;
+	int bpp;
+	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;
+	int *id;
+
+	/*
+	 * fb info initialization
+	 */
+	fix = &fbi->fix;
+	var = &fbi->var;
+
+	fix->type_aux = 0;	/* if type == FB_TYPE_INTERLEAVED_PLANES */
+	fix->visual = FB_VISUAL_TRUECOLOR;	/* True Color */
+	fix->ywrapstep = 0;	/* No support */
+	fix->mmio_start = 0;	/* No MMIO Address */
+	fix->mmio_len = 0;	/* No MMIO Address */
+	fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
+
+	var->xoffset = 0,	/* Offset from virtual to visible */
+	var->yoffset = 0,	/* resolution */
+	var->grayscale = 0,	/* No graylevels */
+	var->nonstd = 0,	/* standard pixel format */
+	var->activate = FB_ACTIVATE_VBL,	/* activate it at vsync */
+	var->height = -1,	/* height of picture in mm */
+	var->width = -1,	/* width of picture in mm */
+	var->accel_flags = 0,	/* acceleration flags */
+	var->sync = 0,	/* see FB_SYNC_* */
+	var->rotate = 0,	/* angle we rotate counter clockwise */
+	mfd->op_enable = false;
+
+	switch (mfd->fb_imgType) {
+	case MDP_RGB_565:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 11;
+		var->blue.length = 5;
+		var->green.length = 6;
+		var->red.length = 5;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 2;
+		break;
+
+	case MDP_RGB_888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 3;
+		break;
+
+	case MDP_ARGB_8888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		bpp = 4;
+		break;
+
+	case MDP_RGBA_8888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 8;
+		var->green.offset = 16;
+		var->red.offset = 24;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 8;
+		bpp = 4;
+		break;
+
+	case MDP_YCRYCB_H2V1:
+		fix->type = FB_TYPE_INTERLEAVED_PLANES;
+		fix->xpanstep = 2;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		/* how about R/G/B offset? */
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 11;
+		var->blue.length = 5;
+		var->green.length = 6;
+		var->red.length = 5;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 2;
+		break;
+
+	default:
+		pr_err("msm_fb_init: fb %d unkown image type!\n",
+			    mfd->index);
+		return ret;
+	}
+
+	fix->type = panel_info->is_3d_panel;
+	fix->line_length = mdss_fb_line_length(mfd->index, panel_info->xres,
+					       bpp);
+	mfd->var_xres = panel_info->xres;
+	mfd->var_yres = panel_info->yres;
+
+	var->pixclock = mfd->panel_info.clk_rate;
+	mfd->var_pixclock = var->pixclock;
+
+	var->xres = panel_info->xres;
+	var->yres = panel_info->yres;
+	var->xres_virtual = panel_info->xres;
+	var->yres_virtual = panel_info->yres * mfd->fb_page;
+	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
+
+	/* id field for fb app  */
+
+	id = (int *)&mfd->panel;
+
+	snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);
+
+	fbi->fbops = &mdss_fb_ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mdss_fb_pseudo_palette;
+
+	mfd->ref_cnt = 0;
+	mfd->panel_power_on = false;
+
+	if (mdss_fb_alloc_fbmem(mfd)) {
+		pr_err("unable to allocate framebuffer memory\n");
+		return -ENOMEM;
+	}
+
+	mfd->op_enable = true;
+
+	/* cursor memory allocation */
+	if (mfd->cursor_update) {
+		mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+					(dma_addr_t *) &mfd->cursor_buf_phys,
+					GFP_KERNEL);
+		if (!mfd->cursor_buf)
+			mfd->cursor_update = 0;
+	}
+
+	if (mfd->lut_update) {
+		ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+		if (ret)
+			pr_err("fb_alloc_cmap() failed!\n");
+	}
+
+	if (register_framebuffer(fbi) < 0) {
+		if (mfd->lut_update)
+			fb_dealloc_cmap(&fbi->cmap);
+
+		if (mfd->cursor_buf)
+			dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+					  mfd->cursor_buf,
+					  (dma_addr_t) mfd->cursor_buf_phys);
+
+		mfd->op_enable = false;
+		return -EPERM;
+	}
+
+	pr_info("FrameBuffer[%d] %dx%d size=%d registered successfully!\n",
+		     mfd->index, fbi->var.xres, fbi->var.yres,
+		     fbi->fix.smem_len);
+
+	ret = 0;
+
+	return ret;
+}
+
+static int mdss_fb_open(struct fb_info *info, int user)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int result;
+
+	result = pm_runtime_get_sync(info->dev);
+
+	if (result < 0)
+		pr_err("pm_runtime: fail to wake up\n");
+
+
+	if (!mfd->ref_cnt) {
+		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
+					   mfd->op_enable);
+		if (result) {
+			pr_err("mdss_fb_open: can't turn on display!\n");
+			return result;
+		}
+	}
+
+	mfd->ref_cnt++;
+	return 0;
+}
+
+static int mdss_fb_release(struct fb_info *info, int user)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int ret = 0;
+
+	if (!mfd->ref_cnt) {
+		pr_info("try to close unopened fb %d!\n", mfd->index);
+		return -EINVAL;
+	}
+
+	mfd->ref_cnt--;
+
+	if (!mfd->ref_cnt) {
+		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
+				       mfd->op_enable);
+		if (ret) {
+			pr_err("can't turn off display!\n");
+			return ret;
+		}
+	}
+
+	pm_runtime_put(info->dev);
+	return ret;
+}
+
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	if ((!mfd->op_enable) || (!mfd->panel_power_on))
+		return -EPERM;
+
+	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
+		return -EINVAL;
+
+	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
+		return -EINVAL;
+
+	if (info->fix.xpanstep)
+		info->var.xoffset =
+		(var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+	if (info->fix.ypanstep)
+		info->var.yoffset =
+		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+	if (mfd->dma_fnc)
+		mfd->dma_fnc(mfd);
+	else
+		pr_warn("dma function not set for panel type=%d\n",
+				mfd->panel.type);
+
+	mdss_fb_update_backlight(mfd);
+
+	++mfd->panel_info.frame_count;
+	return 0;
+}
+
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	u32 len;
+
+	if (var->rotate != FB_ROTATE_UR)
+		return -EINVAL;
+	if (var->grayscale != info->var.grayscale)
+		return -EINVAL;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		if ((var->green.offset != 5) ||
+		    !((var->blue.offset == 11)
+		      || (var->blue.offset == 0)) ||
+		    !((var->red.offset == 11)
+		      || (var->red.offset == 0)) ||
+		    (var->blue.length != 5) ||
+		    (var->green.length != 6) ||
+		    (var->red.length != 5) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0) ||
+		    (var->transp.offset != 0) ||
+		    (var->transp.length != 0))
+			return -EINVAL;
+		break;
+
+	case 24:
+		if ((var->blue.offset != 0) ||
+		    (var->green.offset != 8) ||
+		    (var->red.offset != 16) ||
+		    (var->blue.length != 8) ||
+		    (var->green.length != 8) ||
+		    (var->red.length != 8) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0) ||
+		    !(((var->transp.offset == 0) &&
+		       (var->transp.length == 0)) ||
+		      ((var->transp.offset == 24) &&
+		       (var->transp.length == 8))))
+			return -EINVAL;
+		break;
+
+	case 32:
+		/* Figure out if the user meant RGBA or ARGB
+		   and verify the position of the RGB components */
+
+		if (var->transp.offset == 24) {
+			if ((var->blue.offset != 0) ||
+			    (var->green.offset != 8) ||
+			    (var->red.offset != 16))
+				return -EINVAL;
+		} else if (var->transp.offset == 0) {
+			if ((var->blue.offset != 8) ||
+			    (var->green.offset != 16) ||
+			    (var->red.offset != 24))
+				return -EINVAL;
+		} else
+			return -EINVAL;
+
+		/* Check the common values for both RGBA and ARGB */
+
+		if ((var->blue.length != 8) ||
+		    (var->green.length != 8) ||
+		    (var->red.length != 8) ||
+		    (var->transp.length != 8) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0))
+			return -EINVAL;
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
+		return -EINVAL;
+
+	len = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
+	if (len > info->fix.smem_len)
+		return -EINVAL;
+
+	if ((var->xres == 0) || (var->yres == 0))
+		return -EINVAL;
+
+	if ((var->xres > mfd->panel_info.xres) ||
+	    (var->yres > mfd->panel_info.yres))
+		return -EINVAL;
+
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+
+	if (var->yoffset > (var->yres_virtual - var->yres))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mdss_fb_set_par(struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	int old_imgType;
+	int blank = 0;
+
+	old_imgType = mfd->fb_imgType;
+	switch (var->bits_per_pixel) {
+	case 16:
+		if (var->red.offset == 0)
+			mfd->fb_imgType = MDP_BGR_565;
+		else
+			mfd->fb_imgType	= MDP_RGB_565;
+		break;
+
+	case 24:
+		if ((var->transp.offset == 0) && (var->transp.length == 0))
+			mfd->fb_imgType = MDP_RGB_888;
+		else if ((var->transp.offset == 24) &&
+			 (var->transp.length == 8)) {
+			mfd->fb_imgType = MDP_ARGB_8888;
+			info->var.bits_per_pixel = 32;
+		}
+		break;
+
+	case 32:
+		if (var->transp.offset == 24)
+			mfd->fb_imgType = MDP_ARGB_8888;
+		else
+			mfd->fb_imgType	= MDP_RGBA_8888;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((mfd->var_pixclock != var->pixclock) ||
+	    (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
+				 (mfd->var_pixclock != var->pixclock) ||
+				 (mfd->var_xres != var->xres) ||
+				 (mfd->var_yres != var->yres)))) {
+		mfd->var_xres = var->xres;
+		mfd->var_yres = var->yres;
+		mfd->var_pixclock = var->pixclock;
+		blank = 1;
+	}
+	mfd->fbi->fix.line_length = mdss_fb_line_length(mfd->index, var->xres,
+						var->bits_per_pixel / 8);
+
+	if (blank) {
+		mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
+		mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
+	}
+
+	return 0;
+}
+
+static int mdss_fb_cursor(struct fb_info *info, void __user *p)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_cursor cursor;
+	int ret;
+
+	if (!mfd->cursor_update)
+		return -ENODEV;
+
+	ret = copy_from_user(&cursor, p, sizeof(cursor));
+	if (ret)
+		return ret;
+
+	return mfd->cursor_update(info, &cursor);
+}
+
+static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_cmap cmap;
+	int ret;
+
+	if (!mfd->lut_update)
+		return -ENODEV;
+
+	ret = copy_from_user(&cmap, p, sizeof(cmap));
+	if (ret)
+		return ret;
+
+	mfd->lut_update(info, &cmap);
+	return 0;
+}
+
+static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	void __user *argp = (void __user *)arg;
+	struct mdp_page_protection fb_page_protection;
+	int ret = 0;
+
+	switch (cmd) {
+	case MSMFB_CURSOR:
+		ret = mdss_fb_cursor(info, argp);
+		break;
+
+	case MSMFB_SET_LUT:
+		ret = mdss_fb_set_lut(info, argp);
+		break;
+
+	case MSMFB_GET_PAGE_PROTECTION:
+		fb_page_protection.page_protection =
+			mfd->mdp_fb_page_protection;
+		ret = copy_to_user(argp, &fb_page_protection,
+				   sizeof(fb_page_protection));
+		if (ret)
+			return ret;
+		break;
+
+	default:
+		pr_info("MDP: unknown ioctl (cmd=%x) received!\n", cmd);
+		ret = -ENOSYS;
+		break;
+	}
+
+	return ret;
+}
+
+int mdss_register_panel(struct mdss_panel_data *pdata)
+{
+	struct platform_device *mdss_fb_dev = NULL;
+	struct msm_fb_data_type *mfd;
+	int rc;
+
+	if (!mdss_res) {
+		pr_err("mdss mdp resources not initialized yet\n");
+		return -ENODEV;
+	}
+
+	mdss_fb_dev = platform_device_alloc("mdss_fb", pdata->panel_info.pdest);
+	if (!mdss_fb_dev) {
+		pr_err("unable to allocate mdss_fb device\n");
+		return -ENOMEM;
+	}
+
+	mdss_fb_dev->dev.platform_data = pdata;
+
+	rc = platform_device_add(mdss_fb_dev);
+	if (rc) {
+		platform_device_put(mdss_fb_dev);
+		pr_err("unable to probe mdss_fb device (%d)\n", rc);
+		return rc;
+	}
+
+	mfd = platform_get_drvdata(mdss_fb_dev);
+	if (!mfd)
+		return -ENODEV;
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	mfd->on_fnc = mdss_mdp_ctl_on;
+	mfd->off_fnc = mdss_mdp_ctl_off;
+
+	rc = mdss_mdp_overlay_init(mfd);
+	if (rc)
+		pr_err("unable to init overlay\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(mdss_register_panel);
+
+int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
+{
+	struct fb_info *info;
+
+	if (fb_num > MAX_FBI_LIST)
+		return -EINVAL;
+
+	info = fbi_list[fb_num];
+	if (!info)
+		return -ENOENT;
+
+	*start = info->fix.smem_start;
+	*len = info->fix.smem_len;
+	return 0;
+}
+EXPORT_SYMBOL(mdss_fb_get_phys_info);
+
+int __init mdss_fb_init(void)
+{
+	int rc = -ENODEV;
+
+	if (platform_driver_register(&mdss_fb_driver))
+		return rc;
+
+	return 0;
+}
+
+module_init(mdss_fb_init);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
new file mode 100644
index 0000000..a1fd532
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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 MDSS_FB_H
+#define MDSS_FB_H
+
+#include <linux/ion.h>
+#include <linux/list.h>
+#include <linux/msm_mdp.h>
+#include <linux/types.h>
+
+#include "mdss_mdp.h"
+#include "mdss_panel.h"
+
+#define MSM_FB_DEFAULT_PAGE_SIZE 2
+#define MFD_KEY  0x11161126
+#define MSM_FB_MAX_DEV_LIST 32
+
+#define MSM_FB_ENABLE_DBGFS
+
+#ifndef MAX
+#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#ifndef MIN
+#define  MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+struct disp_info_type_suspend {
+	int op_enable;
+	int panel_power_on;
+};
+
+struct msm_fb_data_type {
+	u32 key;
+	u32 index;
+	u32 ref_cnt;
+	u32 fb_page;
+
+	struct panel_id panel;
+	struct mdss_panel_info panel_info;
+
+	u32 dest;
+	struct fb_info *fbi;
+
+	int op_enable;
+	u32 fb_imgType;
+
+	int hw_refresh;
+
+	int overlay_play_enable;
+
+	int panel_power_on;
+	struct disp_info_type_suspend suspend;
+
+	int (*on_fnc) (struct msm_fb_data_type *mfd);
+	int (*off_fnc) (struct msm_fb_data_type *mfd);
+	void (*dma_fnc) (struct msm_fb_data_type *mfd);
+	int (*cursor_update) (struct fb_info *info,
+			      struct fb_cursor *cursor);
+	int (*lut_update) (struct fb_info *info,
+			   struct fb_cmap *cmap);
+	int (*do_histogram) (struct fb_info *info,
+			     struct mdp_histogram *hist);
+	void *cursor_buf;
+	void *cursor_buf_phys;
+
+	u32 bl_level;
+	struct mutex lock;
+
+	struct platform_device *pdev;
+
+	u32 var_xres;
+	u32 var_yres;
+	u32 var_pixclock;
+
+	u32 mdp_fb_page_protection;
+	struct ion_client *iclient;
+
+	struct mdss_mdp_ctl *ctl;
+};
+
+int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
+void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
+void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
+#endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
new file mode 100644
index 0000000..d1847c3
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -0,0 +1,494 @@
+/*
+ * MDSS MDP Interface (used by framebuffer core)
+ *
+ * Copyright (c) 2007-2012, Code Aurora Forum. 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/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.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 "mdss.h"
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+/* 1.15 mdp clk factor */
+#define MDP_CLK_FACTOR(rate) (((rate) * 23) / 20)
+
+unsigned char *mdss_reg_base;
+
+struct mdss_res_type *mdss_res;
+static struct msm_panel_common_pdata *mdp_pdata;
+
+static DEFINE_SPINLOCK(mdp_lock);
+static DEFINE_MUTEX(mdp_clk_lock);
+static DEFINE_MUTEX(mdp_suspend_mutex);
+
+u32 mdss_mdp_pipe_type_map[MDSS_MDP_MAX_SSPP] = {
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_DMA,
+	MDSS_MDP_PIPE_TYPE_DMA,
+};
+
+u32 mdss_mdp_mixer_type_map[MDSS_MDP_MAX_LAYERMIXER] = {
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_WRITEBACK,
+	MDSS_MDP_MIXER_TYPE_WRITEBACK,
+};
+
+irqreturn_t mdss_irq_handler(int mdss_irq, void *ptr)
+{
+	u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
+
+	mdss_res->irq_buzy = true;
+
+	if (intr & MDSS_INTR_MDP)
+		mdss_mdp_isr(mdss_irq, ptr);
+
+	mdss_res->irq_buzy = false;
+
+	return IRQ_HANDLED;
+}
+
+int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
+{
+	u32 irq;
+	unsigned long irq_flags;
+	int ret = 0;
+
+	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+		intf_num = intf_num << 1;
+
+	irq =  BIT(intr_type + intf_num);
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (mdss_res->irq_mask & irq) {
+		pr_warn("MDSS IRQ-0x%x is already set, mask=%x irq=%d\n",
+			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+		ret = -EBUSY;
+	} else {
+		mdss_res->irq_mask |= irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, irq);
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+		if (!mdss_res->irq_ena) {
+			mdss_res->irq_ena = true;
+			enable_irq(mdss_res->irq);
+		}
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+
+	return ret;
+}
+
+void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
+{
+	u32 irq;
+	unsigned long irq_flags;
+
+
+	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+		intf_num = intf_num << 1;
+
+	irq = BIT(intr_type + intf_num);
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (!(mdss_res->irq_mask & irq)) {
+		pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
+			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+	} else {
+		mdss_res->irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+		if (!mdss_res->irq_mask) {
+			mdss_res->irq_ena = false;
+			disable_irq(mdss_res->irq);
+		}
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
+{
+	u32 irq;
+
+	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+		intf_num = intf_num << 1;
+
+	irq = BIT(intr_type + intf_num);
+
+	spin_lock(&mdp_lock);
+	if (!(mdss_res->irq_mask & irq)) {
+		pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
+			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+	} else {
+		mdss_res->irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+		if (!mdss_res->irq_mask) {
+			mdss_res->irq_ena = false;
+			disable_irq_nosync(mdss_res->irq);
+		}
+	}
+	spin_unlock(&mdp_lock);
+}
+
+static void mdss_mdp_clk_ctrl_update(int enable)
+{
+	if (mdss_res->clk_ena == enable)
+		return;
+
+	pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
+	mdss_res->clk_ena = enable;
+}
+
+void mdss_mdp_clk_ctrl(int enable, int isr)
+{
+	static atomic_t clk_ref = ATOMIC_INIT(0);
+	static DEFINE_MUTEX(clk_ctrl_lock);
+	int force_off = 0;
+
+	pr_debug("clk enable=%d isr=%d clk_ref=%d\n", enable, isr,
+			atomic_read(&clk_ref));
+	/*
+	 * It is assumed that if isr = TRUE then start = OFF
+	 * if start = ON when isr = TRUE it could happen that the usercontext
+	 * could turn off the clocks while the interrupt is updating the
+	 * power to ON
+	 */
+	WARN_ON(isr == true && enable);
+
+	if (enable) {
+		atomic_inc(&clk_ref);
+	} else if (!atomic_add_unless(&clk_ref, -1, 0)) {
+		pr_debug("master power-off req\n");
+		force_off = 1;
+	}
+
+	if (isr) {
+		/* if it's power off send workqueue to turn off clocks */
+		if (mdss_res->clk_ena && !atomic_read(&clk_ref))
+			queue_delayed_work(mdss_res->clk_ctrl_wq,
+					   &mdss_res->clk_ctrl_worker,
+					   mdss_res->timeout);
+	} else {
+		mutex_lock(&clk_ctrl_lock);
+		if (delayed_work_pending(&mdss_res->clk_ctrl_worker))
+			cancel_delayed_work(&mdss_res->clk_ctrl_worker);
+
+		if (atomic_read(&clk_ref)) {
+			mdss_mdp_clk_ctrl_update(true);
+		} else if (mdss_res->clk_ena) {
+			mutex_lock(&mdp_suspend_mutex);
+			if (force_off || mdss_res->suspend) {
+				mdss_mdp_clk_ctrl_update(false);
+			} else {
+				/* send workqueue to turn off mdp power */
+				queue_delayed_work(mdss_res->clk_ctrl_wq,
+						   &mdss_res->clk_ctrl_worker,
+						   mdss_res->timeout);
+			}
+			mutex_unlock(&mdp_suspend_mutex);
+		}
+		mutex_unlock(&clk_ctrl_lock);
+	}
+}
+
+static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
+{
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
+static int mdss_mdp_irq_clk_setup(void)
+{
+	int ret;
+
+	ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
+			  "MDSS", 0);
+	if (ret) {
+		pr_err("mdp request_irq() failed!\n");
+		return ret;
+	}
+	disable_irq(mdss_res->irq);
+
+	mdss_res->fs = regulator_get(NULL, "fs_mdp");
+	if (IS_ERR(mdss_res->fs))
+		mdss_res->fs = NULL;
+	else {
+		regulator_enable(mdss_res->fs);
+		mdss_res->fs_ena = true;
+	}
+
+	return 0;
+}
+
+static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
+	struct device *dev)
+{
+	struct msm_panel_common_pdata *pdata;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		dev_err(dev, "could not allocate memory for pdata\n");
+	return pdata;
+}
+
+static u32 mdss_mdp_res_init(void)
+{
+	u32 rc;
+
+	rc = mdss_mdp_irq_clk_setup();
+	if (rc)
+		return rc;
+
+	mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
+	INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker,
+			  mdss_mdp_clk_ctrl_workqueue_handler);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
+	mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
+	mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
+	mdss_res->pipe_type_map = mdss_mdp_pipe_type_map;
+	mdss_res->mixer_type_map = mdss_mdp_mixer_type_map;
+
+	pr_info("mdss_revision=%x\n", mdss_res->rev);
+	pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev);
+
+	mdss_res->res_init = true;
+	mdss_res->timeout = HZ/20;
+	mdss_res->clk_ena = false;
+	mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
+	mdss_res->suspend = false;
+	mdss_res->prim_ptype = NO_PANEL;
+	mdss_res->irq_ena = false;
+
+	return 0;
+}
+
+static int mdss_mdp_probe(struct platform_device *pdev)
+{
+	struct resource *mdss_mdp_mres;
+	struct resource *mdss_mdp_ires;
+	resource_size_t size;
+	int rc;
+
+	if (!mdss_res) {
+		mdss_res = devm_kzalloc(&pdev->dev, sizeof(*mdss_res),
+				GFP_KERNEL);
+		if (mdss_res == NULL)
+			return -ENOMEM;
+	}
+
+	if (pdev->dev.of_node) {
+		pdev->id = 0;
+		mdp_pdata = mdss_mdp_populate_pdata(&pdev->dev);
+		mdss_mdp_mres = platform_get_resource(pdev,
+						IORESOURCE_MEM, 0);
+		mdss_mdp_ires = platform_get_resource(pdev,
+						IORESOURCE_IRQ, 0);
+		if (!mdss_mdp_mres || !mdss_mdp_ires) {
+			pr_err("unable to get the MDSS resources");
+			rc = -ENOMEM;
+			goto probe_done;
+		}
+		mdss_reg_base = ioremap(mdss_mdp_mres->start,
+					resource_size(mdss_mdp_mres));
+
+		pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+			(int) mdss_mdp_mres->start,
+			(int) mdss_reg_base);
+
+		mdss_res->irq = mdss_mdp_ires->start;
+	} else if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+		mdp_pdata = pdev->dev.platform_data;
+
+		size =  resource_size(&pdev->resource[0]);
+		mdss_reg_base = ioremap(pdev->resource[0].start, size);
+
+		pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+			(int) pdev->resource[0].start,
+			(int) mdss_reg_base);
+
+		mdss_res->irq = platform_get_irq(pdev, 0);
+		if (mdss_res->irq < 0) {
+			pr_err("can not get mdp irq\n");
+			rc = -ENOMEM;
+			goto probe_done;
+		}
+	}
+
+	if (unlikely(!mdss_reg_base)) {
+		rc = -ENOMEM;
+		goto probe_done;
+	}
+
+	rc = mdss_mdp_res_init();
+	if (rc) {
+		pr_err("unable to initialize mdss mdp resources\n");
+		goto probe_done;
+	}
+
+probe_done:
+	if (IS_ERR_VALUE(rc)) {
+		if (mdss_res) {
+			devm_kfree(&pdev->dev, mdss_res);
+			mdss_res = NULL;
+		}
+	}
+
+	return rc;
+}
+
+void mdss_mdp_footswitch_ctrl(int on)
+{
+	mutex_lock(&mdp_suspend_mutex);
+	if (!mdss_res->suspend || mdss_res->eintf_ena || !mdss_res->fs) {
+		mutex_unlock(&mdp_suspend_mutex);
+		return;
+	}
+
+	if (on && !mdss_res->fs_ena) {
+		pr_debug("Enable MDP FS\n");
+		regulator_enable(mdss_res->fs);
+		mdss_res->fs_ena = true;
+	} else if (!on && mdss_res->fs_ena) {
+		pr_debug("Disable MDP FS\n");
+		regulator_disable(mdss_res->fs);
+		mdss_res->fs_ena = false;
+	}
+	mutex_unlock(&mdp_suspend_mutex);
+}
+
+#ifdef CONFIG_PM
+static void mdss_mdp_suspend_sub(void)
+{
+	cancel_delayed_work(&mdss_res->clk_ctrl_worker);
+
+	flush_workqueue(mdss_res->clk_ctrl_wq);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mutex_lock(&mdp_suspend_mutex);
+	mdss_res->suspend = true;
+	mutex_unlock(&mdp_suspend_mutex);
+}
+
+static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	if (pdev->id == 0) {
+		mdss_mdp_suspend_sub();
+		if (mdss_res->clk_ena) {
+			pr_err("MDP suspend failed\n");
+			return -EBUSY;
+		}
+		mdss_mdp_footswitch_ctrl(false);
+	}
+	return 0;
+}
+
+static int mdss_mdp_resume(struct platform_device *pdev)
+{
+	mdss_mdp_footswitch_ctrl(true);
+	mutex_lock(&mdp_suspend_mutex);
+	mdss_res->suspend = false;
+	mutex_unlock(&mdp_suspend_mutex);
+	return 0;
+}
+#else
+#define mdss_mdp_suspend NULL
+#define mdss_mdp_resume NULL
+#endif
+
+static int mdss_mdp_remove(struct platform_device *pdev)
+{
+	if (mdss_res->fs != NULL)
+		regulator_put(mdss_res->fs);
+	iounmap(mdss_reg_base);
+	pm_runtime_disable(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id mdss_mdp_dt_match[] = {
+	{ .compatible = "qcom,mdss_mdp",},
+};
+MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);
+
+static struct platform_driver mdss_mdp_driver = {
+	.probe = mdss_mdp_probe,
+	.remove = mdss_mdp_remove,
+	.suspend = mdss_mdp_suspend,
+	.resume = mdss_mdp_resume,
+	.shutdown = NULL,
+	.driver = {
+		/*
+		 * Driver name must match the device name added in
+		 * platform.c.
+		 */
+		.name = "mdp",
+		.of_match_table = mdss_mdp_dt_match,
+	},
+};
+
+static int mdss_mdp_register_driver(void)
+{
+	return platform_driver_register(&mdss_mdp_driver);
+}
+
+static int __init mdss_mdp_driver_init(void)
+{
+	int ret;
+
+	ret = mdss_mdp_register_driver();
+	if (ret) {
+		pr_err("mdp_register_driver() failed!\n");
+		return ret;
+	}
+
+	return 0;
+
+}
+
+module_init(mdss_mdp_driver_init);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
new file mode 100644
index 0000000..39d6520
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -0,0 +1,289 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_MDP_H
+#define MDSS_MDP_H
+
+#include <linux/io.h>
+#include <linux/msm_mdp.h>
+#include <linux/platform_device.h>
+
+#include "mdss.h"
+#include "mdss_mdp_hwio.h"
+
+#define MDSS_MDP_DEFAULT_INTR_MASK 0
+#define MDSS_MDP_CURSOR_WIDTH 64
+#define MDSS_MDP_CURSOR_HEIGHT 64
+#define MDSS_MDP_CURSOR_SIZE (MDSS_MDP_CURSOR_WIDTH*MDSS_MDP_CURSOR_WIDTH*4)
+
+#define MDP_CLK_DEFAULT_RATE	37500000
+#define PHASE_STEP_SHIFT	21
+#define MAX_MIXER_WIDTH		2048
+#define MAX_MIXER_HEIGHT	2048
+#define MAX_IMG_WIDTH		0x3FFF
+#define MAX_IMG_HEIGHT		0x3FFF
+#define MIN_DST_W		10
+#define MIN_DST_H		10
+#define MAX_DST_W		MAX_MIXER_WIDTH
+#define MAX_DST_H		MAX_MIXER_HEIGHT
+#define MAX_PLANES		4
+#define MAX_DOWNSCALE_RATIO	4
+#define MAX_UPSCALE_RATIO	20
+
+#ifdef MDSS_MDP_DEBUG_REG
+static inline void mdss_mdp_reg_write(u32 addr, u32 val)
+{
+	pr_debug("0x%05X = 0x%08X\n", addr, val);
+	MDSS_REG_WRITE(addr, val);
+}
+#define MDSS_MDP_REG_WRITE(addr, val) mdss_mdp_reg_write((u32)addr, (u32)(val))
+static inline u32 mdss_mdp_reg_read(u32 addr)
+{
+	u32 val;
+	val = MDSS_REG_READ(addr);
+	pr_debug("0x%05X = 0x%08X\n", addr, val);
+	return val;
+}
+#define MDSS_MDP_REG_READ(addr) mdss_mdp_reg_read((u32)(addr))
+#else
+#define MDSS_MDP_REG_WRITE(addr, val)	MDSS_REG_WRITE((u32)(addr), (u32)(val))
+#define MDSS_MDP_REG_READ(addr)		MDSS_REG_READ((u32)(addr))
+#endif
+
+enum mdss_mdp_block_power_state {
+	MDP_BLOCK_POWER_OFF,
+	MDP_BLOCK_POWER_ON
+};
+
+enum mdss_mdp_mixer_type {
+	MDSS_MDP_MIXER_TYPE_UNUSED,
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_WRITEBACK,
+};
+
+enum mdss_mdp_mixer_mux {
+	MDSS_MDP_MIXER_MUX_DEFAULT,
+	MDSS_MDP_MIXER_MUX_LEFT,
+	MDSS_MDP_MIXER_MUX_RIGHT,
+};
+
+enum mdss_mdp_pipe_type {
+	MDSS_MDP_PIPE_TYPE_UNUSED,
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_DMA,
+};
+
+enum mdss_mdp_block_type {
+	MDSS_MDP_BLOCK_UNUSED,
+	MDSS_MDP_BLOCK_SSPP,
+	MDSS_MDP_BLOCK_MIXER,
+	MDSS_MDP_BLOCK_DSPP,
+	MDSS_MDP_BLOCK_WB,
+	MDSS_MDP_BLOCK_MAX
+};
+
+struct mdss_mdp_ctl {
+	u32 num;
+	u32 ref_cnt;
+
+	u32 intf_num;
+	u32 intf_type;
+
+	u32 opmode;
+	u32 flush_bits;
+
+	u32 play_cnt;
+
+	u16 width;
+	u16 height;
+
+	struct msm_fb_data_type *mfd;
+	struct mdss_mdp_mixer *mixer_left;
+	struct mdss_mdp_mixer *mixer_right;
+	struct mutex lock;
+
+	int (*start_fnc) (struct mdss_mdp_ctl *ctl);
+	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
+	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+	int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+
+	void *priv_data;
+};
+
+struct mdss_mdp_mixer {
+	u32 num;
+	u32 ref_cnt;
+	u8 type;
+	u8 params_changed;
+
+	u16 width;
+	u16 height;
+	u8 cursor_enabled;
+	u8 rotator_mode;
+
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
+};
+
+struct mdss_mdp_img_rect {
+	u16 x;
+	u16 y;
+	u16 w;
+	u16 h;
+};
+
+struct mdss_mdp_format_params {
+	u32 format;
+	u8 is_yuv;
+
+	u8 frame_format;
+	u8 chroma_sample;
+	u8 solid_fill;
+	u8 fetch_planes;
+	u8 unpack_align_msb;	/* 0 to LSB, 1 to MSB */
+	u8 unpack_tight;	/* 0 for loose, 1 for tight */
+	u8 unpack_count;	/* 0 = 1 component, 1 = 2 component ... */
+	u8 bpp;
+	u8 alpha_enable;	/*  source has alpha */
+
+	/*
+	 * number of bits for source component,
+	 * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
+	 */
+	u8 a_bit;	/* component 3, alpha */
+	u8 r_bit;	/* component 2, R_Cr */
+	u8 b_bit;	/* component 1, B_Cb */
+	u8 g_bit;	/* component 0, G_lumz */
+
+	/*
+	 * unpack pattern
+	 * A = C3, R = C2, B = C1, G = C0
+	 */
+	u8 element3;
+	u8 element2;
+	u8 element1;
+	u8 element0;
+};
+
+struct mdss_mdp_plane_sizes {
+	u32 num_planes;
+	u32 plane_size[MAX_PLANES];
+	u32 total_size;
+	u32 ystride[MAX_PLANES];
+};
+
+struct mdss_mdp_img_data {
+	u32 addr;
+	u32 len;
+	u32 flags;
+	int p_need;
+	struct file *srcp_file;
+	struct ion_handle *srcp_ihdl;
+	struct ion_client *iclient;
+};
+
+struct mdss_mdp_data {
+	u8 num_planes;
+	u8 bwc_enabled;
+	struct mdss_mdp_img_data p[MAX_PLANES];
+};
+
+struct mdss_mdp_pipe {
+	u32 num;
+	u32 type;
+	u32 ndx;
+	atomic_t ref_cnt;
+	u32 play_cnt;
+
+	u32 flags;
+	u32 bwc_mode;
+
+	u16 img_width;
+	u16 img_height;
+	struct mdss_mdp_img_rect src;
+	struct mdss_mdp_img_rect dst;
+
+	struct mdss_mdp_format_params *src_fmt;
+	struct mdss_mdp_plane_sizes src_planes;
+
+	u8 mixer_stage;
+	u8 is_fg;
+	u8 alpha;
+	u32 transp;
+
+	struct msm_fb_data_type *mfd;
+	struct mdss_mdp_mixer *mixer;
+	struct mutex lock;
+
+	struct mdp_overlay req_data;
+	u32 params_changed;
+
+	unsigned long smp[MAX_PLANES];
+};
+
+static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
+				      u32 reg, u32 val)
+{
+	int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
+	MDSS_MDP_REG_WRITE(offset + reg, val);
+}
+
+static inline u32 mdss_mdp_ctl_read(struct mdss_mdp_ctl *ctl, u32 reg)
+{
+	int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
+	return MDSS_MDP_REG_READ(offset + reg);
+}
+
+irqreturn_t mdss_mdp_isr(int irq, void *ptr);
+int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
+void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
+void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
+int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
+			       void (*fnc_ptr)(void *), void *arg);
+
+unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
+int mdss_mdp_vsync_clk_enable(int enable);
+void mdss_mdp_clk_ctrl(int enable, int isr);
+void mdss_mdp_footswitch_ctrl(int on);
+
+int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
+
+int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd);
+int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd);
+
+struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
+struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
+						int mux, int stage);
+int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
+int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
+struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx);
+int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe);
+
+int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd);
+int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
+			     struct mdss_mdp_data *src_data);
+
+int mdss_mdp_data_check(struct mdss_mdp_data *data,
+			struct mdss_mdp_plane_sizes *ps);
+int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
+			     struct mdss_mdp_plane_sizes *ps);
+struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
+
+#endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
new file mode 100644
index 0000000..182cffc
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -0,0 +1,598 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/errno.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+static DEFINE_MUTEX(mdss_mdp_ctl_lock);
+static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
+static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
+
+static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(void)
+{
+	struct mdss_mdp_ctl *ctl = NULL;
+	int cnum;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
+		if (mdss_mdp_ctl_list[cnum].ref_cnt == 0) {
+			ctl = &mdss_mdp_ctl_list[cnum];
+			ctl->num = cnum;
+			ctl->ref_cnt++;
+			mutex_init(&ctl->lock);
+
+			pr_debug("alloc ctl_num=%d\n", ctl->num);
+			break;
+		}
+	}
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return ctl;
+}
+
+static int mdss_mdp_ctl_free(struct mdss_mdp_ctl *ctl)
+{
+	if (!ctl)
+		return -ENODEV;
+
+	pr_debug("free ctl_num=%d ref_cnt=%d\n", ctl->num, ctl->ref_cnt);
+
+	if (!ctl->ref_cnt) {
+		pr_err("called with ref_cnt=0\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	if (--ctl->ref_cnt == 0)
+		memset(ctl, 0, sizeof(*ctl));
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return 0;
+}
+
+static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(u32 type)
+{
+	struct mdss_mdp_mixer *mixer = NULL;
+	int mnum;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	for (mnum = 0; mnum < MDSS_MDP_MAX_LAYERMIXER; mnum++) {
+		if (type == mdss_res->mixer_type_map[mnum] &&
+		    mdss_mdp_mixer_list[mnum].ref_cnt == 0) {
+			mixer = &mdss_mdp_mixer_list[mnum];
+			mixer->num = mnum;
+			mixer->ref_cnt++;
+			mixer->params_changed++;
+			mixer->type = type;
+
+			pr_debug("mixer_num=%d\n", mixer->num);
+			break;
+		}
+	}
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return mixer;
+}
+
+static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer)
+{
+	if (!mixer)
+		return -ENODEV;
+
+	pr_debug("free mixer_num=%d ref_cnt=%d\n", mixer->num, mixer->ref_cnt);
+
+	if (!mixer->ref_cnt) {
+		pr_err("called with ref_cnt=0\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	if (--mixer->ref_cnt == 0)
+		memset(mixer, 0, sizeof(*mixer));
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return 0;
+}
+
+static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_ctl *ctl;
+	u32 width, height;
+
+	if (!mfd)
+		return -ENODEV;
+
+	width = mfd->fbi->var.xres;
+	height = mfd->fbi->var.yres;
+
+	if (width > (2 * MAX_MIXER_WIDTH)) {
+		pr_err("unsupported resolution\n");
+		return -EINVAL;
+	}
+
+	ctl = mdss_mdp_ctl_alloc();
+
+	if (!ctl) {
+		pr_err("unable to allocate ctl\n");
+		return -ENOMEM;
+	}
+
+	ctl->mfd = mfd;
+	ctl->width = width;
+	ctl->height = height;
+
+	ctl->mixer_left = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+	if (!ctl->mixer_left) {
+		pr_err("unable to allocate layer mixer\n");
+		mdss_mdp_ctl_free(ctl);
+		return -ENOMEM;
+	}
+
+	ctl->mixer_left->width = MIN(width, MAX_MIXER_WIDTH);
+	ctl->mixer_left->height = height;
+	ctl->mixer_left->ctl = ctl;
+
+	width -= ctl->mixer_left->width;
+
+	if (width) {
+		ctl->mixer_right =
+		mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+		if (!ctl->mixer_right) {
+			pr_err("unable to allocate layer mixer\n");
+			mdss_mdp_mixer_free(ctl->mixer_left);
+			mdss_mdp_ctl_free(ctl);
+			return -ENOMEM;
+		}
+		ctl->mixer_right->width = width;
+		ctl->mixer_right->height = height;
+		ctl->mixer_right->ctl = ctl;
+	}
+
+	switch (mfd->panel_info.type) {
+	case WRITEBACK_PANEL:
+		ctl->intf_num = MDSS_MDP_NO_INTF;
+		ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
+		break;
+	default:
+		pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
+		mdss_mdp_ctl_free(ctl);
+		return -EINVAL;
+
+	}
+
+	ctl->opmode |= (ctl->intf_num << 4);
+
+	if (ctl->mixer_right) {
+		ctl->opmode |= MDSS_MDP_CTL_OP_PACK_3D_ENABLE |
+			       MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT;
+	}
+
+	mfd->ctl = ctl;
+
+	return 0;
+}
+
+static int mdss_mdp_ctl_destroy(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_ctl *ctl;
+	if (!mfd || !mfd->ctl)
+		return -ENODEV;
+
+	ctl = mfd->ctl;
+	mfd->ctl = NULL;
+
+	if (ctl->mixer_left)
+		mdss_mdp_mixer_free(ctl->mixer_left);
+	if (ctl->mixer_right)
+		mdss_mdp_mixer_free(ctl->mixer_right);
+	mdss_mdp_ctl_free(ctl);
+
+	return 0;
+}
+
+int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd)
+{
+	struct mdss_panel_data *pdata;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_mixer *mixer;
+	u32 outsize, temp, off;
+	int ret = 0;
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected\n");
+		return -ENODEV;
+	}
+
+	if (!mfd->ctl) {
+		if (mdss_mdp_ctl_init(mfd)) {
+			pr_err("unable to initialize ctl\n");
+			return -ENODEV;
+		}
+	}
+	ctl = mfd->ctl;
+
+	mutex_lock(&ctl->lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (ctl->start_fnc)
+		ret = ctl->start_fnc(ctl);
+	else
+		pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
+				mfd->panel_info.type);
+
+	if (ret) {
+		pr_err("unable to start intf\n");
+		goto start_fail;
+	}
+
+	pr_debug("ctl_num=%d\n", ctl->num);
+
+	mixer = ctl->mixer_left;
+	mixer->params_changed++;
+
+	temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
+	temp |= (ctl->intf_type << (ctl->intf_num * 8));
+	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_DISP_INTF_SEL, temp);
+
+	outsize = (mixer->height << 16) | mixer->width;
+	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+
+	if (ctl->mixer_right) {
+		mixer = ctl->mixer_right;
+		mixer->params_changed++;
+		outsize = (mixer->height << 16) | mixer->width;
+		off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
+	}
+
+	ret = pdata->on(pdata);
+
+start_fail:
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	mutex_unlock(&ctl->lock);
+
+	return ret;
+}
+
+int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd)
+{
+	struct mdss_panel_data *pdata;
+	struct mdss_mdp_ctl *ctl;
+	int ret = 0;
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (!mfd->ctl) {
+		pr_err("ctl not initialized\n");
+		return -ENODEV;
+	}
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected\n");
+		return -ENODEV;
+	}
+
+	ctl = mfd->ctl;
+
+	pr_debug("ctl_num=%d\n", mfd->ctl->num);
+
+	mutex_lock(&ctl->lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (ctl->stop_fnc)
+		ret = ctl->stop_fnc(ctl);
+	else
+		pr_warn("no stop func for ctl=%d\n", ctl->num);
+
+	if (ret)
+		pr_warn("error powering off intf ctl=%d\n", ctl->num);
+
+	ret = pdata->off(pdata);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	ctl->play_cnt = 0;
+	mutex_unlock(&ctl->lock);
+
+	mdss_mdp_pipe_release_all(mfd);
+
+	if (!mfd->ref_cnt)
+		mdss_mdp_ctl_destroy(mfd);
+
+
+	return ret;
+}
+
+static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
+				struct mdss_mdp_mixer *mixer)
+{
+	struct mdss_mdp_pipe *pipe, *bgpipe = NULL;
+	u32 off, blend_op, blend_stage;
+	u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
+	int stage;
+
+	if (!mixer)
+		return -ENODEV;
+
+	pr_debug("setup mixer=%d\n", mixer->num);
+
+	for (stage = MDSS_MDP_STAGE_BASE; stage < MDSS_MDP_MAX_STAGE; stage++) {
+		pipe = mixer->stage_pipe[stage];
+		if (pipe == NULL) {
+			if (stage == MDSS_MDP_STAGE_BASE)
+				mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
+			continue;
+		}
+
+		if (stage != pipe->mixer_stage) {
+			mixer->stage_pipe[stage] = NULL;
+			continue;
+		}
+		mixercfg |= stage << (3 * pipe->num);
+
+		if (stage == MDSS_MDP_STAGE_BASE) {
+			bgpipe = pipe;
+			if (pipe->src_fmt->alpha_enable)
+				bgalpha = 1;
+			continue;
+		}
+
+		blend_stage = stage - MDSS_MDP_STAGE_0;
+		off = MDSS_MDP_REG_LM_OFFSET(mixer->num) +
+		      MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);
+
+		if (pipe->is_fg) {
+			bgalpha = 0;
+			if (bgpipe) {
+				mixercfg &= ~(0x7 << (3 * bgpipe->num));
+				mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
+			}
+			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+			/* keep fg alpha */
+			blend_color_out |= 1 << (blend_stage + 1);
+
+			pr_debug("pnum=%d stg=%d alpha=IS_FG\n", pipe->num,
+					stage);
+		} else if (pipe->src_fmt->alpha_enable) {
+			bgalpha = 0;
+			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL |
+				    MDSS_MDP_BLEND_BG_INV_ALPHA);
+			/* keep fg alpha */
+			blend_color_out |= 1 << (blend_stage + 1);
+
+			pr_debug("pnum=%d stg=%d alpha=FG PIXEL\n", pipe->num,
+					stage);
+		} else if (bgalpha) {
+			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL |
+				    MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL |
+				    MDSS_MDP_BLEND_FG_INV_ALPHA);
+			/* keep bg alpha */
+			pr_debug("pnum=%d stg=%d alpha=BG_PIXEL\n", pipe->num,
+					stage);
+		} else {
+			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+			pr_debug("pnum=%d stg=%d alpha=CONST\n", pipe->num,
+					stage);
+		}
+
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
+				   pipe->alpha);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA,
+				   0xFF - pipe->alpha);
+	}
+
+	if (mixer->cursor_enabled)
+		mixercfg |= MDSS_MDP_LM_CURSOR_OUT;
+
+	pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
+
+	ctl->flush_bits |= BIT(6) << mixer->num;	/* LAYER_MIXER */
+
+	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(mixer->num), mixercfg);
+
+	return 0;
+}
+
+struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
+{
+	struct mdss_mdp_mixer *mixer = NULL;
+	if (!ctl)
+		return NULL;
+
+	switch (mux) {
+	case MDSS_MDP_MIXER_MUX_DEFAULT:
+	case MDSS_MDP_MIXER_MUX_LEFT:
+		mixer = ctl->mixer_left;
+		break;
+	case MDSS_MDP_MIXER_MUX_RIGHT:
+		mixer = ctl->mixer_right;
+		break;
+	}
+
+	return mixer;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
+						int mux, int stage)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	struct mdss_mdp_mixer *mixer;
+	if (!ctl)
+		return NULL;
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return NULL;
+
+	mixer = mdss_mdp_mixer_get(ctl, mux);
+	if (mixer)
+		pipe = mixer->stage_pipe[stage];
+	mutex_unlock(&ctl->lock);
+
+	return pipe;
+}
+
+int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)
+{
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_mixer *mixer;
+
+	if (!pipe)
+		return -EINVAL;
+	mixer = pipe->mixer;
+	if (!mixer)
+		return -EINVAL;
+	ctl = mixer->ctl;
+	if (!ctl)
+		return -EINVAL;
+
+	if (pipe->mixer_stage >= MDSS_MDP_MAX_STAGE) {
+		pr_err("invalid mixer stage\n");
+		return -EINVAL;
+	}
+
+	pr_debug("pnum=%x mixer=%d stage=%d\n", pipe->num, mixer->num,
+			pipe->mixer_stage);
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return -EINTR;
+
+	if (params_changed) {
+		mixer->params_changed++;
+		mixer->stage_pipe[pipe->mixer_stage] = pipe;
+	}
+
+	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
+		ctl->flush_bits |= BIT(pipe->num) << 5;
+	else /* RGB/VIG pipe */
+		ctl->flush_bits |= BIT(pipe->num);
+
+	mutex_unlock(&ctl->lock);
+
+	return 0;
+}
+
+int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe)
+{
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_mixer *mixer;
+
+	if (!pipe)
+		return -EINVAL;
+	mixer = pipe->mixer;
+	if (!mixer)
+		return -EINVAL;
+	ctl = mixer->ctl;
+	if (!ctl)
+		return -EINVAL;
+
+	pr_debug("unstage pnum=%d stage=%d mixer=%d\n", pipe->num,
+			pipe->mixer_stage, mixer->num);
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return -EINTR;
+
+	mixer->params_changed++;
+	mixer->stage_pipe[pipe->mixer_stage] = NULL;
+
+	mutex_unlock(&ctl->lock);
+
+	return 0;
+}
+
+static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer)
+{
+	mixer->params_changed = 0;
+
+	/* skip mixer setup for rotator */
+	if (!mixer->rotator_mode)
+		mdss_mdp_mixer_setup(mixer->ctl, mixer);
+
+	return 0;
+}
+
+int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	int mixer1_changed, mixer2_changed;
+	int ret = 0;
+
+	if (!ctl) {
+		pr_err("display function not set\n");
+		return -ENODEV;
+	}
+
+	pr_debug("commit ctl=%d\n", ctl->num);
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return -EINTR;
+
+	mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed);
+	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (mixer1_changed || mixer2_changed) {
+		if (ctl->prepare_fnc)
+			ret = ctl->prepare_fnc(ctl, arg);
+		if (ret) {
+			pr_err("error preparing display\n");
+			goto done;
+		}
+
+		if (mixer1_changed)
+			mdss_mdp_mixer_update(ctl->mixer_left);
+		if (mixer2_changed)
+			mdss_mdp_mixer_update(ctl->mixer_right);
+
+		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode);
+		ctl->flush_bits |= BIT(17);	/* CTL */
+	}
+
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
+	wmb();
+	ctl->flush_bits = 0;
+
+	if (ctl->display_fnc)
+		ret = ctl->display_fnc(ctl, arg); /* kickoff */
+	if (ret)
+		pr_warn("error displaying frame\n");
+
+	ctl->play_cnt++;
+
+done:
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mutex_unlock(&ctl->lock);
+
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
new file mode 100644
index 0000000..07eefc1
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -0,0 +1,328 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_MDP_FORMATS_H
+#define MDSS_MDP_FORMATS_H
+
+#include <linux/msm_mdp.h>
+
+#include "mdss_mdp.h"
+
+#define C3_ALPHA	3	/* alpha */
+#define C2_R_Cr		2	/* R/Cr */
+#define C1_B_Cb		1	/* B/Cb */
+#define C0_G_Y		0	/* G/luma */
+
+static struct mdss_mdp_format_params mdss_mdp_format_map[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = {
+		.format = MDP_RGB_565,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 0,
+		.r_bit = 1,	/* R, 5 bits */
+		.b_bit = 1,	/* B, 5 bits */
+		.g_bit = 2,	/* G, 6 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 2,
+		.element2 = C2_R_Cr,
+		.element1 = C0_G_Y,
+		.element0 = C1_B_Cb,
+		.bpp = 1,	/* 2 bpp */
+	},
+	[MDP_BGR_565] = {
+		.format = MDP_BGR_565,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 0,
+		.r_bit = 1,	/* R, 5 bits */
+		.b_bit = 1,	/* B, 5 bits */
+		.g_bit = 2,	/* G, 6 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 2,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 1,	/* 2 bpp */
+	},
+	[MDP_RGB_888] = {
+		.format = MDP_RGB_888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 2,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 2,	/* 3 bpp */
+	},
+	[MDP_XRGB_8888] = {
+		.format = MDP_XRGB_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C1_B_Cb,
+		.element2 = C0_G_Y,
+		.element1 = C2_R_Cr,
+		.element0 = C3_ALPHA,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_ARGB_8888] = {
+		.format = MDP_ARGB_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 1,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C1_B_Cb,
+		.element2 = C0_G_Y,
+		.element1 = C2_R_Cr,
+		.element0 = C3_ALPHA,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_RGBA_8888] = {
+		.format = MDP_RGBA_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 1,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C3_ALPHA,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_RGBX_8888] = {
+		.format = MDP_RGBX_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C3_ALPHA,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_BGRA_8888] = {
+		.format = MDP_BGRA_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 1,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C3_ALPHA,
+		.element2 = C2_R_Cr,
+		.element1 = C0_G_Y,
+		.element0 = C1_B_Cb,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_YCRYCB_H2V1] = {
+		.format = MDP_YCRYCB_H2V1,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
+		.unpack_count = 3,
+		.element3 = C0_G_Y,
+		.element2 = C2_R_Cr,
+		.element1 = C0_G_Y,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CRCB_H2V1] = {
+		.format = MDP_Y_CRCB_H2V1,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
+		.element1 = C1_B_Cb,
+		.element0 = C2_R_Cr,
+	},
+	[MDP_Y_CBCR_H2V1] = {
+		.format = MDP_Y_CBCR_H2V1,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
+		.element1 = C2_R_Cr,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CRCB_H1V2] = {
+		.format = MDP_Y_CRCB_H1V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H1V2,
+		.element1 = C1_B_Cb,
+		.element0 = C2_R_Cr,
+	},
+	[MDP_Y_CBCR_H1V2] = {
+		.format = MDP_Y_CBCR_H1V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H1V2,
+		.element1 = C2_R_Cr,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CRCB_H2V2] = {
+		.format = MDP_Y_CRCB_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+		.element1 = C1_B_Cb,
+		.element0 = C2_R_Cr,
+	},
+	[MDP_Y_CBCR_H2V2] = {
+		.format = MDP_Y_CBCR_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+		.element1 = C2_R_Cr,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CR_CB_H2V2] = {
+		.format = MDP_Y_CR_CB_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+	},
+	[MDP_Y_CB_CR_H2V2] = {
+		.format = MDP_Y_CB_CR_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+	},
+	[MDP_Y_CR_CB_GH2V2] = {
+		.format = MDP_Y_CR_CB_GH2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+	},
+};
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
new file mode 100644
index 0000000..4ca1dce
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -0,0 +1,430 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_MDP_HWIO_H
+#define MDSS_MDP_HWIO_H
+
+#include <linux/bitops.h>
+
+#define MDSS_REG_HW_VERSION				0x0
+#define MDSS_REG_HW_INTR_STATUS				0x10
+
+#define MDSS_INTR_MDP				BIT(0)
+#define MDSS_INTR_DSI0				BIT(4)
+#define MDSS_INTR_DSI1				BIT(5)
+#define MDSS_INTR_HDMI				BIT(8)
+#define MDSS_INTR_EDP				BIT(12)
+
+#define MDSS_MDP_REG_HW_VERSION				0x00100
+#define MDSS_MDP_REG_DISP_INTF_SEL			0x00104
+#define MDSS_MDP_REG_INTR_EN				0x00110
+#define MDSS_MDP_REG_INTR_STATUS			0x00114
+#define MDSS_MDP_REG_INTR_CLEAR				0x00118
+#define MDSS_MDP_REG_HIST_INTR_EN			0x0011C
+#define MDSS_MDP_REG_HIST_INTR_STATUS			0x00120
+#define MDSS_MDP_REG_HIST_INTR_CLEAR			0x00124
+
+#define MDSS_INTF_DSI	0x1
+#define MDSS_INTF_HDMI	0x3
+#define MDSS_INTF_LCDC	0x5
+#define MDSS_INTF_EDP	0x9
+
+#define MDSS_MDP_INTR_WB_0_DONE				BIT(0)
+#define MDSS_MDP_INTR_WB_1_DONE				BIT(1)
+#define MDSS_MDP_INTR_WB_2_DONE				BIT(4)
+#define MDSS_MDP_INTR_PING_PONG_0_DONE			BIT(8)
+#define MDSS_MDP_INTR_PING_PONG_1_DONE			BIT(9)
+#define MDSS_MDP_INTR_PING_PONG_2_DONE			BIT(10)
+#define MDSS_MDP_INTR_PING_PONG_0_RD_PTR		BIT(12)
+#define MDSS_MDP_INTR_PING_PONG_1_RD_PTR		BIT(13)
+#define MDSS_MDP_INTR_PING_PONG_2_RD_PTR		BIT(14)
+#define MDSS_MDP_INTR_PING_PONG_0_WR_PTR		BIT(16)
+#define MDSS_MDP_INTR_PING_PONG_1_WR_PTR		BIT(17)
+#define MDSS_MDP_INTR_PING_PONG_2_WR_PTR		BIT(18)
+#define MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE	BIT(20)
+#define MDSS_MDP_INTR_PING_PONG_1_AUTOREFRESH_DONE	BIT(21)
+#define MDSS_MDP_INTR_PING_PONG_2_AUTOREFRESH_DONE	BIT(22)
+#define MDSS_MDP_INTR_INTF_0_UNDERRUN			BIT(24)
+#define MDSS_MDP_INTR_INTF_0_VSYNC			BIT(25)
+#define MDSS_MDP_INTR_INTF_1_UNDERRUN			BIT(26)
+#define MDSS_MDP_INTR_INTF_1_VSYNC			BIT(27)
+#define MDSS_MDP_INTR_INTF_2_UNDERRUN			BIT(28)
+#define MDSS_MDP_INTR_INTF_2_VSYNC			BIT(29)
+#define MDSS_MDP_INTR_INTF_3_UNDERRUN			BIT(30)
+#define MDSS_MDP_INTR_INTF_3_VSYNC			BIT(31)
+
+enum mdss_mdp_intr_type {
+	MDSS_MDP_IRQ_WB_ROT_COMP = 0,
+	MDSS_MDP_IRQ_WB_WFD = 4,
+	MDSS_MDP_IRQ_PING_PONG_COMP = 8,
+	MDSS_MDP_IRQ_PING_PONG_RD_PTR = 12,
+	MDSS_MDP_IRQ_PING_PONG_WR_PTR = 16,
+	MDSS_MDP_IRQ_PING_PONG_AUTO_REF = 20,
+	MDSS_MDP_IRQ_INTF_UNDER_RUN = 24,
+	MDSS_MDP_IRQ_INTF_VSYNC = 25,
+};
+
+enum mdss_mdp_ctl_index {
+	MDSS_MDP_CTL0,
+	MDSS_MDP_CTL1,
+	MDSS_MDP_CTL2,
+	MDSS_MDP_CTL3,
+	MDSS_MDP_CTL4,
+	MDSS_MDP_MAX_CTL
+};
+
+#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
+
+#define MDSS_MDP_REG_CTL_LAYER(lm)			((lm) * 0x004)
+#define MDSS_MDP_REG_CTL_TOP				0x014
+#define MDSS_MDP_REG_CTL_FLUSH				0x018
+#define MDSS_MDP_REG_CTL_START				0x01C
+#define MDSS_MDP_REG_CTL_PACK_3D			0x020
+
+#define MDSS_MDP_CTL_OP_VIDEO_MODE		(0 << 17)
+#define MDSS_MDP_CTL_OP_CMD_MODE		(1 << 17)
+
+#define MDSS_MDP_CTL_OP_ROT0_MODE		0x1
+#define MDSS_MDP_CTL_OP_ROT1_MODE		0x2
+#define MDSS_MDP_CTL_OP_WB0_MODE		0x3
+#define MDSS_MDP_CTL_OP_WB1_MODE		0x4
+#define MDSS_MDP_CTL_OP_WFD_MODE		0x5
+
+#define MDSS_MDP_CTL_OP_PACK_3D_ENABLE		BIT(19)
+#define MDSS_MDP_CTL_OP_PACK_3D_FRAME_INT	(0 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT	(1 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_V_ROW_INT	(2 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_COL_INT		(3 << 20)
+
+enum mdss_mdp_sspp_index {
+	MDSS_MDP_SSPP_VIG0,
+	MDSS_MDP_SSPP_VIG1,
+	MDSS_MDP_SSPP_VIG2,
+	MDSS_MDP_SSPP_RGB0,
+	MDSS_MDP_SSPP_RGB1,
+	MDSS_MDP_SSPP_RGB2,
+	MDSS_MDP_SSPP_DMA0,
+	MDSS_MDP_SSPP_DMA1,
+	MDSS_MDP_MAX_SSPP
+};
+
+enum mdss_mdp_sspp_fetch_type {
+	MDSS_MDP_PLANE_INTERLEAVED,
+	MDSS_MDP_PLANE_PLANAR,
+	MDSS_MDP_PLANE_PSEUDO_PLANAR,
+};
+
+enum mdss_mdp_sspp_chroma_samp_type {
+	MDSS_MDP_CHROMA_RGB,
+	MDSS_MDP_CHROMA_H2V1,
+	MDSS_MDP_CHROMA_H1V2,
+	MDSS_MDP_CHROMA_420
+};
+
+#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
+
+#define MDSS_MDP_REG_SSPP_SRC_SIZE			0x000
+#define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE			0x004
+#define MDSS_MDP_REG_SSPP_SRC_XY			0x008
+#define MDSS_MDP_REG_SSPP_OUT_SIZE			0x00C
+#define MDSS_MDP_REG_SSPP_OUT_XY			0x010
+#define MDSS_MDP_REG_SSPP_SRC0_ADDR			0x014
+#define MDSS_MDP_REG_SSPP_SRC1_ADDR			0x018
+#define MDSS_MDP_REG_SSPP_SRC2_ADDR			0x01C
+#define MDSS_MDP_REG_SSPP_SRC3_ADDR			0x020
+#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE0			0x024
+#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE1			0x028
+#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE		0x02C
+#define MDSS_MDP_REG_SSPP_SRC_FORMAT			0x030
+#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN		0x034
+
+#define MDSS_MDP_REG_SSPP_SRC_OP_MODE			0x038
+#define MDSS_MDP_OP_DEINTERLACE			BIT(22)
+#define MDSS_MDP_OP_DEINTERLACE_ODD		BIT(23)
+#define MDSS_MDP_OP_FLIP_UD			BIT(14)
+#define MDSS_MDP_OP_FLIP_LR			BIT(13)
+#define MDSS_MDP_OP_BWC_EN			BIT(0)
+#define MDSS_MDP_OP_BWC_LOSSLESS		(0 << 1)
+#define MDSS_MDP_OP_BWC_Q_HIGH			(1 << 1)
+#define MDSS_MDP_OP_BWC_Q_MED			(2 << 1)
+
+#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR		0x03C
+#define MDSS_MDP_REG_SSPP_FETCH_CONFIG			0x048
+#define MDSS_MDP_REG_SSPP_VC1_RANGE			0x04C
+
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC0_ADDR		0x0A4
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC1_ADDR		0x0A8
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR		0x0AC
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR		0x0B0
+#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C03		0x0B4
+#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C12		0x0B8
+
+#define MDSS_MDP_REG_VIG_OP_MODE			0x200
+#define MDSS_MDP_REG_VIG_QSEED2_CONFIG			0x204
+#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX		0x210
+#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY		0x214
+#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX		0x218
+#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY		0x21C
+#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX		0x220
+#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY		0x224
+#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX		0x228
+#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY		0x22C
+
+#define MDSS_MDP_REG_SCALE_CONFIG			0x204
+#define MDSS_MDP_REG_SCALE_PHASE_STEP_X			0x210
+#define MDSS_MDP_REG_SCALE_PHASE_STEP_Y			0x214
+#define MDSS_MDP_REG_SCALE_INIT_PHASE_X			0x220
+#define MDSS_MDP_REG_SCALE_INIT_PHASE_Y			0x224
+
+#define MDSS_MDP_REG_VIG_CSC_0_BASE			0x280
+#define MDSS_MDP_REG_VIG_CSC_1_BASE			0x320
+
+#define MDSS_MDP_SCALE_FILTER_NEAREST		0x0
+#define MDSS_MDP_SCALE_FILTER_BIL		0x1
+#define MDSS_MDP_SCALE_FILTER_PCMN		0x2
+#define MDSS_MDP_SCALE_FILTER_CA		0x3
+#define MDSS_MDP_SCALEY_EN			BIT(1)
+#define MDSS_MDP_SCALEX_EN			BIT(0)
+
+#define MDSS_MDP_NUM_REG_MIXERS 3
+#define MDSS_MDP_NUM_WB_MIXERS 2
+
+enum mdss_mdp_mixer_index {
+	MDSS_MDP_LAYERMIXER0,
+	MDSS_MDP_LAYERMIXER1,
+	MDSS_MDP_LAYERMIXER2,
+	MDSS_MDP_LAYERMIXER3,
+	MDSS_MDP_LAYERMIXER4,
+	MDSS_MDP_MAX_LAYERMIXER
+};
+
+enum mdss_mdp_stage_index {
+	MDSS_MDP_STAGE_UNUSED,
+	MDSS_MDP_STAGE_BASE,
+	MDSS_MDP_STAGE_0,
+	MDSS_MDP_STAGE_1,
+	MDSS_MDP_STAGE_2,
+	MDSS_MDP_STAGE_3,
+	MDSS_MDP_MAX_STAGE
+};
+
+enum mdss_mdp_blend_index {
+	MDSS_MDP_BLEND_STAGE0,
+	MDSS_MDP_BLEND_STAGE1,
+	MDSS_MDP_BLEND_STAGE2,
+	MDSS_MDP_BLEND_STAGE3,
+	MDSS_MDP_MAX_BLEND_STAGE,
+};
+
+#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
+
+#define MDSS_MDP_REG_LM_OP_MODE				0x000
+#define MDSS_MDP_REG_LM_OUT_SIZE			0x004
+#define MDSS_MDP_REG_LM_BORDER_COLOR_0			0x008
+#define MDSS_MDP_REG_LM_BORDER_COLOR_1			0x010
+
+#define MDSS_MDP_REG_LM_BLEND_OFFSET(stage)	(0x20 + ((stage) * 0x30))
+#define MDSS_MDP_REG_LM_BLEND_OP			0x00
+#define MDSS_MDP_REG_LM_BLEND_FG_ALPHA			0x04
+#define MDSS_MDP_REG_LM_BLEND_BG_ALPHA			0x08
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW0		0x0C
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW1		0x10
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH0		0x14
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH1		0x18
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW0		0x1C
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW1		0x20
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH0		0x24
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH1		0x28
+
+#define MDSS_MDP_REG_LM_CURSOR_IMG_SIZE			0xE0
+#define MDSS_MDP_REG_LM_CURSOR_SIZE			0xE4
+#define MDSS_MDP_REG_LM_CURSOR_XY			0xE8
+#define MDSS_MDP_REG_LM_CURSOR_STRIDE			0xDC
+#define MDSS_MDP_REG_LM_CURSOR_FORMAT			0xEC
+#define MDSS_MDP_REG_LM_CURSOR_BASE_ADDR		0xF0
+#define MDSS_MDP_REG_LM_CURSOR_START_XY			0xF4
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG		0xF8
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM		0xFC
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0	0x100
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1	0x104
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0	0x108
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1	0x10C
+
+#define MDSS_MDP_LM_BORDER_COLOR		(1 << 24)
+#define MDSS_MDP_LM_CURSOR_OUT			(1 << 25)
+#define MDSS_MDP_BLEND_FG_ALPHA_FG_CONST	(0 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_BG_CONST	(1 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_FG_PIXEL	(2 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL	(3 << 0)
+#define MDSS_MDP_BLEND_FG_INV_ALPHA		(1 << 2)
+#define MDSS_MDP_BLEND_FG_MOD_ALPHA		(1 << 3)
+#define MDSS_MDP_BLEND_FG_INV_MOD_ALPHA		(1 << 4)
+#define MDSS_MDP_BLEND_FG_TRANSP_EN		(1 << 5)
+#define MDSS_MDP_BLEND_BG_ALPHA_FG_CONST	(0 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_BG_CONST	(1 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL	(2 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL	(3 << 8)
+#define MDSS_MDP_BLEND_BG_INV_ALPHA		(1 << 10)
+#define MDSS_MDP_BLEND_BG_MOD_ALPHA		(1 << 11)
+#define MDSS_MDP_BLEND_BG_INV_MOD_ALPHA		(1 << 12)
+#define MDSS_MDP_BLEND_BG_TRANSP_EN		(1 << 13)
+
+enum mdss_mdp_writeback_index {
+	MDSS_MDP_WRITEBACK0,
+	MDSS_MDP_WRITEBACK1,
+	MDSS_MDP_WRITEBACK2,
+	MDSS_MDP_WRITEBACK3,
+	MDSS_MDP_WRITEBACK4,
+	MDSS_MDP_MAX_WRITEBACK
+};
+
+#define MDSS_MDP_REG_WB_OFFSET(wb)	(0x11100 + ((wb) * 0x2000))
+
+#define MDSS_MDP_REG_WB_DST_FORMAT			0x000
+#define MDSS_MDP_REG_WB_DST_OP_MODE			0x004
+#define MDSS_MDP_REG_WB_DST_PACK_PATTERN		0x008
+#define MDSS_MDP_REG_WB_DST0_ADDR			0x00C
+#define MDSS_MDP_REG_WB_DST1_ADDR			0x010
+#define MDSS_MDP_REG_WB_DST2_ADDR			0x014
+#define MDSS_MDP_REG_WB_DST3_ADDR			0x018
+#define MDSS_MDP_REG_WB_DST_YSTRIDE0			0x01C
+#define MDSS_MDP_REG_WB_DST_YSTRIDE1			0x020
+#define MDSS_MDP_REG_WB_DST_YSTRIDE1			0x020
+#define MDSS_MDP_REG_WB_DST_DITHER_BITDEPTH		0x024
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW0			0x030
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW1			0x034
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW2			0x038
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW3			0x03C
+#define MDSS_MDP_REG_WB_ROTATION_DNSCALER		0x050
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C03		0x060
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C12		0x064
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C03		0x068
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C12		0x06C
+#define MDSS_MDP_REG_WB_OUT_SIZE			0x074
+#define MDSS_MDP_REG_WB_ALPHA_X_VALUE			0x078
+#define MDSS_MDP_REG_WB_CSC_BASE			0x260
+
+enum mdss_mdp_dspp_index {
+	MDSS_MDP_DSPP0,
+	MDSS_MDP_DSPP1,
+	MDSS_MDP_DSPP2,
+	MDSS_MDP_MAX_DSPP
+};
+
+enum mdss_mpd_intf_index {
+	MDSS_MDP_NO_INTF,
+	MDSS_MDP_INTF0,
+	MDSS_MDP_INTF1,
+	MDSS_MDP_INTF2,
+	MDSS_MDP_INTF3,
+	MDSS_MDP_MAX_INTF
+};
+
+#define MDSS_MDP_REG_INTF_OFFSET(intf)		(0x20F00 + ((intf) * 0x200))
+
+#define MDSS_MDP_REG_INTF_TIMING_ENGINE_EN		0x000
+#define MDSS_MDP_REG_INTF_CONFIG			0x004
+#define MDSS_MDP_REG_INTF_HSYNC_CTL			0x008
+#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0		0x00C
+#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F1		0x010
+#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0		0x014
+#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F1		0x018
+#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F0		0x01C
+#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F1		0x020
+#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F0		0x024
+#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F1		0x028
+#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F0		0x02C
+#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F1		0x030
+#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F0		0x034
+#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F1		0x038
+#define MDSS_MDP_REG_INTF_DISPLAY_HCTL			0x03C
+#define MDSS_MDP_REG_INTF_ACTIVE_HCTL			0x040
+#define MDSS_MDP_REG_INTF_BORDER_COLOR			0x044
+#define MDSS_MDP_REG_INTF_UNDERFLOW_COLOR		0x048
+#define MDSS_MDP_REG_INTF_HSYNC_SKEW			0x04C
+#define MDSS_MDP_REG_INTF_POLARITY_CTL			0x050
+#define MDSS_MDP_REG_INTF_TEST_CTL			0x054
+#define MDSS_MDP_REG_INTF_TP_COLOR0			0x058
+#define MDSS_MDP_REG_INTF_TP_COLOR1			0x05C
+
+#define MDSS_MDP_REG_INTF_DEFLICKER_CONFIG		0x0F0
+#define MDSS_MDP_REG_INTF_DEFLICKER_STRNG_COEFF		0x0F4
+#define MDSS_MDP_REG_INTF_DEFLICKER_WEAK_COEFF		0x0F8
+
+#define MDSS_MDP_REG_INTF_DSI_CMD_MODE_TRIGGER_EN	0x084
+#define MDSS_MDP_REG_INTF_PANEL_FORMAT			0x090
+#define MDSS_MDP_REG_INTF_TPG_ENABLE			0x100
+#define MDSS_MDP_REG_INTF_TPG_MAIN_CONTROL		0x104
+#define MDSS_MDP_REG_INTF_TPG_VIDEO_CONFIG		0x108
+#define MDSS_MDP_REG_INTF_TPG_COMPONENT_LIMITS		0x10C
+#define MDSS_MDP_REG_INTF_TPG_RECTANGLE			0x110
+#define MDSS_MDP_REG_INTF_TPG_INITIAL_VALUE		0x114
+#define MDSS_MDP_REG_INTF_TPG_BLK_WHITE_PATTERN_FRAMES	0x118
+#define MDSS_MDP_REG_INTF_TPG_RGB_MAPPING		0x11C
+
+#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN		0x0A8
+#define MDSS_MDP_REG_INTF_FRAME_COUNT			0x0AC
+#define MDSS_MDP_REG_INTF_LINE_COUNT			0x0B0
+
+enum mdss_mdp_pingpong_index {
+	MDSS_MDP_PINGPONG0,
+	MDSS_MDP_PINGPONG1,
+	MDSS_MDP_PINGPONG2,
+	MDSS_MDP_MAX_PINGPONG
+};
+
+#define MDSS_MDP_REG_PP_OFFSET(pp)	(0x21B00 + ((pp) * 0x100))
+
+#define MDSS_MDP_REG_PP_TEAR_CHECK_EN			0x000
+#define MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC		0x004
+#define MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT		0x008
+#define MDSS_MDP_REG_PP_SYNC_WRCOUNT			0x00C
+#define MDSS_MDP_REG_PP_VSYNC_INIT_VAL			0x010
+#define MDSS_MDP_REG_PP_INT_COUNT_VAL			0x014
+#define MDSS_MDP_REG_PP_SYNC_THRESH			0x018
+#define MDSS_MDP_REG_PP_START_POS			0x01C
+#define MDSS_MDP_REG_PP_RD_PTR_IRQ			0x020
+#define MDSS_MDP_REG_PP_WR_PTR_IRQ			0x024
+#define MDSS_MDP_REG_PP_OUT_LINE_COUNT			0x028
+#define MDSS_MDP_REG_PP_LINE_COUNT			0x02C
+#define MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG		0x030
+
+#define MDSS_MDP_REG_SMP_ALLOC_W0			0x00180
+#define MDSS_MDP_REG_SMP_ALLOC_R0			0x00230
+
+#define MDSS_MDP_SMP_MMB_SIZE		4096
+#define MDSS_MDP_SMP_MMB_BLOCKS		22
+
+enum mdss_mdp_smp_client_index {
+	MDSS_MDP_SMP_CLIENT_UNUSED,
+	MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_RGB0_FETCH,
+	MDSS_MDP_SMP_CLIENT_RGB1_FETCH,
+	MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
+};
+
+#endif /* MDSS_MDP_HWIO_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
new file mode 100644
index 0000000..517f8f5
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -0,0 +1,465 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#define CHECK_BOUNDS(offset, size, max_size) \
+	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
+
+static int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
+				      struct mdp_overlay *req,
+				      struct mdss_mdp_format_params *fmt)
+{
+	u32 xres, yres;
+	u32 dst_w, dst_h;
+
+	xres = mfd->fbi->var.xres;
+	yres = mfd->fbi->var.yres;
+
+	if (req->z_order >= MDSS_MDP_MAX_STAGE) {
+		pr_err("zorder %d out of range\n", req->z_order);
+		return -ERANGE;
+	}
+
+	if (req->src.width > MAX_IMG_WIDTH ||
+	    req->src.height > MAX_IMG_HEIGHT ||
+	    req->src_rect.w == 0 || req->src_rect.h == 0 ||
+	    req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+	    req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H ||
+	    CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
+	    CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height) ||
+	    CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
+	    CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres)) {
+		pr_err("invalid image img_w=%d img_h=%d\n",
+				req->src.width, req->src.height);
+
+		pr_err("\tsrc_rect=%d,%d,%d,%d dst_rect=%d,%d,%d,%d\n",
+		       req->src_rect.x, req->src_rect.y,
+		       req->src_rect.w, req->src_rect.h,
+		       req->dst_rect.x, req->dst_rect.y,
+		       req->dst_rect.w, req->dst_rect.h);
+		return -EINVAL;
+	}
+
+	if (req->flags & MDP_ROT_90) {
+		dst_h = req->dst_rect.w;
+		dst_w = req->dst_rect.h;
+	} else {
+		dst_w = req->dst_rect.w;
+		dst_h = req->dst_rect.h;
+	}
+
+	if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
+		pr_err("too much upscaling Width %d->%d\n",
+		       req->src_rect.w, req->dst_rect.w);
+		return -EINVAL;
+	}
+
+	if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
+		pr_err("too much upscaling. Height %d->%d\n",
+		       req->src_rect.h, req->dst_rect.h);
+		return -EINVAL;
+	}
+
+	if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
+		pr_err("too much downscaling. Width %d->%d\n",
+		       req->src_rect.w, req->dst_rect.w);
+		return -EINVAL;
+	}
+
+	if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
+		pr_err("too much downscaling. Height %d->%d\n",
+		       req->src_rect.h, req->dst_rect.h);
+		return -EINVAL;
+	}
+
+	if (fmt->is_yuv) {
+		if ((req->src_rect.x & 0x1) || (req->src_rect.y & 0x1) ||
+		    (req->src_rect.w & 0x1) || (req->src_rect.h & 0x1)) {
+			pr_err("invalid odd src resolution\n");
+			return -EINVAL;
+		}
+		if ((req->dst_rect.x & 0x1) || (req->dst_rect.y & 0x1) ||
+		    (req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
+			pr_err("invalid odd dst resolution\n");
+			return -EINVAL;
+		}
+
+		if (((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w) &&
+		    (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+		     fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+			pr_err("too much YUV upscaling Width %d->%d\n",
+			       req->src_rect.w, req->dst_rect.w);
+			return -EINVAL;
+		}
+
+		if (((req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) &&
+		    (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+		     fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+			pr_err("too much YUV upscaling Height %d->%d\n",
+			       req->src_rect.h, req->dst_rect.h);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
+				       struct mdp_overlay *req,
+				       struct mdss_mdp_pipe **ppipe)
+{
+	struct mdss_mdp_format_params *fmt;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_mixer *mixer = NULL;
+	u32 pipe_type, mixer_mux;
+	int ret;
+
+	if (mfd == NULL || mfd->ctl == NULL)
+		return -ENODEV;
+
+	if (req->flags & MDSS_MDP_RIGHT_MIXER)
+		mixer_mux = MDSS_MDP_MIXER_MUX_RIGHT;
+	else
+		mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
+
+	pr_debug("pipe ctl=%u req id=%x mux=%d\n", mfd->ctl->num, req->id,
+			mixer_mux);
+
+	if (req->flags & MDP_ROT_90) {
+		pr_err("unsupported inline rotation\n");
+		return -ENOTSUPP;
+	}
+
+	fmt = mdss_mdp_get_format_params(req->src.format);
+	if (!fmt) {
+		pr_err("invalid pipe format %d\n", req->src.format);
+		return -EINVAL;
+	}
+
+	ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
+	if (ret)
+		return ret;
+
+	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
+	if (pipe && pipe->ndx != req->id) {
+		pr_err("stage %d taken by pnum=%d\n", req->z_order, pipe->num);
+		return -EBUSY;
+	}
+
+
+	if (req->id == MSMFB_NEW_REQUEST) {
+		mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+		if (!mixer) {
+			pr_err("unable to get mixer\n");
+			return -ENODEV;
+		}
+
+		if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+		else
+			pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
+
+		pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+
+		/* VIG pipes can also support RGB format */
+		if (!pipe && pipe_type == MDSS_MDP_PIPE_TYPE_RGB) {
+			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+			pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+		}
+
+		if (pipe == NULL) {
+			pr_err("error allocating pipe\n");
+			return -ENOMEM;
+		}
+
+		pipe->mixer = mixer;
+		pipe->mfd = mfd;
+	} else {
+		pipe = mdss_mdp_pipe_get_locked(req->id);
+		if (pipe == NULL) {
+			pr_err("invalid pipe ndx=%x\n", req->id);
+			return -ENODEV;
+		}
+	}
+
+	pipe->flags = req->flags;
+
+	pipe->img_width = req->src.width & 0x3fff;
+	pipe->img_height = req->src.height & 0x3fff;
+	pipe->src.x = req->src_rect.x;
+	pipe->src.y = req->src_rect.y;
+	pipe->src.w = req->src_rect.w;
+	pipe->src.h = req->src_rect.h;
+	pipe->dst.x = req->dst_rect.x;
+	pipe->dst.y = req->dst_rect.y;
+	pipe->dst.w = req->dst_rect.w;
+	pipe->dst.h = req->dst_rect.h;
+
+	pipe->src_fmt = fmt;
+
+	pipe->mixer_stage = req->z_order;
+	pipe->is_fg = req->is_fg;
+	pipe->alpha = req->alpha;
+	pipe->transp = req->transp_mask;
+
+	pipe->req_data = *req;
+
+	pipe->params_changed++;
+
+	req->id = pipe->ndx;
+
+	*ppipe = pipe;
+
+	mdss_mdp_pipe_unlock(pipe);
+
+	return ret;
+}
+
+static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd,
+					struct mdss_mdp_pipe **ppipe,
+					int mixer_mux)
+{
+	struct mdss_mdp_pipe *pipe;
+
+	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux,
+					 MDSS_MDP_STAGE_BASE);
+	if (pipe == NULL) {
+		struct mdp_overlay req;
+		int ret;
+
+		memset(&req, 0, sizeof(req));
+
+		req.id = MSMFB_NEW_REQUEST;
+		req.src.format = mfd->fb_imgType;
+		req.src.height = mfd->fbi->var.yres;
+		req.src.width = mfd->fbi->var.xres;
+		if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
+			if (req.src.width <= MAX_MIXER_WIDTH)
+				return -ENODEV;
+
+			req.flags |= MDSS_MDP_RIGHT_MIXER;
+			req.src_rect.x = MAX_MIXER_WIDTH;
+			req.src_rect.w = req.src.width - MAX_MIXER_WIDTH;
+		} else {
+			req.src_rect.x = 0;
+			req.src_rect.w = MIN(req.src.width, MAX_MIXER_WIDTH);
+		}
+
+		req.src_rect.y = 0;
+		req.src_rect.h = req.src.height;
+		req.dst_rect.x = req.src_rect.x;
+		req.dst_rect.y = 0;
+		req.dst_rect.w = req.src_rect.w;
+		req.dst_rect.h = req.src_rect.h;
+		req.z_order = MDSS_MDP_STAGE_BASE;
+
+		pr_debug("allocating base pipe mux=%d\n", mixer_mux);
+
+		ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
+		if (ret)
+			return ret;
+
+		pr_debug("ctl=%d pnum=%d\n", mfd->ctl->num, pipe->num);
+	}
+
+	*ppipe = pipe;
+	return 0;
+}
+
+static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_data data;
+	struct mdss_mdp_pipe *pipe;
+	struct fb_info *fbi;
+	u32 offset;
+	int bpp, ret;
+
+	if (!mfd)
+		return;
+
+	if (!mfd->ctl || !mfd->panel_power_on)
+		return;
+
+	fbi = mfd->fbi;
+
+	if (fbi->fix.smem_len == 0) {
+		pr_warn("fb memory not allocated\n");
+		return;
+	}
+
+	memset(&data, 0, sizeof(data));
+
+	bpp = fbi->var.bits_per_pixel / 8;
+	offset = fbi->var.xoffset * bpp +
+		 fbi->var.yoffset * fbi->fix.line_length;
+
+	data.p[0].addr = fbi->fix.smem_start + offset;
+	data.p[0].len = fbi->fix.smem_len - offset;
+	data.num_planes = 1;
+
+	ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
+	if (ret) {
+		pr_err("unable to allocate base pipe\n");
+		return;
+	}
+
+	mdss_mdp_pipe_lock(pipe);
+	ret = mdss_mdp_pipe_queue_data(pipe, &data);
+	mdss_mdp_pipe_unlock(pipe);
+	if (ret) {
+		pr_err("unable to queue data\n");
+		return;
+	}
+
+	if (fbi->var.xres > MAX_MIXER_WIDTH) {
+		ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
+						   MDSS_MDP_MIXER_MUX_RIGHT);
+		if (ret) {
+			pr_err("unable to allocate right base pipe\n");
+			return;
+		}
+		mdss_mdp_pipe_lock(pipe);
+		ret = mdss_mdp_pipe_queue_data(pipe, &data);
+		mdss_mdp_pipe_unlock(pipe);
+		if (ret) {
+			pr_err("unable to queue right data\n");
+			return;
+		}
+	}
+
+	mdss_mdp_display_commit(mfd->ctl, NULL);
+}
+
+static int mdss_mdp_hw_cursor_update(struct fb_info *info,
+				     struct fb_cursor *cursor)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct mdss_mdp_mixer *mixer;
+	struct fb_image *img = &cursor->image;
+	int calpha_en, transp_en, blendcfg, alpha;
+	int off, ret = 0;
+
+	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+
+	if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
+	    (img->height > MDSS_MDP_CURSOR_HEIGHT) ||
+	    (img->depth != 32))
+		return -EINVAL;
+
+	pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable,
+			cursor->set);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	blendcfg = MDSS_MDP_REG_READ(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG);
+
+	if (cursor->set & FB_CUR_SETPOS)
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_START_XY,
+				   (img->dy << 16) | img->dx);
+
+	if (cursor->set & FB_CUR_SETIMAGE) {
+		ret = copy_from_user(mfd->cursor_buf, img->data,
+				     img->width * img->height * 4);
+		if (ret)
+			return ret;
+
+		if (img->bg_color == 0xffffffff)
+			transp_en = 0;
+		else
+			transp_en = 1;
+
+		alpha = (img->fg_color & 0xff000000) >> 24;
+
+		if (alpha)
+			calpha_en = 0x0; /* xrgb */
+		else
+			calpha_en = 0x2; /* argb */
+
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE,
+				   (img->height << 16) | img->width);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
+				   img->width * 4);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
+				   mfd->cursor_buf_phys);
+
+		wmb();
+
+		blendcfg &= ~0x1;
+		blendcfg |= (transp_en << 3) | (calpha_en << 1);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
+				   blendcfg);
+		if (calpha_en)
+			MDSS_MDP_REG_WRITE(off +
+					   MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM,
+					   alpha);
+
+		if (transp_en) {
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0,
+				   ((img->bg_color & 0xff00) << 8) |
+				   (img->bg_color & 0xff));
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1,
+				   ((img->bg_color & 0xff0000) >> 16));
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0,
+				   ((img->bg_color & 0xff00) << 8) |
+				   (img->bg_color & 0xff));
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1,
+				   ((img->bg_color & 0xff0000) >> 16));
+		}
+	}
+
+	if (!cursor->enable != !(blendcfg & 0x1)) {
+		if (cursor->enable)
+			blendcfg |= 0x1;
+		else
+			blendcfg &= ~0x1;
+
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
+				   blendcfg);
+
+		mixer->cursor_enabled = cursor->enable;
+		mixer->params_changed++;
+	}
+
+	mixer->ctl->flush_bits |= BIT(6) << mixer->num;
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return 0;
+}
+
+int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
+{
+	mfd->on_fnc = mdss_mdp_ctl_on;
+	mfd->off_fnc = mdss_mdp_ctl_off;
+	mfd->hw_refresh = true;
+	mfd->lut_update = NULL;
+	mfd->do_histogram = NULL;
+	mfd->overlay_play_enable = false;
+	mfd->cursor_update = mdss_mdp_hw_cursor_update;
+	mfd->dma_fnc = mdss_mdp_overlay_pan_display;
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
new file mode 100644
index 0000000..b52cff5
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -0,0 +1,675 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/bitmap.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+
+#include "mdss_mdp.h"
+
+#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
+
+static DEFINE_MUTEX(mdss_mdp_sspp_lock);
+static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
+
+static struct mdss_mdp_pipe mdss_mdp_pipe_list[MDSS_MDP_MAX_SSPP];
+
+static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
+{
+	u32 i, mmb;
+
+	/* reserve more blocks if needed, but can't free mmb at this point */
+	for (i = bitmap_weight(smp, SMP_MB_CNT); i < n; i++) {
+		if (bitmap_full(mdss_mdp_smp_mmb_pool, SMP_MB_CNT))
+			break;
+
+		mmb = find_first_zero_bit(mdss_mdp_smp_mmb_pool, SMP_MB_CNT);
+		set_bit(mmb, smp);
+		set_bit(mmb, mdss_mdp_smp_mmb_pool);
+	}
+	return i;
+}
+
+static void mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
+{
+	u32 mmb, off, data, s;
+
+	for_each_set_bit(mmb, smp, SMP_MB_CNT) {
+		off = (mmb / 3) * 4;
+		s = (mmb % 3) * 8;
+		data = MDSS_MDP_REG_READ(MDSS_MDP_REG_SMP_ALLOC_W0 + off);
+		data &= ~(0xFF << s);
+		data |= client_id << s;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_W0 + off, data);
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_R0 + off, data);
+	}
+}
+
+static void mdss_mdp_smp_mmb_free(unsigned long *smp)
+{
+	if (!bitmap_empty(smp, SMP_MB_CNT)) {
+		mdss_mdp_smp_mmb_set(MDSS_MDP_SMP_CLIENT_UNUSED, smp);
+		bitmap_andnot(mdss_mdp_smp_mmb_pool, mdss_mdp_smp_mmb_pool,
+			      smp, SMP_MB_CNT);
+		bitmap_zero(smp, SMP_MB_CNT);
+	}
+}
+
+static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
+{
+	mdss_mdp_smp_mmb_free(&pipe->smp[0]);
+	mdss_mdp_smp_mmb_free(&pipe->smp[1]);
+	mdss_mdp_smp_mmb_free(&pipe->smp[2]);
+}
+
+static int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
+{
+	u32 num_blks = 0, reserved = 0;
+	int i;
+
+	if ((pipe->src_planes.num_planes > 1) &&
+	    (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < pipe->src_planes.num_planes; i++) {
+		num_blks = DIV_ROUND_UP(2 * pipe->src_planes.ystride[i],
+					mdss_res->smp_mb_size);
+
+		pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
+				num_blks, pipe->num, i);
+		reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i], num_blks);
+
+		if (reserved < num_blks)
+			break;
+	}
+
+	if (reserved < num_blks) {
+		pr_err("insufficient MMB blocks\n");
+		mdss_mdp_smp_free(pipe);
+		return -ENOMEM;
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+
+	return 0;
+}
+
+static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
+{
+	u32 client_id;
+	int i;
+
+	switch (pipe->num) {
+	case MDSS_MDP_SSPP_VIG0:
+		client_id = MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_VIG1:
+		client_id = MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_VIG2:
+		client_id = MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_RGB0:
+		client_id = MDSS_MDP_SMP_CLIENT_RGB0_FETCH;
+		break;
+	case MDSS_MDP_SSPP_RGB1:
+		client_id = MDSS_MDP_SMP_CLIENT_RGB1_FETCH;
+		break;
+	case MDSS_MDP_SSPP_RGB2:
+		client_id = MDSS_MDP_SMP_CLIENT_RGB2_FETCH;
+		break;
+	case MDSS_MDP_SSPP_DMA0:
+		client_id = MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_DMA1:
+		client_id = MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y;
+		break;
+	default:
+		pr_err("no valid smp client for pnum=%d\n", pipe->num);
+		return -EINVAL;
+	}
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < pipe->src_planes.num_planes; i++)
+		mdss_mdp_smp_mmb_set(client_id + i, &pipe->smp[i]);
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	return 0;
+}
+
+void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe)
+{
+	atomic_dec(&pipe->ref_cnt);
+	mutex_unlock(&pipe->lock);
+}
+
+int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe)
+{
+	if (atomic_inc_not_zero(&pipe->ref_cnt)) {
+		if (mutex_lock_interruptible(&pipe->lock)) {
+			atomic_dec(&pipe->ref_cnt);
+			return -EINTR;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static struct mdss_mdp_pipe *mdss_mdp_pipe_init(u32 pnum)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+
+	if (atomic_read(&mdss_mdp_pipe_list[pnum].ref_cnt) == 0) {
+		pipe = &mdss_mdp_pipe_list[pnum];
+		memset(pipe, 0, sizeof(*pipe));
+
+		mutex_init(&pipe->lock);
+		atomic_set(&pipe->ref_cnt, 1);
+
+		if (mdss_mdp_pipe_lock(pipe) == 0) {
+			pipe->num = pnum;
+			pipe->type = mdss_res->pipe_type_map[pnum];
+			pipe->ndx = BIT(pnum);
+
+			pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
+		} else {
+			atomic_set(&pipe->ref_cnt, 0);
+			pipe = NULL;
+		}
+	}
+	return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	mutex_lock(&mdss_mdp_sspp_lock);
+	if (mdss_res->pipe_type_map[pnum] != MDSS_MDP_PIPE_TYPE_UNUSED)
+		pipe = mdss_mdp_pipe_init(pnum);
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	int pnum;
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (pnum = 0; pnum < MDSS_MDP_MAX_SSPP; pnum++) {
+		if (type == mdss_res->pipe_type_map[pnum]) {
+			pipe = mdss_mdp_pipe_init(pnum);
+			if (pipe)
+				break;
+		}
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+
+	return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	int i;
+
+	if (!ndx)
+		return NULL;
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
+		pipe = &mdss_mdp_pipe_list[i];
+		if (ndx == pipe->ndx)
+			break;
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+
+	if (i == MDSS_MDP_MAX_SSPP)
+		return NULL;
+
+	if (mdss_mdp_pipe_lock(pipe))
+		return NULL;
+
+	if (pipe->ndx != ndx) {
+		mdss_mdp_pipe_unlock(pipe);
+		pipe = NULL;
+	}
+
+	return pipe;
+}
+
+
+static void mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe)
+{
+	mdss_mdp_smp_free(pipe);
+	pipe->ndx = 0;
+	atomic_dec(&pipe->ref_cnt);
+	mdss_mdp_pipe_unlock(pipe);
+}
+
+int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe)
+{
+	pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num,
+			atomic_read(&pipe->ref_cnt));
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mutex_lock(&mdss_mdp_sspp_lock);
+	mdss_mdp_pipe_free(pipe);
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return 0;
+}
+
+int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_pipe *pipe;
+	int i;
+
+	if (!mfd)
+		return -ENODEV;
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
+		pipe = &mdss_mdp_pipe_list[i];
+		if (atomic_read(&pipe->ref_cnt) && pipe->mfd == mfd) {
+			pr_debug("release pnum=%d\n", pipe->num);
+			if (mdss_mdp_pipe_lock(pipe) == 0) {
+				mdss_mdp_mixer_pipe_unstage(pipe);
+				mdss_mdp_pipe_free(pipe);
+			} else {
+				pr_err("unable to lock pipe=%d for release",
+				       pipe->num);
+			}
+		}
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return 0;
+}
+
+static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
+				       u32 reg, u32 val)
+{
+	int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
+	MDSS_MDP_REG_WRITE(offset + reg, val);
+}
+
+static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
+{
+	int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
+	return MDSS_MDP_REG_READ(offset + reg);
+}
+
+static int mdss_mdp_leading_zero(u32 num)
+{
+	u32 bit = 0x80000000;
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		if (bit & num)
+			return i;
+		bit >>= 1;
+	}
+
+	return i;
+}
+
+static u32 mdss_mdp_scale_phase_step(int f_num, u32 src, u32 dst)
+{
+	u32 val, s;
+	int n;
+
+	n = mdss_mdp_leading_zero(src);
+	if (n > f_num)
+		n = f_num;
+	s = src << n;	/* maximum to reduce lose of resolution */
+	val = s / dst;
+	if (n < f_num) {
+		n = f_num - n;
+		val <<= n;
+		val |= ((s % dst) << n) / dst;
+	}
+
+	return val;
+}
+
+static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
+{
+	u32 scale_config = 0;
+	u32 phasex_step = 0, phasey_step = 0;
+	u32 chroma_sample;
+
+	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA) {
+		if (!(pipe->flags & MDP_ROT_90) && (pipe->dst.h != pipe->src.h
+						|| pipe->dst.w != pipe->src.w))
+			return -EINVAL;	/* no scaling supported on dma pipes */
+		else
+			return 0;
+	}
+
+	chroma_sample = pipe->src_fmt->chroma_sample;
+
+	if ((pipe->src.h != pipe->dst.h) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+		pr_debug("scale y - src_h=%d dst_h=%d\n",
+				pipe->src.h, pipe->dst.h);
+
+		if ((pipe->src.h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
+			pr_err("too much downscaling height=%d->%d",
+			       pipe->src.h, pipe->dst.h);
+			return -EINVAL;
+		}
+
+		scale_config |= MDSS_MDP_SCALEY_EN;
+
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+			u32 chr_dst_h = pipe->dst.h;
+			if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+			    (chroma_sample == MDSS_MDP_CHROMA_H1V2))
+				chr_dst_h *= 2;	/* 2x upsample chroma */
+
+			if (pipe->src.h <= pipe->dst.h)
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+			else
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+
+			if (pipe->src.h <= chr_dst_h)
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_BIL << 14);
+			else
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 14);
+
+			phasey_step = mdss_mdp_scale_phase_step(
+				PHASE_STEP_SHIFT, pipe->src.h, chr_dst_h);
+
+			mdss_mdp_pipe_write(pipe,
+					MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY,
+					phasey_step);
+		} else {
+			if (pipe->src.h <= pipe->dst.h)
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+			else
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+		}
+
+		phasey_step = mdss_mdp_scale_phase_step(
+			PHASE_STEP_SHIFT, pipe->src.h, pipe->dst.h);
+	}
+
+	if ((pipe->src.w != pipe->dst.w) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+		pr_debug("scale x - src_w=%d dst_w=%d\n",
+				pipe->src.w, pipe->dst.w);
+
+		if ((pipe->src.w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
+			pr_err("too much downscaling width=%d->%d",
+			       pipe->src.w, pipe->dst.w);
+			return -EINVAL;
+		}
+
+		scale_config |= MDSS_MDP_SCALEX_EN;
+
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+			u32 chr_dst_w = pipe->dst.w;
+
+			if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+			    (chroma_sample == MDSS_MDP_CHROMA_H2V1))
+				chr_dst_w *= 2;	/* 2x upsample chroma */
+
+			if (pipe->src.w <= pipe->dst.w)
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+			else
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+
+			if (pipe->src.w <= chr_dst_w)
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_BIL << 12);
+			else
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 12);
+
+			phasex_step = mdss_mdp_scale_phase_step(
+				PHASE_STEP_SHIFT, pipe->src.w, chr_dst_w);
+			mdss_mdp_pipe_write(pipe,
+					MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX,
+					phasex_step);
+		} else {
+			if (pipe->src.w <= pipe->dst.w)
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+			else
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+		}
+
+		phasex_step = mdss_mdp_scale_phase_step(
+			PHASE_STEP_SHIFT, pipe->src.w, pipe->dst.w);
+	}
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_CONFIG, scale_config);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_X, phasex_step);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_Y, phasey_step);
+	return 0;
+}
+
+static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
+{
+	u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
+
+	pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
+		   pipe->num, pipe->img_width, pipe->img_height,
+		   pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
+		   pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
+
+	if (mdss_mdp_scale_setup(pipe))
+		return -EINVAL;
+
+	mdss_mdp_get_plane_sizes(pipe->src_fmt->format, pipe->img_width,
+				 pipe->img_height, &pipe->src_planes);
+
+	img_size = (pipe->img_height << 16) | pipe->img_width;
+	src_size = (pipe->src.h << 16) | pipe->src.w;
+	src_xy = (pipe->src.y << 16) | pipe->src.x;
+	dst_size = (pipe->dst.h << 16) | pipe->dst.w;
+	dst_xy = (pipe->dst.y << 16) | pipe->dst.x;
+	ystride0 =  (pipe->src_planes.ystride[0]) |
+		    (pipe->src_planes.ystride[1] << 16);
+	ystride1 =  (pipe->src_planes.ystride[2]) |
+		    (pipe->src_planes.ystride[3] << 16);
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_XY, src_xy);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_SIZE, dst_size);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_XY, dst_xy);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE0, ystride0);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE1, ystride1);
+
+	return 0;
+}
+
+static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
+{
+	struct mdss_mdp_format_params *fmt;
+	u32 rot90, opmode, chroma_samp;
+
+	fmt = pipe->src_fmt;
+
+	opmode = pipe->bwc_mode;
+	if (pipe->flags & MDP_FLIP_LR)
+		opmode |= MDSS_MDP_OP_FLIP_LR;
+	if (pipe->flags & MDP_FLIP_UD)
+		opmode |= MDSS_MDP_OP_FLIP_UD;
+
+	pr_debug("pnum=%d format=%d opmode=%x\n", pipe->num, fmt->format,
+			opmode);
+
+	rot90 = !!(pipe->flags & MDP_SOURCE_ROTATED_90);
+
+	chroma_samp = fmt->chroma_sample;
+	if (rot90) {
+		if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
+			chroma_samp = MDSS_MDP_CHROMA_H1V2;
+		else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
+			chroma_samp = MDSS_MDP_CHROMA_H2V1;
+	}
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT,
+			    (chroma_samp << 23) |
+			    (fmt->fetch_planes << 19) |
+			    (fmt->unpack_align_msb << 18) |
+			    (fmt->unpack_tight << 17) |
+			    (fmt->unpack_count << 12) |
+			    (rot90 << 11) |
+			    (fmt->bpp << 9) |
+			    (fmt->alpha_enable << 8) |
+			    (fmt->a_bit << 6) |
+			    (fmt->r_bit << 4) |
+			    (fmt->b_bit << 2) |
+			    (fmt->g_bit << 0));
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN,
+			    (fmt->element3 << 24) |
+			    (fmt->element2 << 16) |
+			    (fmt->element1 << 8) |
+			    (fmt->element0 << 0));
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
+
+	return 0;
+}
+
+static int mdss_mdp_vig_setup(struct mdss_mdp_pipe *pipe)
+{
+	u32 opmode = 0;
+
+	pr_debug("pnum=%x\n", pipe->num);
+
+	if (pipe->src_fmt->is_yuv)
+		opmode |= (0 << 19) |	/* DST_DATA=RGB */
+			  (1 << 18) |	/* SRC_DATA=YCBCR */
+			  (1 << 17);	/* CSC_1_EN */
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
+
+	return 0;
+}
+
+static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
+				   struct mdss_mdp_data *data)
+{
+	int ret;
+
+	pr_debug("pnum=%d\n", pipe->num);
+
+	if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
+		data->bwc_enabled = pipe->bwc_mode;
+
+	ret = mdss_mdp_data_check(data, &pipe->src_planes);
+	if (ret)
+		return ret;
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
+
+	return 0;
+}
+
+int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
+			     struct mdss_mdp_data *src_data)
+{
+	int ret = 0;
+	u32 params_changed;
+
+	if (!pipe) {
+		pr_err("pipe not setup properly for queue\n");
+		return -ENODEV;
+	}
+
+	if (!pipe->mixer) {
+		pr_err("pipe mixer not setup properly for queue\n");
+		return -ENODEV;
+	}
+
+	pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	params_changed = pipe->params_changed;
+	if (params_changed) {
+		pipe->params_changed = 0;
+
+		ret = mdss_mdp_image_setup(pipe);
+		if (ret) {
+			pr_err("image setup error for pnum=%d\n", pipe->num);
+			goto done;
+		}
+
+		ret = mdss_mdp_format_setup(pipe);
+		if (ret) {
+			pr_err("format %d setup error pnum=%d\n",
+			       pipe->src_fmt->format, pipe->num);
+			goto done;
+		}
+
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
+			mdss_mdp_vig_setup(pipe);
+
+		ret = mdss_mdp_smp_reserve(pipe);
+		if (ret) {
+			pr_err("unable to reserve smp for pnum=%d\n",
+			       pipe->num);
+			goto done;
+		}
+
+		mdss_mdp_smp_alloc(pipe);
+	}
+
+	ret = mdss_mdp_src_addr_setup(pipe, src_data);
+	if (ret) {
+		pr_err("addr setup error for pnum=%d\n", pipe->num);
+		goto done;
+	}
+
+	mdss_mdp_mixer_pipe_update(pipe, params_changed);
+
+	pipe->play_cnt++;
+
+done:
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
new file mode 100644
index 0000000..dc35a73
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -0,0 +1,278 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/android_pmem.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ion.h>
+#include <linux/msm_kgsl.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+#include "mdss_mdp_formats.h"
+
+enum {
+	MDP_INTR_VSYNC_INTF_0,
+	MDP_INTR_VSYNC_INTF_1,
+	MDP_INTR_VSYNC_INTF_2,
+	MDP_INTR_VSYNC_INTF_3,
+	MDP_INTR_PING_PONG_0,
+	MDP_INTR_PING_PONG_1,
+	MDP_INTR_PING_PONG_2,
+	MDP_INTR_WB_0,
+	MDP_INTR_WB_1,
+	MDP_INTR_WB_2,
+	MDP_INTR_MAX,
+};
+
+struct intr_callback {
+	void (*func)(void *);
+	void *arg;
+};
+
+struct intr_callback mdp_intr_cb[MDP_INTR_MAX];
+static DEFINE_SPINLOCK(mdss_mdp_intr_lock);
+
+static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
+{
+	int index = -1;
+	switch (intr_type) {
+	case MDSS_MDP_IRQ_INTF_VSYNC:
+		index = MDP_INTR_VSYNC_INTF_0 + intf_num;
+		break;
+	case MDSS_MDP_IRQ_PING_PONG_COMP:
+		index = MDP_INTR_PING_PONG_0 + intf_num;
+		break;
+	case MDSS_MDP_IRQ_WB_ROT_COMP:
+		index = MDP_INTR_WB_0 + intf_num;
+		break;
+	case MDSS_MDP_IRQ_WB_WFD:
+		index = MDP_INTR_WB_2 + intf_num;
+		break;
+	}
+
+	return index;
+}
+
+int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
+			       void (*fnc_ptr)(void *), void *arg)
+{
+	unsigned long flags;
+	int index, ret;
+
+	index = mdss_mdp_intr2index(intr_type, intf_num);
+	if (index < 0) {
+		pr_warn("invalid intr type=%u intf_num=%u\n",
+				intr_type, intf_num);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&mdss_mdp_intr_lock, flags);
+	if (!mdp_intr_cb[index].func) {
+		mdp_intr_cb[index].func = fnc_ptr;
+		mdp_intr_cb[index].arg = arg;
+		ret = 0;
+	} else {
+		ret = -EBUSY;
+	}
+	spin_unlock_irqrestore(&mdss_mdp_intr_lock, flags);
+
+	return ret;
+}
+
+static inline void mdss_mdp_intr_done(int index)
+{
+	void (*fnc)(void *);
+	void *arg;
+
+	spin_lock(&mdss_mdp_intr_lock);
+	fnc = mdp_intr_cb[index].func;
+	arg = mdp_intr_cb[index].arg;
+	if (fnc != NULL)
+		mdp_intr_cb[index].func = NULL;
+	spin_unlock(&mdss_mdp_intr_lock);
+	if (fnc)
+		fnc(arg);
+}
+
+irqreturn_t mdss_mdp_isr(int irq, void *ptr)
+{
+	u32 isr, mask;
+
+
+	isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
+	if (isr == 0)
+		goto done;
+
+	pr_devel("isr=%x\n", isr);
+
+	mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
+	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
+
+	isr &= mask;
+	if (isr == 0)
+		goto done;
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_1);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
+
+	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
+
+	if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
+
+	if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
+
+	if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
+
+	if (isr & MDSS_MDP_INTR_WB_0_DONE)
+		mdss_mdp_intr_done(MDP_INTR_WB_0);
+
+	if (isr & MDSS_MDP_INTR_WB_1_DONE)
+		mdss_mdp_intr_done(MDP_INTR_WB_1);
+
+	if (isr & MDSS_MDP_INTR_WB_2_DONE)
+		mdss_mdp_intr_done(MDP_INTR_WB_2);
+
+done:
+	return IRQ_HANDLED;
+}
+
+struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format)
+{
+	struct mdss_mdp_format_params *fmt = NULL;
+	if (format < MDP_IMGTYPE_LIMIT) {
+		fmt = &mdss_mdp_format_map[format];
+		if (fmt->format != format)
+			fmt = NULL;
+	}
+
+	return fmt;
+}
+
+int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
+			     struct mdss_mdp_plane_sizes *ps)
+{
+	struct mdss_mdp_format_params *fmt;
+	int i;
+
+	if (ps == NULL)
+		return -EINVAL;
+
+	if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT))
+		return -ERANGE;
+
+	fmt = mdss_mdp_get_format_params(format);
+	if (!fmt)
+		return -EINVAL;
+
+	memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
+
+	if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+		u32 bpp = fmt->bpp + 1;
+		ps->num_planes = 1;
+		ps->plane_size[0] = w * h * bpp;
+		ps->ystride[0] = w * bpp;
+	} else {
+		u8 hmap[] = { 1, 2, 1, 2 };
+		u8 vmap[] = { 1, 1, 2, 2 };
+		u8 horiz, vert;
+
+		horiz = hmap[fmt->chroma_sample];
+		vert = vmap[fmt->chroma_sample];
+
+		if (format == MDP_Y_CR_CB_GH2V2) {
+			ps->plane_size[0] = ALIGN(w, 16) * h;
+			ps->plane_size[1] = ALIGN(w / horiz, 16) * (h / vert);
+			ps->ystride[0] = ALIGN(w, 16);
+			ps->ystride[1] = ALIGN(w / horiz, 16);
+		} else {
+			ps->plane_size[0] = w * h;
+			ps->plane_size[1] = (w / horiz) * (h / vert);
+			ps->ystride[0] = w;
+			ps->ystride[1] = (w / horiz);
+		}
+
+		if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
+			ps->num_planes = 2;
+			ps->plane_size[1] *= 2;
+			ps->ystride[1] *= 2;
+		} else { /* planar */
+			ps->num_planes = 3;
+			ps->plane_size[2] = ps->plane_size[1];
+			ps->ystride[2] = ps->ystride[1];
+		}
+	}
+
+	for (i = 0; i < ps->num_planes; i++)
+		ps->total_size += ps->plane_size[i];
+
+	return 0;
+}
+
+int mdss_mdp_data_check(struct mdss_mdp_data *data,
+			struct mdss_mdp_plane_sizes *ps)
+{
+	if (!ps)
+		return 0;
+
+	if (!data || data->num_planes == 0)
+		return -ENOMEM;
+
+	if (data->bwc_enabled) {
+		return -EPERM; /* not supported */
+	} else {
+		struct mdss_mdp_img_data *prev, *curr;
+		int i;
+
+		pr_debug("srcp0=%x len=%u frame_size=%u\n", data->p[0].addr,
+				data->p[0].len, ps->total_size);
+
+		for (i = 0; i < ps->num_planes; i++) {
+			curr = &data->p[i];
+			if (i >= data->num_planes) {
+				u32 psize = ps->plane_size[i-1];
+				prev = &data->p[i-1];
+				if (prev->len > psize) {
+					curr->len = prev->len - psize;
+					prev->len = psize;
+				}
+				curr->addr = prev->addr + psize;
+			}
+			if (curr->len < ps->plane_size[i]) {
+				pr_err("insufficient mem=%u p=%d len=%u\n",
+				       curr->len, i, ps->plane_size[i]);
+				return -ENOMEM;
+			}
+			pr_debug("plane[%d] addr=%x len=%u\n", i,
+					curr->addr, curr->len);
+		}
+		data->num_planes = ps->num_planes;
+	}
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
new file mode 100644
index 0000000..3fd943d
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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 MDSS_PANEL_H
+#define MDSS_PANEL_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* panel id type */
+struct panel_id {
+	u16 id;
+	u16 type;
+};
+
+/* panel type list */
+#define NO_PANEL		0xffff	/* No Panel */
+#define MDDI_PANEL		1	/* MDDI */
+#define EBI2_PANEL		2	/* EBI2 */
+#define LCDC_PANEL		3	/* internal LCDC type */
+#define EXT_MDDI_PANEL		4	/* Ext.MDDI */
+#define TV_PANEL		5	/* TV */
+#define HDMI_PANEL		6	/* HDMI TV */
+#define DTV_PANEL		7	/* DTV */
+#define MIPI_VIDEO_PANEL	8	/* MIPI */
+#define MIPI_CMD_PANEL		9	/* MIPI */
+#define WRITEBACK_PANEL		10	/* Wifi display */
+#define LVDS_PANEL		11	/* LVDS */
+#define EDP_PANEL		12	/* LVDS */
+
+/* panel class */
+enum {
+	DISPLAY_LCD = 0,	/* lcd = ebi2/mddi */
+	DISPLAY_LCDC,		/* lcdc */
+	DISPLAY_TV,		/* TV Out */
+	DISPLAY_EXT_MDDI,	/* External MDDI */
+	DISPLAY_WRITEBACK,
+};
+
+/* panel device locaiton */
+enum {
+	DISPLAY_1 = 0,		/* attached as first device */
+	DISPLAY_2,		/* attached on second device */
+	DISPLAY_3,              /* attached on third writeback device */
+	MAX_PHYS_TARGET_NUM,
+};
+
+/* panel info type */
+struct lcd_panel_info {
+	u32 vsync_enable;
+	u32 refx100;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 v_pulse_width;
+	u32 hw_vsync_mode;
+	u32 vsync_notifier_period;
+	u32 rev;
+};
+
+struct lcdc_panel_info {
+	u32 h_back_porch;
+	u32 h_front_porch;
+	u32 h_pulse_width;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 v_pulse_width;
+	u32 border_clr;
+	u32 underflow_clr;
+	u32 hsync_skew;
+	/* Pad width */
+	u32 xres_pad;
+	/* Pad height */
+	u32 yres_pad;
+};
+
+struct mipi_panel_info {
+	char mode;		/* video/cmd */
+	char interleave_mode;
+	char crc_check;
+	char ecc_check;
+	char dst_format;	/* shared by video and command */
+	char data_lane0;
+	char data_lane1;
+	char data_lane2;
+	char data_lane3;
+	char dlane_swap;	/* data lane swap */
+	char rgb_swap;
+	char b_sel;
+	char g_sel;
+	char r_sel;
+	char rx_eot_ignore;
+	char tx_eot_append;
+	char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
+	char t_clk_pre;  /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
+	char vc;	/* virtual channel */
+	struct mipi_dsi_phy_ctrl *dsi_phy_db;
+	/* video mode */
+	char pulse_mode_hsa_he;
+	char hfp_power_stop;
+	char hbp_power_stop;
+	char hsa_power_stop;
+	char eof_bllp_power_stop;
+	char bllp_power_stop;
+	char traffic_mode;
+	char frame_rate;
+	/* command mode */
+	char interleave_max;
+	char insert_dcs_cmd;
+	char wr_mem_continue;
+	char wr_mem_start;
+	char te_sel;
+	char stream;	/* 0 or 1 */
+	char mdp_trigger;
+	char dma_trigger;
+	u32 dsi_pclk_rate;
+	/* The packet-size should not bet changed */
+	char no_max_pkt_size;
+	/* Clock required during LP commands */
+	char force_clk_lane_hs;
+};
+
+enum lvds_mode {
+	LVDS_SINGLE_CHANNEL_MODE,
+	LVDS_DUAL_CHANNEL_MODE,
+};
+
+struct lvds_panel_info {
+	enum lvds_mode channel_mode;
+	/* Channel swap in dual mode */
+	char channel_swap;
+};
+
+struct mdss_panel_info {
+	u32 xres;
+	u32 yres;
+	u32 bpp;
+	u32 type;
+	u32 wait_cycle;
+	u32 pdest;
+	u32 bl_max;
+	u32 bl_min;
+	u32 fb_num;
+	u32 clk_rate;
+	u32 clk_min;
+	u32 clk_max;
+	u32 frame_count;
+	u32 is_3d_panel;
+	u32 out_format;
+
+	struct lcd_panel_info lcd;
+	struct lcdc_panel_info lcdc;
+	struct mipi_panel_info mipi;
+	struct lvds_panel_info lvds;
+};
+
+struct mdss_panel_data {
+	struct mdss_panel_info panel_info;
+	void (*set_backlight) (u32 bl_level);
+
+	/* function entry chain */
+	int (*on) (struct mdss_panel_data *pdata);
+	int (*off) (struct mdss_panel_data *pdata);
+};
+
+int mdss_register_panel(struct mdss_panel_data *pdata);
+#endif /* MDSS_PANEL_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index f757fae..8b6351f 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -86,6 +86,8 @@
 	MDP_YCRYCB_H2V1,  /* YCrYCb interleave */
 	MDP_Y_CRCB_H2V1,  /* Y and CrCb, pseduo planer w/ Cr is in MSB */
 	MDP_Y_CBCR_H2V1,   /* Y and CrCb, pseduo planer w/ Cr is in MSB */
+	MDP_Y_CRCB_H1V2,
+	MDP_Y_CBCR_H1V2,
 	MDP_RGBA_8888,    /* ARGB 888 */
 	MDP_BGRA_8888,	  /* ABGR 888 */
 	MDP_RGBX_8888,	  /* RGBX 888 */
@@ -98,10 +100,10 @@
 	MDP_Y_CBCR_H1V1,  /* Y and CbCr, pseduo planer w/ Cb is in MSB */
 	MDP_YCRCB_H1V1,   /* YCrCb interleave */
 	MDP_YCBCR_H1V1,   /* YCbCr interleave */
+	MDP_BGR_565,      /* BGR 565 planer */
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
-	MDP_BGR_565 = MDP_IMGTYPE2_START,      /* BGR 565 planer */
-	MDP_FB_FORMAT,    /* framebuffer format */
+	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
 	MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */
 };
 
@@ -118,6 +120,8 @@
 	NUM_HSIC_PARAM,
 };
 
+#define MDSS_MDP_RIGHT_MIXER		0x100
+
 /* mdp_blit_req flag values */
 #define MDP_ROT_NOP 0
 #define MDP_FLIP_LR 0x1