drm/msm/sde: add driver for sde support

Initial DRM/KMS driver to support snapdragon display engine.

Change-Id: I2f93d7cd24acf77359682f90b6b9647017ed62ba
Signed-off-by: Abhijit Kulkarni <kabhijit@codeaurora.org>
Signed-off-by: Narendra Muppalla <NarendraM@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 4e2806c..eee0b0c 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -39,6 +39,11 @@
 	mdp/mdp5/mdp5_kms.o \
 	mdp/mdp5/mdp5_plane.o \
 	mdp/mdp5/mdp5_smp.o \
+	sde/sde_crtc.o \
+	sde/sde_encoder.o \
+	sde/sde_irq.o \
+	sde/sde_kms.o \
+	sde/sde_plane.o \
 	msm_atomic.o \
 	msm_debugfs.o \
 	msm_drv.o \
@@ -80,3 +85,15 @@
 endif
 
 obj-$(CONFIG_DRM_MSM)	+= msm.o
+
+obj-$(CONFIG_DRM_MSM) += sde/sde_hw_catalog.o \
+	sde/sde_hw_catalog_8996.o \
+	sde/sde_hw_cdm.o \
+	sde/sde_hw_dspp.o \
+	sde/sde_hw_intf.o \
+	sde/sde_hw_lm.o \
+	sde/sde_hw_mdp_ctl.o \
+	sde/sde_hw_mdp_util.o \
+	sde/sde_hw_sspp.o \
+	sde/sde_hw_wb.o \
+	sde/sde_hw_pingpong.o
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 46568fc..f6e2e23 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -257,11 +257,30 @@
 	return 0;
 }
 
+#define KMS_MDP4 0
+#define KMS_MDP5 1
+#define KMS_SDE  2
+
 static int get_mdp_ver(struct platform_device *pdev)
 {
+#ifdef CONFIG_OF
+	static const struct of_device_id match_types[] = { {
+		.compatible = "qcom,mdss_mdp",
+		.data	= (void	*)KMS_MDP5,
+	},
+	{
+		.compatible = "qcom,sde-kms",
+		.data	= (void	*)KMS_SDE,
+		/* end node */
+	} };
 	struct device *dev = &pdev->dev;
+	const struct of_device_id *match;
 
-	return (int) (unsigned long) of_device_get_match_data(dev);
+	match = of_match_node(match_types, dev->of_node);
+	if (match)
+		return (int)(unsigned long)match->data;
+#endif
+	return KMS_MDP4;
 }
 
 #include <linux/of_address.h>
@@ -399,12 +418,14 @@
 	msm_gem_shrinker_init(ddev);
 
 	switch (get_mdp_ver(pdev)) {
-	case 4:
-		kms = mdp4_kms_init(ddev);
-		priv->kms = kms;
+	case KMS_MDP4:
+		kms = mdp4_kms_init(dev);
 		break;
-	case 5:
-		kms = mdp5_kms_init(ddev);
+	case KMS_MDP5:
+		kms = mdp5_kms_init(dev);
+		break;
+	case KMS_SDE:
+		kms = sde_kms_init(dev);
 		break;
 	default:
 		kms = ERR_PTR(-ENODEV);
@@ -1048,8 +1069,9 @@
 }
 
 static const struct of_device_id dt_match[] = {
-	{ .compatible = "qcom,mdp4", .data = (void *)4 },	/* MDP4 */
-	{ .compatible = "qcom,mdss", .data = (void *)5 },	/* MDP5 MDSS */
+	{ .compatible = "qcom,mdp" },      /* mdp4 */
+	{ .compatible = "qcom,mdss_mdp" }, /* mdp5 */
+	{ .compatible = "qcom,sde-kms" },  /* sde  */
 	{}
 };
 MODULE_DEVICE_TABLE(of, dt_match);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index d0da52f..3bccfc8 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -53,7 +53,12 @@
 struct msm_fence_context;
 struct msm_fence_cb;
 
-#define NUM_DOMAINS 2    /* one for KMS, then one per gpu core (?) */
+#define NUM_DOMAINS    2    /* one for KMS, then one per gpu core (?) */
+#define MAX_CRTCS      8
+#define MAX_PLANES     12
+#define MAX_ENCODERS   8
+#define MAX_BRIDGES    8
+#define MAX_CONNECTORS 8
 
 struct msm_file_private {
 	/* currently we don't do anything useful with this.. but when
@@ -126,19 +131,19 @@
 	struct msm_mmu *mmus[NUM_DOMAINS];
 
 	unsigned int num_planes;
-	struct drm_plane *planes[8];
+	struct drm_plane *planes[MAX_PLANES];
 
 	unsigned int num_crtcs;
-	struct drm_crtc *crtcs[8];
+	struct drm_crtc *crtcs[MAX_CRTCS];
 
 	unsigned int num_encoders;
-	struct drm_encoder *encoders[8];
+	struct drm_encoder *encoders[MAX_ENCODERS];
 
 	unsigned int num_bridges;
-	struct drm_bridge *bridges[8];
+	struct drm_bridge *bridges[MAX_BRIDGES];
 
 	unsigned int num_connectors;
-	struct drm_connector *connectors[8];
+	struct drm_connector *connectors[MAX_CONNECTORS];
 
 	/* Properties */
 	struct drm_property *plane_property[PLANE_PROP_MAX_NUM];
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 40e41e5..ef8b392 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -73,7 +73,6 @@
 
 struct msm_kms *mdp4_kms_init(struct drm_device *dev);
 struct msm_kms *mdp5_kms_init(struct drm_device *dev);
-int msm_mdss_init(struct drm_device *dev);
-void msm_mdss_destroy(struct drm_device *dev);
+struct msm_kms *sde_kms_init(struct drm_device *dev);
 
 #endif /* __MSM_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
new file mode 100644
index 0000000..4812a5f
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -0,0 +1,148 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drm_mode.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_flip_work.h>
+
+#include "sde_kms.h"
+#include "sde_hw_lm.h"
+#include "sde_hw_mdss.h"
+
+struct sde_crtc {
+	struct drm_crtc base;
+	char name[8];
+	struct drm_plane *plane;
+	struct drm_plane *planes[8];
+	int id;
+	bool enabled;
+	enum sde_lm mixer;
+	enum sde_ctl ctl_path;
+};
+
+#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
+
+static void sde_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
+
+	drm_crtc_cleanup(crtc);
+	kfree(sde_crtc);
+}
+
+static void sde_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+}
+
+static bool sde_crtc_mode_fixup(struct drm_crtc *crtc,
+		const struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static int sde_crtc_mode_set(struct drm_crtc *crtc,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode,
+		int x, int y,
+		struct drm_framebuffer *old_fb)
+{
+	return 0;
+}
+
+static void sde_crtc_prepare(struct drm_crtc *crtc)
+{
+}
+
+static void sde_crtc_commit(struct drm_crtc *crtc)
+{
+}
+
+static int sde_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+		struct drm_framebuffer *old_fb)
+{
+	return 0;
+}
+
+static void sde_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static int sde_crtc_page_flip(struct drm_crtc *crtc,
+		struct drm_framebuffer *new_fb,
+		struct drm_pending_vblank_event *event,
+		uint32_t page_flip_flags)
+{
+	return 0;
+}
+
+static int sde_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_property *property, uint64_t val)
+{
+	return -EINVAL;
+}
+
+static const struct drm_crtc_funcs sde_crtc_funcs = {
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = sde_crtc_destroy,
+	.page_flip = sde_crtc_page_flip,
+	.set_property = sde_crtc_set_property,
+};
+
+static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = {
+	.dpms = sde_crtc_dpms,
+	.mode_fixup = sde_crtc_mode_fixup,
+	.mode_set = sde_crtc_mode_set,
+	.prepare = sde_crtc_prepare,
+	.commit = sde_crtc_commit,
+	.mode_set_base = sde_crtc_mode_set_base,
+	.load_lut = sde_crtc_load_lut,
+};
+
+uint32_t sde_crtc_vblank(struct drm_crtc *crtc)
+{
+	return 0;
+}
+
+void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
+{
+}
+
+void sde_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+}
+
+void sde_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+}
+
+struct drm_crtc *sde_crtc_init(struct drm_device *dev,
+		struct drm_encoder *encoder,
+		struct drm_plane *plane, int id)
+{
+	struct drm_crtc *crtc = NULL;
+	struct sde_crtc *sde_crtc;
+
+	sde_crtc = kzalloc(sizeof(*sde_crtc), GFP_KERNEL);
+	if (!sde_crtc)
+		return ERR_PTR(-ENOMEM);
+
+	crtc = &sde_crtc->base;
+
+	sde_crtc->id = id;
+
+	/* find out if we need one or two lms */
+
+	drm_crtc_helper_add(crtc, &sde_crtc_helper_funcs);
+	return crtc;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
new file mode 100644
index 0000000..3c28e31
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_kms.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+struct sde_encoder {
+	struct drm_encoder base;
+	int intf;
+};
+#define to_sde_encoder(x) container_of(x, struct sde_encoder, base)
+
+static void sde_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct sde_encoder *sde_encoder = to_sde_encoder(encoder);
+
+	drm_encoder_cleanup(encoder);
+	kfree(sde_encoder);
+}
+
+static const struct drm_encoder_funcs sde_encoder_funcs = {
+	.destroy = sde_encoder_destroy,
+};
+
+static void sde_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool sde_encoder_mode_fixup(struct drm_encoder *encoder,
+		const struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void sde_encoder_mode_set(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void sde_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void sde_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static const struct drm_encoder_helper_funcs sde_encoder_helper_funcs = {
+	.dpms = sde_encoder_dpms,
+	.mode_fixup = sde_encoder_mode_fixup,
+	.mode_set = sde_encoder_mode_set,
+	.prepare = sde_encoder_prepare,
+	.commit = sde_encoder_commit,
+};
+
+/* initialize encoder */
+struct drm_encoder *sde_encoder_init(struct drm_device *dev, int intf)
+{
+	struct drm_encoder *encoder = NULL;
+	struct sde_encoder *sde_encoder;
+	int ret;
+
+	sde_encoder = kzalloc(sizeof(*sde_encoder), GFP_KERNEL);
+	if (!sde_encoder) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	sde_encoder->intf = intf;
+	encoder = &sde_encoder->base;
+
+	drm_encoder_init(dev, encoder, &sde_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+	drm_encoder_helper_add(encoder, &sde_encoder_helper_funcs);
+
+	return encoder;
+
+fail:
+	if (encoder)
+		sde_encoder_destroy(encoder);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
new file mode 100644
index 0000000..97faec3
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -0,0 +1,37 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_catalog.h"
+
+struct sde_mdss_hw_cfg_handler cfg_table[] = {
+	{ .major = 1, .minor = 7, .cfg_init = sde_mdss_cfg_170_init},
+};
+
+/**
+ * sde_hw_catalog_init: Returns the catalog information for the
+ * passed HW version
+ * @major:  Major version of the MDSS HW
+ * @minor: Minor version
+ * @step: step version
+ */
+struct sde_mdss_cfg *sde_hw_catalog_init(u32 major, u32 minor, u32 step)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cfg_table); i++) {
+		if ((cfg_table[i].major == major) &&
+		(cfg_table[i].minor == minor))
+			return cfg_table[i].cfg_init(step);
+	}
+
+	return ERR_PTR(-ENODEV);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
new file mode 100644
index 0000000..604efe9
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -0,0 +1,468 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_CATALOG_H
+#define _SDE_HW_CATALOG_H
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/bitmap.h>
+#include <linux/err.h>
+
+#define MAX_BLOCKS    8
+#define MAX_LAYERS    12
+
+#define SDE_HW_VER(MAJOR, MINOR, STEP) (((MAJOR & 0xF) << 28)    |\
+		((MINOR & 0xFFF) << 16)  |\
+		(STEP & 0xFFFF))
+
+#define SDE_HW_MAJOR(rev)		((rev) >> 28)
+#define SDE_HW_MINOR(rev)		.(((rev) >> 16) & 0xFFF)
+#define SDE_HW_STEP(rev)		((rev) & 0xFFFF)
+#define SDE_HW_MAJOR_MINOR(rev)		((rev) >> 16)
+
+#define IS_SDE_MAJOR_MINOR_SAME(rev1, rev2)   \
+	(SDE_HW_MAJOR_MINOR((rev1)) == SDE_HW_MAJOR_MINOR((rev2)))
+
+#define SDE_HW_VER_170	SDE_HW_VER(1, 7, 0) /* 8996 v1.0 */
+#define SDE_HW_VER_171	SDE_HW_VER(1, 7, 1) /* 8996 v2.0 */
+#define SDE_HW_VER_172	SDE_HW_VER(1, 7, 2) /* 8996 v3.0 */
+#define SDE_HW_VER_300	SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */
+
+/**
+ * MDP TOP BLOCK features
+ * @SDE_MDP_PANIC_PER_PIPE Panic configuration needs to be be done per pipe
+ * @SDE_MDP_10BIT_SUPPORT, Chipset supports 10 bit pixel formats
+ * @SDE_MDP_BWC,           MDSS HW supports Bandwidth compression.
+ * @SDE_MDP_UBWC_1_0,      This chipsets supports Universal Bandwidth
+ *                         compression initial revision
+ * @SDE_MDP_UBWC_1_5,      Universal Bandwidth compression version 1.5
+ * @SDE_MDP_CDP,           Client driven prefetch
+ * @SDE_MDP_MAX            Maximum value
+
+ */
+enum {
+	SDE_MDP_PANIC_PER_PIPE = 0x1,
+	SDE_MDP_10BIT_SUPPORT,
+	SDE_MDP_BWC,
+	SDE_MDP_UBWC_1_0,
+	SDE_MDP_UBWC_1_5,
+	SDE_MDP_CDP,
+	SDE_MDP_MAX
+};
+
+/**
+ * SSPP sub-blocks/features
+ * @SDE_SSPP_SRC             Src and fetch part of the pipes,
+ * @SDE_SSPP_SCALAR_QSEED2,  QSEED2 algorithm support
+ * @SDE_SSPP_SCALAR_QSEED3,  QSEED3 algorithm support
+ * @SDE_SSPP_SCALAR_RGB,     RGB Scalar, supported by RGB pipes
+ * @SDE_SSPP_CSC,            Support of Color space conversion
+ * @SDE_SSPP_PA_V1,          Common op-mode register for PA blocks
+ * @SDE_SSPP_HIST_V1         Histogram programming method V1
+ * @SDE_SSPP_IGC,            Inverse gamma correction
+ * @SDE_SSPP_PCC,            Color correction support
+ * @SDE_SSPP_CURSOR,         SSPP can be used as a cursor layer
+ * @SDE_SSPP_MAX             maximum value
+ */
+enum {
+	SDE_SSPP_SRC = 0x1,
+	SDE_SSPP_SCALAR_QSEED2,
+	SDE_SSPP_SCALAR_QSEED3,
+	SDE_SSPP_SCALAR_RGB,
+	SDE_SSPP_CSC,
+	SDE_SSPP_PA_V1, /* Common op-mode register for PA blocks */
+	SDE_SSPP_HIST_V1,
+	SDE_SSPP_IGC,
+	SDE_SSPP_PCC,
+	SDE_SSPP_CURSOR,
+	SDE_SSPP_MAX
+};
+
+/*
+ * MIXER sub-blocks/features
+ * @SDE_MIXER_LAYER           Layer mixer layer blend configuration,
+ * @SDE_MIXER_SOURCESPLIT     Layer mixer supports source-split configuration
+ * @SDE_MIXER_GC              Gamma correction block
+ * @SDE_MIXER_MAX             maximum value
+ */
+enum {
+	SDE_MIXER_LAYER = 0x1,
+	SDE_MIXER_SOURCESPLIT,
+	SDE_MIXER_GC,
+	SDE_MIXER_MAX
+};
+
+/**
+ * DSPP sub-blocks
+ * @SDE_DSPP_IGC             DSPP Inverse gamma correction block
+ * @SDE_DSPP_PCC             Panel color correction block
+ * @SDE_DSPP_GC              Gamma correction block
+ * @SDE_DSPP_PA              Picture adjustment block
+ * @SDE_DSPP_GAMUT           Gamut bloc
+ * @SDE_DSPP_DITHER          Dither block
+ * @SDE_DSPP_HIST            Histogram bloc
+ * @SDE_DSPP_MAX             maximum value
+ */
+enum {
+	SDE_DSPP_IGC = 0x1,
+	SDE_DSPP_PCC,
+	SDE_DSPP_GC,
+	SDE_DSPP_PA,
+	SDE_DSPP_GAMUT,
+	SDE_DSPP_DITHER,
+	SDE_DSPP_HIST,
+	SDE_DSPP_MAX
+};
+
+/**
+ * PINGPONG sub-blocks
+ * @SDE_PINGPONG_TE         Tear check block
+ * @SDE_PINGPONG_TE2        Additional tear check block for split pipes
+ * @SDE_PINGPONG_SPLIT      PP block supports split fifo
+ * @SDE_PINGPONG_DSC,       Display stream compression blocks
+ * @SDE_PINGPONG_MAX
+ */
+enum {
+	SDE_PINGPONG_TE = 0x1,
+	SDE_PINGPONG_TE2,
+	SDE_PINGPONG_SPLIT,
+	SDE_PINGPONG_DSC,
+	SDE_PINGPONG_MAX
+};
+
+/**
+ * WB sub-blocks and features
+ * @SDE_WB_LINE_MODE        Writeback module supports line/linear mode
+ * @SDE_WB_BLOCK_MODE       Writeback module supports block mode read
+ * @SDE_WB_ROTATE           rotation support,this is available if writeback
+ *                          supports block mode read
+ * @SDE_WB_CSC              Writeback color conversion block support
+ * @SDE_WB_CHROMA_DOWN,     Writeback chroma down block,
+ * @SDE_WB_DOWNSCALE,       Writeback integer downscaler,
+ * @SDE_WB_DITHER,          Dither block
+ * @SDE_WB_TRAFFIC_SHAPER,  Writeback traffic shaper bloc
+ * @SDE_WB_UBWC_1_0,        Writeback Universal bandwidth compression 1.0
+ *                          support
+ * @SDE_WB_WBWC_1_5         UBWC 1.5 support
+ * @SDE_WB_MAX              maximum value
+ */
+enum {
+	SDE_WB_LINE_MODE = 0x1,
+	SDE_WB_BLOCK_MODE,
+	SDE_WB_ROTATE = SDE_WB_BLOCK_MODE,
+	SDE_WB_CSC,
+	SDE_WB_CHROMA_DOWN,
+	SDE_WB_DOWNSCALE,
+	SDE_WB_DITHER,
+	SDE_WB_TRAFFIC_SHAPER,
+	SDE_WB_UBWC_1_0,
+	SDE_WB_MAX
+};
+
+/**
+ * MACRO SDE_HW_BLK_INFO - information of HW blocks inside SDE
+ * @id:                enum identifying this block
+ * @base:              register base offset to mdss
+ * @features           bit mask identifying sub-blocks/features
+ */
+#define SDE_HW_BLK_INFO \
+	u32 id; \
+	u32 base; \
+	unsigned long features
+
+/**
+ * MACRO SDE_HW_SUBBLK_INFO - information of HW sub-block inside SDE
+ * @id:                enum identifying this sub-block
+ * @base:              offset of this sub-block relative to the block
+ *                     offset
+ * @len                register block length of this sub-block
+ */
+#define SDE_HW_SUBBLK_INFO \
+	u32 id; \
+	u32 base; \
+	u32 len
+
+/**
+ * struct sde_src_blk: SSPP part of the source pipes
+ * @info:   HW register and features supported by this sub-blk
+ */
+struct sde_src_blk {
+	SDE_HW_SUBBLK_INFO;
+};
+
+/**
+ * struct sde_scalar_info: Scalar information
+ * @info:   HW register and features supported by this sub-blk
+ */
+struct sde_scalar_blk {
+	SDE_HW_SUBBLK_INFO;
+};
+
+struct sde_csc_blk {
+	SDE_HW_SUBBLK_INFO;
+};
+
+/**
+ * struct sde_pp_blk : Pixel processing sub-blk information
+ * @info:   HW register and features supported by this sub-blk
+ * @version: HW Algorithm version
+ */
+struct sde_pp_blk {
+	SDE_HW_SUBBLK_INFO;
+	u32 version;
+};
+
+/**
+ * struct sde_sspp_sub_blks : SSPP sub-blocks
+ * @maxdwnscale: max downscale ratio supported(without DECIMATION)
+ * @maxupscale:  maxupscale ratio supported
+ * @maxwidth:    max pixelwidth supported by this pipe
+ * @danger_lut:  LUT to generate danger signals
+ * @safe_lut:    LUT to generate safe signals
+ * @src_blk:
+ * @scalar_blk:
+ * @csc_blk:
+ * @pa_blk:
+ * @hist_lut:
+ * @pcc_blk:
+ */
+struct sde_sspp_sub_blks {
+	u32 maxlinewidth;
+	u32 danger_lut;
+	u32 safe_lut;
+	u32 maxdwnscale;
+	u32 maxupscale;
+	struct sde_src_blk src_blk;
+	struct sde_scalar_blk scalar_blk;
+	struct sde_pp_blk csc_blk;
+	struct sde_pp_blk pa_blk;
+	struct sde_pp_blk hist_lut;
+	struct sde_pp_blk pcc_blk;
+};
+
+/**
+ * struct sde_lm_sub_blks:      information of mixer block
+ * @maxwidth:               Max pixel width supported by this mixer
+ * @maxblendstages:         Max number of blend-stages supported
+ * @blendstage_base:        Blend-stage register base offset
+ */
+struct sde_lm_sub_blks {
+	u32 maxwidth;
+	u32 maxblendstages;
+	u32 blendstage_base[MAX_BLOCKS];
+};
+
+struct sde_dspp_sub_blks {
+	struct sde_pp_blk igc;
+	struct sde_pp_blk pcc;
+	struct sde_pp_blk gc;
+	struct sde_pp_blk pa;
+	struct sde_pp_blk gamut;
+	struct sde_pp_blk dither;
+	struct sde_pp_blk hist;
+};
+
+struct sde_pingpong_sub_blks {
+	struct sde_pp_blk te;
+	struct sde_pp_blk te2;
+	struct sde_pp_blk dsc;
+};
+
+struct sde_wb_sub_blocks {
+	u32 maxlinewidth;
+};
+
+/* struct sde_mdp_cfg : MDP TOP-BLK instance info
+ * @id:                index identifying this block
+ * @base:              register base offset to mdss
+ * @features           bit mask identifying sub-blocks/features
+ * @highest_bank_bit:  UBWC parameter
+ */
+struct sde_mdp_cfg {
+	SDE_HW_BLK_INFO;
+	u32 highest_bank_bit;
+};
+
+/* struct sde_mdp_cfg : MDP TOP-BLK instance info
+ * @id:                index identifying this block
+ * @base:              register base offset to mdss
+ * @features           bit mask identifying sub-blocks/features
+ */
+struct sde_ctl_cfg {
+	SDE_HW_BLK_INFO;
+};
+
+/**
+ * struct sde_sspp_cfg - information of source pipes
+ * @id:                index identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ * @sblk:              Sub-blocks of SSPP
+ */
+struct sde_sspp_cfg {
+	SDE_HW_BLK_INFO;
+	const struct sde_sspp_sub_blks *sblk;
+};
+
+/**
+ * struct sde_lm_cfg - information of layer mixer blocks
+ * @id:                index identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ * @sblk:              Sub-blocks of SSPP
+ */
+struct sde_lm_cfg {
+	SDE_HW_BLK_INFO;
+	const struct sde_lm_sub_blks *sblk;
+};
+
+/**
+ * struct sde_dspp_cfg - information of DSPP blocks
+ * @id                 enum identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ *                     supported by this block
+ * @sblk               sub-blocks information
+ */
+struct sde_dspp_cfg  {
+	SDE_HW_BLK_INFO;
+	const struct sde_dspp_sub_blks *sblk;
+};
+
+/**
+ * struct sde_pingpong_cfg - information of PING-PONG blocks
+ * @id                 enum identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ * @sblk               sub-blocks information
+ */
+struct sde_pingpong_cfg  {
+	SDE_HW_BLK_INFO;
+	const struct sde_pingpong_sub_blks *sblk;
+};
+
+/**
+ * struct sde_cdm_cfg - information of chroma down blocks
+ * @id                 enum identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ * @intf_connect       Connects to which interfaces
+ * @wb_connect:        Connects to which writebacks
+ */
+struct sde_cdm_cfg   {
+	SDE_HW_BLK_INFO;
+	u32 intf_connect[MAX_BLOCKS];
+	u32 wb_connect[MAX_BLOCKS];
+};
+
+/**
+ * struct sde_intf_cfg - information of timing engine blocks
+ * @id                 enum identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ * @type:              Interface type(DSI, DP, HDMI)
+ */
+struct sde_intf_cfg  {
+	SDE_HW_BLK_INFO;
+	u32 type;   /* interface type*/
+};
+
+/**
+ * struct sde_wb_cfg - information of writeback blocks
+ * @id                 enum identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ */
+struct sde_wb_cfg {
+	SDE_HW_BLK_INFO;
+	struct sde_wb_sub_blocks *sblk;
+};
+
+/**
+ * struct sde_ad_cfg - information of Assertive Display blocks
+ * @id                 enum identifying this block
+ * @base               register offset of this block
+ * @features           bit mask identifying sub-blocks/features
+ */
+struct sde_ad_cfg {
+	SDE_HW_BLK_INFO;
+};
+
+/**
+ * struct sde_mdss_cfg - information of MDSS HW
+ * This is the main catalog data structure representing
+ * this HW version. Contains number of instances,
+ * register offsets, capabilities of the all MDSS HW sub-blocks.
+ */
+struct sde_mdss_cfg {
+	u32 hwversion;
+
+	u32 mdp_count;
+	struct sde_mdp_cfg mdp[MAX_BLOCKS];
+
+	u32 ctl_count;
+	struct sde_ctl_cfg ctl[MAX_BLOCKS];
+
+	u32 sspp_count;
+	struct sde_sspp_cfg sspp[MAX_LAYERS];
+
+	u32 mixer_count;
+	struct sde_lm_cfg mixer[MAX_BLOCKS];
+
+	u32 dspp_count;
+	struct sde_dspp_cfg dspp[MAX_BLOCKS];
+
+	u32 pingpong_count;
+	struct sde_pingpong_cfg pingpong[MAX_BLOCKS];
+
+	u32 cdm_count;
+	struct sde_cdm_cfg cdm[MAX_BLOCKS];
+
+	u32 intf_count;
+	struct sde_intf_cfg intf[MAX_BLOCKS];
+
+	u32 wb_count;
+	struct sde_wb_cfg wb[MAX_BLOCKS];
+
+	u32 ad_count;
+	struct sde_ad_cfg ad[MAX_BLOCKS];
+	/* Add additional block data structures here */
+};
+
+struct sde_mdss_hw_cfg_handler {
+	u32 major;
+	u32 minor;
+	struct sde_mdss_cfg* (*cfg_init)(u32);
+};
+
+/*
+ * Access Macros
+ */
+#define BLK_MDP(s) ((s)->mdp)
+#define BLK_CTL(s) ((s)->ctl)
+#define BLK_VIG(s) ((s)->vig)
+#define BLK_RGB(s) ((s)->rgb)
+#define BLK_DMA(s) ((s)->dma)
+#define BLK_CURSOR(s) ((s)->cursor)
+#define BLK_MIXER(s) ((s)->mixer)
+#define BLK_DSPP(s) ((s)->dspp)
+#define BLK_PINGPONG(s) ((s)->pingpong)
+#define BLK_CDM(s) ((s)->cdm)
+#define BLK_INTF(s) ((s)->intf)
+#define BLK_WB(s) ((s)->wb)
+#define BLK_AD(s) ((s)->ad)
+
+struct sde_mdss_cfg *sde_mdss_cfg_170_init(u32 step);
+struct sde_mdss_cfg *sde_hw_catalog_init(u32 major, u32 minor, u32 step);
+
+#endif /* _SDE_HW_CATALOG_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
new file mode 100644
index 0000000..68782de
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
@@ -0,0 +1,295 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_hwio.h"
+
+/* VIG layer capability */
+#define VIG_17X_MASK \
+	(BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_SCALAR_QSEED2) |\
+	BIT(SDE_SSPP_CSC) | BIT(SDE_SSPP_PA_V1) |\
+	BIT(SDE_SSPP_HIST_V1) | BIT(SDE_SSPP_PCC) |\
+	BIT(SDE_SSPP_IGC))
+
+/* RGB layer capability */
+#define RGB_17X_MASK \
+	(BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_SCALAR_RGB) |\
+	BIT(SDE_SSPP_PCC) | BIT(SDE_SSPP_IGC))
+
+/* DMA layer capability */
+#define DMA_17X_MASK \
+	(BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_PA_V1) |\
+	BIT(SDE_SSPP_PCC) | BIT(SDE_SSPP_IGC))
+
+/* Cursor layer capability */
+#define CURSOR_17X_MASK  (BIT(SDE_SSPP_SRC) | BIT(SDE_SSPP_CURSOR))
+
+#define MIXER_17X_MASK (BIT(SDE_MIXER_SOURCESPLIT) |\
+	BIT(SDE_MIXER_GC))
+
+#define DSPP_17X_MASK \
+	(BIT(SDE_DSPP_IGC) | BIT(SDE_DSPP_PCC) |\
+	BIT(SDE_DSPP_GC) | BIT(SDE_DSPP_PA) | BIT(SDE_DSPP_GAMUT) |\
+	BIT(SDE_DSPP_DITHER) | BIT(SDE_DSPP_HIST))
+
+#define PINGPONG_17X_MASK \
+	(BIT(SDE_PINGPONG_TE) | BIT(SDE_PINGPONG_DSC))
+
+#define PINGPONG_17X_SPLIT_MASK \
+	(PINGPONG_17X_MASK | BIT(SDE_PINGPONG_SPLIT) |\
+	BIT(SDE_PINGPONG_TE2))
+
+#define WB01_17X_MASK \
+	(BIT(SDE_WB_LINE_MODE) | BIT(SDE_WB_BLOCK_MODE) |\
+	BIT(SDE_WB_CSC) | BIT(SDE_WB_CHROMA_DOWN) | BIT(SDE_WB_DOWNSCALE) |\
+	BIT(SDE_WB_DITHER) | BIT(SDE_WB_TRAFFIC_SHAPER) |\
+	BIT(SDE_WB_UBWC_1_0))
+
+#define WB2_17X_MASK \
+	(BIT(SDE_WB_LINE_MODE) | BIT(SDE_WB_TRAFFIC_SHAPER))
+
+/**
+ * set_cfg_1xx_init(): populate sde sub-blocks reg offsets and instance counts
+ */
+static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
+{
+
+	/* Layer capability */
+	static const struct sde_sspp_sub_blks layer = {
+		.maxlinewidth = 2560,
+		.danger_lut = 0xFFFF,
+		.safe_lut = 0xFF00,
+		.maxdwnscale = 4, .maxupscale = 20,
+		.src_blk = {.id = SDE_SSPP_SRC,
+			.base = 0x00, .len = 0x150,},
+		.scalar_blk = {.id = SDE_SSPP_SCALAR_QSEED2,
+			.base = 0x200, .len = 0x70,},
+		.csc_blk = {.id = SDE_SSPP_CSC,
+			.base = 0x320, .len = 0x44,},
+		.pa_blk = {.id = SDE_SSPP_PA_V1,
+			.base = 0x200, .len = 0x0,},
+		.hist_lut = {.id = SDE_SSPP_HIST_V1,
+			.base = 0xA00, .len = 0x400,},
+		.pcc_blk = {.id = SDE_SSPP_PCC,
+			.base = 0x1780, .len = 0x64,},
+	};
+
+	static const struct sde_sspp_sub_blks dma = {
+		.maxlinewidth = 2560,
+		.danger_lut = 0xFFFF,
+		.safe_lut = 0xFF00,
+		.maxdwnscale = 0, .maxupscale = 0,
+		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,},
+		.scalar_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+		.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+		.pa_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+		.hist_lut = {.id = 0, .base = 0x00, .len = 0x0,},
+		.pcc_blk = {.id = SDE_SSPP_PCC, .base = 0x01780, .len = 0x64,},
+	};
+
+	static const struct sde_sspp_sub_blks cursor = {
+		.maxlinewidth = 128,
+		.danger_lut = 0xFFFF,
+		.safe_lut = 0xFF00,
+		.maxdwnscale = 0, .maxupscale = 0,
+		.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,},
+		.scalar_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+		.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+		.pa_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+		.hist_lut = {.id = 0, .base = 0x00, .len = 0x0,},
+		.pcc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
+	};
+
+	/* MIXER capability */
+	static const struct sde_lm_sub_blks lm = {
+		.maxwidth = 2560,
+		.maxblendstages = 7, /* excluding base layer */
+		.blendstage_base = { /* offsets relative to mixer base */
+			0x20, 0x50, 0x80, 0xB0, 0x230, 0x260, 0x290 }
+	};
+
+	/* DSPP capability */
+	static const struct sde_dspp_sub_blks pp = {
+		.igc = {.id = SDE_DSPP_GC, .base = 0x17c0, .len = 0x0,
+			.version = 0x1},
+		.pcc = {.id = SDE_DSPP_PCC, .base = 0x00, .len = 0x0,
+			.version = 0x1},
+		.gamut = {.id = SDE_DSPP_GAMUT, .base = 0x01600, .len = 0x0,
+			.version = 0x1},
+		.dither = {.id = SDE_DSPP_DITHER, .base = 0x00, .len = 0x0,
+			.version = 0x1},
+		.pa = {.id = SDE_DSPP_PA, .base = 0x00, .len = 0x0,
+			.version = 0x1},
+		.hist = {.id = SDE_DSPP_HIST, .base = 0x00, .len = 0x0,
+			.version = 0x1},
+	};
+
+	/* PINGPONG capability */
+	static const struct sde_pingpong_sub_blks p_p = {
+		.te = {.id = SDE_PINGPONG_TE, .base = 0x0000, .len = 0x0,
+			.version = 0x1},
+		.te2 = {.id = SDE_PINGPONG_TE2, .base = 0x2000, .len = 0x0,
+			.version = 0x1},
+		.dsc = {.id = SDE_PINGPONG_DSC, .base = 0x10000, .len = 0x0,
+			.version = 0x1},
+	};
+
+	/* Setup Register maps and defaults */
+	*cfg = (struct sde_mdss_cfg){
+		.mdp_count = 1,
+		.mdp = {
+			{.id = MDP_TOP, .base = 0x00001000, .features = 0,
+				.highest_bank_bit = 0x2},
+		},
+		.ctl_count = 5,
+		.ctl = {
+			{.id = CTL_0, .base = 0x00002000},
+			{.id = CTL_1, .base = 0x00002200},
+			{.id = CTL_2, .base = 0x00002400},
+			{.id = CTL_3, .base = 0x00002600},
+			{.id = CTL_4, .base = 0x00002800},
+		},
+			/* 4 VIG, + 4 RGB + 2 DMA + 2 CURSOR */
+		.sspp_count = 12,
+		.sspp = {
+			{.id = SSPP_VIG0, .base = 0x00005000,
+			.features = VIG_17X_MASK, .sblk = &layer},
+			{.id = SSPP_VIG1, .base = 0x00007000,
+			.features = VIG_17X_MASK, .sblk = &layer},
+			{.id = SSPP_VIG2, .base = 0x00009000,
+			.features = VIG_17X_MASK, .sblk = &layer},
+			{.id = SSPP_VIG3, .base = 0x0000b000,
+			.features = VIG_17X_MASK, .sblk = &layer},
+
+			{.id = SSPP_RGB0, .base = 0x00001500,
+			.features = RGB_17X_MASK, .sblk = &layer},
+			{.id = SSPP_RGB1, .base = 0x00001700,
+			.features = RGB_17X_MASK, .sblk = &layer},
+			{.id = SSPP_RGB2, .base = 0x00001900,
+			.features = RGB_17X_MASK, .sblk = &layer},
+			{.id = SSPP_RGB3, .base = 0x00001B00,
+			.features = RGB_17X_MASK, .sblk = &layer},
+
+			{.id = SSPP_DMA0, .base = 0x00025000,
+			.features = DMA_17X_MASK, .sblk = &dma},
+			{.id = SSPP_DMA1, .base = 0x00027000,
+			.features = DMA_17X_MASK, .sblk = &dma},
+
+			{.id = SSPP_CURSOR0, .base = 0x00035000,
+			.features = CURSOR_17X_MASK, .sblk = &cursor},
+			{.id = SSPP_CURSOR1, .base = 0x00037000,
+			.features = CURSOR_17X_MASK, .sblk = &cursor},
+		},
+		.mixer_count = 6,
+		.mixer = {
+			{.id = LM_0, .base = 0x00045000,
+				.features = MIXER_17X_MASK,
+				.sblk = &lm},
+			{.id = LM_1, .base = 0x00046000,
+				.features = MIXER_17X_MASK,
+				.sblk = &lm},
+			{.id = LM_2, .base = 0x00047000,
+				.features = MIXER_17X_MASK,
+				.sblk = &lm},
+			{.id = LM_3, .base = 0x00048000,
+				.features = MIXER_17X_MASK,
+				.sblk = &lm},
+			{.id = LM_4, .base = 0x00049000,
+				.features = MIXER_17X_MASK,
+				.sblk = &lm},
+			{.id = LM_5, .base = 0x0004a000,
+				.features = MIXER_17X_MASK,
+				.sblk = &lm},
+		},
+		.dspp_count = 2,
+		.dspp = {
+			{.id = DSPP_0, .base = 0x00055000,
+			.features = DSPP_17X_MASK,
+				.sblk = &pp},
+			{.id = DSPP_1, .base = 0x00057000,
+			.features = DSPP_17X_MASK,
+				.sblk = &pp},
+		},
+		.pingpong_count = 4,
+		.pingpong = {
+			{.id = PINGPONG_0, .base = 0x00071000,
+				.features = PINGPONG_17X_SPLIT_MASK,
+				.sblk = &p_p},
+			{.id = PINGPONG_1, .base = 0x00071800,
+				.features = PINGPONG_17X_SPLIT_MASK,
+				.sblk = &p_p},
+			{.id = PINGPONG_2, .base = 0x00072000,
+				.features = PINGPONG_17X_MASK,
+				.sblk = &p_p},
+			{.id = PINGPONG_3, .base = 0x00072800,
+				.features = PINGPONG_17X_MASK,
+				.sblk = &p_p},
+		},
+		.cdm_count = 1,
+		.cdm = {
+			{.id = CDM_0, .base = 0x0007A200, .features = 0,
+				.intf_connect = { BIT(INTF_3)},
+				.wb_connect = { BIT(WB_2)},}
+		},
+		.intf_count = 4,
+		.intf = {
+			{.id = INTF_0, .base = 0x0006B000,
+				.type = INTF_NONE},
+			{.id = INTF_1, .base = 0x0006B800,
+				.type = INTF_DSI},
+			{.id = INTF_2, .base = 0x0006C000,
+				.type = INTF_DSI},
+			{.id = INTF_3, .base = 0x0006C800,
+				.type = INTF_HDMI},
+		},
+		.wb_count = 3,
+		.wb = {
+			{.id = WB_0, .base = 0x00065000,
+				.features = WB01_17X_MASK},
+			{.id = WB_1, .base = 0x00065800,
+				.features = WB01_17X_MASK},
+			{.id = WB_2, .base = 0x00066000,
+				.features = WB2_17X_MASK},
+		},
+		.ad_count = 2,
+		.ad = {
+			{.id = AD_0, .base = 0x00079000},
+			{.id = AD_1, .base = 0x00079800},
+		},
+	};
+	return 0;
+}
+
+/**
+ * sde_mdp_cfg_170_init(): Populate the sde sub-blocks catalog information
+ */
+struct sde_mdss_cfg *sde_mdss_cfg_170_init(u32 step)
+{
+	struct sde_mdss_cfg *m = NULL;
+
+	/*
+	 * This function, for each sub-block sets,
+	 * instance count, IO regions,
+	 * default capabilities and this version capabilities,
+	 * Additional catalog items
+	 */
+
+	m = kzalloc(sizeof(*m), GFP_KERNEL);
+	if (!m)
+		return NULL;
+
+	set_cfg_1xx_init(m);
+	m->hwversion = SDE_HW_VER(1, 7, step);
+
+	return m;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
new file mode 100644
index 0000000..9697553
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
@@ -0,0 +1,296 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_mdss.h"
+#include "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_cdm.h"
+
+#define CDM_CSC_10_OPMODE                  0x000
+#define CDM_CSC_10_BASE                    0x004
+
+#define CDM_CDWN2_OP_MODE                  0x100
+#define CDM_CDWN2_CLAMP_OUT                0x104
+#define CDM_CDWN2_PARAMS_3D_0              0x108
+#define CDM_CDWN2_PARAMS_3D_1              0x10C
+#define CDM_CDWN2_COEFF_COSITE_H_0         0x110
+#define CDM_CDWN2_COEFF_COSITE_H_1         0x114
+#define CDM_CDWN2_COEFF_COSITE_H_2         0x118
+#define CDM_CDWN2_COEFF_OFFSITE_H_0        0x11C
+#define CDM_CDWN2_COEFF_OFFSITE_H_1        0x120
+#define CDM_CDWN2_COEFF_OFFSITE_H_2        0x124
+#define CDM_CDWN2_COEFF_COSITE_V           0x128
+#define CDM_CDWN2_COEFF_OFFSITE_V          0x12C
+#define CDM_CDWN2_OUT_SIZE                 0x130
+
+#define CDM_HDMI_PACK_OP_MODE              0x200
+#define CDM_CSC_10_MATRIX_COEFF_0          0x204
+
+/**
+ * Horizontal coeffiecients for cosite chroma downscale
+ * s13 repesentation of coefficients
+ */
+static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e};
+
+/**
+ * Horizontal coefficients for offsite chroma downscale
+ */
+static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046};
+
+/**
+ * Vertical coefficients for cosite chroma downscale
+ */
+static u32 cosite_v_coeff[] = {0x00080004};
+/**
+ * Vertical coefficients for offsite chroma downscale
+ */
+static u32 offsite_v_coeff[] = {0x00060002};
+
+/* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */
+static struct sde_csc_cfg rgb2yuv_cfg = {
+	{
+		0x0083, 0x0102, 0x0032,
+		0x1fb5, 0x1f6c, 0x00e1,
+		0x00e1, 0x1f45, 0x1fdc
+	},
+	{ 0x00, 0x00, 0x00 },
+	{ 0x0040, 0x0200, 0x0200 },
+	{ 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff },
+	{ 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 },
+};
+
+static struct sde_cdm_cfg *_cdm_offset(enum sde_cdm cdm,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->cdm_count; i++) {
+		if (cdm == m->cdm[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->cdm[i].base;
+			b->hwversion = m->hwversion;
+			return &m->cdm[i];
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static void sde_hw_cdm_setup_csc_10bit(struct sde_hw_cdm *ctx,
+		struct sde_csc_cfg *data)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+	sde_hw_csc_setup(c, CDM_CSC_10_MATRIX_COEFF_0, data);
+}
+
+int sde_hw_cdm_setup_cdwn(struct sde_hw_cdm *ctx,
+		struct sde_hw_cdm_cfg *cfg)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 opmode = 0;
+	u32 out_size = 0;
+
+	if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT)
+		opmode &= ~BIT(7);
+	else
+		opmode |= BIT(7);
+
+	/* ENABLE DWNS_H bit */
+	opmode |= BIT(1);
+
+	switch (cfg->h_cdwn_type) {
+	case CDM_CDWN_DISABLE:
+		/* CLEAR METHOD_H field */
+		opmode &= ~(0x18);
+		/* CLEAR DWNS_H bit */
+		opmode &= ~BIT(1);
+		break;
+	case CDM_CDWN_PIXEL_DROP:
+		/* Clear METHOD_H field (pixel drop is 0) */
+		opmode &= ~(0x18);
+		break;
+	case CDM_CDWN_AVG:
+		/* Clear METHOD_H field (Average is 0x1) */
+		opmode &= ~(0x18);
+		opmode |= (0x1 << 0x3);
+		break;
+	case CDM_CDWN_COSITE:
+		/* Clear METHOD_H field (Average is 0x2) */
+		opmode &= ~(0x18);
+		opmode |= (0x2 << 0x3);
+		/* Co-site horizontal coefficients */
+		SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0,
+				cosite_h_coeff[0]);
+		SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1,
+				cosite_h_coeff[1]);
+		SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2,
+				cosite_h_coeff[2]);
+		break;
+	case CDM_CDWN_OFFSITE:
+		/* Clear METHOD_H field (Average is 0x3) */
+		opmode &= ~(0x18);
+		opmode |= (0x3 << 0x3);
+
+		/* Off-site horizontal coefficients */
+		SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0,
+				offsite_h_coeff[0]);
+		SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1,
+				offsite_h_coeff[1]);
+		SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2,
+				offsite_h_coeff[2]);
+		break;
+	default:
+		pr_err("%s invalid horz down sampling type\n", __func__);
+		return -EINVAL;
+	}
+
+	/* ENABLE DWNS_V bit */
+	opmode |= BIT(2);
+
+	switch (cfg->v_cdwn_type) {
+	case CDM_CDWN_DISABLE:
+		/* CLEAR METHOD_V field */
+		opmode &= ~(0x60);
+		/* CLEAR DWNS_V bit */
+		opmode &= ~BIT(2);
+		break;
+	case CDM_CDWN_PIXEL_DROP:
+		/* Clear METHOD_V field (pixel drop is 0) */
+		opmode &= ~(0x60);
+		break;
+	case CDM_CDWN_AVG:
+		/* Clear METHOD_V field (Average is 0x1) */
+		opmode &= ~(0x60);
+		opmode |= (0x1 << 0x5);
+		break;
+	case CDM_CDWN_COSITE:
+		/* Clear METHOD_V field (Average is 0x2) */
+		opmode &= ~(0x60);
+		opmode |= (0x2 << 0x5);
+		/* Co-site vertical coefficients */
+		SDE_REG_WRITE(c,
+				CDM_CDWN2_COEFF_COSITE_V,
+				cosite_v_coeff[0]);
+		break;
+	case CDM_CDWN_OFFSITE:
+		/* Clear METHOD_V field (Average is 0x3) */
+		opmode &= ~(0x60);
+		opmode |= (0x3 << 0x5);
+
+		/* Off-site vertical coefficients */
+		SDE_REG_WRITE(c,
+				CDM_CDWN2_COEFF_OFFSITE_V,
+				offsite_v_coeff[0]);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (cfg->v_cdwn_type || cfg->h_cdwn_type)
+		opmode |= BIT(0); /* EN CDWN module */
+	else
+		opmode &= ~BIT(0);
+
+	out_size = (cfg->output_width & 0xFFFF) |
+		((cfg->output_height & 0xFFFF) << 16);
+	SDE_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size);
+	SDE_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode);
+	SDE_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT,
+			((0x3FF << 16) | 0x0));
+
+	return 0;
+}
+
+int sde_hw_cdm_enable(struct sde_hw_cdm *ctx,
+		struct sde_hw_cdm_cfg *cdm)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	struct sde_mdp_format_params *fmt = cdm->output_fmt;
+	u32 opmode = 0;
+	u32 cdm_enable = 0;
+	u32 csc = 0;
+
+	if (!fmt->is_yuv)
+		return 0;
+
+	if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
+		if (fmt->chroma_sample != SDE_MDP_CHROMA_H1V2)
+			return -EINVAL; /*unsupported format */
+		opmode = BIT(0);
+		opmode |= (fmt->chroma_sample << 1);
+		cdm_enable |= BIT(19);
+	} else {
+		opmode = 0;
+		cdm_enable = BIT(24);
+	}
+
+	csc |= BIT(2);
+	csc &= ~BIT(1);
+	csc |= BIT(0);
+
+	/* For this register we need to offset it to MDP TOP BLOCK */
+	SDE_REG_WRITE(c, MDP_OUT_CTL_0, cdm_enable);
+
+	SDE_REG_WRITE(c, CDM_CSC_10_OPMODE, csc);
+	SDE_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode);
+	return 0;
+}
+
+void sde_hw_cdm_disable(struct sde_hw_cdm *ctx)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+	/* mdp top block */
+	SDE_REG_WRITE(c, MDP_OUT_CTL_0, 0); /* bypass mode */
+}
+
+static void _setup_cdm_ops(struct sde_hw_cdm_ops *ops,
+	unsigned long features)
+{
+	ops->setup_csc_data = sde_hw_cdm_setup_csc_10bit;
+	ops->setup_cdwn = sde_hw_cdm_setup_cdwn;
+	ops->enable = sde_hw_cdm_enable;
+	ops->disable = sde_hw_cdm_disable;
+}
+
+struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m)
+{
+	struct sde_hw_cdm *c;
+	struct sde_cdm_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _cdm_offset(idx, m, addr, &c->hw);
+	if (IS_ERR_OR_NULL(cfg)) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	c->idx = idx;
+	c->cdm_hw_cap = cfg;
+	_setup_cdm_ops(&c->ops, c->cdm_hw_cap->features);
+
+	/*
+	 * Perform any default initialization for the chroma down module
+	 * @setup default csc coefficients
+	 */
+	sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg);
+
+	return c;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.h b/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
new file mode 100644
index 0000000..d606ef5
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_CDM_H
+#define _SDE_HW_CDM_H
+
+#include "sde_hw_mdss.h"
+
+struct sde_hw_cdm;
+
+struct sde_hw_cdm_cfg {
+	u32 output_width;
+	u32 output_height;
+	u32 output_bit_depth;
+	u32 h_cdwn_type;
+	u32 v_cdwn_type;
+	struct sde_mdp_format_params *output_fmt;
+	u32 output_type;
+	int flags;
+};
+
+enum sde_hw_cdwn_type {
+	CDM_CDWN_DISABLE,
+	CDM_CDWN_PIXEL_DROP,
+	CDM_CDWN_AVG,
+	CDM_CDWN_COSITE,
+	CDM_CDWN_OFFSITE,
+};
+
+enum sde_hw_cdwn_output_type {
+	CDM_CDWN_OUTPUT_HDMI,
+	CDM_CDWN_OUTPUT_WB,
+};
+
+enum sde_hw_cdwn_output_bit_depth {
+	CDM_CDWN_OUTPUT_8BIT,
+	CDM_CDWN_OUTPUT_10BIT,
+};
+
+/**
+ * struct sde_hw_cdm_ops : Interface to the chroma down Hw driver functions
+ *                         Assumption is these functions will be called after
+ *                         clocks are enabled
+ *  @setup_csc:            Programs the csc matrix
+ *  @setup_cdwn:           Sets up the chroma down sub module
+ *  @enable:               Enables the output to interface and programs the
+ *                         output packer
+ *  @disable:              Puts the cdm in bypass mode
+ */
+struct sde_hw_cdm_ops {
+	/**
+	 * Programs the CSC matrix for conversion from RGB space to YUV space,
+	 * it is optinal to call this function as this matrix is automatically
+	 * set during initialization, user should call this if it wants
+	 * to program a different matrix than default matrix.
+	 * @cdm:          Pointer to the chroma down context structure
+	 * @data          Pointer to CSC configuration data
+	 */
+	void (*setup_csc_data)(struct sde_hw_cdm *cdm,
+			struct sde_csc_cfg *data);
+
+	/**
+	 * Programs the Chroma downsample part.
+	 * @cdm         Pointer to chroma down context
+	 */
+	int (*setup_cdwn)(struct sde_hw_cdm *cdm,
+	struct sde_hw_cdm_cfg *cfg);
+
+	/**
+	 * Enable the CDM module
+	 * @cdm         Pointer to chroma down context
+	 */
+	int (*enable)(struct sde_hw_cdm *cdm,
+	struct sde_hw_cdm_cfg *cfg);
+
+	/**
+	 * Disable the CDM module
+	 * @cdm         Pointer to chroma down context
+	 */
+	void (*disable)(struct sde_hw_cdm *cdm);
+};
+
+struct sde_hw_cdm {
+	/* base */
+	struct sde_hw_blk_reg_map hw;
+
+	/* chroma down */
+	const struct sde_cdm_cfg   *cdm_hw_cap;
+	enum  sde_cdm  idx;
+
+	/* ops */
+	struct sde_hw_cdm_ops ops;
+};
+
+/**
+ * sde_hw_cdm_init(): Initializes the cdm hw driver object.
+ * should be called once before accessing every cdm.
+ * @idx:  cdm index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m :   pointer to mdss catalog data
+ */
+struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_CDM_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
new file mode 100644
index 0000000..fe8917f
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -0,0 +1,105 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_mdss.h"
+#include "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_dspp.h"
+
+static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->dspp_count; i++) {
+		if (dspp == m->dspp[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->dspp[i].base;
+			b->hwversion = m->hwversion;
+			return &m->dspp[i];
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+void sde_dspp_setup_histogram(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+void sde_dspp_read_histogram(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+void sde_dspp_update_igc(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+void sde_dspp_setup_pa(struct sde_hw_dspp *dspp, void *cfg)
+{
+}
+
+void sde_dspp_setup_pcc(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+void sde_dspp_setup_sharpening(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+void sde_dspp_setup_pa_memcolor(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+void sde_dspp_setup_sixzone(struct sde_hw_dspp *dspp)
+{
+}
+
+void sde_dspp_setup_danger_safe(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+void sde_dspp_setup_dither(struct sde_hw_dspp *ctx, void *cfg)
+{
+}
+
+static void _setup_dspp_ops(struct sde_hw_dspp_ops *ops,
+		unsigned long features)
+{
+}
+struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
+			void __iomem *addr,
+			struct sde_mdss_cfg *m)
+{
+	struct sde_hw_dspp *c;
+	struct sde_dspp_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _dspp_offset(idx, m, addr, &c->hw);
+	if (IS_ERR_OR_NULL(cfg)) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Assign ops */
+	c->idx = idx;
+	c->cap = cfg;
+	_setup_dspp_ops(&c->ops, c->cap->features);
+
+	return c;
+}
+
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
new file mode 100644
index 0000000..28c3cf1
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_DSPP_H
+#define _SDE_HW_DSPP_H
+
+struct sde_hw_dspp;
+
+/**
+ * struct sde_hw_dspp_ops - interface to the dspp hardware driver functions
+ * Caller must call the init function to get the dspp context for each dspp
+ * Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_dspp_ops {
+	/**
+	 * setup_histogram - setup dspp histogram
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_histogram)(struct sde_hw_dspp *ctx, void *cfg);
+
+	/**
+	 * read_histogram - read dspp histogram
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*read_histogram)(struct sde_hw_dspp *ctx, void *cfg);
+
+	/**
+	 * update_igc - update dspp igc
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*update_igc)(struct sde_hw_dspp *ctx, void *cfg);
+
+	/**
+	 * setup_pa - setup dspp pa
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_pa)(struct sde_hw_dspp *dspp, void *cfg);
+
+	/**
+	 * setup_pcc - setup dspp pcc
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_pcc)(struct sde_hw_dspp *ctx, void *cfg);
+
+	/**
+	 * setup_sharpening - setup dspp sharpening
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_sharpening)(struct sde_hw_dspp *ctx, void *cfg);
+
+	/**
+	 * setup_pa_memcolor - setup dspp memcolor
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_pa_memcolor)(struct sde_hw_dspp *ctx, void *cfg);
+
+	/**
+	 * setup_sixzone - setup dspp six zone
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_sixzone)(struct sde_hw_dspp *dspp);
+
+	/**
+	 * setup_danger_safe - setup danger safe LUTS
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_danger_safe)(struct sde_hw_dspp *ctx, void *cfg);
+	/**
+	 * setup_dither - setup dspp dither
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_dither)(struct sde_hw_dspp *ctx, void *cfg);
+};
+
+/**
+ * struct sde_hw_dspp - dspp description
+ * @base_off:     MDP register mapped offset
+ * @blk_off:      DSPP offset relative to mdss offset
+ * @length        Length of register block offset
+ * @hwversion     Mdss hw version number
+ * @idx:          DSPP index
+ * @dspp_hw_cap:  Pointer to layer_cfg
+ * @highest_bank_bit:
+ * @ops:          Pointer to operations possible for this dspp
+ */
+struct sde_hw_dspp {
+	/* base */
+	 struct sde_hw_blk_reg_map hw;
+
+	/* dspp */
+	enum sde_dspp idx;
+	const struct sde_dspp_cfg *cap;
+
+	/* Ops */
+	struct sde_hw_dspp_ops ops;
+};
+
+/**
+ * sde_hw_dspp_init - initializes the dspp hw driver object.
+ * should be called once before accessing every dspp.
+ * @idx:  DSPP index for which driver object is required
+ * @addr: Mapped register io address of MDP
+ */
+struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
+			void __iomem *addr,
+			struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_DSPP_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
new file mode 100644
index 0000000..6981425
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -0,0 +1,373 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_intf.h"
+
+#define INTF_TIMING_ENGINE_EN           0x000
+#define INTF_CONFIG                     0x004
+#define INTF_HSYNC_CTL                  0x008
+#define INTF_VSYNC_PERIOD_F0            0x00C
+#define INTF_VSYNC_PERIOD_F1            0x010
+#define INTF_VSYNC_PULSE_WIDTH_F0       0x014
+#define INTF_VSYNC_PULSE_WIDTH_F1       0x018
+#define INTF_DISPLAY_V_START_F0         0x01C
+#define INTF_DISPLAY_V_START_F1         0x020
+#define INTF_DISPLAY_V_END_F0           0x024
+#define INTF_DISPLAY_V_END_F1           0x028
+#define INTF_ACTIVE_V_START_F0          0x02C
+#define INTF_ACTIVE_V_START_F1          0x030
+#define INTF_ACTIVE_V_END_F0            0x034
+#define INTF_ACTIVE_V_END_F1            0x038
+#define INTF_DISPLAY_HCTL               0x03C
+#define INTF_ACTIVE_HCTL                0x040
+#define INTF_BORDER_COLOR               0x044
+#define INTF_UNDERFLOW_COLOR            0x048
+#define INTF_HSYNC_SKEW                 0x04C
+#define INTF_POLARITY_CTL               0x050
+#define INTF_TEST_CTL                   0x054
+#define INTF_TP_COLOR0                  0x058
+#define INTF_TP_COLOR1                  0x05C
+#define INTF_FRAME_LINE_COUNT_EN        0x0A8
+#define INTF_FRAME_COUNT                0x0AC
+#define   INTF_LINE_COUNT               0x0B0
+
+#define   INTF_DEFLICKER_CONFIG         0x0F0
+#define   INTF_DEFLICKER_STRNG_COEFF    0x0F4
+#define   INTF_DEFLICKER_WEAK_COEFF     0x0F8
+
+#define   INTF_DSI_CMD_MODE_TRIGGER_EN  0x084
+#define   INTF_PANEL_FORMAT             0x090
+#define   INTF_TPG_ENABLE               0x100
+#define   INTF_TPG_MAIN_CONTROL         0x104
+#define   INTF_TPG_VIDEO_CONFIG         0x108
+#define   INTF_TPG_COMPONENT_LIMITS     0x10C
+#define   INTF_TPG_RECTANGLE            0x110
+#define   INTF_TPG_INITIAL_VALUE        0x114
+#define   INTF_TPG_BLK_WHITE_PATTERN_FRAMES   0x118
+#define   INTF_TPG_RGB_MAPPING          0x11C
+#define   INTF_PROG_FETCH_START         0x170
+
+#define   INTF_FRAME_LINE_COUNT_EN      0x0A8
+#define   INTF_FRAME_COUNT              0x0AC
+#define   INTF_LINE_COUNT               0x0B0
+
+static struct sde_intf_cfg *_intf_offset(enum sde_intf intf,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->intf_count; i++) {
+		if (intf == m->intf[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->intf[i].base;
+			b->hwversion = m->hwversion;
+			return &m->intf[i];
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx,
+		struct intf_timing_params *p,
+		struct sde_mdp_format_params *fmt)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 hsync_period, vsync_period;
+	u32 display_v_start, display_v_end;
+	u32 hsync_start_x, hsync_end_x;
+	u32 active_h_start, active_h_end;
+	u32 active_v_start, active_v_end;
+	u32 active_hctl, display_hctl, hsync_ctl;
+	u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
+	u32 panel_format;
+	u32 intf_cfg;
+
+	/* read interface_cfg */
+	intf_cfg = SDE_REG_READ(c, INTF_CONFIG);
+	hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
+	p->h_front_porch;
+	vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
+	p->v_front_porch;
+
+	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
+	hsync_period) + p->hsync_skew;
+	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
+	p->hsync_skew - 1;
+
+	if (ctx->cap->type == INTF_EDP) {
+		display_v_start += p->hsync_pulse_width + p->h_back_porch;
+		display_v_end -= p->h_front_porch;
+	}
+
+	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
+	hsync_end_x = hsync_period - p->h_front_porch - 1;
+
+	if (p->width != p->xres) {
+		active_h_start = hsync_start_x;
+		active_h_end = active_h_start + p->xres - 1;
+	} else {
+		active_h_start = 0;
+		active_h_end = 0;
+	}
+
+	if (p->height != p->yres) {
+		active_v_start = display_v_start;
+		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
+	} else {
+		active_v_start = 0;
+		active_v_end = 0;
+	}
+
+	if (active_h_end) {
+		active_hctl = (active_h_end << 16) | active_h_start;
+		intf_cfg |= BIT(29);	/* ACTIVE_H_ENABLE */
+	} else {
+		active_hctl = 0;
+	}
+
+	if (active_v_end)
+		intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */
+
+	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
+	display_hctl = (hsync_end_x << 16) | hsync_start_x;
+
+	den_polarity = 0;
+	if (ctx->cap->type == INTF_HDMI) {
+		hsync_polarity = p->yres >= 720 ? 0 : 1;
+		vsync_polarity = p->yres >= 720 ? 0 : 1;
+	} else {
+		hsync_polarity = 0;
+		vsync_polarity = 0;
+	}
+	polarity_ctl = (den_polarity << 2) | /*  DEN Polarity  */
+		(vsync_polarity << 1) | /* VSYNC Polarity */
+		(hsync_polarity << 0);  /* HSYNC Polarity */
+
+	if (!fmt->is_yuv)
+		panel_format = (fmt->bits[0] |
+				(fmt->bits[1] << 2) |
+				(fmt->bits[2] << 4) |
+				(0x21 << 8));
+	else
+	/* Interface treats all the pixel data in RGB888 format */
+		panel_format |= (COLOR_8BIT      |
+				(COLOR_8BIT << 2) |
+				(COLOR_8BIT << 4) |
+				(0x21 << 8));
+
+	SDE_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
+	SDE_REG_WRITE(c, INTF_VSYNC_PERIOD_F0,
+			vsync_period * hsync_period);
+	SDE_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
+			p->vsync_pulse_width * hsync_period);
+	SDE_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl);
+	SDE_REG_WRITE(c, INTF_DISPLAY_V_START_F0,
+			display_v_start);
+	SDE_REG_WRITE(c, INTF_DISPLAY_V_END_F0,
+			display_v_end);
+	SDE_REG_WRITE(c, INTF_ACTIVE_HCTL,  active_hctl);
+	SDE_REG_WRITE(c, INTF_ACTIVE_V_START_F0,
+			active_v_start);
+	SDE_REG_WRITE(c, INTF_ACTIVE_V_END_F0,
+			active_v_end);
+
+	SDE_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr);
+	SDE_REG_WRITE(c, INTF_UNDERFLOW_COLOR,
+			p->underflow_clr);
+	SDE_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew);
+	SDE_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl);
+	SDE_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
+	SDE_REG_WRITE(c, INTF_CONFIG, intf_cfg);
+	SDE_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
+}
+
+static void sde_hw_intf_enable_timing_engine(
+		struct sde_hw_intf *intf,
+		u8 enable)
+{
+	struct sde_hw_blk_reg_map *c = &intf->hw;
+	u32 intf_sel;
+
+	/* Display interface select */
+	if (enable) {
+		intf_sel = SDE_REG_READ(c, DISP_INTF_SEL);
+
+		intf_sel |= (intf->cap->type << ((intf->idx) * 8));
+		SDE_REG_WRITE(c, DISP_INTF_SEL,  intf_sel);
+	}
+
+	SDE_REG_WRITE(c, INTF_TIMING_ENGINE_EN,
+			enable & 0x1);
+}
+
+static void sde_hw_intf_setup_prg_fetch(
+		struct sde_hw_intf *intf,
+		struct intf_prog_fetch *fetch)
+{
+	struct sde_hw_blk_reg_map *c = &intf->hw;
+	int fetch_enable;
+
+	/*
+	 * Fetch should always be outside the active lines. If the fetching
+	 * is programmed within active region, hardware behavior is unknown.
+	 */
+
+	fetch_enable = SDE_REG_READ(c, INTF_CONFIG);
+	if (fetch->enable) {
+		fetch_enable |= BIT(31);
+		SDE_REG_WRITE(c, INTF_PROG_FETCH_START,
+				fetch->fetch_start);
+	} else {
+		fetch_enable &= ~BIT(31);
+	}
+
+	SDE_REG_WRITE(c, INTF_CONFIG, fetch_enable);
+}
+
+static void sde_hw_intf_get_timing_config(
+		struct sde_hw_intf *intf,
+		struct intf_timing_params *cfg)
+{
+	struct sde_hw_blk_reg_map *c = &intf->hw;
+	u32 vsync_period;
+	u32 display_v_start, display_v_end;
+	u32 hsync_start_x, hsync_end_x;
+	u32 active_v_start, active_v_end;
+	u32 active_hctl, display_hctl, hsync_ctl;
+	u32 polarity_ctl;
+	u32 pulse_width;
+	u32 htotal, vtotal;
+	u32 intf_cfg;
+
+	hsync_ctl = SDE_REG_READ(c, INTF_HSYNC_CTL);
+	vsync_period = SDE_REG_READ(c, INTF_VSYNC_PERIOD_F0);
+	pulse_width = SDE_REG_READ(c, INTF_VSYNC_PULSE_WIDTH_F0);
+	display_hctl = SDE_REG_READ(c, INTF_DISPLAY_HCTL);
+	display_v_start = SDE_REG_READ(c, INTF_DISPLAY_V_START_F0);
+	display_v_end = SDE_REG_READ(c, INTF_DISPLAY_V_END_F0);
+	active_hctl = SDE_REG_READ(c, INTF_ACTIVE_HCTL);
+	active_v_start = SDE_REG_READ(c, INTF_ACTIVE_V_START_F0);
+	active_v_end = SDE_REG_READ(c, INTF_ACTIVE_V_END_F0);
+	intf_cfg = SDE_REG_READ(c, INTF_CONFIG);
+	cfg->border_clr = SDE_REG_READ(c, INTF_BORDER_COLOR);
+	cfg->underflow_clr = SDE_REG_READ(c, INTF_UNDERFLOW_COLOR);
+	cfg->hsync_skew = SDE_REG_READ(c, INTF_HSYNC_SKEW);
+	polarity_ctl = SDE_REG_READ(c, INTF_POLARITY_CTL);
+
+	hsync_start_x = (display_hctl & 0xffff);
+	hsync_end_x = (display_hctl & 0xffff0000) >> 16;
+	cfg->hsync_pulse_width = (hsync_ctl & 0xffff);
+	htotal = (hsync_ctl & 0xffff0000) >> 16;
+
+	if (htotal != 0) {
+		vtotal = vsync_period / htotal;
+		cfg->vsync_pulse_width = pulse_width/htotal;
+
+		/* porches */
+		cfg->h_front_porch = htotal - hsync_end_x - 1;
+		cfg->h_back_porch = hsync_start_x - cfg->hsync_pulse_width;
+		cfg->v_front_porch = vsync_period - display_v_end;
+		cfg->v_back_porch = display_v_start - cfg->vsync_pulse_width;
+
+		/* active resolution */
+		cfg->width = htotal - cfg->hsync_pulse_width -
+		cfg->h_back_porch -
+			cfg->h_front_porch;
+		cfg->height =  vtotal - cfg->vsync_pulse_width -
+		cfg->v_back_porch - cfg->v_front_porch;
+
+		/* display panel resolution */
+		if (intf_cfg & BIT(29))
+			cfg->xres = ((active_hctl & 0xffff0000) >> 16) -
+			(active_hctl & 0xffff) + 1;
+		else
+			cfg->xres = cfg->width;
+
+		if (intf_cfg & BIT(30))
+			cfg->yres = (active_v_end - active_v_start + 1
+			)/htotal;
+		else
+			cfg->yres = cfg->height;
+	} else {
+		cfg->vsync_pulse_width = 0;
+		cfg->h_front_porch = 0;
+		cfg->h_back_porch = 0;
+		cfg->v_front_porch = 0;
+		cfg->v_back_porch = 0;
+		cfg->width = 0;
+		cfg->height = 0;
+	}
+
+	cfg->hsync_polarity = polarity_ctl & 1;
+	cfg->vsync_polarity = (polarity_ctl & 2) >> 1;
+}
+
+static void sde_hw_intf_get_status(
+		struct sde_hw_intf *intf,
+		struct intf_status *s)
+{
+	struct sde_hw_blk_reg_map *c = &intf->hw;
+
+	s->is_en = SDE_REG_READ(c, INTF_TIMING_ENGINE_EN);
+	if (s->is_en) {
+		s->frame_count = SDE_REG_READ(c, INTF_FRAME_COUNT);
+		s->line_count = SDE_REG_READ(c, INTF_LINE_COUNT);
+	} else {
+		s->line_count = 0;
+		s->frame_count = 0;
+	}
+}
+
+static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
+		unsigned long cap)
+{
+	ops->setup_timing_gen = sde_hw_intf_setup_timing_engine;
+	ops->setup_prg_fetch  = sde_hw_intf_setup_prg_fetch;
+	ops->get_timing_gen = sde_hw_intf_get_timing_config;
+	ops->get_status = sde_hw_intf_get_status;
+	ops->enable_timing = sde_hw_intf_enable_timing_engine;
+}
+
+struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m)
+{
+	struct sde_hw_intf *c;
+	struct sde_intf_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _intf_offset(idx, m, addr, &c->hw);
+	if (!cfg) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/*
+	 * Assign ops
+	 */
+	c->idx = idx;
+	c->cap = cfg;
+	_setup_intf_ops(&c->ops, c->cap->features);
+
+	/*
+	 * Perform any default initialization for the intf
+	 */
+	return c;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
new file mode 100644
index 0000000..ce51906
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_INTF_H
+#define _SDE_HW_INTF_H
+
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+
+struct sde_hw_intf;
+
+/* intf timing settings */
+struct intf_timing_params {
+	u32 width;		/* active width */
+	u32 height;		/* active height */
+	u32 xres;		/* Display panel width */
+	u32 yres;		/* Display panel height */
+
+	u32 h_back_porch;
+	u32 h_front_porch;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 hsync_pulse_width;
+	u32 vsync_pulse_width;
+	u32 hsync_polarity;
+	u32 vsync_polarity;
+	u32 border_clr;
+	u32 underflow_clr;
+	u32 hsync_skew;
+};
+
+struct intf_prog_fetch {
+	u8 enable;
+	/* vsync counter for the front porch pixel line */
+	u32 fetch_start;
+};
+
+struct intf_status {
+	u8 is_en;		/* interface timing engine is enabled or not */
+	u32 frame_count;	/* frame count since timing engine enabled */
+	u32 line_count;		/* current line count including blanking */
+};
+
+/**
+ * struct sde_hw_intf_ops : Interface to the interface Hw driver functions
+ *  Assumption is these functions will be called after clocks are enabled
+ * @ setup_timing_gen : programs the timing engine
+ * @ setup_prog_fetch : enables/disables the programmable fetch logic
+ * @ enable_timing: enable/disable timing engine
+ * @ get_timing_gen: get timing generator programmed configuration
+ * @ get_status: returns if timing engine is enabled or not
+ */
+struct sde_hw_intf_ops {
+	void (*setup_timing_gen)(struct sde_hw_intf *intf,
+			struct intf_timing_params *p,
+			struct sde_mdp_format_params *fmt);
+
+	void (*setup_prg_fetch)(struct sde_hw_intf *intf,
+			struct intf_prog_fetch *fetch);
+
+	void (*enable_timing)(struct sde_hw_intf *intf,
+			u8 enable);
+
+	void (*get_timing_gen)(struct sde_hw_intf *intf,
+			struct intf_timing_params *cfg);
+
+	void (*get_status)(struct sde_hw_intf *intf,
+			struct intf_status *status);
+};
+
+struct sde_hw_intf {
+	/* base */
+	struct sde_hw_blk_reg_map hw;
+
+	/* intf */
+	enum sde_intf idx;
+	const struct sde_intf_cfg *cap;
+
+	/* ops */
+	struct sde_hw_intf_ops ops;
+};
+
+/**
+ * sde_hw_intf_init(): Initializes the intf driver for the passed
+ * interface idx.
+ * @idx:  interface index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m :   pointer to mdss catalog data
+ */
+struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_INTF_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
new file mode 100644
index 0000000..e9aeab7
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -0,0 +1,192 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_catalog.h"
+#include "sde_hwio.h"
+#include "sde_hw_lm.h"
+#include "sde_hw_mdss.h"
+
+#define LM_OP_MODE                        0x00
+#define LM_OUT_SIZE                       0x04
+#define LM_BORDER_COLOR_0                 0x08
+#define LM_BORDER_COLOR_1                 0x010
+
+/* These register are offset to mixer base + stage base */
+#define LM_BLEND0_OP                     0x00
+#define LM_BLEND0_FG_ALPHA               0x04
+#define LM_BLEND0_BG_ALPHA               0x08
+
+static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->mixer_count; i++) {
+		if (mixer == m->mixer[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->mixer[i].base;
+			b->hwversion = m->hwversion;
+			return &m->mixer[i];
+		}
+	}
+
+	return ERR_PTR(-ENOMEM);
+}
+
+/**
+ * _stage_offset(): returns the relative offset of the blend registers
+ * for the stage to be setup
+ * @c:     mixer ctx contains the mixer to be programmed
+ * @stage: stage index to setup
+ */
+static inline int _stage_offset(struct sde_hw_mixer *ctx, enum sde_stage stage)
+{
+	const struct sde_lm_sub_blks *sblk = ctx->cap->sblk;
+
+	if (WARN_ON(stage == SDE_STAGE_BASE))
+		return -EINVAL;
+
+	if ((stage - SDE_STAGE_0) <= sblk->maxblendstages)
+		return sblk->blendstage_base[stage];
+	else
+		return -EINVAL;
+}
+
+static void sde_hw_lm_setup_out(struct sde_hw_mixer *ctx,
+		struct sde_hw_mixer_cfg *mixer)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 outsize;
+	u32 opmode;
+
+	opmode = SDE_REG_READ(c, LM_OP_MODE);
+
+	outsize = mixer->out_height << 16 | mixer->out_width;
+	SDE_REG_WRITE(c, LM_OUT_SIZE, outsize);
+
+	/* SPLIT_LEFT_RIGHT */
+	opmode = (opmode & ~(1 << 31)) | (mixer->right_mixer & 1 << 31);
+	SDE_REG_WRITE(c, LM_OP_MODE, opmode);
+}
+
+static void sde_hw_lm_setup_border_color(struct sde_hw_mixer *ctx,
+		struct sde_mdss_color *color,
+		u8 border_en)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+	if (border_en) {
+		SDE_REG_WRITE(c, LM_BORDER_COLOR_0,
+			(color->color_0 & 0xFFF) |
+			((color->color_1 & 0xFFF) << 0x10));
+		SDE_REG_WRITE(c, LM_BORDER_COLOR_1,
+			(color->color_2 & 0xFFF) |
+			((color->color_3 & 0xFFF) << 0x10));
+	}
+}
+
+static void sde_hw_lm_setup_blendcfg(struct sde_hw_mixer *ctx,
+			int stage,
+			struct sde_hw_blend_cfg *blend)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 blend_op;
+	struct sde_hw_alpha_cfg *fg, *bg;
+	int stage_off;
+
+	stage_off = _stage_offset(ctx, stage);
+	if (WARN_ON(stage_off < 0))
+		return;
+
+	fg = &(blend->fg);
+	bg = &(blend->bg);
+
+	/* fg */
+	blend_op =  (fg->alpha_sel & 3);
+	blend_op |= (fg->inv_alpha_sel & 1) << 2;
+	blend_op |=  (fg->mod_alpha & 1) << 3;
+	blend_op |=  (fg->inv_mode_alpha & 1) << 4;
+
+	/* bg */
+	blend_op |= (bg->alpha_sel & 3) << 8;
+	blend_op |= (bg->inv_alpha_sel & 1) << 2;
+	blend_op |= (bg->mod_alpha & 1) << 3;
+	blend_op |= (bg->inv_mode_alpha & 1) << 4;
+
+	SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off,
+			fg->const_alpha);
+	SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off,
+			bg->const_alpha);
+	SDE_REG_WRITE(c, LM_OP_MODE, blend_op);
+}
+
+static void sde_hw_lm_setup_color3(struct sde_hw_mixer *ctx,
+		struct sde_hw_color3_cfg *cfg)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	int maxblendstages = ctx->cap->sblk->maxblendstages;
+	int i;
+	int op_mode;
+
+	/* read the existing op_mode configuration */
+	op_mode = SDE_REG_READ(c, LM_OP_MODE);
+
+	for (i = 0; i < maxblendstages; i++)
+		op_mode |= ((cfg->keep_fg[i]  & 0x1) << i);
+
+	SDE_REG_WRITE(c, LM_OP_MODE, op_mode);
+}
+
+static void sde_hw_lm_gammacorrection(struct sde_hw_mixer *mixer,
+			void *cfg)
+{
+}
+
+static void _setup_mixer_ops(struct sde_hw_lm_ops *ops,
+		unsigned long cap)
+{
+	ops->setup_mixer_out = sde_hw_lm_setup_out;
+	ops->setup_blend_config = sde_hw_lm_setup_blendcfg;
+	ops->setup_alpha_out = sde_hw_lm_setup_color3;
+	ops->setup_border_color = sde_hw_lm_setup_border_color;
+	ops->setup_gammcorrection = sde_hw_lm_gammacorrection;
+};
+
+struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m)
+{
+	struct sde_hw_mixer *c;
+	struct sde_lm_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _lm_offset(idx, m, addr, &c->hw);
+	if (IS_ERR_OR_NULL(cfg)) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Assign ops */
+	c->idx = idx;
+	c->cap = cfg;
+	_setup_mixer_ops(&c->ops, c->cap->features);
+
+	/*
+	 * Perform any default initialization for the sspp blocks
+	 */
+	return c;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
new file mode 100644
index 0000000..8129b29
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_LM_H
+#define _SDE_HW_LM_H
+
+#include "sde_hw_mdss.h"
+#include "sde_hw_mdp_util.h"
+
+struct sde_hw_mixer;
+
+struct sde_hw_mixer_cfg {
+	u32 out_width;
+	u32 out_height;
+	bool right_mixer;
+	int flags;
+};
+
+struct sde_hw_color3_cfg {
+	u8 keep_fg[SDE_STAGE_MAX];
+};
+
+/**
+ *
+ * struct sde_hw_lm_ops : Interface to the mixer Hw driver functions
+ *  Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_lm_ops {
+	/*
+	 * Sets up mixer output width and height
+	 * and border color if enabled
+	 */
+	void (*setup_mixer_out)(struct sde_hw_mixer *ctx,
+		struct sde_hw_mixer_cfg *cfg);
+
+	/*
+	 * Alpha blending configuration
+	 * for the specified stage
+	 */
+	void (*setup_blend_config)(struct sde_hw_mixer *ctx,
+			int stage,
+			struct sde_hw_blend_cfg *blend);
+
+	/*
+	 * Alpha color component selection from either fg or bg
+	 */
+	void (*setup_alpha_out)(struct sde_hw_mixer *ctx,
+			struct sde_hw_color3_cfg *cfg);
+
+	/**
+	 * setup_border_color : enable/disable border color
+	 */
+	void (*setup_border_color)(struct sde_hw_mixer *ctx,
+		struct sde_mdss_color *color,
+		u8 border_en);
+
+	void (*setup_gammcorrection)(struct sde_hw_mixer *mixer,
+			void *cfg);
+
+};
+
+struct sde_hw_mixer {
+	/* base */
+	struct sde_hw_blk_reg_map hw;
+
+	/* lm */
+	enum sde_lm  idx;
+	const struct sde_lm_cfg   *cap;
+	const struct sde_mdp_cfg  *mdp;
+	const struct sde_ctl_cfg  *ctl;
+
+	/* ops */
+	struct sde_hw_lm_ops ops;
+};
+
+/**
+ * sde_hw_lm_init(): Initializes the mixer hw driver object.
+ * should be called once before accessing every mixer.
+ * @idx:  mixer index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m :   pointer to mdss catalog data
+ */
+struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_LM_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c
new file mode 100644
index 0000000..5611515
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.c
@@ -0,0 +1,338 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include "sde_hwio.h"
+#include "sde_hw_mdp_ctl.h"
+
+#define   CTL_LAYER(lm)                 \
+	(((lm) == 5) ? (0x024) : ((lm) * 0x004))
+#define   CTL_LAYER_EXT(lm)             \
+	(0x40 + ((lm) * 0x004))
+#define   CTL_TOP                       0x014
+#define   CTL_FLUSH                     0x018
+#define   CTL_START                     0x01C
+#define   CTL_PACK_3D                   0x020
+#define   CTL_SW_RESET                  0x030
+#define   CTL_LAYER_EXTN_OFFSET         0x40
+
+#define SDE_REG_RESET_TIMEOUT_COUNT    20
+
+static struct sde_ctl_cfg *_ctl_offset(enum sde_ctl ctl,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->ctl_count; i++) {
+		if (ctl == m->ctl[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->ctl[i].base;
+			b->hwversion = m->hwversion;
+			return &m->ctl[i];
+		}
+	}
+	return ERR_PTR(-ENOMEM);
+}
+
+static int _mixer_stages(const struct sde_lm_cfg *mixer, int count,
+		enum sde_lm lm)
+{
+	int i;
+	int stages = -EINVAL;
+
+	for (i = 0; i < count; i++) {
+		if (lm == mixer[i].id) {
+			stages = mixer[i].sblk->maxblendstages;
+			break;
+		}
+	}
+
+	return stages;
+}
+
+static inline void sde_hw_ctl_setup_flush(struct sde_hw_ctl *ctx, u32 flushbits,
+		u8 force_start)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+	SDE_REG_WRITE(c, CTL_FLUSH, flushbits);
+
+	if (force_start)
+		SDE_REG_WRITE(c, CTL_START, 0x1);
+}
+
+static inline int sde_hw_ctl_get_bitmask_sspp(struct sde_hw_ctl *ctx,
+		u32 *flushbits, enum sde_sspp sspp)
+{
+	switch (sspp) {
+	case SSPP_VIG0:
+		*flushbits |=  BIT(0);
+		break;
+	case SSPP_VIG1:
+		*flushbits |= BIT(1);
+		break;
+	case SSPP_VIG2:
+		*flushbits |= BIT(2);
+		break;
+	case SSPP_VIG3:
+		*flushbits |= BIT(18);
+		break;
+	case SSPP_RGB0:
+		*flushbits |= BIT(3);
+		break;
+	case SSPP_RGB1:
+		*flushbits |= BIT(4);
+		break;
+	case SSPP_RGB2:
+		*flushbits |= BIT(5);
+		break;
+	case SSPP_RGB3:
+		*flushbits |= BIT(19);
+		break;
+	case SSPP_DMA0:
+		*flushbits |= BIT(11);
+		break;
+	case SSPP_DMA1:
+		*flushbits |= BIT(12);
+		break;
+	case SSPP_CURSOR0:
+		*flushbits |= BIT(22);
+		break;
+	case SSPP_CURSOR1:
+		*flushbits |= BIT(23);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline int sde_hw_ctl_get_bitmask_mixer(struct sde_hw_ctl *ctx,
+		u32 *flushbits, enum sde_lm lm)
+{
+	switch (lm) {
+	case LM_0:
+		*flushbits |= BIT(6);
+		break;
+	case LM_1:
+		*flushbits |= BIT(7);
+		break;
+	case LM_2:
+		*flushbits |= BIT(8);
+		break;
+	case LM_3:
+		*flushbits |= BIT(9);
+		break;
+	case LM_4:
+		*flushbits |= BIT(10);
+		break;
+	case LM_5:
+		*flushbits |= BIT(20);
+		break;
+	default:
+		return -EINVAL;
+	}
+	*flushbits |= BIT(17); /* CTL */
+	return 0;
+}
+
+static inline int sde_hw_ctl_get_bitmask_dspp(struct sde_hw_ctl *ctx,
+		u32 *flushbits, enum sde_dspp dspp)
+{
+	switch (dspp) {
+	case DSPP_0:
+		*flushbits |= BIT(13);
+		break;
+	case DSPP_1:
+		*flushbits |= BIT(14);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline int sde_hw_ctl_get_bitmask_intf(struct sde_hw_ctl *ctx,
+		u32 *flushbits, enum sde_intf intf)
+{
+	switch (intf) {
+	case INTF_0:
+		*flushbits |= BIT(31);
+		break;
+	case INTF_1:
+		*flushbits |= BIT(30);
+		break;
+	case INTF_2:
+		*flushbits |= BIT(29);
+		break;
+	case INTF_3:
+		*flushbits |= BIT(28);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline int sde_hw_ctl_get_bitmask_cdm(struct sde_hw_ctl *ctx,
+		u32 *flushbits, enum sde_cdm cdm)
+{
+	switch (cdm) {
+	case CDM_0:
+		*flushbits |= BIT(26);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int sde_hw_ctl_reset_control(struct sde_hw_ctl *ctx)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	int count = SDE_REG_RESET_TIMEOUT_COUNT;
+	int reset;
+
+	SDE_REG_WRITE(c, CTL_SW_RESET, 0x1);
+
+	for (; count > 0; count--) {
+		/* insert small delay to avoid spinning the cpu while waiting */
+		usleep_range(20, 50);
+		reset = SDE_REG_READ(c, CTL_SW_RESET);
+		if (reset == 0)
+			return 0;
+	}
+
+	return -EINVAL;
+}
+
+static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx,
+		enum sde_lm lm,
+		struct sde_hw_stage_cfg *cfg)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 mixercfg, mixercfg_ext;
+	int i, j;
+	u8 stages;
+	int pipes_per_stage;
+
+	stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm);
+	if (WARN_ON(stages < 0))
+		return;
+
+	if (test_bit(SDE_MIXER_SOURCESPLIT,
+		&ctx->mixer_hw_caps->features))
+		pipes_per_stage = PIPES_PER_STAGE;
+	else
+		pipes_per_stage = 1;
+
+	mixercfg = cfg->border_enable >> 24; /* BORDER_OUT */
+;
+	for (i = 0; i <= stages; i++) {
+		for (j = 0; j < pipes_per_stage; j++) {
+			switch (cfg->stage[i][j]) {
+			case SSPP_VIG0:
+				mixercfg |= (i + 1) << 0;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0;
+				break;
+			case SSPP_VIG1:
+				mixercfg |= (i + 1) << 3;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 2;
+				break;
+			case SSPP_VIG2:
+				mixercfg |= (i + 1) << 6;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 4;
+				break;
+			case SSPP_VIG3:
+				mixercfg |= (i + 1) << 26;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 4;
+				break;
+			case SSPP_RGB0:
+				mixercfg |= (i + 1) << 9;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 8;
+				break;
+			case SSPP_RGB1:
+				mixercfg |= (i + 1) << 12;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 10;
+				break;
+			case SSPP_RGB2:
+				mixercfg |= (i + 1) << 15;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 12;
+				break;
+			case SSPP_RGB3:
+				mixercfg |= (i + 1) << 29;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 14;
+				break;
+			case SSPP_DMA0:
+				mixercfg |= (i + 1) << 0;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0;
+				break;
+			case SSPP_DMA1:
+				mixercfg |= (i + 1) << 0;
+				mixercfg_ext |= ((i > SDE_STAGE_5) ? 1:0) << 0;
+				break;
+			case SSPP_CURSOR0:
+				mixercfg_ext |= (i + 1) << 20;
+				break;
+			case SSPP_CURSOR1:
+				mixercfg_ext |= (i + 1) << 26;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	SDE_REG_WRITE(c, CTL_LAYER(lm), mixercfg);
+	SDE_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext);
+}
+
+static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
+		unsigned long cap)
+{
+	ops->setup_flush = sde_hw_ctl_setup_flush;
+	ops->reset = sde_hw_ctl_reset_control;
+	ops->get_bitmask_sspp = sde_hw_ctl_get_bitmask_sspp;
+	ops->get_bitmask_mixer = sde_hw_ctl_get_bitmask_mixer;
+	ops->get_bitmask_dspp = sde_hw_ctl_get_bitmask_dspp;
+	ops->get_bitmask_intf = sde_hw_ctl_get_bitmask_intf;
+	ops->get_bitmask_cdm = sde_hw_ctl_get_bitmask_cdm;
+	ops->setup_blendstage = sde_hw_ctl_setup_blendstage;
+};
+
+struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m)
+{
+	struct sde_hw_ctl *c;
+	struct sde_ctl_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _ctl_offset(idx, m, addr, &c->hw);
+	if (cfg) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	c->caps = cfg;
+	_setup_ctl_ops(&c->ops, c->caps->features);
+	c->idx = idx;
+	c->mixer_count = m->mixer_count;
+	c->mixer_hw_caps = m->mixer;
+
+	return c;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h
new file mode 100644
index 0000000..14a519f
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_ctl.h
@@ -0,0 +1,99 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_MDP_CTL_H
+#define _SDE_HW_MDP_CTL_H
+
+#include "sde_hw_mdss.h"
+#include "sde_hw_catalog.h"
+
+struct sde_hw_ctl;
+/**
+ * struct sde_hw_stage_cfg - blending stage cfg
+ * @stage
+ * @border_enable
+ */
+struct sde_hw_stage_cfg {
+	enum sde_sspp stage[SDE_STAGE_MAX][PIPES_PER_STAGE];
+	u8 border_enable;
+};
+
+/**
+ * struct sde_hw_ctl_ops - Interface to the wb Hw driver functions
+ * Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_ctl_ops {
+	void (*setup_flush)(struct sde_hw_ctl *ctx,
+		u32  flushbits,
+		u8 force_start);
+
+	int (*reset)(struct sde_hw_ctl *c);
+
+	int (*get_bitmask_sspp)(struct sde_hw_ctl *ctx,
+		u32 *flushbits,
+		enum sde_sspp blk);
+
+	int (*get_bitmask_mixer)(struct sde_hw_ctl *ctx,
+		u32 *flushbits,
+		enum sde_lm blk);
+
+	int (*get_bitmask_dspp)(struct sde_hw_ctl *ctx,
+		u32 *flushbits,
+		enum sde_dspp blk);
+
+	int (*get_bitmask_intf)(struct sde_hw_ctl *ctx,
+		u32 *flushbits,
+		enum sde_intf blk);
+
+	int (*get_bitmask_cdm)(struct sde_hw_ctl *ctx,
+		u32 *flushbits,
+		enum sde_cdm blk);
+
+	void (*setup_blendstage)(struct sde_hw_ctl *ctx,
+		enum sde_lm lm,
+		struct sde_hw_stage_cfg *cfg);
+};
+
+/**
+ * struct sde_hw_ctl : CTL PATH driver object
+ * @struct sde_hw_blk_reg_map *hw;
+ * @idx
+ * @ctl_hw_caps
+ * @mixer_hw_caps
+ * @ops
+ */
+struct sde_hw_ctl {
+	/* base */
+	struct sde_hw_blk_reg_map hw;
+
+	/* ctl path */
+	int idx;
+	const struct sde_ctl_cfg *caps;
+	int mixer_count;
+	const struct sde_lm_cfg *mixer_hw_caps;
+
+	/* ops */
+	struct sde_hw_ctl_ops ops;
+};
+
+/**
+ * sde_hw_ctl_init(): Initializes the ctl_path hw driver object.
+ * should be called before accessing every mixer.
+ * @idx:  ctl_path index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m :   pointer to mdss catalog data
+ */
+struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_MDP_CTL_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_hwio.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_hwio.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_hwio.h
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.c
new file mode 100644
index 0000000..8162efc
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_mdp_util.h"
+
+void sde_hw_reg_write(void  __iomem *base, u32 blk_off, u32 reg_off, u32 val)
+{
+	writel_relaxed(val, base + blk_off + reg_off);
+}
+
+u32 sde_hw_reg_read(void  __iomem *base, u32 blk_off, u32 reg_off)
+{
+	return readl_relaxed(base + blk_off + reg_off);
+}
+
+void sde_hw_csc_setup(struct sde_hw_blk_reg_map  *c,
+		u32 csc_reg_off,
+		struct sde_csc_cfg *data)
+{
+	u32 val;
+
+	/* Matrix coeff */
+	val = (data->csc_mv[0] & 0x1FF) |
+		((data->csc_mv[1] & 0x1FF) << 16);
+	SDE_REG_WRITE(c, csc_reg_off,  val);
+	val = (data->csc_mv[2] & 0x1FF) |
+		((data->csc_mv[3] & 0x1FF) << 16);
+	SDE_REG_WRITE(c, csc_reg_off + 0x4, val);
+	val = (data->csc_mv[4] & 0x1FF) |
+		((data->csc_mv[5] & 0x1FF) >> 16);
+	SDE_REG_WRITE(c, csc_reg_off + 0x8, val);
+	val = (data->csc_mv[6] & 0x1FF) |
+		((data->csc_mv[7] & 0x1FF) << 16);
+	SDE_REG_WRITE(c, csc_reg_off + 0xc, val);
+	val = data->csc_mv[8] & 0x1FF;
+	SDE_REG_WRITE(c, csc_reg_off + 0x10, val);
+
+	/* Pre clamp */
+	val = (data->csc_pre_lv[0] << 8) | data->csc_pre_lv[1];
+	SDE_REG_WRITE(c, csc_reg_off + 0x14,  val);
+	val = (data->csc_pre_lv[2] << 8) | data->csc_pre_lv[3];
+	SDE_REG_WRITE(c, csc_reg_off  + 0x18, val);
+	val = (data->csc_pre_lv[4] << 8) | data->csc_pre_lv[5];
+	SDE_REG_WRITE(c, csc_reg_off  + 0x1c, val);
+
+	/* Post clamp */
+	val = (data->csc_post_lv[0] << 8) | data->csc_post_lv[1];
+	SDE_REG_WRITE(c, csc_reg_off + 0x20,  val);
+	val = (data->csc_post_lv[2] << 8) | data->csc_post_lv[3];
+	SDE_REG_WRITE(c, csc_reg_off  + 0x24, val);
+	val = (data->csc_post_lv[4] << 8) | data->csc_post_lv[5];
+	SDE_REG_WRITE(c, csc_reg_off  + 0x28, val);
+
+	/* Pre-Bias */
+	SDE_REG_WRITE(c, csc_reg_off + 0x2c,  data->csc_pre_bv[0]);
+	SDE_REG_WRITE(c, csc_reg_off + 0x30, data->csc_pre_bv[1]);
+	SDE_REG_WRITE(c, csc_reg_off + 0x34, data->csc_pre_bv[2]);
+
+	/* Post-Bias */
+	SDE_REG_WRITE(c, csc_reg_off + 0x38,  data->csc_post_bv[0]);
+	SDE_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]);
+	SDE_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]);
+}
+
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.h b/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.h
new file mode 100644
index 0000000..2a7af83
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_util.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_MDP_UTIL_H
+#define _SDE_HW_MDP_UTIL_H
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include "sde_hw_mdss.h"
+
+/*
+ * This is the common struct maintained by each sub block
+ * for mapping the register offsets in this block to the
+ * absoulute IO address
+ * @base_off:     mdp register mapped offset
+ * @blk_off:      pipe offset relative to mdss offset
+ * @length        length of register block offset
+ * @hwversion     mdss hw version number
+ */
+struct sde_hw_blk_reg_map {
+	void __iomem *base_off;
+	u32 blk_off;
+	u32 length;
+	u32 hwversion;
+};
+
+void sde_hw_reg_write(void __iomem *base, u32 blk_offset, u32 reg, u32 val);
+
+u32 sde_hw_reg_read(void __iomem *base, u32 blk_offset, u32 reg);
+
+static inline void SDE_REG_WRITE(struct sde_hw_blk_reg_map *c, u32 reg_off,
+		u32 val)
+{
+	sde_hw_reg_write(c->base_off, c->blk_off, reg_off, val);
+}
+
+static inline int SDE_REG_READ(struct sde_hw_blk_reg_map *c, u32 reg_off)
+{
+	return sde_hw_reg_read(c->base_off, c->blk_off, reg_off);
+}
+
+void sde_hw_csc_setup(struct sde_hw_blk_reg_map  *c,
+		u32 csc_reg_off,
+		struct sde_csc_cfg *data);
+
+#endif /* _SDE_HW_MDP_UTIL_H */
+
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
new file mode 100644
index 0000000..ce5a90b
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -0,0 +1,320 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_MDSS_H
+#define _SDE_HW_MDSS_H
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#define SDE_CSC_MATRIX_COEFF_SIZE	9
+#define SDE_CSC_CLAMP_SIZE		6
+#define SDE_CSC_BIAS_SIZE		3
+
+#define SDE_MAX_PLANES			4
+#define PIPES_PER_STAGE			2
+#define VALID_ROT_WB_FORMAT		BIT(0)
+
+enum sde_mdp {
+	MDP_TOP = 0x1,
+	MDP_MAX,
+};
+
+enum sde_sspp {
+	SSPP_NONE,
+	SSPP_VIG0,
+	SSPP_VIG1,
+	SSPP_VIG2,
+	SSPP_VIG3,
+	SSPP_RGB0,
+	SSPP_RGB1,
+	SSPP_RGB2,
+	SSPP_RGB3,
+	SSPP_DMA0,
+	SSPP_DMA1,
+	SSPP_DMA2,
+	SSPP_DMA3,
+	SSPP_CURSOR0,
+	SSPP_CURSOR1,
+	SSPP_MAX
+};
+
+enum sde_sspp_type {
+	SSPP_TYPE_VIG,
+	SSPP_TYPE_RGB,
+	SSPP_TYPE_DMA,
+	SSPP_TYPE_CURSOR,
+	SSPP_TYPE_MAX
+};
+
+enum sde_lm {
+	LM_0 = 0,
+	LM_1,
+	LM_2,
+	LM_3,
+	LM_4,
+	LM_5,
+	LM_6,
+	LM_MAX
+};
+
+enum sde_stage {
+	SDE_STAGE_BASE = 0,
+	SDE_STAGE_0,
+	SDE_STAGE_1,
+	SDE_STAGE_2,
+	SDE_STAGE_3,
+	SDE_STAGE_4,
+	SDE_STAGE_5,
+	SDE_STAGE_6,
+	SDE_STAGE_MAX
+};
+enum sde_dspp {
+	DSPP_0 = 0,
+	DSPP_1,
+	DSPP_2,
+	DSPP_3,
+	DSPP_MAX
+};
+
+enum sde_ctl {
+	CTL_0 = 0,
+	CTL_1,
+	CTL_2,
+	CTL_3,
+	CTL_4,
+	CTL_MAX
+};
+
+enum sde_cdm {
+	CDM_0 = 0,
+	CDM_1,
+	CDM_MAX
+};
+
+enum sde_pingpong {
+	PINGPONG_0 = 0,
+	PINGPONG_1,
+	PINGPONG_2,
+	PINGPONG_3,
+	PINGPONG_4,
+	PINGPONG_MAX
+};
+
+enum sde_intf {
+	INTF_0 = 0,
+	INTF_1,
+	INTF_2,
+	INTF_3,
+	INTF_4,
+	INTF_5,
+	INTF_6,
+	INTF_MAX
+};
+
+enum sde_intf_type {
+	INTF_NONE = 0x0,
+	INTF_DSI = 0x1,
+	INTF_HDMI = 0x3,
+	INTF_LCDC = 0x5,
+	INTF_EDP = 0x9,
+	INTF_TYPE_MAX
+};
+
+enum sde_intf_mode {
+	INTF_MODE_NONE = 0,
+	INTF_MODE_CMD,
+	INTF_MODE_VIDEO,
+	INTF_MODE_WB_BLOCK,
+	INTF_MODE_WB_LINE,
+	INTF_MODE_MAX
+};
+
+enum sde_wb {
+	WB_0 = 1,
+	WB_1,
+	WB_2,
+	WB_3,
+	WB_MAX
+};
+
+enum sde_ad {
+	AD_0 = 0x1,
+	AD_1,
+	AD_MAX
+};
+
+/**
+ * MDP HW,Component order color map
+ */
+enum {
+	C0_G_Y = 0,
+	C1_B_Cb = 1,
+	C2_R_Cr = 2,
+	C3_ALPHA = 3
+};
+
+/**
+ * enum sde_mdp_plane_type - defines how the color component pixel packing
+ * @SDE_MDP_PLANE_INTERLEAVED   : Color components in single plane
+ * @SDE_MDP_PLANE_PLANAR        : Color component in separate planes
+ * @SDE_MDP_PLANE_PSEUDO_PLANAR : Chroma components interleaved in separate
+ *                                plane
+ */
+enum sde_mdp_plane_type {
+	SDE_MDP_PLANE_INTERLEAVED,
+	SDE_MDP_PLANE_PLANAR,
+	SDE_MDP_PLANE_PSEUDO_PLANAR,
+};
+
+/**
+ * enum sde_mdp_chroma_samp_type - chroma sub-samplng type
+ * @SDE_MDP_CHROMA_RGB   : no chroma subsampling
+ * @SDE_MDP_CHROMA_H2V1  : chroma pixels are horizontally subsampled
+ * @SDE_MDP_CHROMA_H1V2  : chroma pixels are vertically subsampled
+ * @SDE_MDP_CHROMA_420   : 420 subsampling
+ */
+enum sde_mdp_chroma_samp_type {
+	SDE_MDP_CHROMA_RGB,
+	SDE_MDP_CHROMA_H2V1,
+	SDE_MDP_CHROMA_H1V2,
+	SDE_MDP_CHROMA_420
+};
+
+/**
+ * enum sde_mdp_fetch_type - format id, used by drm-driver only to map drm forcc
+ * Defines How MDP HW fetches data
+ * @SDE_MDP_FETCH_LINEAR   : fetch is line by line
+ * @SDE_MDP_FETCH_TILE     : fetches data in Z order from a tile
+ * @SDE_MDP_FETCH_UBWC     : fetch and decompress data
+ */
+enum sde_mdp_fetch_type {
+	SDE_MDP_FETCH_LINEAR,
+	SDE_MDP_FETCH_TILE,
+	SDE_MDP_FETCH_UBWC
+};
+
+/**
+ * Value of enum chosen to fit the number of bits
+ * expected by the HW programming.
+ */
+enum {
+	COLOR_4BIT,
+	COLOR_5BIT,
+	COLOR_6BIT,
+	COLOR_8BIT,
+	COLOR_ALPHA_1BIT = 0,
+	COLOR_ALPHA_4BIT = 1,
+};
+
+enum sde_alpha_blend_type {
+	ALPHA_FG_CONST = 0,
+	ALPHA_BG_CONST,
+	ALPHA_FG_PIXEL,
+	ALPHA_BG_PIXEL,
+	ALPHA_MAX
+};
+
+struct addr_info {
+	u32 plane[SDE_MAX_PLANES];
+};
+
+/**
+ * struct sde_mdp_format_params - defines the format configuration which
+ * allows MDP HW to correctly fetch and decode the format
+ * @format : format id, used by drm-driver only to map drm forcc
+ * @flag
+ * @chroma_sample
+ * @fetch_planes
+ * @unpack_align_msb
+ * @unpack_tight
+ * @unpack_count
+ * @bpp
+ * @alpha_enable
+ * @fetch_mode
+ * @bits
+ * @element
+ */
+struct sde_mdp_format_params {
+	u32 format;
+	enum sde_mdp_plane_type fetch_planes;
+	u8 element[SDE_MAX_PLANES];
+	u8 bits[SDE_MAX_PLANES];
+	enum sde_mdp_chroma_samp_type chroma_sample;
+	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;                 /* Bytes per pixel */
+	u8 alpha_enable;	/*  source has alpha */
+	enum sde_mdp_fetch_type fetch_mode;
+	u8 is_yuv;
+	u32 flag;
+};
+
+/**
+ * struct sde_hw_source_info - format information of the source pixel data
+ * @format : pixel format parameters
+ * @width : image width @height: image height
+ * @num_planes : number of planes including the meta data planes for the
+ * compressed formats @plane: per plane information
+ */
+struct sde_hw_source_info {
+	struct sde_mdp_format_params *format;
+	u32 width;
+	u32 height;
+	u32 num_planes;
+	u32 ystride[SDE_MAX_PLANES];
+};
+
+struct sde_rect {
+	u16 x;
+	u16 y;
+	u16 w;
+	u16 h;
+};
+
+struct sde_hw_alpha_cfg {
+	u32 const_alpha;
+	enum sde_alpha_blend_type alpha_sel;
+	u8 inv_alpha_sel;
+	u8 mod_alpha;
+	u8 inv_mode_alpha;
+};
+
+struct sde_hw_blend_cfg {
+	struct sde_hw_alpha_cfg fg;
+	struct sde_hw_alpha_cfg bg;
+};
+
+struct sde_csc_cfg {
+	uint32_t csc_mv[SDE_CSC_MATRIX_COEFF_SIZE];
+	uint32_t csc_pre_bv[SDE_CSC_BIAS_SIZE];
+	uint32_t csc_post_bv[SDE_CSC_BIAS_SIZE];
+	uint32_t csc_pre_lv[SDE_CSC_CLAMP_SIZE];
+	uint32_t csc_post_lv[SDE_CSC_CLAMP_SIZE];
+};
+
+/**
+ * struct sde_mdss_color - mdss color description
+ * color 0 : green
+ * color 1 : blue
+ * color 2 : red
+ * color 3 : alpha
+ */
+struct sde_mdss_color {
+	u32 color_0;
+	u32 color_1;
+	u32 color_2;
+	u32 color_3;
+};
+
+#endif  /* _SDE_HW_MDSS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
new file mode 100644
index 0000000..e678003
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -0,0 +1,159 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_mdss.h"
+#include "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_pingpong.h"
+
+#define PP_TEAR_CHECK_EN                0x000
+#define PP_SYNC_CONFIG_VSYNC            0x004
+#define PP_SYNC_CONFIG_HEIGHT           0x008
+#define PP_SYNC_WRCOUNT                 0x00C
+#define PP_VSYNC_INIT_VAL               0x010
+#define PP_INT_COUNT_VAL                0x014
+#define PP_SYNC_THRESH                  0x018
+#define PP_START_POS                    0x01C
+#define PP_RD_PTR_IRQ                   0x020
+#define PP_WR_PTR_IRQ                   0x024
+#define PP_OUT_LINE_COUNT               0x028
+#define PP_LINE_COUNT                   0x02C
+#define PP_AUTOREFRESH_CONFIG           0x030
+
+#define PP_FBC_MODE                     0x034
+#define PP_FBC_BUDGET_CTL               0x038
+#define PP_FBC_LOSSY_MODE               0x03C
+#define PP_DSC_MODE                     0x0a0
+#define PP_DCE_DATA_IN_SWAP             0x0ac
+#define PP_DCE_DATA_OUT_SWAP            0x0c8
+
+static struct sde_pingpong_cfg *_pingpong_offset(enum sde_pingpong pp,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->pingpong_count; i++) {
+		if (pp == m->pingpong[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->pingpong[i].base;
+			b->hwversion = m->hwversion;
+			return &m->pingpong[i];
+		}
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static int sde_hw_pp_setup_te_config(struct sde_hw_pingpong *pp,
+		struct sde_hw_tear_check *te)
+{
+	struct sde_hw_blk_reg_map *c = &pp->hw;
+	int cfg;
+
+	cfg = BIT(19); /*VSYNC_COUNTER_EN */
+	if (te->hw_vsync_mode)
+		cfg |= BIT(20);
+
+	cfg |= te->vsync_count;
+
+	SDE_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg);
+	SDE_REG_WRITE(c, PP_SYNC_CONFIG_HEIGHT, te->sync_cfg_height);
+	SDE_REG_WRITE(c, PP_VSYNC_INIT_VAL, te->vsync_init_val);
+	SDE_REG_WRITE(c, PP_RD_PTR_IRQ, te->rd_ptr_irq);
+	SDE_REG_WRITE(c, PP_START_POS, te->start_pos);
+	SDE_REG_WRITE(c, PP_SYNC_THRESH,
+			((te->sync_threshold_continue << 16) |
+			 te->sync_threshold_start));
+	SDE_REG_WRITE(c, PP_SYNC_WRCOUNT,
+			(te->start_pos + te->sync_threshold_start + 1));
+
+	return 0;
+}
+
+int sde_hw_pp_setup_autorefresh_config(struct sde_hw_pingpong *pp,
+		struct sde_hw_autorefresh *cfg)
+{
+	struct sde_hw_blk_reg_map *c = &pp->hw;
+	u32 refresh_cfg;
+
+	if (cfg->enable)
+		refresh_cfg = BIT(31) | cfg->frame_count;
+	else
+		refresh_cfg = 0;
+
+	SDE_REG_WRITE(c, PP_AUTOREFRESH_CONFIG,
+			refresh_cfg);
+
+	return 0;
+}
+
+int sde_hw_pp_setup_dsc_compression(struct sde_hw_pingpong *pp,
+		struct sde_hw_dsc_cfg *cfg)
+{
+	return 0;
+}
+int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable)
+{
+	struct sde_hw_blk_reg_map *c = &pp->hw;
+
+	SDE_REG_WRITE(c, PP_TEAR_CHECK_EN, enable);
+	return 0;
+}
+
+int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp,
+		struct sde_hw_pp_vsync_info *info)
+{
+	struct sde_hw_blk_reg_map *c = &pp->hw;
+
+	info->init_val = SDE_REG_READ(c, PP_VSYNC_INIT_VAL) & 0xffff;
+	info->vsync_count = SDE_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xffff;
+	info->line_count = SDE_REG_READ(c, PP_INT_COUNT_VAL) & 0xffff;
+
+	return 0;
+}
+
+static void _setup_pingpong_ops(struct sde_hw_pingpong_ops *ops,
+		unsigned long cap)
+{
+	ops->setup_tearcheck = sde_hw_pp_setup_te_config;
+	ops->enable_tearcheck = sde_hw_pp_enable_te;
+	ops->get_vsync_info = sde_hw_pp_get_vsync_info;
+	ops->setup_autorefresh = sde_hw_pp_setup_autorefresh_config;
+	ops->setup_dsc = sde_hw_pp_setup_dsc_compression;
+};
+
+struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m)
+{
+	struct sde_hw_pingpong *c;
+	struct sde_pingpong_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _pingpong_offset(idx, m, addr, &c->hw);
+	if (IS_ERR_OR_NULL(cfg)) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	c->idx = idx;
+	c->pingpong_hw_cap = cfg;
+	_setup_pingpong_ops(&c->ops, c->pingpong_hw_cap->features);
+
+	return c;
+}
+
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
new file mode 100644
index 0000000..a2bf86f
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_PINGPONG_H
+#define _SDE_HW_PINGPONG_H
+
+struct sde_hw_pingpong;
+
+struct sde_hw_tear_check {
+	/*
+	 * This is ratio of MDP VSYNC clk freq(Hz) to
+	 * refresh rate divided by no of lines
+	 */
+	u32 vsync_count;
+	u32 sync_cfg_height;
+	u32 vsync_init_val;
+	u32 sync_threshold_start;
+	u32 sync_threshold_continue;
+	u32 start_pos;
+	u32 rd_ptr_irq;
+	u8 hw_vsync_mode;
+};
+
+struct sde_hw_autorefresh {
+	bool  enable;
+	u32 frame_count;
+};
+
+struct sde_hw_pp_vsync_info {
+	u32 init_val; /* value of rd pointer at vsync edge */
+	u32 vsync_count;    /* mdp clocks to complete one line */
+	u32 line_count;   /* current line count */
+};
+
+struct sde_hw_dsc_cfg {
+	u8 enable;
+};
+
+/**
+ *
+ * struct sde_hw_pingpong_ops : Interface to the pingpong Hw driver functions
+ *  Assumption is these functions will be called after clocks are enabled
+ *  @setup_tearcheck :
+ *  @enable_tearcheck :
+ *  @get_vsync_info :
+ *  @setup_autorefresh :
+ *  #setup_dsc :
+ */
+struct sde_hw_pingpong_ops {
+	/**
+	 * enables vysnc generation and sets up init value of
+	 * read pointer and programs the tear check cofiguration
+	 */
+	int (*setup_tearcheck)(struct sde_hw_pingpong *pp,
+			struct sde_hw_tear_check *cfg);
+
+	/**
+	 * enables tear check block
+	 */
+	int (*enable_tearcheck)(struct sde_hw_pingpong *pp,
+			bool enable);
+
+	/**
+	 * provides the programmed and current
+	 * line_count
+	 */
+	int (*get_vsync_info)(struct sde_hw_pingpong *pp,
+			struct sde_hw_pp_vsync_info  *info);
+
+	/**
+	 * configure and enable the autorefresh config
+	 */
+	int (*setup_autorefresh)(struct sde_hw_pingpong *pp,
+			struct sde_hw_autorefresh *cfg);
+
+	/**
+	 * Program the dsc compression block
+	 */
+	int (*setup_dsc)(struct sde_hw_pingpong *pp,
+			struct sde_hw_dsc_cfg *cfg);
+};
+
+struct sde_hw_pingpong {
+	/* base */
+	struct sde_hw_blk_reg_map hw;
+
+	/* pingpong */
+	enum sde_pingpong idx;
+	const struct sde_pingpong_cfg *pingpong_hw_cap;
+
+	/* ops */
+	struct sde_hw_pingpong_ops ops;
+};
+
+/**
+ * sde_hw_pingpong_init(): Initializes the pingpong driver for the passed
+ *        pingpong idx.
+ * @idx:  pingpong index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m :   pointer to mdss catalog data
+ */
+struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_PINGPONG_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
new file mode 100644
index 0000000..181f8be
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -0,0 +1,591 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_sspp.h"
+#include "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_lm.h"
+
+#define SDE_MDP_FETCH_CONFIG_RESET_VALUE   0x00000087
+
+/* SDE_SSPP_SRC */
+#define SSPP_SRC_SIZE                      0x00
+#define SSPP_SRC_XY                        0x08
+#define SSPP_OUT_SIZE                      0x0c
+#define SSPP_OUT_XY                        0x10
+#define SSPP_SRC0_ADDR                     0x14
+#define SSPP_SRC1_ADDR                     0x18
+#define SSPP_SRC2_ADDR                     0x1C
+#define SSPP_SRC3_ADDR                     0x20
+#define SSPP_SRC_YSTRIDE0                  0x24
+#define SSPP_SRC_YSTRIDE1                  0x28
+#define SSPP_SRC_FORMAT                    0x30
+#define SSPP_SRC_UNPACK_PATTERN            0x34
+#define SSPP_SRC_OP_MODE                   0x38
+#define MDSS_MDP_OP_DEINTERLACE            BIT(22)
+
+#define MDSS_MDP_OP_DEINTERLACE_ODD        BIT(23)
+#define MDSS_MDP_OP_IGC_ROM_1              BIT(18)
+#define MDSS_MDP_OP_IGC_ROM_0              BIT(17)
+#define MDSS_MDP_OP_IGC_EN                 BIT(16)
+#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_PE_OVERRIDE            BIT(31)
+#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 SSPP_SRC_CONSTANT_COLOR            0x3c
+#define SSPP_FETCH_CONFIG                  0x048
+#define SSPP_DANGER_LUT                    0x60
+#define SSPP_SAFE_LUT                      0x64
+#define SSPP_CREQ_LUT                      0x68
+#define SSPP_DECIMATION_CONFIG             0xB4
+#define SSPP_SRC_ADDR_SW_STATUS            0x70
+#define SSPP_SW_PIX_EXT_C0_LR              0x100
+#define SSPP_SW_PIX_EXT_C0_TB              0x104
+#define SSPP_SW_PIX_EXT_C0_REQ_PIXELS      0x108
+#define SSPP_SW_PIX_EXT_C1C2_LR            0x110
+#define SSPP_SW_PIX_EXT_C1C2_TB            0x114
+#define SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS    0x118
+#define SSPP_SW_PIX_EXT_C3_LR              0x120
+#define SSPP_SW_PIX_EXT_C3_TB              0x124
+#define SSPP_SW_PIX_EXT_C3_REQ_PIXELS      0x128
+#define SSPP_UBWC_ERROR_STATUS             0x138
+#define SSPP_VIG_OP_MODE                   0x200
+
+/* SDE_SSPP_SCALAR_QSEED2 */
+#define SCALE_CONFIG                       0x04
+#define COMP0_3_PHASE_STEP_X               0x10
+#define COMP0_3_PHASE_STEP_Y               0x14
+#define COMP1_2_PHASE_STEP_X               0x18
+#define COMP1_2_PHASE_STEP_Y               0x1c
+#define COMP0_3_INIT_PHASE_X               0x20
+#define COMP0_3_INIT_PHASE_Y               0x24
+#define COMP1_2_INIT_PHASE_X               0x28
+#define COMP1_2_INIT_PHASE_Y               0x2C
+#define VIG_0_QSEED2_SHARP                 0x30
+
+#define VIG_0_CSC_1_MATRIX_COEFF_0         0x20
+#define VIG_0_CSC_1_COMP_0_PRE_CLAMP       0x34
+#define VIG_0_CSC_1_COMP_0_POST_CLAMP      0x40
+#define VIG_0_CSC_1_COMP_0_PRE_BIAS        0x4C
+#define VIG_0_CSC_1_COMP_0_POST_BIAS       0x60
+
+/*
+ * MDP Solid fill configuration
+ * argb8888
+ */
+#define SSPP_SOLID_FILL                   0x4037ff
+
+enum {
+	CSC = 0x1,
+	PA,
+	HIST,
+	SKIN_COL,
+	FOIL,
+	SKY_COL,
+	MEM_PROT_HUE,
+	MEM_PROT_SAT,
+	MEM_PROT_VAL,
+	MEM_PROT_CONT,
+	MEM_PROT_BLEND,
+	PA_SAT_ADJ
+};
+
+static inline int _sspp_subblk_offset(struct sde_hw_pipe *ctx,
+		int s_id,
+		u32 *idx)
+{
+	int rc = 0;
+	const struct sde_sspp_sub_blks *sblk = ctx->cap->sblk;
+
+	switch (s_id) {
+	case SDE_SSPP_SRC:
+		*idx = sblk->src_blk.base;
+		break;
+	case SDE_SSPP_SCALAR_QSEED2:
+	case SDE_SSPP_SCALAR_QSEED3:
+	case SDE_SSPP_SCALAR_RGB:
+		*idx = sblk->scalar_blk.base;
+		break;
+	case SDE_SSPP_CSC:
+		*idx = sblk->csc_blk.base;
+		break;
+	case SDE_SSPP_PA_V1:
+		*idx = sblk->pa_blk.base;
+		break;
+	case SDE_SSPP_HIST_V1:
+		*idx = sblk->hist_lut.base;
+		break;
+	case SDE_SSPP_PCC:
+		*idx = sblk->pcc_blk.base;
+		break;
+	default:
+		rc = -EINVAL;
+		pr_err("Unsupported SSPP sub-blk for this hw\n");
+	}
+
+	return rc;
+}
+
+static void _sspp_setup_opmode(struct sde_hw_pipe *ctx,
+		u32 op, u8 en)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 idx;
+	u32 opmode;
+
+	if (ctx->cap->features == SDE_SSPP_PA_V1) {
+
+		if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+			return;
+
+		opmode = SDE_REG_READ(c, SSPP_VIG_OP_MODE + idx);
+
+		/* ops */
+		switch (op) {
+		case CSC:
+			if (en)
+				/* CSC_1_EN and CSC_SRC_DATA_FORMAT*/
+				opmode |= BIT(18) | BIT(17);
+			else
+				opmode &= ~BIT(17);
+			break;
+		default:
+			pr_err(" Unsupported operation\n");
+		}
+		SDE_REG_WRITE(c, SSPP_VIG_OP_MODE + idx, opmode);
+	}
+}
+/**
+ * Setup source pixel format, flip,
+ */
+static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx,
+		struct sde_hw_pipe_cfg *cfg,
+		u32 flags)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	struct sde_mdp_format_params *fmt;
+	u32 chroma_samp, unpack, src_format;
+	u32 secure = 0;
+	u32 opmode = 0;
+	u32 idx;
+
+	if (!_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	opmode = SDE_REG_READ(c, SSPP_SRC_OP_MODE + idx);
+
+	/* format info */
+	fmt = cfg->src.format;
+	if (WARN_ON(!fmt))
+		return;
+
+	if (flags & SDE_SSPP_SECURE_OVERLAY_SESSION)
+		secure = 0xF;
+
+	if (flags & SDE_SSPP_FLIP_LR)
+		opmode |= MDSS_MDP_OP_FLIP_LR;
+	if (flags & SDE_SSPP_FLIP_UD)
+		opmode |= MDSS_MDP_OP_FLIP_UD;
+
+	chroma_samp = fmt->chroma_sample;
+	if (flags & SDE_SSPP_SOURCE_ROTATED_90) {
+		if (chroma_samp == SDE_MDP_CHROMA_H2V1)
+			chroma_samp = SDE_MDP_CHROMA_H1V2;
+		else if (chroma_samp == SDE_MDP_CHROMA_H1V2)
+			chroma_samp = SDE_MDP_CHROMA_H2V1;
+	}
+
+	src_format = (chroma_samp << 23) | (fmt->fetch_planes << 19) |
+		(fmt->bits[C3_ALPHA] << 6) | (fmt->bits[C2_R_Cr] << 4) |
+		(fmt->bits[C0_G_Y] << 0);
+
+	if (flags & SDE_SSPP_ROT_90)
+		src_format |= BIT(11); /* ROT90 */
+
+	if (fmt->alpha_enable &&
+			fmt->fetch_planes != SDE_MDP_PLANE_INTERLEAVED)
+		src_format |= BIT(8); /* SRCC3_EN */
+
+	unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
+		(fmt->element[1] << 8) | (fmt->element[0] << 0);
+	src_format |= ((fmt->unpack_count - 1) << 12) |
+		(fmt->unpack_tight << 17) |
+		(fmt->unpack_align_msb << 18) |
+		((fmt->bpp - 1) << 9);
+
+	if (fmt->fetch_mode != SDE_MDP_FETCH_LINEAR) {
+		opmode |= MDSS_MDP_OP_BWC_EN;
+		src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */
+		SDE_REG_WRITE(c, SSPP_FETCH_CONFIG,
+			SDE_MDP_FETCH_CONFIG_RESET_VALUE |
+			ctx->highest_bank_bit << 18);
+	}
+
+	/* if this is YUV pixel format, enable CSC */
+	if (fmt->is_yuv) {
+		_sspp_setup_opmode(ctx, CSC, 0x0);
+	} else {
+		src_format |= BIT(15);
+		_sspp_setup_opmode(ctx, CSC, 0x1);
+	}
+
+	opmode |= MDSS_MDP_OP_PE_OVERRIDE;
+
+	SDE_REG_WRITE(c, SSPP_SRC_FORMAT + idx, src_format);
+	SDE_REG_WRITE(c, SSPP_SRC_UNPACK_PATTERN + idx, unpack);
+	SDE_REG_WRITE(c, SSPP_SRC_OP_MODE + idx, opmode);
+	SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
+
+	/* clear previous UBWC error */
+	SDE_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS + idx, BIT(31));
+}
+
+static void sde_hw_sspp_setup_pe_config(struct sde_hw_pipe *ctx,
+		struct sde_hw_pipe_cfg *cfg,
+		struct sde_hw_pixel_ext *pe_ext)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u8 color;
+	u32 lr_pe[4], tb_pe[4], tot_req_pixels[4];
+	const u32 bytemask = 0xffff;
+	const u8 shortmask = 0xff;
+	u32 idx;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	/* program SW pixel extension override for all pipes*/
+	for (color = 0; color < 4; color++) {
+		/* color 2 has the same set of registers as color 1 */
+		if (color == 2)
+			continue;
+
+		lr_pe[color] = ((pe_ext->right_ftch[color] & bytemask) << 24)|
+			((pe_ext->right_rpt[color] & bytemask) << 16)|
+			((pe_ext->left_ftch[color] & bytemask) << 8)|
+			(pe_ext->left_rpt[color] & bytemask);
+
+		tb_pe[color] = ((pe_ext->btm_ftch[color] & bytemask) << 24)|
+			((pe_ext->btm_rpt[color] & bytemask) << 16)|
+			((pe_ext->top_ftch[color] & bytemask) << 8)|
+			(pe_ext->top_rpt[color] & bytemask);
+
+		tot_req_pixels[color] = (((cfg->src.height +
+			pe_ext->num_ext_pxls_top[color] +
+			pe_ext->num_ext_pxls_btm[color]) & shortmask) << 16) |
+			((pe_ext->roi_w[color] +
+			pe_ext->num_ext_pxls_left[color] +
+			pe_ext->num_ext_pxls_right[color]) & shortmask);
+	}
+
+	/* color 0 */
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_LR + idx, lr_pe[0]);
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_TB + idx, tb_pe[0]);
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_REQ_PIXELS + idx,
+			tot_req_pixels[0]);
+
+	/* color 1 and color 2 */
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_LR + idx, lr_pe[1]);
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_TB + idx, tb_pe[1]);
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS + idx,
+			tot_req_pixels[1]);
+
+	/* color 3 */
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_LR + idx, lr_pe[3]);
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_TB + idx, lr_pe[3]);
+	SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_REQ_PIXELS + idx,
+			tot_req_pixels[3]);
+}
+
+static void sde_hw_sspp_setup_scalar(struct sde_hw_pipe *ctx,
+		struct sde_hw_pixel_ext *pe_ext)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	int scale_config;
+	const u8 mask = 0x3;
+	u32 idx;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALAR_QSEED2, &idx))
+		return;
+
+	scale_config = BIT(0) | BIT(1);
+	/* RGB/YUV config */
+	scale_config |= (pe_ext->horz_filter[0] & mask) << 8;
+	scale_config |= (pe_ext->vert_filter[0] & mask) << 10;
+	/* Aplha config*/
+	scale_config |= (pe_ext->horz_filter[3] & mask) << 16;
+	scale_config |= (pe_ext->vert_filter[3] & mask) << 18;
+
+	SDE_REG_WRITE(c, SCALE_CONFIG + idx,  scale_config);
+	SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_X + idx,
+			pe_ext->init_phase_x[0]);
+	SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_Y + idx,
+			pe_ext->init_phase_y[0]);
+	SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_X + idx,
+			pe_ext->phase_step_x[0]);
+	SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_Y + idx,
+			pe_ext->phase_step_y[0]);
+
+	SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_X + idx,
+			pe_ext->init_phase_x[1]);
+	SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_Y + idx,
+			pe_ext->init_phase_y[1]);
+	SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_X + idx,
+			pe_ext->phase_step_x[1]);
+	SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_Y + idx,
+			pe_ext->phase_step_y[0]);
+}
+
+/**
+ * sde_hw_sspp_setup_rects()
+ */
+static void sde_hw_sspp_setup_rects(struct sde_hw_pipe *ctx,
+		struct sde_hw_pipe_cfg *cfg,
+		struct sde_hw_pixel_ext *pe_ext)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
+	u32 decimation = 0;
+	u32 idx;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	/* program pixel extension override */
+	if (!pe_ext)
+		sde_hw_sspp_setup_pe_config(ctx, cfg, pe_ext);
+
+	/* src and dest rect programming */
+	src_xy = (cfg->src_rect.y << 16) |
+		(cfg->src_rect.x);
+	src_size = (cfg->src_rect.h << 16) |
+		(cfg->src_rect.w);
+	dst_xy = (cfg->dst_rect.y << 16) |
+		(cfg->dst_rect.x);
+	dst_size = (cfg->dst_rect.h << 16) |
+		(cfg->dst_rect.w);
+
+	ystride0 =  (cfg->src.ystride[0]) |
+		(cfg->src.ystride[1] << 16);
+	ystride1 =  (cfg->src.ystride[2]) |
+		(cfg->src.ystride[3] << 16);
+
+	/* program scalar, phase registers, if pipes supporting scaling */
+	if (src_size != dst_size) {
+		if (test_bit(SDE_SSPP_SCALAR_RGB, &ctx->cap->features) ||
+			test_bit(SDE_SSPP_SCALAR_QSEED2, &ctx->cap->features)) {
+			/* program decimation */
+			if (!cfg->horz_decimation)
+				decimation = (cfg->horz_decimation - 1) <<  8;
+			if (!cfg->vert_decimation)
+				decimation |= (cfg->vert_decimation - 1);
+
+			sde_hw_sspp_setup_scalar(ctx, pe_ext);
+		}
+	}
+
+	/* Rectangle Register programming */
+	SDE_REG_WRITE(c, SSPP_SRC_SIZE + idx,  src_size);
+	SDE_REG_WRITE(c, SSPP_SRC_XY + idx, src_xy);
+	SDE_REG_WRITE(c, SSPP_OUT_SIZE + idx, dst_size);
+	SDE_REG_WRITE(c, SSPP_OUT_XY + idx, dst_xy);
+
+	SDE_REG_WRITE(c, SSPP_SRC_YSTRIDE0 + idx, ystride0);
+	SDE_REG_WRITE(c, SSPP_SRC_YSTRIDE1 + idx, ystride1);
+	SDE_REG_WRITE(c, SSPP_DECIMATION_CONFIG + idx, decimation);
+}
+
+static void sde_hw_sspp_setup_sourceaddress(struct sde_hw_pipe *ctx,
+		struct sde_hw_pipe_cfg *cfg)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	int i;
+	u32 idx;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	for (i = 0; i < cfg->src.num_planes; i++)
+		SDE_REG_WRITE(c, SSPP_SRC0_ADDR  + idx + i*0x4,
+			cfg->addr.plane[i]);
+
+}
+
+static void sde_hw_sspp_setup_csc_8bit(struct sde_hw_pipe *ctx,
+		struct sde_csc_cfg *data)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+	sde_hw_csc_setup(c, VIG_0_CSC_1_MATRIX_COEFF_0, data);
+}
+
+static void sde_hw_sspp_setup_sharpening(struct sde_hw_pipe *ctx,
+		struct sde_hw_sharp_cfg *cfg)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 idx;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx, cfg->strength);
+	SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0x4, cfg->edge_thr);
+	SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0x8, cfg->smooth_thr);
+	SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0xC, cfg->noise_thr);
+}
+
+static void sde_hw_sspp_setup_solidfill(struct sde_hw_pipe *ctx,
+		u32 const_color,
+		u32 flags)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 secure = 0;
+	u32 unpack, src_format, opmode = 0;
+	u32 idx;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	/* format info */
+	src_format = SSPP_SOLID_FILL;
+	unpack = (C3_ALPHA << 24) | (C2_R_Cr << 16) |
+		(C1_B_Cb << 8) | (C0_G_Y << 0);
+	secure = (flags & SDE_SSPP_SECURE_OVERLAY_SESSION) ? 0xF : 0x00;
+	opmode = MDSS_MDP_OP_PE_OVERRIDE;
+
+	SDE_REG_WRITE(c, SSPP_SRC_FORMAT + idx, src_format);
+	SDE_REG_WRITE(c, SSPP_SRC_UNPACK_PATTERN + idx, unpack);
+	SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
+	SDE_REG_WRITE(c, SSPP_SRC_CONSTANT_COLOR + idx, const_color);
+	SDE_REG_WRITE(c, SSPP_SRC_OP_MODE + idx, opmode);
+}
+
+static void sde_hw_sspp_setup_histogram_v1(struct sde_hw_pipe *ctx,
+			void *cfg)
+{
+
+}
+
+static void sde_hw_sspp_setup_memcolor(struct sde_hw_pipe *ctx,
+		u32 memcolortype, u8 en)
+{
+}
+
+static void sde_hw_sspp_setup_igc(struct sde_hw_pipe *ctx)
+{
+}
+
+void sde_sspp_setup_pa(struct sde_hw_pipe *c)
+{
+}
+
+static void sde_hw_sspp_setup_danger_safe(struct sde_hw_pipe *ctx,
+		u32 danger_lut, u32 safe_lut)
+{
+	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	u32 idx;
+
+	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+		return;
+
+	SDE_REG_WRITE(c, SSPP_DANGER_LUT + idx, danger_lut);
+	SDE_REG_WRITE(c, SSPP_SAFE_LUT + idx, safe_lut);
+}
+
+static void sde_hw_sspp_qseed2_coeff(void *ctx)
+{
+}
+
+static void _setup_layer_ops(struct sde_hw_sspp_ops *ops,
+		unsigned long features)
+{
+	if (test_bit(SDE_SSPP_SRC, &features)) {
+		ops->setup_sourceformat = sde_hw_sspp_setup_format;
+		ops->setup_rects = sde_hw_sspp_setup_rects;
+		ops->setup_sourceaddress = sde_hw_sspp_setup_sourceaddress;
+		ops->setup_solidfill = sde_hw_sspp_setup_solidfill;
+		ops->setup_danger_safe = sde_hw_sspp_setup_danger_safe;
+	}
+	if (test_bit(SDE_SSPP_CSC, &features))
+		ops->setup_csc = sde_hw_sspp_setup_csc_8bit;
+
+	if (test_bit(SDE_SSPP_PA_V1, &features)) {
+		ops->setup_sharpening = sde_hw_sspp_setup_sharpening;
+		ops->setup_pa_memcolor = sde_hw_sspp_setup_memcolor;
+	}
+	if (test_bit(SDE_SSPP_HIST_V1, &features))
+		ops->setup_histogram = sde_hw_sspp_setup_histogram_v1;
+
+	if (test_bit(SDE_SSPP_IGC, &features))
+		ops->setup_igc = sde_hw_sspp_setup_igc;
+}
+
+static struct sde_sspp_cfg *_sspp_offset(enum sde_sspp sspp,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->sspp_count; i++) {
+		if (sspp == m->sspp[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->sspp[i].base;
+			b->hwversion = m->hwversion;
+			return &m->sspp[i];
+		}
+	}
+
+	return ERR_PTR(-ENOMEM);
+}
+
+struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx,
+			void __iomem *addr,
+			struct sde_mdss_cfg *m)
+{
+	struct sde_hw_pipe *c;
+	struct sde_sspp_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _sspp_offset(idx, m, addr, &c->hw);
+	if (IS_ERR_OR_NULL(cfg)) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Assign ops */
+	c->idx = idx;
+	c->cap = cfg;
+	_setup_layer_ops(&c->ops, c->cap->features);
+	c->highest_bank_bit = m->mdp[0].highest_bank_bit;
+
+	/*
+	 * Perform any default initialization for the sspp blocks
+	 */
+	if (test_bit(SDE_SSPP_SCALAR_QSEED2, &cfg->features))
+		sde_hw_sspp_qseed2_coeff(c);
+
+	if (test_bit(SDE_MDP_PANIC_PER_PIPE, &m->mdp[0].features))
+		sde_hw_sspp_setup_danger_safe(c,
+				cfg->sblk->danger_lut,
+				cfg->sblk->safe_lut);
+
+	return c;
+}
+
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
new file mode 100644
index 0000000..0c3873b
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -0,0 +1,266 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_SSPP_H
+#define _SDE_HW_SSPP_H
+
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_mdp_formats.h"
+#include "sde_hw_mdp_util.h"
+
+struct sde_hw_pipe;
+
+/**
+ * Flags
+ */
+#define SDE_SSPP_SECURE_OVERLAY_SESSION 0x1
+#define SDE_SSPP_FLIP_LR	 0x2
+#define SDE_SSPP_FLIP_UD	 0x4
+#define SDE_SSPP_SOURCE_ROTATED_90 0x8
+#define SDE_SSPP_ROT_90  0x10
+
+enum {
+	SDE_MDP_FRAME_LINEAR,
+	SDE_MDP_FRAME_TILE_A4X,
+	SDE_MDP_FRAME_TILE_A5X,
+};
+
+enum sde_hw_filter {
+	SDE_MDP_SCALE_FILTER_NEAREST = 0,
+	SDE_MDP_SCALE_FILTER_BIL,
+	SDE_MDP_SCALE_FILTER_PCMN,
+	SDE_MDP_SCALE_FILTER_CA,
+	SDE_MDP_SCALE_FILTER_MAX
+};
+
+struct sde_hw_sharp_cfg {
+	u32 strength;
+	u32 edge_thr;
+	u32 smooth_thr;
+	u32 noise_thr;
+};
+
+struct sde_hw_pixel_ext {
+	/* scaling factors are enabled for this input layer */
+	uint8_t enable_pxl_ext;
+
+	int init_phase_x[SDE_MAX_PLANES];
+	int phase_step_x[SDE_MAX_PLANES];
+	int init_phase_y[SDE_MAX_PLANES];
+	int phase_step_y[SDE_MAX_PLANES];
+
+	/*
+	 * Number of pixels extension in left, right, top and bottom direction
+	 * for all color components. This pixel value for each color component
+	 * should be sum of fetch + repeat pixels.
+	 */
+	int num_ext_pxls_left[SDE_MAX_PLANES];
+	int num_ext_pxls_right[SDE_MAX_PLANES];
+	int num_ext_pxls_top[SDE_MAX_PLANES];
+	int num_ext_pxls_btm[SDE_MAX_PLANES];
+
+	/*
+	 * Number of pixels needs to be overfetched in left, right, top and
+	 * bottom directions from source image for scaling.
+	 */
+	int left_ftch[SDE_MAX_PLANES];
+	int right_ftch[SDE_MAX_PLANES];
+	int top_ftch[SDE_MAX_PLANES];
+	int btm_ftch[SDE_MAX_PLANES];
+
+	/*
+	 * Number of pixels needs to be repeated in left, right, top and
+	 * bottom directions for scaling.
+	 */
+	int left_rpt[SDE_MAX_PLANES];
+	int right_rpt[SDE_MAX_PLANES];
+	int top_rpt[SDE_MAX_PLANES];
+	int btm_rpt[SDE_MAX_PLANES];
+
+	uint32_t roi_w[SDE_MAX_PLANES];
+
+	/*
+	 * Filter type to be used for scaling in horizontal and vertical
+	 * directions
+	 */
+	enum sde_hw_filter horz_filter[SDE_MAX_PLANES];
+	enum sde_hw_filter vert_filter[SDE_MAX_PLANES];
+
+};
+
+/**
+ * struct sde_hw_pipe_cfg : Pipe description
+ * @src:       source surface information
+ * @src_rect:  src ROI, caller takes into account the different operations
+ *             such as decimation, flip etc to program this field
+ * @dest_rect: destination ROI.
+ * @ horz_decimation : horizontal decimation factor( 0, 2, 4, 8, 16)
+ * @ vert_decimation : vertical decimation factor( 0, 2, 4, 8, 16)
+ *              2: Read 1 line/pixel drop 1 line/pixel
+ *              4: Read 1 line/pixel drop 3  lines/pixels
+ *              8: Read 1 line/pixel drop 7 lines/pixels
+ *              16: Read 1 line/pixel drop 15 line/pixels
+ * @addr:      source surface address
+ */
+struct sde_hw_pipe_cfg {
+	struct sde_hw_source_info src;
+	struct sde_rect src_rect;
+	struct sde_rect dst_rect;
+	u8 horz_decimation;
+	u8 vert_decimation;
+	struct addr_info addr;
+};
+
+/**
+ * struct danger_safe_cfg:
+ * @danger_lut:
+ * @safe_lut:
+ */
+struct danger_safe_cfg {
+	u32 danger_lut;
+	u32 safe_lut;
+};
+
+/**
+ * struct sde_hw_sspp_ops - interface to the SSPP Hw driver functions
+ * Caller must call the init function to get the pipe context for each pipe
+ * Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_sspp_ops {
+	/**
+	 * setup_sourceformat - setup pixel format cropping rectangle, flip
+	 * @ctx: Pointer to pipe context
+	 * @cfg: Pointer to pipe config structure
+	 * @flags: Format flags
+	 */
+	void (*setup_sourceformat)(struct sde_hw_pipe *ctx,
+			struct sde_hw_pipe_cfg *cfg,
+			u32 flags);
+
+	/**
+	 * setup_rects - setup pipe ROI rectangles
+	 * @ctx: Pointer to pipe context
+	 * @cfg: Pointer to pipe config structure
+	 * @pe_ext: Pointer to pixel ext settings
+	 */
+	void (*setup_rects)(struct sde_hw_pipe *ctx,
+			struct sde_hw_pipe_cfg *cfg,
+			struct sde_hw_pixel_ext *pe_ext);
+
+	/**
+	 * setup_sourceaddress - setup pipe source addresses
+	 * @ctx: Pointer to pipe context
+	 * @cfg: Pointer to pipe config structure
+	 */
+	void (*setup_sourceaddress)(struct sde_hw_pipe *ctx,
+			struct sde_hw_pipe_cfg *cfg);
+
+	/**
+	 * setup_csc - setup color space coversion
+	 * @ctx: Pointer to pipe context
+	 * @data: Pointer to config structure
+	 */
+	void (*setup_csc)(struct sde_hw_pipe *ctx,
+			struct sde_csc_cfg *data);
+
+	/**
+	 * setup_solidfill - enable/disable colorfill
+	 * @ctx: Pointer to pipe context
+	 * @const_color: Fill color value
+	 * @flags: Pipe flags
+	 */
+	void (*setup_solidfill)(struct sde_hw_pipe *ctx,
+			u32 const_color,
+			u32 flags);
+
+	/**
+	 * setup_sharpening - setup sharpening
+	 * @ctx: Pointer to pipe context
+	 * @cfg: Pointer to config structure
+	 */
+	void (*setup_sharpening)(struct sde_hw_pipe *ctx,
+			struct sde_hw_sharp_cfg *cfg);
+
+	/**
+	 * setup_pa_memcolor - setup source color processing
+	 * @ctx: Pointer to pipe context
+	 * @memcolortype: Memcolor type
+	 * @en: PA enable
+	 */
+	void (*setup_pa_memcolor)(struct sde_hw_pipe *ctx,
+			u32 memcolortype, u8 en);
+
+	/**
+	 * setup_igc - setup inverse gamma correction
+	 * @ctx: Pointer to pipe context
+	 */
+	void (*setup_igc)(struct sde_hw_pipe *ctx);
+
+	/**
+	 * setup_danger_safe - setup danger safe LUTS
+	 * @ctx: Pointer to pipe context
+	 * @danger_lut: Danger LUT setting
+	 * @safe_lut: Safe LUT setting
+	 */
+	void (*setup_danger_safe)(struct sde_hw_pipe *ctx,
+			u32 danger_lut,
+			u32 safe_lut);
+
+	/**
+	 * setup_histogram - setup histograms
+	 * @ctx: Pointer to pipe context
+	 * @cfg: Pointer to histogram configuration
+	 */
+	void (*setup_histogram)(struct sde_hw_pipe *ctx,
+			void *cfg);
+};
+
+/**
+ * struct sde_hw_pipe - pipe description
+ * @base_off:     mdp register mapped offset
+ * @blk_off:      pipe offset relative to mdss offset
+ * @length        length of register block offset
+ * @hwversion     mdss hw version number
+ * @idx:          pipe index
+ * @type :        pipe type, VIG/DMA/RGB/CURSOR, certain operations are not
+ *                supported for each pipe type
+ * @pipe_hw_cap:  pointer to layer_cfg
+ * @highest_bank_bit:
+ * @ops:          pointer to operations possible for this pipe
+ */
+struct sde_hw_pipe {
+	/* base */
+	 struct sde_hw_blk_reg_map hw;
+
+	/* Pipe */
+	enum sde_sspp idx;
+	const struct sde_sspp_cfg *cap;
+	u32 highest_bank_bit;
+
+	/* Ops */
+	struct sde_hw_sspp_ops ops;
+};
+
+/**
+ * sde_hw_sspp_init - initializes the sspp hw driver object.
+ * Should be called once before accessing every pipe.
+ * @idx:  Pipe index for which driver object is required
+ * @addr: Mapped register io address of MDP
+ * @m:    pointer to mdss catalog data @ops:
+ */
+struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx,
+			void __iomem *addr,
+			struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_SSPP_H */
+
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.c b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
new file mode 100644
index 0000000..1eaad18
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
@@ -0,0 +1,120 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_mdss.h"
+#include "sde_hwio.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_wb.h"
+
+static struct sde_wb_cfg *_wb_offset(enum sde_wb wb,
+		struct sde_mdss_cfg *m,
+		void __iomem *addr,
+		struct sde_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->wb_count; i++) {
+		if (wb == m->wb[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->wb[i].base;
+			b->hwversion = m->hwversion;
+			return &m->wb[i];
+		}
+	}
+	return ERR_PTR(-EINVAL);
+}
+
+static void sde_hw_wb_setup_csc_8bit(struct sde_hw_wb *ctx,
+		struct sde_csc_cfg *data)
+{
+}
+
+static void sde_hw_wb_setup_outaddress(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *data)
+{
+}
+
+static void sde_hw_wb_setup_format(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *data)
+{
+}
+
+static void sde_hw_wb_setup_rotator(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *data)
+{
+}
+
+static void sde_hw_setup_dither(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *data)
+{
+}
+
+static void sde_hw_wb_setup_cdwn(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *data)
+{
+}
+static void sde_hw_wb_traffic_shaper(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *data)
+{
+}
+
+static void _setup_wb_ops(struct sde_hw_wb_ops *ops,
+	unsigned long features)
+{
+	if (test_bit(SDE_WB_CSC, &features))
+		ops->setup_csc_data = sde_hw_wb_setup_csc_8bit;
+
+	ops->setup_outaddress = sde_hw_wb_setup_outaddress;
+	ops->setup_outformat = sde_hw_wb_setup_format;
+
+	if (test_bit(SDE_WB_BLOCK_MODE, &features))
+		ops->setup_rotator = sde_hw_wb_setup_rotator;
+
+	if (test_bit(SDE_WB_DITHER, &features))
+		ops->setup_dither = sde_hw_setup_dither;
+
+	if (test_bit(SDE_WB_CHROMA_DOWN, &features))
+		ops->setup_cdwn = sde_hw_wb_setup_cdwn;
+
+	if (test_bit(SDE_WB_TRAFFIC_SHAPER, &features))
+		ops->setup_trafficshaper = sde_hw_wb_traffic_shaper;
+}
+
+struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m)
+{
+	struct sde_hw_wb *c;
+	struct sde_wb_cfg *cfg;
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _wb_offset(idx, m, addr, &c->hw);
+	if (!cfg) {
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Assign ops */
+	c->idx = idx;
+	c->caps = cfg;
+	_setup_wb_ops(&c->ops, c->caps->features);
+
+	/*
+	 * Perform any default initialization for the chroma down module
+	 */
+
+	return c;
+}
+
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.h b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
new file mode 100644
index 0000000..623af6e
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_WB_H
+#define _SDE_HW_WB_H
+
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+#include "sde_hw_mdp_util.h"
+
+struct sde_hw_wb;
+
+struct sde_hw_wb_cfg {
+	struct sde_hw_source_info dest;
+};
+
+/**
+ *
+ * struct sde_hw_wb_ops : Interface to the wb Hw driver functions
+ *  Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_wb_ops {
+	void (*setup_csc_data)(struct sde_hw_wb *ctx,
+			struct sde_csc_cfg *data);
+
+	void (*setup_outaddress)(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *wb);
+
+	void (*setup_outformat)(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *wb);
+
+	void (*setup_rotator)(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *wb);
+
+	void (*setup_dither)(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *wb);
+
+	void (*setup_cdwn)(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *wb);
+
+	void (*setup_trafficshaper)(struct sde_hw_wb *ctx,
+		struct sde_hw_wb_cfg *wb);
+};
+
+/**
+ * struct sde_hw_wb : WB driver object
+ * @struct sde_hw_blk_reg_map *hw;
+ * @idx
+ * @wb_hw_caps
+ * @mixer_hw_caps
+ * @ops
+ */
+struct sde_hw_wb {
+	/* base */
+	struct sde_hw_blk_reg_map hw;
+
+	/* wb path */
+	int idx;
+	const struct sde_wb_cfg *caps;
+
+	/* ops */
+	struct sde_hw_wb_ops ops;
+};
+
+/**
+ * sde_hw_wb_init(): Initializes the wb_path hw driver object.
+ * should be called before accessing every mixer.
+ * @idx:  wb_path index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m :   pointer to mdss catalog data
+ */
+struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx,
+		void __iomem *addr,
+		struct sde_mdss_cfg *m);
+
+#endif /*_SDE_HW_WB_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h
new file mode 100644
index 0000000..c8d98a4
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hwio.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HWIO_H
+#define _SDE_HWIO_H
+
+#include "sde_hw_mdp_util.h"
+
+/**
+ * MDP TOP block Register and bit fields and defines
+ */
+#define DISP_INTF_SEL                   0x004
+#define INTR_EN                         0x010
+#define INTR_STATUS                     0x014
+#define INTR_CLEAR                      0x018
+#define INTR2_EN                        0x008
+#define INTR2_STATUS                    0x00c
+#define INTR2_CLEAR                     0x02c
+#define HIST_INTR_EN                    0x01c
+#define HIST_INTR_STATUS                0x020
+#define HIST_INTR_CLEAR                 0x024
+#define SPLIT_DISPLAY_EN                0x2F4
+#define SPLIT_DISPLAY_UPPER_PIPE_CTRL   0x2F8
+#define DSPP_IGC_COLOR0_RAM_LUTN        0x300
+#define DSPP_IGC_COLOR1_RAM_LUTN        0x304
+#define DSPP_IGC_COLOR2_RAM_LUTN        0x308
+#define PPB0_CNTL                       0x330
+#define PPB0_CONFIG                     0x334
+#define PPB1_CNTL                       0x338
+#define PPB1_CONFIG                     0x33C
+#define HW_EVENTS_CTL                   0x37C
+#define CLK_CTRL3                       0x3A8
+#define CLK_STATUS3                     0x3AC
+#define CLK_CTRL4                       0x3B0
+#define CLK_STATUS4                     0x3B4
+#define CLK_CTRL5                       0x3B8
+#define CLK_STATUS5                     0x3BC
+#define CLK_CTRL7                       0x3D0
+#define CLK_STATUS7                     0x3D4
+#define SPLIT_DISPLAY_LOWER_PIPE_CTRL   0x3F0
+#define SPLIT_DISPLAY_TE_LINE_INTERVAL  0x3F4
+#define INTF_SW_RESET_MASK              0x3FC
+#define MDP_OUT_CTL_0                   0x410
+#define MDP_VSYNC_SEL                   0x414
+#define DCE_SEL                         0x450
+
+#endif /*_SDE_HWIO_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c
new file mode 100644
index 0000000..bc47f47
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_irq.c
@@ -0,0 +1,120 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+
+#include "msm_drv.h"
+#include "sde_kms.h"
+
+void sde_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+	uint32_t old_irqmask)
+{
+}
+
+void sde_irq_preinstall(struct msm_kms *kms)
+{
+}
+
+int sde_irq_postinstall(struct msm_kms *kms)
+{
+	return 0;
+}
+
+void sde_irq_uninstall(struct msm_kms *kms)
+{
+}
+
+irqreturn_t sde_irq(struct msm_kms *kms)
+{
+	return IRQ_HANDLED;
+}
+
+int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+	return 0;
+}
+
+void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+}
+
+static void sde_hw_irq_mask(struct irq_data *irqd)
+{
+	struct sde_kms *sde_kms = irq_data_get_irq_chip_data(irqd);
+
+	/* memory barrier */
+	smp_mb__before_atomic();
+	clear_bit(irqd->hwirq, &sde_kms->irqcontroller.enabled_mask);
+	/* memory barrier */
+	smp_mb__after_atomic();
+}
+
+static void sde_hw_irq_unmask(struct irq_data *irqd)
+{
+	struct sde_kms *sde_kms = irq_data_get_irq_chip_data(irqd);
+
+	/* memory barrier */
+	smp_mb__before_atomic();
+	set_bit(irqd->hwirq, &sde_kms->irqcontroller.enabled_mask);
+	/* memory barrier */
+	smp_mb__after_atomic();
+}
+
+static struct irq_chip sde_hw_irq_chip = {
+	.name = "sde",
+	.irq_mask = sde_hw_irq_mask,
+	.irq_unmask = sde_hw_irq_unmask,
+};
+
+static int sde_hw_irqdomain_map(struct irq_domain *d,
+		unsigned int irq, irq_hw_number_t hwirq)
+{
+	struct sde_kms *sde_kms = d->host_data;
+
+	irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq);
+	irq_set_chip_data(irq, sde_kms);
+
+	return 0;
+}
+
+static const struct irq_domain_ops sde_hw_irqdomain_ops = {
+	.map = sde_hw_irqdomain_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+int sde_irq_domain_init(struct sde_kms *sde_kms)
+{
+	struct device *dev = sde_kms->dev->dev;
+	struct irq_domain *d;
+
+	d = irq_domain_add_linear(dev->of_node, 32,
+			&sde_hw_irqdomain_ops, sde_kms);
+
+	if (!d)
+		return -ENXIO;
+
+	sde_kms->irqcontroller.enabled_mask = 0;
+	sde_kms->irqcontroller.domain = d;
+
+	return 0;
+}
+
+int sde_irq_domain_fini(struct sde_kms *sde_kms)
+{
+	if (sde_kms->irqcontroller.domain) {
+		irq_domain_remove(sde_kms->irqcontroller.domain);
+		sde_kms->irqcontroller.domain = NULL;
+	}
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
new file mode 100644
index 0000000..740b9c0
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -0,0 +1,306 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drm_crtc.h>
+#include "msm_drv.h"
+#include "sde_kms.h"
+#include "sde_hw_mdss.h"
+
+static int modeset_init_intf(struct sde_kms *sde_kms, int intf_num)
+{
+	struct sde_mdss_cfg *catalog = sde_kms->catalog;
+	u32 intf_type = catalog->intf[intf_num].type;
+
+	switch (intf_type) {
+	case INTF_NONE:
+		break;
+	case INTF_DSI:
+		break;
+	case INTF_LCDC:
+		break;
+	case INTF_HDMI:
+		break;
+	case INTF_EDP:
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int modeset_init(struct sde_kms *sde_kms)
+{
+	struct msm_drm_private *priv = sde_kms->dev->dev_private;
+	int i;
+	int ret;
+	struct sde_mdss_cfg *catalog = sde_kms->catalog;
+	struct drm_device *dev = sde_kms->dev;
+	struct drm_plane *primary_planes[MAX_PLANES];
+	int primary_planes_idx = 0;
+
+	int num_private_planes = catalog->mixer_count;
+
+	ret = sde_irq_domain_init(sde_kms);
+	if (ret)
+		goto fail;
+
+	/* Create the planes */
+	for (i = 0; i < catalog->sspp_count; i++) {
+		struct drm_plane *plane;
+		bool primary = true;
+
+		if (catalog->sspp[i].features & BIT(SDE_SSPP_CURSOR)
+			|| !num_private_planes)
+			primary = false;
+
+		plane = sde_plane_init(dev, primary);
+		if (IS_ERR(plane)) {
+			ret = PTR_ERR(plane);
+			goto fail;
+		}
+		priv->planes[priv->num_planes++] = plane;
+
+		if (primary)
+			primary_planes[primary_planes_idx++] = plane;
+		if (num_private_planes)
+			num_private_planes--;
+	}
+
+	/* Need enough primary planes to assign one per mixer (CRTC) */
+	if (primary_planes_idx < catalog->mixer_count) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	/* Create one CRTC per mixer */
+	for (i = 0; i < catalog->mixer_count; i++) {
+		/*
+		 * Each mixer receives a private plane. We start
+		 * with first RGB, and then DMA and then VIG.
+		 */
+		struct drm_crtc *crtc;
+
+		crtc = sde_crtc_init(dev, NULL, primary_planes[i], i);
+		if (IS_ERR(crtc)) {
+			ret = PTR_ERR(crtc);
+			goto fail;
+		}
+		priv->crtcs[priv->num_crtcs++] = crtc;
+	}
+
+	for (i = 0; i < catalog->intf_count; i++) {
+		ret = modeset_init_intf(sde_kms, i);
+		if (ret)
+			goto fail;
+	}
+	return 0;
+fail:
+	return ret;
+}
+
+static int sde_hw_init(struct msm_kms *kms)
+{
+	return 0;
+}
+
+static long sde_round_pixclk(struct msm_kms *kms, unsigned long rate,
+		struct drm_encoder *encoder)
+{
+	return rate;
+}
+
+static void sde_preclose(struct msm_kms *kms, struct drm_file *file)
+{
+}
+
+static void sde_destroy(struct msm_kms *kms)
+{
+	struct sde_kms *sde_kms = to_sde_kms(to_mdp_kms(kms));
+
+	sde_irq_domain_fini(sde_kms);
+	kfree(sde_kms);
+}
+
+static const struct mdp_kms_funcs kms_funcs = {
+	.base = {
+		.hw_init         = sde_hw_init,
+		.irq_preinstall  = sde_irq_preinstall,
+		.irq_postinstall = sde_irq_postinstall,
+		.irq_uninstall   = sde_irq_uninstall,
+		.irq             = sde_irq,
+		.enable_vblank   = sde_enable_vblank,
+		.disable_vblank  = sde_disable_vblank,
+		.get_format      = mdp_get_format,
+		.round_pixclk    = sde_round_pixclk,
+		.preclose        = sde_preclose,
+		.destroy         = sde_destroy,
+	},
+	.set_irqmask         = sde_set_irqmask,
+};
+
+static int get_clk(struct platform_device *pdev, struct clk **clkp,
+		const char *name, bool mandatory)
+{
+	struct device *dev = &pdev->dev;
+	struct clk *clk = devm_clk_get(dev, name);
+
+	if (IS_ERR(clk) && mandatory) {
+		dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
+		return PTR_ERR(clk);
+	}
+	if (IS_ERR(clk))
+		DBG("skipping %s", name);
+	else
+		*clkp = clk;
+
+	return 0;
+}
+
+struct sde_kms *sde_hw_setup(struct platform_device *pdev)
+{
+	struct sde_kms *sde_kms;
+	struct msm_kms *kms = NULL;
+	int ret;
+
+	sde_kms = kzalloc(sizeof(*sde_kms), GFP_KERNEL);
+	if (!sde_kms)
+		return NULL;
+
+	mdp_kms_init(&sde_kms->base, &kms_funcs);
+
+	kms = &sde_kms->base.base;
+
+	sde_kms->mmio = msm_ioremap(pdev, "mdp_phys", "SDE");
+	if (IS_ERR(sde_kms->mmio)) {
+		ret = PTR_ERR(sde_kms->mmio);
+		goto fail;
+	}
+
+	sde_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF");
+	if (IS_ERR(sde_kms->vbif)) {
+		ret = PTR_ERR(sde_kms->vbif);
+		goto fail;
+	}
+
+	sde_kms->venus = devm_regulator_get_optional(&pdev->dev, "gdsc-venus");
+	if (IS_ERR(sde_kms->venus)) {
+		ret = PTR_ERR(sde_kms->venus);
+		DBG("failed to get Venus GDSC regulator: %d\n", ret);
+		sde_kms->venus = NULL;
+	}
+
+	if (sde_kms->venus) {
+		ret = regulator_enable(sde_kms->venus);
+		if (ret) {
+			DBG("failed to enable venus GDSC: %d\n", ret);
+			goto fail;
+		}
+	}
+
+	sde_kms->vdd = devm_regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR(sde_kms->vdd)) {
+		ret = PTR_ERR(sde_kms->vdd);
+		goto fail;
+	}
+
+	ret = regulator_enable(sde_kms->vdd);
+	if (ret) {
+		DBG("failed to enable regulator vdd: %d\n", ret);
+		goto fail;
+	}
+
+	sde_kms->mmagic = devm_regulator_get_optional(&pdev->dev, "mmagic");
+	if (IS_ERR(sde_kms->mmagic)) {
+		ret = PTR_ERR(sde_kms->mmagic);
+		DBG("failed to get mmagic GDSC regulator: %d\n", ret);
+		sde_kms->mmagic = NULL;
+	}
+
+	/* mandatory clocks: */
+	ret = get_clk(pdev, &sde_kms->axi_clk, "bus_clk", true);
+	if (ret)
+		goto fail;
+	ret = get_clk(pdev, &sde_kms->ahb_clk, "iface_clk", true);
+	if (ret)
+		goto fail;
+	ret = get_clk(pdev, &sde_kms->src_clk, "core_clk_src", true);
+	if (ret)
+		goto fail;
+	ret = get_clk(pdev, &sde_kms->core_clk, "core_clk", true);
+	if (ret)
+		goto fail;
+	ret = get_clk(pdev, &sde_kms->vsync_clk, "vsync_clk", true);
+	if (ret)
+		goto fail;
+
+	/* optional clocks: */
+	get_clk(pdev, &sde_kms->lut_clk, "lut_clk", false);
+	get_clk(pdev, &sde_kms->mmagic_clk, "mmagic_clk", false);
+	get_clk(pdev, &sde_kms->iommu_clk, "iommu_clk", false);
+
+	return sde_kms;
+
+fail:
+	if (kms)
+		sde_destroy(kms);
+
+	return ERR_PTR(ret);
+}
+
+struct msm_kms *sde_kms_init(struct drm_device *dev)
+{
+	struct platform_device *pdev = dev->platformdev;
+	struct sde_mdss_cfg *catalog;
+	struct sde_kms *sde_kms;
+	struct msm_kms *msm_kms;
+	int ret = 0;
+
+	sde_kms = sde_hw_setup(pdev);
+	if (IS_ERR(sde_kms)) {
+		ret = PTR_ERR(sde_kms);
+		goto fail;
+	}
+
+	sde_kms->dev = dev;
+	msm_kms = &sde_kms->base.base;
+
+	/*
+	 * Currently hardcoding to MDSS version 1.7.0 (8996)
+	 */
+	catalog = sde_hw_catalog_init(1, 7, 0);
+	if (!catalog)
+		goto fail;
+
+	sde_kms->catalog = catalog;
+
+	/*
+	 * Now we need to read the HW catalog and initialize resources such as
+	 * clocks, regulators, GDSC/MMAGIC, ioremap the register ranges etc
+	 */
+
+	/*
+	 * modeset_init should create the DRM related objects i.e. CRTCs,
+	 * planes, encoders, connectors and so forth
+	 */
+	modeset_init(sde_kms);
+
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+
+	return msm_kms;
+
+fail:
+	if (msm_kms)
+		sde_destroy(msm_kms);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
new file mode 100644
index 0000000..1afe1bb
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -0,0 +1,116 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SDE_KMS_H__
+#define __SDE_KMS_H__
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "mdp/mdp_kms.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_mdss.h"
+
+struct sde_kms {
+	struct mdp_kms base;
+	struct drm_device *dev;
+	int rev;
+	struct sde_mdss_cfg *catalog;
+
+	struct msm_mmu *mmu;
+
+	/* io/register spaces: */
+	void __iomem *mmio, *vbif;
+
+	struct regulator *vdd;
+	struct regulator *mmagic;
+	struct regulator *venus;
+
+	struct clk *axi_clk;
+	struct clk *ahb_clk;
+	struct clk *src_clk;
+	struct clk *core_clk;
+	struct clk *lut_clk;
+	struct clk *mmagic_clk;
+	struct clk *iommu_clk;
+	struct clk *vsync_clk;
+
+	struct {
+		unsigned long enabled_mask;
+		struct irq_domain *domain;
+	} irqcontroller;
+};
+
+#define to_sde_kms(x) container_of(x, struct sde_kms, base)
+
+struct sde_plane_state {
+	struct drm_plane_state base;
+
+	/* aligned with property */
+	uint8_t premultiplied;
+	uint8_t zpos;
+	uint8_t alpha;
+
+	/* assigned by crtc blender */
+	enum sde_stage stage;
+
+	/* some additional transactional status to help us know in the
+	 * apply path whether we need to update SMP allocation, and
+	 * whether current update is still pending:
+	 */
+	bool mode_changed : 1;
+	bool pending : 1;
+};
+
+#define to_sde_plane_state(x) \
+		container_of(x, struct sde_plane_state, base)
+
+int sde_disable(struct sde_kms *sde_kms);
+int sde_enable(struct sde_kms *sde_kms);
+
+void sde_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
+		uint32_t old_irqmask);
+void sde_irq_preinstall(struct msm_kms *kms);
+int sde_irq_postinstall(struct msm_kms *kms);
+void sde_irq_uninstall(struct msm_kms *kms);
+irqreturn_t sde_irq(struct msm_kms *kms);
+int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+
+enum sde_sspp sde_plane_pipe(struct drm_plane *plane);
+void sde_plane_install_properties(struct drm_plane *plane,
+		struct drm_mode_object *obj);
+void sde_plane_set_scanout(struct drm_plane *plane,
+		struct drm_framebuffer *fb);
+int sde_plane_mode_set(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		int crtc_x, int crtc_y,
+		unsigned int crtc_w, unsigned int crtc_h,
+		uint32_t src_x, uint32_t src_y,
+		uint32_t src_w, uint32_t src_h);
+void sde_plane_complete_flip(struct drm_plane *plane);
+struct drm_plane *sde_plane_init(struct drm_device *dev, bool private_plane);
+
+uint32_t sde_crtc_vblank(struct drm_crtc *crtc);
+
+void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
+void sde_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
+void sde_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
+struct drm_crtc *sde_crtc_init(struct drm_device *dev,
+		struct drm_encoder *encoder,
+		struct drm_plane *plane, int id);
+
+struct drm_encoder *sde_encoder_init(struct drm_device *dev, int intf);
+
+int sde_irq_domain_init(struct sde_kms *sde_kms);
+int sde_irq_domain_fini(struct sde_kms *sde_kms);
+
+#endif /* __sde_kms_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_mdp_formats.h b/drivers/gpu/drm/msm/sde/sde_mdp_formats.h
new file mode 100644
index 0000000..4ad3ad3
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_mdp_formats.h
@@ -0,0 +1,213 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_MDP_FORMATS_H
+#define _SDE_MDP_FORMATS_H
+
+#include <drm/drm_fourcc.h>
+#include "sde_hw_mdss.h"
+
+/**
+ * MDP supported format packing, bpp, and other format
+ * information.
+ * MDP currently only supports interleaved RGB formats
+ * UBWC support for a pixel format is indicated by the flag,
+ * there is additional meta data plane for such formats
+ */
+
+#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, alpha, bp, flg) \
+{                                                                         \
+	.format = DRM_FORMAT_ ## fmt,                                     \
+	.fetch_planes = SDE_MDP_PLANE_INTERLEAVED,                        \
+	.alpha_enable = alpha,                                            \
+	.element = { (e0), (e1), (e2), (e3) },                            \
+	.bits = { a, r, g, b},                                            \
+	.chroma_sample = SDE_MDP_CHROMA_RGB,                              \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = (alpha == true) ? 4:3,                            \
+	.bpp = bp,                                                        \
+	.fetch_mode = SDE_MDP_FETCH_LINEAR,                               \
+	.is_yuv = false,                                                  \
+	.flag = flg                                                      \
+}
+
+#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3,               \
+alpha, chroma, count, bp, flg)                                          \
+{                                                                         \
+	.format = DRM_FORMAT_ ## fmt,                                     \
+	.fetch_planes = SDE_MDP_PLANE_INTERLEAVED,                        \
+	.alpha_enable = alpha,                                            \
+	.element = { (e0), (e1), (e2), (e3)},                             \
+	.bits = { a, r, g, b},                                            \
+	.chroma_sample = chroma,                                          \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = count,                                            \
+	.bpp = bp,                                                       \
+	.fetch_mode = SDE_MDP_FETCH_LINEAR,                               \
+	.is_yuv = true,                                                   \
+	.flag = flg                                                      \
+}
+#define PSEDUO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg)             \
+{                                                                         \
+	.format = DRM_FORMAT_ ## fmt,                                     \
+	.fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR,                      \
+	.alpha_enable = false,                                            \
+	.element = { (e0), (e1), 0, 0 },                                  \
+	.bits = { a, r, g, b},                                            \
+	.chroma_sample = chroma,                                          \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = 2,                                                \
+	.bpp = 2,                                                         \
+	.fetch_mode = SDE_MDP_FETCH_LINEAR,                               \
+	.is_yuv = true,                                                   \
+	.flag = flg                                                      \
+}
+
+#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, flg)\
+{                                                                            \
+	.format = DRM_FORMAT_ ## fmt,                                        \
+	.fetch_planes = SDE_MDP_PLANE_INTERLEAVED,                           \
+	.alpha_enable = alpha,                                               \
+	.element = { (e0), (e1), (e2), 0 },                               \
+	.bits = { a, r, g, b},                                               \
+	.chroma_sample = chroma,                                             \
+	.unpack_align_msb = 0,                                               \
+	.unpack_tight = 1,                                                   \
+	.unpack_count = 0,                                                   \
+	.bpp = bp,                                                          \
+	.fetch_mode = SDE_MDP_FETCH_LINEAR,                                  \
+	.is_yuv = true,                                                      \
+	.flag = flg                                                         \
+}
+
+static struct sde_mdp_format_params sde_mdp_format_map[] = {
+	INTERLEAVED_RGB_FMT(ARGB8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA,
+		true, 4, 0),
+
+	INTERLEAVED_RGB_FMT(ABGR8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA,
+		true, 4, 0),
+
+	INTERLEAVED_RGB_FMT(RGBA8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr,
+		true, 4, 0),
+
+	INTERLEAVED_RGB_FMT(BGRA8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb,
+		true, 4, 0),
+
+	INTERLEAVED_RGB_FMT(XRGB8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA,
+		true, 4, 0),
+
+	INTERLEAVED_RGB_FMT(RGB888,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, 0,
+		false, 3, 0),
+
+	INTERLEAVED_RGB_FMT(BGR888,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, 0,
+		false, 3, 0),
+
+	INTERLEAVED_RGB_FMT(RGB565,
+		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, 0,
+		false, 2, 0),
+
+	INTERLEAVED_RGB_FMT(BGR565,
+		0, 5, 6, 5,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, 0,
+		false, 2, 0),
+
+	PSEDUO_YUV_FMT(NV12,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C2_R_Cr,
+		SDE_MDP_CHROMA_420, 0),
+
+	PSEDUO_YUV_FMT(NV21,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C1_B_Cb,
+		SDE_MDP_CHROMA_420, 0),
+
+	PSEDUO_YUV_FMT(NV16,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C2_R_Cr,
+		SDE_MDP_CHROMA_H2V1, 0),
+
+	PSEDUO_YUV_FMT(NV61,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C1_B_Cb,
+		SDE_MDP_CHROMA_H2V1, 0),
+
+	INTERLEAVED_YUV_FMT(VYUY,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y,
+		false, SDE_MDP_CHROMA_H2V1, 4, 2,
+		0),
+
+	INTERLEAVED_YUV_FMT(UYVY,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y,
+		false, SDE_MDP_CHROMA_H2V1, 4, 2,
+		0),
+
+	INTERLEAVED_YUV_FMT(YUYV,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr,
+		false, SDE_MDP_CHROMA_H2V1, 4, 2,
+		0),
+
+	INTERLEAVED_YUV_FMT(YVYU,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb,
+		false, SDE_MDP_CHROMA_H2V1, 4, 2,
+		0),
+
+	PLANAR_YUV_FMT(YUV420,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C1_B_Cb, C0_G_Y,
+		false, SDE_MDP_CHROMA_420, 2,
+		0),
+
+	PLANAR_YUV_FMT(YVU420,
+		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C1_B_Cb, C2_R_Cr, C0_G_Y,
+		false, SDE_MDP_CHROMA_420, 2,
+		0),
+};
+
+struct sde_mdp_format_params *sde_mdp_get_format_params(u32 format,
+		u32 fmt_modifier)
+{
+	u32 i = 0;
+	struct sde_mdp_format_params *fmt = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(sde_mdp_format_map); i++)
+		if (format == sde_mdp_format_map[i].format) {
+			fmt = &sde_mdp_format_map[i];
+			break;
+		}
+
+	return fmt;
+}
+
+#endif /*_SDE_MDP_FORMATS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
new file mode 100644
index 0000000..17b7303
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -0,0 +1,115 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_kms.h"
+
+struct sde_plane {
+	struct drm_plane base;
+	const char *name;
+	uint32_t nformats;
+	uint32_t formats[32];
+};
+#define to_sde_plane(x) container_of(x, struct sde_plane, base)
+
+static int sde_plane_update(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		int crtc_x, int crtc_y,
+		unsigned int crtc_w, unsigned int crtc_h,
+		uint32_t src_x, uint32_t src_y,
+		uint32_t src_w, uint32_t src_h)
+{
+	return 0;
+}
+
+static int sde_plane_disable(struct drm_plane *plane)
+{
+	return 0;
+}
+
+static void sde_plane_destroy(struct drm_plane *plane)
+{
+	struct sde_plane *sde_plane = to_sde_plane(plane);
+	struct msm_drm_private *priv = plane->dev->dev_private;
+
+	if (priv->kms)
+		sde_plane_disable(plane);
+
+	drm_plane_cleanup(plane);
+
+	kfree(sde_plane);
+}
+
+/* helper to install properties which are common to planes and crtcs */
+void sde_plane_install_properties(struct drm_plane *plane,
+		struct drm_mode_object *obj)
+{
+}
+
+int sde_plane_set_property(struct drm_plane *plane,
+		struct drm_property *property, uint64_t val)
+{
+	return -EINVAL;
+}
+
+static const struct drm_plane_funcs sde_plane_funcs = {
+		.update_plane = sde_plane_update,
+		.disable_plane = sde_plane_disable,
+		.destroy = sde_plane_destroy,
+		.set_property = sde_plane_set_property,
+};
+
+void sde_plane_set_scanout(struct drm_plane *plane,
+		struct drm_framebuffer *fb)
+{
+}
+
+int sde_plane_mode_set(struct drm_plane *plane,
+		struct drm_crtc *crtc, struct drm_framebuffer *fb,
+		int crtc_x, int crtc_y,
+		unsigned int crtc_w, unsigned int crtc_h,
+		uint32_t src_x, uint32_t src_y,
+		uint32_t src_w, uint32_t src_h)
+{
+	return 0;
+}
+
+/* initialize plane */
+struct drm_plane *sde_plane_init(struct drm_device *dev, bool private_plane)
+{
+	struct drm_plane *plane = NULL;
+	struct sde_plane *sde_plane;
+	int ret;
+	enum drm_plane_type type;
+
+	sde_plane = kzalloc(sizeof(*sde_plane), GFP_KERNEL);
+	if (!sde_plane) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	plane = &sde_plane->base;
+
+	type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
+				 sde_plane->formats, sde_plane->nformats,
+				 type);
+
+	sde_plane_install_properties(plane, &plane->base);
+
+	return plane;
+
+fail:
+	if (plane)
+		sde_plane_destroy(plane);
+
+	return ERR_PTR(ret);
+}