diff --git a/drivers/gpu/drm/omapdrm/dss/Kconfig b/drivers/gpu/drm/omapdrm/dss/Kconfig
index f24ebf7..82faea6 100644
--- a/drivers/gpu/drm/omapdrm/dss/Kconfig
+++ b/drivers/gpu/drm/omapdrm/dss/Kconfig
@@ -132,3 +132,11 @@ config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
 	  disable the sleep if it doesn't cause problems on your platform.
 
 endif
+
+config TI_DSS6
+	tristate "TI DSS6 support"
+	select OMAP_DSS_BASE
+	select VIDEOMODE_HELPERS
+	select OMAP2_DSS_INIT
+	help
+	  Enable support for Texas Instruments DSS6 IP.
diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile b/drivers/gpu/drm/omapdrm/dss/Makefile
index 5950c3f..c669b2f 100644
--- a/drivers/gpu/drm/omapdrm/dss/Makefile
+++ b/drivers/gpu/drm/omapdrm/dss/Makefile
@@ -18,3 +18,6 @@ omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o
 omapdss-$(CONFIG_OMAP4_DSS_HDMI_CEC) += hdmi4_cec.o
 omapdss-$(CONFIG_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o
 ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
+
+obj-$(CONFIG_TI_DSS6) += omapdss6.o
+omapdss6-y := dss6.o dispc6.o dpi6.o
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc6.c b/drivers/gpu/drm/omapdrm/dss/dispc6.c
new file mode 100644
index 0000000..fbe4de5
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dispc6.c
@@ -0,0 +1,1438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <drm/drm_fourcc.h>
+
+#include "omapdss.h"
+#include "dss6.h"
+#include "dispc6.h"
+
+#define REG_GET(dispc, idx, start, end)	\
+	FLD_GET(dispc6_read(dispc, idx), start, end)
+
+#define REG_FLD_MOD(dispc, idx, val, start, end) \
+	dispc6_write(dispc, idx, FLD_MOD(dispc6_read(dispc, idx), val, start, end))
+
+#define VID_REG_GET(dispc, plane, idx, start, end) \
+	FLD_GET(dispc6_vid_read(dispc, plane, idx), start, end)
+
+#define VID_REG_FLD_MOD(dispc, plane, idx, val, start, end) \
+	dispc6_vid_write(dispc, plane, idx, FLD_MOD(dispc6_vid_read(dispc, plane, idx), val, start, end))
+
+
+#define VP_REG_GET(dispc, vp, idx, start, end) \
+	FLD_GET(dispc6_vp_read(dispc, vp, idx), start, end)
+
+#define VP_REG_FLD_MOD(dispc, vp, idx, val, start, end)	\
+	dispc6_vp_write(dispc, vp, idx, FLD_MOD(dispc6_vp_read(dispc, vp, idx), val, start, end))
+
+struct dispc_features {
+	/* XXX should these come from the .dts? Min pclk is not feature of DSS IP */
+	unsigned long min_pclk;
+	unsigned long max_pclk;
+};
+
+/* Note: 9MHz is a special allowed case, and is handled separately in the code */
+static const struct dispc_features k2g_dispc_feats = {
+	.min_pclk = 43750000,
+	.max_pclk = 150000000,
+};
+
+static const struct of_device_id dispc6_of_match[];
+
+struct dispc_device {
+	struct platform_device *pdev;
+
+	struct dss6_device *dss6;
+
+	void __iomem *base_common;
+	void __iomem *base_vid1;
+	void __iomem *base_ovr1;
+	void __iomem *base_vp1;
+
+	int irq;
+	irq_handler_t user_handler;
+	void *user_data;
+
+	const struct dispc_features *feat;
+
+	struct clk *fclk;
+	struct clk *vp_clk;
+
+	bool is_enabled;
+
+	bool ctx_valid;
+	u32 ctx_vid1[0x400];
+
+	u32 gamma_table[256];
+};
+
+static void dispc6_write(struct dispc_device *dispc, u16 reg, u32 val)
+{
+	iowrite32(val, dispc->base_common + reg);
+}
+
+static u32 dispc6_read(struct dispc_device *dispc, u16 reg)
+{
+	return ioread32(dispc->base_common + reg);
+}
+
+static void dispc6_vid_write(struct dispc_device *dispc,
+			     enum omap_plane_id plane, u16 reg, u32 val)
+{
+	void __iomem *base = dispc->base_vid1;
+
+	iowrite32(val, base + reg);
+}
+
+static u32 dispc6_vid_read(struct dispc_device *dispc,
+			   enum omap_plane_id plane, u16 reg)
+{
+	void __iomem *base = dispc->base_vid1;
+
+	return ioread32(base + reg);
+}
+
+static void dispc6_ovr_write(struct dispc_device *dispc,
+			     enum omap_channel channel, u16 reg, u32 val)
+{
+	void __iomem *base = dispc->base_ovr1;
+
+	iowrite32(val, base + reg);
+}
+#if 0	/* not used at the moment */
+static u32 dispc6_ovr_read(struct dispc_device *dispc,
+			   enum omap_channel channel, u16 reg)
+{
+	void __iomem *base = dispc->base_ovr1;
+
+	return ioread32(base + reg);
+}
+#endif
+static void dispc6_vp_write(struct dispc_device *dispc,
+			    enum omap_channel channel, u16 reg, u32 val)
+{
+	void __iomem *base = dispc->base_vp1;
+
+	iowrite32(val, base + reg);
+}
+
+static u32 dispc6_vp_read(struct dispc_device *dispc,
+			  enum omap_channel channel, u16 reg)
+{
+	void __iomem *base = dispc->base_vp1;
+
+	return ioread32(base + reg);
+}
+
+int dispc6_runtime_get(struct dispc_device *dispc)
+{
+	int r;
+
+	dev_dbg(&dispc->pdev->dev, "dispc_runtime_get\n");
+
+	r = pm_runtime_get_sync(&dispc->pdev->dev);
+	WARN_ON(r < 0);
+	return r < 0 ? r : 0;
+}
+
+void dispc6_runtime_put(struct dispc_device *dispc)
+{
+	int r;
+
+	dev_dbg(&dispc->pdev->dev, "dispc_runtime_put\n");
+
+	r = pm_runtime_put_sync(&dispc->pdev->dev);
+	WARN_ON(r < 0);
+}
+
+static void dispc6_save_context(struct dispc_device *dispc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dispc->ctx_vid1); ++i)
+		dispc->ctx_vid1[i] = dispc6_vid_read(dispc, 0, i);
+
+	dispc->ctx_valid = true;
+}
+
+static void dispc6_restore_context(struct dispc_device *dispc)
+{
+	int i;
+
+	if (!dispc->ctx_valid)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(dispc->ctx_vid1); ++i)
+		dispc6_vid_write(dispc, 0, i, dispc->ctx_vid1[i]);
+}
+
+static irqreturn_t dispc6_irq_handler(int irq, void *arg)
+{
+	struct dispc_device *dispc = arg;
+	u32 stat;
+
+	if (!dispc->is_enabled)
+		return IRQ_NONE;
+
+	stat = dispc6_read(dispc, DISPC_IRQSTATUS);
+
+	if (stat == 0)
+		return IRQ_NONE;
+
+	dispc6_write(dispc, DISPC_IRQSTATUS, stat);
+
+	return dispc->user_handler(irq, dispc->user_data);
+}
+
+static int dispc6_request_irq(struct dispc_device *dispc,
+			      irq_handler_t handler, void *dev_id)
+{
+	int r;
+
+	if (dispc->user_handler != NULL)
+		return -EBUSY;
+
+	dispc->user_handler = handler;
+	dispc->user_data = dev_id;
+
+	/* ensure the dispc6_irq_handler sees the values above */
+	smp_wmb();
+
+	r = devm_request_irq(&dispc->pdev->dev, dispc->irq, dispc6_irq_handler,
+			     IRQF_SHARED, "DISPC", dispc);
+	if (r) {
+		dispc->user_handler = NULL;
+		dispc->user_data = NULL;
+	}
+
+	return r;
+}
+
+static void dispc6_free_irq(struct dispc_device *dispc, void *dev_id)
+{
+	dispc6_write(dispc, DISPC_IRQENABLE_CLR, 0xffffffff);
+
+	devm_free_irq(&dispc->pdev->dev, dispc->irq, &dispc);
+
+	dispc->user_handler = NULL;
+	dispc->user_data = NULL;
+}
+
+u64 dispc6_vp_irq_from_raw(u32 stat)
+{
+	uint channel = 0;
+	u64 vp_stat = 0;
+
+	if (stat & BIT(0))
+		vp_stat |= DSS_IRQ_MGR_FRAME_DONE(channel);
+	if (stat & BIT(1))
+		vp_stat |= DSS_IRQ_MGR_VSYNC_EVEN(channel);
+	if (stat & BIT(2))
+		vp_stat |= DSS_IRQ_MGR_VSYNC_ODD(channel);
+	if (stat & BIT(4))
+		vp_stat |= DSS_IRQ_MGR_SYNC_LOST(channel);
+
+	return vp_stat;
+}
+
+static u32 dispc6_vp_irq_to_raw(u64 vpstat)
+{
+	uint channel = 0;
+	u32 stat = 0;
+
+	if (vpstat & DSS_IRQ_MGR_FRAME_DONE(channel))
+		stat |= BIT(0);
+	if (vpstat & DSS_IRQ_MGR_VSYNC_EVEN(channel))
+		stat |= BIT(1);
+	if (vpstat & DSS_IRQ_MGR_VSYNC_ODD(channel))
+		stat |= BIT(2);
+	if (vpstat & DSS_IRQ_MGR_SYNC_LOST(channel))
+		stat |= BIT(4);
+
+	return stat;
+}
+
+static u64 dispc6_vid_irq_from_raw(u32 stat)
+{
+	uint plane = 0;
+	u64 vid_stat = 0;
+
+	if (stat & BIT(0))
+		vid_stat |= DSS_IRQ_OVL_FIFO_UNDERFLOW(plane);
+
+	return vid_stat;
+}
+
+static u32 dispc6_vid_irq_to_raw(u64 vidstat)
+{
+	uint plane = 0;
+	u32 stat = 0;
+
+	if (vidstat & DSS_IRQ_OVL_FIFO_UNDERFLOW(plane))
+		stat |= BIT(0);
+
+	return stat;
+}
+
+
+static u64 dispc6_vp_read_irqstatus(struct dispc_device *dispc,
+				    enum omap_channel channel)
+{
+	u32 stat = dispc6_vp_read(dispc, channel, DISPC_VP_IRQSTATUS);
+
+	return dispc6_vp_irq_from_raw(stat);
+}
+
+static void dispc6_vp_write_irqstatus(struct dispc_device *dispc,
+				      enum omap_channel channel,
+				      u64 vpstat)
+{
+	u32 stat = dispc6_vp_irq_to_raw(vpstat);
+
+	dispc6_vp_write(dispc, channel, DISPC_VP_IRQSTATUS, stat);
+}
+
+static u64 dispc6_vid_read_irqstatus(struct dispc_device *dispc,
+				     enum omap_plane_id plane)
+{
+	u32 stat = dispc6_vid_read(dispc, plane, DISPC_VID_IRQSTATUS);
+
+	return dispc6_vid_irq_from_raw(stat);
+}
+
+static void dispc6_vid_write_irqstatus(struct dispc_device *dispc,
+				       enum omap_plane_id plane,
+				       u64 vidstat)
+{
+	u32 stat = dispc6_vid_irq_to_raw(vidstat);
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_IRQSTATUS, stat);
+}
+
+
+static u64 dispc6_vp_read_irqenable(struct dispc_device *dispc,
+				    enum omap_channel channel)
+{
+	u32 stat = dispc6_vp_read(dispc, channel, DISPC_VP_IRQENABLE);
+
+	return dispc6_vp_irq_from_raw(stat);
+}
+
+static void dispc6_vp_write_irqenable(struct dispc_device *dispc,
+				      enum omap_channel channel,
+				      u64 vpstat)
+{
+	u32 stat = dispc6_vp_irq_to_raw(vpstat);
+
+	dispc6_vp_write(dispc, channel, DISPC_VP_IRQENABLE, stat);
+}
+
+static u64 dispc6_vid_read_irqenable(struct dispc_device *dispc,
+				     enum omap_plane_id plane)
+{
+	u32 stat = dispc6_vid_read(dispc, plane, DISPC_VID_IRQENABLE);
+
+	return dispc6_vid_irq_from_raw(stat);
+}
+
+static void dispc6_vid_write_irqenable(struct dispc_device *dispc,
+				       enum omap_plane_id plane,
+				       u64 vidstat)
+{
+	u32 stat = dispc6_vid_irq_to_raw(vidstat);
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_IRQENABLE, stat);
+}
+
+
+static void dispc6_clear_irqstatus(struct dispc_device *dispc, u64 mask)
+{
+	dispc6_vp_write_irqstatus(dispc, 0, mask);
+	dispc6_vid_write_irqstatus(dispc, 0, mask);
+}
+
+static u64 dispc6_read_and_clear_irqstatus(struct dispc_device *dispc)
+{
+	u64 stat = 0;
+
+	stat |= dispc6_vp_read_irqstatus(dispc, 0);
+	stat |= dispc6_vid_read_irqstatus(dispc, 0);
+
+	dispc6_clear_irqstatus(dispc, stat);
+
+	return stat;
+}
+
+static u64 dispc6_read_irqenable(struct dispc_device *dispc)
+{
+	u64 stat = 0;
+
+	stat |= dispc6_vp_read_irqenable(dispc, 0);
+	stat |= dispc6_vid_read_irqenable(dispc, 0);
+
+	return stat;
+}
+
+static void dispc6_write_irqenable(struct dispc_device *dispc, u64 mask)
+{
+	u64 old_mask = dispc6_read_irqenable(dispc);
+
+	/* clear the irqstatus for newly enabled irqs */
+	dispc6_clear_irqstatus(dispc, (mask ^ old_mask) & mask);
+
+	dispc6_vp_write_irqenable(dispc, 0, mask);
+	dispc6_vid_write_irqenable(dispc, 0, mask);
+
+	dispc6_write(dispc, DISPC_IRQENABLE_SET, (1 << 0) | (1 << 7));
+
+	/* flush posted write */
+	dispc6_read_irqenable(dispc);
+}
+
+
+static bool dispc6_mgr_go_busy(struct dispc_device *dispc,
+			       enum omap_channel channel)
+{
+	return VP_REG_GET(dispc, channel, DISPC_VP_CONTROL, 5, 5);
+}
+
+static void dispc6_mgr_go(struct dispc_device *dispc,
+			  enum omap_channel channel)
+{
+	VP_REG_FLD_MOD(dispc, channel, DISPC_VP_CONTROL, 1, 5, 5);
+}
+
+static void dispc6_mgr_enable(struct dispc_device *dispc,
+			      enum omap_channel channel, bool enable)
+{
+	VP_REG_FLD_MOD(dispc, channel, DISPC_VP_CONTROL, !!enable, 0, 0);
+}
+
+static bool dispc6_mgr_is_enabled(struct dispc_device *dispc,
+				  enum omap_channel channel)
+{
+	return VP_REG_GET(dispc, channel, DISPC_VP_CONTROL, 0, 0);
+}
+
+static u16 c8_to_c12(u8 c8)
+{
+	u16 c12;
+
+	c12 = c8 << 4;
+
+	/* Replication logic: Copy c8 4 MSB to 4 LSB for full scale c12 */
+	c12 = c8 >> 4;
+
+	return c12;
+}
+
+static u64 argb8888_to_argb12121212(u32 argb8888)
+{
+	u8 a, r, g, b;
+	u64 v;
+
+	a = (argb8888 >> 24) & 0xff;
+	r = (argb8888 >> 16) & 0xff;
+	g = (argb8888 >> 8) & 0xff;
+	b = (argb8888 >> 0) & 0xff;
+
+	v = ((u64)c8_to_c12(a) << 36) | ((u64)c8_to_c12(r) << 24) |
+	    ((u64)c8_to_c12(g) << 12) | (u64)c8_to_c12(b);
+
+	return v;
+}
+
+static void dispc6_mgr_setup(struct dispc_device *dispc,
+			     enum omap_channel channel,
+			     const struct omap_overlay_manager_info *info)
+{
+	u64 v;
+
+	v = argb8888_to_argb12121212(info->default_color);
+
+	dispc6_ovr_write(dispc, 0, DISPC_OVR_DEFAULT_COLOR, v & 0xffffffff);
+	dispc6_ovr_write(dispc, 0, DISPC_OVR_DEFAULT_COLOR2, (v >> 32) & 0xffff);
+}
+
+static void dispc6_set_num_datalines(struct dispc_device *dispc,
+				     enum omap_channel channel, int num_lines)
+{
+	int v;
+
+	switch (num_lines) {
+	case 12:
+		v = 0; break;
+	case 16:
+		v = 1; break;
+	case 18:
+		v = 2; break;
+	case 24:
+		v = 3; break;
+	case 30:
+		v = 4; break;
+	case 36:
+		v = 5; break;
+	default:
+		__WARN();
+		v = 3;
+		break;
+	}
+
+	VP_REG_FLD_MOD(dispc, channel, DISPC_VP_CONTROL, v, 10, 8);
+}
+
+static void dispc6_mgr_set_lcd_config(struct dispc_device *dispc,
+				      enum omap_channel channel,
+				      const struct dss_lcd_mgr_config *config)
+{
+	dispc6_set_num_datalines(dispc, channel, config->video_port_width);
+}
+
+static bool dispc6_lcd_timings_ok(int hsw, int hfp, int hbp,
+				  int vsw, int vfp, int vbp)
+{
+	if (hsw < 1 || hsw > 256 ||
+	    hfp < 1 || hfp > 4096 ||
+	    hbp < 1 || hbp > 4096 ||
+	    vsw < 1 || vsw > 256 ||
+	    vfp < 0 || vfp > 4095 ||
+	    vbp < 0 || vbp > 4095)
+		return false;
+	return true;
+}
+
+bool dispc6_mgr_timings_ok(struct dispc_device *dispc,
+			   enum omap_channel channel,
+			   const struct videomode *vm)
+{
+	if (vm->pixelclock < dispc->feat->min_pclk && vm->pixelclock != 9000000)
+		return false;
+
+	if (vm->pixelclock > dispc->feat->max_pclk)
+		return false;
+
+	if (vm->hactive > 4096)
+		return false;
+
+	if (vm->vactive > 4096)
+		return false;
+
+	/* TODO: add interlace support */
+	if (vm->flags & DISPLAY_FLAGS_INTERLACED)
+		return false;
+
+	if (!dispc6_lcd_timings_ok(vm->hsync_len, vm->hfront_porch, vm->hback_porch,
+				   vm->vsync_len, vm->vfront_porch, vm->vback_porch))
+		return false;
+
+	return true;
+}
+
+static void dispc6_mgr_set_timings(struct dispc_device *dispc,
+				   enum omap_channel channel,
+				   const struct videomode *vm)
+{
+	bool align, onoff, rf, ieo, ipc, ihs, ivs;
+
+	dispc6_vp_write(dispc, channel, DISPC_VP_TIMING_H,
+			FLD_VAL(vm->hsync_len - 1, 7, 0) |
+			FLD_VAL(vm->hfront_porch - 1, 19, 8) |
+			FLD_VAL(vm->hback_porch - 1, 31, 20));
+
+	dispc6_vp_write(dispc, channel, DISPC_VP_TIMING_V,
+			FLD_VAL(vm->vsync_len - 1, 7, 0) |
+			FLD_VAL(vm->vfront_porch, 19, 8) |
+			FLD_VAL(vm->vback_porch, 31, 20));
+
+	if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+		ivs = false;
+	else
+		ivs = true;
+
+	if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+		ihs = false;
+	else
+		ihs = true;
+
+	if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
+		ieo = false;
+	else
+		ieo = true;
+
+	if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+		ipc = false;
+	else
+		ipc = true;
+
+	/* always use the 'rf' setting */
+	onoff = true;
+
+	if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
+		rf = true;
+	else
+		rf = false;
+
+	/* always use aligned syncs */
+	align = true;
+
+	dispc6_vp_write(dispc, channel, DISPC_VP_POL_FREQ,
+			FLD_VAL(align, 18, 18) |
+			FLD_VAL(onoff, 17, 17) |
+			FLD_VAL(rf, 16, 16) |
+			FLD_VAL(ieo, 15, 15) |
+			FLD_VAL(ipc, 14, 14) |
+			FLD_VAL(ihs, 13, 13) |
+			FLD_VAL(ivs, 12, 12));
+
+	dispc6_vp_write(dispc, channel, DISPC_VP_SIZE_SCREEN,
+			FLD_VAL(vm->hactive - 1, 11, 0) |
+			FLD_VAL(vm->vactive - 1, 27, 16));
+}
+
+int dispc6_vp_enable_clk(struct dispc_device *dispc, enum omap_channel channel)
+{
+	return clk_prepare_enable(dispc->vp_clk);
+}
+void dispc6_vp_disable_clk(struct dispc_device *dispc,
+			   enum omap_channel channel)
+{
+	clk_disable_unprepare(dispc->vp_clk);
+}
+
+int dispc6_vp_set_clk_rate(struct dispc_device *dispc,
+			   enum omap_channel channel, unsigned long rate)
+{
+	int r;
+	unsigned long new_rate;
+
+	r = clk_set_rate(dispc->vp_clk, rate);
+	if (r) {
+		dev_err(&dispc->pdev->dev, "Failed to set vp clk rate to %lu\n",
+			rate);
+		return r;
+	}
+
+	new_rate = clk_get_rate(dispc->vp_clk);
+
+	if (rate != new_rate)
+		dev_warn(&dispc->pdev->dev,
+			 "Failed to get exact pix clock %lu != %lu\n",
+			 rate, new_rate);
+
+	dev_dbg(&dispc->pdev->dev, "New VP rate %lu Hz (requested %lu Hz)\n",
+		clk_get_rate(dispc->vp_clk), rate);
+
+	return 0;
+}
+
+/* CSC */
+
+struct color_conv_coef {
+	int ry, rcb, rcr;
+	int gy, gcb, gcr;
+	int by, bcb, bcr;
+	int roffset, goffset, boffset;
+	bool full_range;
+};
+
+static void dispc6_vid_write_color_conv_coefs(struct dispc_device *dispc,
+					      enum omap_plane_id plane,
+					      const struct color_conv_coef *ct)
+{
+#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_CONV_COEF(0), CVAL(ct->rcr, ct->ry));
+	dispc6_vid_write(dispc, plane, DISPC_VID_CONV_COEF(1), CVAL(ct->gy,  ct->rcb));
+	dispc6_vid_write(dispc, plane, DISPC_VID_CONV_COEF(2), CVAL(ct->gcb, ct->gcr));
+	dispc6_vid_write(dispc, plane, DISPC_VID_CONV_COEF(3), CVAL(ct->bcr, ct->by));
+	dispc6_vid_write(dispc, plane, DISPC_VID_CONV_COEF(4), CVAL(0, ct->bcb));
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_CONV_COEF(5),
+			 FLD_VAL(ct->roffset, 15, 3) | FLD_VAL(ct->goffset, 31, 19));
+	dispc6_vid_write(dispc, plane, DISPC_VID_CONV_COEF(6),
+			 FLD_VAL(ct->boffset, 15, 3));
+
+	VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES, ct->full_range, 11, 11);
+
+#undef CVAL
+}
+
+static void dispc6_vid_csc_setup(struct dispc_device *dispc)
+{
+	/* YUV -> RGB, ITU-R BT.601, full range */
+	const struct color_conv_coef coefs_yuv2rgb_bt601_full = {
+		256,   0,  358,
+		256, -88, -182,
+		256, 452,    0,
+		0, -2048, -2048,
+		true,
+	};
+
+	dispc6_vid_write_color_conv_coefs(dispc, 0, &coefs_yuv2rgb_bt601_full);
+}
+
+static void dispc6_vid_csc_enable(struct dispc_device *dispc,
+				  enum omap_plane_id plane, bool enable)
+{
+	VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES, !!enable, 9, 9);
+}
+
+/* SCALER */
+
+static u32 dispc6_calc_fir_inc(u32 in, u32 out)
+{
+	return (u32)div_u64(0x200000ull * in, out);
+}
+
+struct dispc6_vid_fir_coefs {
+	s16 c2[16];
+	s16 c1[16];
+	u16 c0[9];
+};
+
+static const struct dispc6_vid_fir_coefs dispc6_fir_coefs_null = {
+	.c2 = {	0 },
+	.c1 = { 0 },
+	.c0 = { 512, 512, 512, 512, 512, 512, 512, 512, 256,  },
+};
+
+/* M=8, Upscale x >= 1 */
+static const struct dispc6_vid_fir_coefs dispc6_fir_coefs_m8 = {
+	.c2 = {	0, -4, -8, -16, -24, -32, -40, -48, 0, 2, 4, 6, 8, 6, 4, 2,  },
+	.c1 = { 0, 28, 56, 94, 132, 176, 220, 266, -56, -60, -64, -62, -60, -50, -40, -20,  },
+	.c0 = { 512, 506, 500, 478, 456, 424, 392, 352, 312,  },
+};
+
+/* 5-tap, M=22, Downscale Ratio 2.5 < x < 3 */
+static const struct dispc6_vid_fir_coefs dispc6_fir_coefs_m22_5tap = {
+	.c2 = { 16, 20, 24, 30, 36, 42, 48, 56, 0, 0, 0, 2, 4, 8, 12, 14,  },
+	.c1 = { 132, 140, 148, 156, 164, 172, 180, 186, 64, 72, 80, 88, 96, 104, 112, 122,  },
+	.c0 = { 216, 216, 216, 214, 212, 208, 204, 198, 192,  },
+};
+
+/* 3-tap, M=22, Downscale Ratio 2.5 < x < 3 */
+static const struct dispc6_vid_fir_coefs dispc6_fir_coefs_m22_3tap = {
+	.c1 = { 100, 118, 136, 156, 176, 196, 216, 236, 0, 10, 20, 30, 40, 54, 68, 84,  },
+	.c0 = { 312, 310, 308, 302, 296, 286, 276, 266, 256,  },
+};
+
+enum dispc6_vid_fir_coef_set {
+	DISPC6_VID_FIR_COEF_HORIZ,
+	DISPC6_VID_FIR_COEF_HORIZ_UV,
+	DISPC6_VID_FIR_COEF_VERT,
+	DISPC6_VID_FIR_COEF_VERT_UV,
+};
+
+static void dispc6_vid_write_fir_coefs(struct dispc_device *dispc,
+				       enum omap_plane_id plane,
+				       enum dispc6_vid_fir_coef_set coef_set,
+				       const struct dispc6_vid_fir_coefs *coefs)
+{
+	static const u16 c0_regs[] = {
+		[DISPC6_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H0,
+		[DISPC6_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H0_C,
+		[DISPC6_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V0,
+		[DISPC6_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V0_C,
+	};
+
+	static const u16 c12_regs[] = {
+		[DISPC6_VID_FIR_COEF_HORIZ] = DISPC_VID_FIR_COEFS_H12,
+		[DISPC6_VID_FIR_COEF_HORIZ_UV] = DISPC_VID_FIR_COEFS_H12_C,
+		[DISPC6_VID_FIR_COEF_VERT] = DISPC_VID_FIR_COEFS_V12,
+		[DISPC6_VID_FIR_COEF_VERT_UV] = DISPC_VID_FIR_COEFS_V12_C,
+	};
+
+	const u16 c0_base = c0_regs[coef_set];
+	const u16 c12_base = c12_regs[coef_set];
+	int phase;
+
+	for (phase = 0; phase <= 8; ++phase) {
+		u16 reg = c0_base + phase * 4;
+		u16 c0 = coefs->c0[phase];
+
+		dispc6_vid_write(dispc, plane, reg, c0);
+	}
+
+	for (phase = 0; phase <= 15; ++phase) {
+		u16 reg = c12_base + phase * 4;
+		s16 c1, c2;
+		u32 c12;
+
+		c1 = coefs->c1[phase];
+		c2 = coefs->c2[phase];
+		c12 = FLD_VAL(c1, 19, 10) | FLD_VAL(c2, 29, 20);
+
+		dispc6_vid_write(dispc, plane, reg, c12);
+	}
+}
+
+static void dispc6_vid_write_scale_coefs(struct dispc_device *dispc,
+					 enum omap_plane_id plane)
+{
+	dispc6_vid_write_fir_coefs(dispc, plane, DISPC6_VID_FIR_COEF_HORIZ, &dispc6_fir_coefs_null);
+	dispc6_vid_write_fir_coefs(dispc, plane, DISPC6_VID_FIR_COEF_HORIZ_UV, &dispc6_fir_coefs_null);
+	dispc6_vid_write_fir_coefs(dispc, plane, DISPC6_VID_FIR_COEF_VERT, &dispc6_fir_coefs_null);
+	dispc6_vid_write_fir_coefs(dispc, plane, DISPC6_VID_FIR_COEF_VERT_UV, &dispc6_fir_coefs_null);
+}
+
+static void dispc6_vid_set_scaling(struct dispc_device *dispc,
+				   enum omap_plane_id plane,
+				   u32 orig_width, u32 orig_height,
+				   u32 out_width, u32 out_height,
+				   u32 fourcc)
+{
+	u32 in_w, in_h, in_w_uv, in_h_uv;
+	u32 fir_hinc, fir_vinc, fir_hinc_uv, fir_vinc_uv;
+	bool scale_x, scale_y;
+	bool five_taps = false;		/* XXX always 3-tap for now */
+
+	in_w = in_w_uv = orig_width;
+	in_h = in_h_uv = orig_height;
+
+	switch (fourcc) {
+	case DRM_FORMAT_NV12:
+		/* UV is subsampled by 2 horizontally and vertically */
+		in_h_uv >>= 1;
+		in_w_uv >>= 1;
+		break;
+
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+		/* UV is subsampled by 2 horizontally */
+		in_w_uv >>= 1;
+		break;
+
+	default:
+		break;
+	}
+
+	scale_x = in_w != out_width || in_w_uv != out_width;
+	scale_y = in_h != out_height || in_h_uv != out_height;
+
+	/* HORIZONTAL RESIZE ENABLE */
+	VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES, scale_x, 7, 7);
+
+	/* VERTICAL RESIZE ENABLE */
+	VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES, scale_y, 8, 8);
+
+	/* Skip the rest if no scaling is used */
+	if (!scale_x && !scale_y)
+		return;
+
+	/* VERTICAL 5-TAPS  */
+	VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES, five_taps, 21, 21);
+
+	/* FIR INC */
+
+	fir_hinc = dispc6_calc_fir_inc(in_w, out_width);
+	fir_vinc = dispc6_calc_fir_inc(in_h, out_height);
+	fir_hinc_uv = dispc6_calc_fir_inc(in_w_uv, out_width);
+	fir_vinc_uv = dispc6_calc_fir_inc(in_h_uv, out_height);
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_FIRH, fir_hinc);
+	dispc6_vid_write(dispc, plane, DISPC_VID_FIRV, fir_vinc);
+	dispc6_vid_write(dispc, plane, DISPC_VID_FIRH2, fir_hinc_uv);
+	dispc6_vid_write(dispc, plane, DISPC_VID_FIRV2, fir_vinc_uv);
+
+	dispc6_vid_write_scale_coefs(dispc, plane);
+}
+
+/* OTHER */
+
+static const enum omap_color_mode dispc6_supported_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_NV12,
+	0
+};
+
+static const struct {
+	u32 fourcc;
+	u8 dss_code;
+	u8 bytespp;
+} dispc6_color_formats[] = {
+	{ DRM_FORMAT_XRGB8888, 0x27, 4, },
+	{ DRM_FORMAT_ARGB8888, 0x7, 4, },
+
+	{ DRM_FORMAT_RGBX8888, 0x29, 4, },
+	{ DRM_FORMAT_RGBA8888, 0x9, 4, },
+
+	{ DRM_FORMAT_YUYV, 0x3e, 2, },
+	{ DRM_FORMAT_UYVY, 0x3f, 2, },
+
+	{ DRM_FORMAT_NV12, 0x3d, 2, },
+};
+
+static bool dispc6_fourcc_is_yuv(u32 fourcc)
+{
+	switch (fourcc) {
+	case DRM_FORMAT_YUYV:
+	case DRM_FORMAT_UYVY:
+	case DRM_FORMAT_NV12:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void dispc6_ovl_set_pixel_format(struct dispc_device *dispc,
+					enum omap_plane_id plane, u32 fourcc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dispc6_color_formats); ++i) {
+		if (dispc6_color_formats[i].fourcc == fourcc) {
+			VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES,
+					dispc6_color_formats[i].dss_code,
+					6, 1);
+			return;
+		}
+	}
+
+	__WARN();
+}
+
+static int dispc6_fourcc_to_bytespp(u32 fourcc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dispc6_color_formats); ++i) {
+		if (dispc6_color_formats[i].fourcc == fourcc)
+			return dispc6_color_formats[i].bytespp;
+	}
+
+	__WARN();
+	return 4;
+}
+
+static s32 pixinc(int pixels, u8 ps)
+{
+	if (pixels == 1)
+		return 1;
+	else if (pixels > 1)
+		return 1 + (pixels - 1) * ps;
+	else if (pixels < 0)
+		return 1 - (-pixels + 1) * ps;
+
+	__WARN();
+	return 0;
+}
+
+static int dispc6_ovl_setup(struct dispc_device *dispc,
+			    enum omap_plane_id plane,
+			    const struct omap_overlay_info *oi,
+			    const struct videomode *vm, bool mem_to_mem,
+			    enum omap_channel channel)
+{
+	u32 fourcc = oi->fourcc;
+	int bytespp = dispc6_fourcc_to_bytespp(fourcc);
+
+	dispc6_ovl_set_pixel_format(dispc, plane, fourcc);
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_BA_0, oi->paddr);
+	dispc6_vid_write(dispc, plane, DISPC_VID_BA_1, oi->paddr);
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_BA_UV_0, oi->p_uv_addr);
+	dispc6_vid_write(dispc, plane, DISPC_VID_BA_UV_1, oi->p_uv_addr);
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_PICTURE_SIZE,
+			 (oi->width - 1) | ((oi->height - 1) << 16));
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_PIXEL_INC, pixinc(1, bytespp));
+	dispc6_vid_write(dispc, plane, DISPC_VID_ROW_INC,
+			 pixinc(1 + oi->screen_width - oi->width, bytespp));
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_POSITION,
+			 oi->pos_x | (oi->pos_y << 16));
+
+	dispc6_vid_write(dispc, plane, DISPC_VID_SIZE,
+			 (oi->out_width - 1) | ((oi->out_height - 1) << 16));
+
+	dispc6_vid_set_scaling(dispc, plane,
+			       oi->width, oi->height, oi->out_width, oi->out_height,
+			       fourcc);
+
+	/* enable YUV->RGB color conversion */
+	if (dispc6_fourcc_is_yuv(fourcc))
+		dispc6_vid_csc_enable(dispc, plane, true);
+	else
+		dispc6_vid_csc_enable(dispc, plane, false);
+
+	/* channel */
+	VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES, 0, 16, 14);
+
+	return 0;
+}
+
+static int dispc6_ovl_enable(struct dispc_device *dispc,
+			     enum omap_plane_id plane, bool enable)
+{
+	VID_REG_FLD_MOD(dispc, plane, DISPC_VID_ATTRIBUTES, !!enable, 0, 0);
+	return 0;
+}
+
+static u32 dispc6_vid_get_fifo_size(struct dispc_device *dispc,
+				    enum omap_plane_id plane)
+{
+	const u32 unit_size = 16;	/* 128-bits */
+
+	return VID_REG_GET(dispc, plane, DISPC_VID_BUF_SIZE_STATUS, 15, 0) * unit_size;
+}
+
+static void dispc6_vid_set_mflag_threshold(struct dispc_device *dispc,
+					   enum omap_plane_id plane,
+					   u32 low, u32 high)
+{
+	dispc6_vid_write(dispc, plane, DISPC_VID_MFLAG_THRESHOLD,
+			 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
+}
+
+static void dispc6_mflag_setup(struct dispc_device *dispc)
+{
+	enum omap_plane_id plane = 0;
+	const u32 unit_size = 16;	/* 128-bits */
+	u32 size = dispc6_vid_get_fifo_size(dispc, plane);
+	u32 low, high;
+
+	/* MFLAG_CTRL */
+	REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 1, 1, 0);
+	/* MFLAG_START */
+	REG_FLD_MOD(dispc, DISPC_GLOBAL_MFLAG_ATTRIBUTE, 0, 2, 2);
+
+	/*
+	 * Simulation team suggests below thesholds:
+	 * HT = fifosize * 5 / 8;
+	 * LT = fifosize * 4 / 8;
+	 */
+
+	low = size * 4 / 8 / unit_size;
+	high = size * 5 / 8 / unit_size;
+
+	dispc6_vid_set_mflag_threshold(dispc, plane, low, high);
+}
+
+static void dispc6_vp_setup(struct dispc_device *dispc)
+{
+	/* Enable the gamma Shadow bit-field */
+	VP_REG_FLD_MOD(dispc, 0, DISPC_VP_CONFIG, 1, 2, 2);
+}
+
+static void dispc6_initial_config(struct dispc_device *dispc)
+{
+	dispc6_vid_csc_setup(dispc);
+	dispc6_mflag_setup(dispc);
+	dispc6_vp_setup(dispc);
+}
+
+static int dispc6_init_features(struct dispc_device *dispc)
+{
+	struct platform_device *pdev = dispc->pdev;
+	const struct of_device_id *match;
+
+	match = of_match_node(dispc6_of_match, pdev->dev.of_node);
+	if (!match) {
+		dev_err(&pdev->dev, "Unsupported DISPC version\n");
+		return -ENODEV;
+	}
+
+	dispc->feat = match->data;
+
+	return 0;
+}
+
+static enum omap_dss_output_id
+dispc6_mgr_get_supported_outputs(struct dispc_device *dispc,
+				 enum omap_channel channel)
+{
+	return OMAP_DSS_OUTPUT_DPI;
+}
+
+static const u32 *dispc6_ovl_get_color_modes(struct dispc_device *dispc,
+					     enum omap_plane_id plane)
+{
+	return dispc6_supported_formats;
+}
+
+static int dispc6_get_num_ovls(struct dispc_device *dispc)
+{
+	return 1;
+}
+
+static int dispc6_get_num_mgrs(struct dispc_device *dispc)
+{
+	return 1;
+}
+
+static u32 dispc6_mgr_gamma_size(struct dispc_device *dispc,
+				 enum omap_channel channel)
+{
+	return ARRAY_SIZE(dispc->gamma_table);
+}
+
+static void dispc6_mgr_write_gamma_table(struct dispc_device *dispc,
+					 enum omap_channel channel)
+{
+	u32 *table = dispc->gamma_table;
+	uint hwlen = ARRAY_SIZE(dispc->gamma_table);
+	unsigned int i;
+
+	dev_dbg(&dispc->pdev->dev, "%s: channel %d\n", __func__, channel);
+
+	for (i = 0; i < hwlen; ++i) {
+		u32 v = table[i];
+
+		v |= i << 24;
+
+		dispc6_vp_write(dispc, channel, DISPC_VP_GAMMA_TABLE, v);
+	}
+}
+
+static void dispc6_restore_gamma_tables(struct dispc_device *dispc)
+{
+	dev_dbg(&dispc->pdev->dev, "%s()\n", __func__);
+
+	dispc6_mgr_write_gamma_table(dispc, 0);
+}
+
+static const struct drm_color_lut dispc6_mgr_gamma_default_lut[] = {
+	{ .red = 0, .green = 0, .blue = 0, },
+	{ .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
+};
+
+static void dispc6_mgr_set_gamma(struct dispc_device *dispc,
+			 enum omap_channel channel,
+			 const struct drm_color_lut *lut,
+			 unsigned int length)
+{
+	u32 *table = dispc->gamma_table;
+	uint hwlen = ARRAY_SIZE(dispc->gamma_table);
+	static const uint hwbits = 8;
+	uint i;
+
+	dev_dbg(&dispc->pdev->dev, "%s: channel %d, lut len %u, hw len %u\n",
+		__func__, channel, length, hwlen);
+
+	if (lut == NULL || length < 2) {
+		lut = dispc6_mgr_gamma_default_lut;
+		length = ARRAY_SIZE(dispc6_mgr_gamma_default_lut);
+	}
+
+	for (i = 0; i < length - 1; ++i) {
+		uint first = i * (hwlen - 1) / (length - 1);
+		uint last = (i + 1) * (hwlen - 1) / (length - 1);
+		uint w = last - first;
+		u16 r, g, b;
+		uint j;
+
+		if (w == 0)
+			continue;
+
+		for (j = 0; j <= w; j++) {
+			r = (lut[i].red * (w - j) + lut[i+1].red * j) / w;
+			g = (lut[i].green * (w - j) + lut[i+1].green * j) / w;
+			b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w;
+
+			r >>= 16 - hwbits;
+			g >>= 16 - hwbits;
+			b >>= 16 - hwbits;
+
+			table[first + j] = (r << (hwbits * 2)) |
+				(g << hwbits) | b;
+		}
+	}
+
+	if (dispc->is_enabled)
+		dispc6_mgr_write_gamma_table(dispc, channel);
+}
+
+static int dispc6_init_gamma_tables(struct dispc_device *dispc)
+{
+	dispc6_mgr_set_gamma(dispc, 0, NULL, 0);
+
+	return 0;
+}
+
+static u32 dispc6_get_memory_bandwidth_limit(struct dispc_device *dispc)
+{
+	u32 limit = 0;
+
+	/* Optional maximum memory bandwidth */
+	of_property_read_u32(dispc->pdev->dev.of_node, "max-memory-bandwidth",
+			     &limit);
+
+	return limit;
+}
+
+static const char *dispc6_ovl_name(struct dispc_device *dispc,
+				   enum omap_plane_id plane)
+{
+	return "vid1";
+}
+
+static const char *dispc6_mgr_name(struct dispc_device *dispc,
+				   enum omap_channel channel)
+{
+	return "vp1";
+}
+
+static bool dispc6_mgr_has_framedone(struct dispc_device *dispc,
+				     enum omap_channel channel)
+{
+	return true;
+}
+
+static const struct dispc_ops dispc6_ops = {
+	.read_and_clear_irqstatus = dispc6_read_and_clear_irqstatus,
+	.write_irqenable = dispc6_write_irqenable,
+
+	.request_irq = dispc6_request_irq,
+	.free_irq = dispc6_free_irq,
+
+	.runtime_get = dispc6_runtime_get,
+	.runtime_put = dispc6_runtime_put,
+
+	.get_num_ovls = dispc6_get_num_ovls,
+	.get_num_mgrs = dispc6_get_num_mgrs,
+
+	.ovl_name = dispc6_ovl_name,
+	.mgr_name = dispc6_mgr_name,
+
+	.mgr_has_framedone = dispc6_mgr_has_framedone,
+
+	.get_memory_bandwidth_limit = dispc6_get_memory_bandwidth_limit,
+
+	.mgr_enable = dispc6_mgr_enable,
+	.mgr_is_enabled = dispc6_mgr_is_enabled,
+	.mgr_go_busy = dispc6_mgr_go_busy,
+	.mgr_go = dispc6_mgr_go,
+	.mgr_set_lcd_config = dispc6_mgr_set_lcd_config,
+	.mgr_set_timings = dispc6_mgr_set_timings,
+	.mgr_setup = dispc6_mgr_setup,
+	.mgr_get_supported_outputs = dispc6_mgr_get_supported_outputs,
+	.mgr_gamma_size = dispc6_mgr_gamma_size,
+	.mgr_set_gamma = dispc6_mgr_set_gamma,
+
+	.ovl_enable = dispc6_ovl_enable,
+	.ovl_setup = dispc6_ovl_setup,
+	.ovl_get_color_modes = dispc6_ovl_get_color_modes,
+};
+
+static int dispc6_iomap_resource(struct platform_device *pdev, const char *name,
+				 void __iomem **base)
+{
+	struct resource *res;
+	void __iomem *b;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+	if (!res) {
+		dev_err(&pdev->dev, "cannot get mem resource '%s'\n", name);
+		return -EINVAL;
+	}
+
+	b = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(b)) {
+		dev_err(&pdev->dev, "cannot ioremap resource '%s'\n", name);
+		return PTR_ERR(b);
+	}
+
+	*base = b;
+
+	return 0;
+}
+
+static int dispc6_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dss6_device *dss6 = dss6_get_device(master);
+	struct dispc_device *dispc;
+	int r = 0;
+
+	dispc = kzalloc(sizeof(*dispc), GFP_KERNEL);
+	if (!dispc)
+		return -ENOMEM;
+
+	dispc->pdev = pdev;
+	platform_set_drvdata(pdev, dispc);
+	dispc->dss6 = dss6;
+
+	r = dispc6_init_features(dispc);
+	if (r)
+		goto err_free;
+
+	r = dispc6_iomap_resource(pdev, "common", &dispc->base_common);
+	if (r)
+		goto err_free;
+
+	r = dispc6_iomap_resource(pdev, "vid1", &dispc->base_vid1);
+	if (r)
+		goto err_free;
+
+	r = dispc6_iomap_resource(pdev, "ovr1", &dispc->base_ovr1);
+	if (r)
+		goto err_free;
+
+	r = dispc6_iomap_resource(pdev, "vp1", &dispc->base_vp1);
+	if (r)
+		goto err_free;
+
+	dispc->irq = platform_get_irq(dispc->pdev, 0);
+	if (dispc->irq < 0) {
+		dev_err(dev, "platform_get_irq failed\n");
+		r = -ENODEV;
+		goto err_free;
+	}
+
+	dispc->fclk = devm_clk_get(dev, "fck");
+	if (IS_ERR(dispc->fclk)) {
+		dev_err(dev, "Failed to get fclk\n");
+		r = PTR_ERR(dispc->fclk);
+		goto err_free;
+	}
+
+	dispc->vp_clk = devm_clk_get(dev, "vp");
+	if (IS_ERR(dispc->vp_clk)) {
+		dev_err(dev, "Failed to get vp clk\n");
+		r = PTR_ERR(dispc->vp_clk);
+		goto err_free;
+	}
+
+	r = dispc6_init_gamma_tables(dispc);
+	if (r)
+		goto err_free;
+
+	pm_runtime_enable(&pdev->dev);
+
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 200);
+	pm_runtime_use_autosuspend(&pdev->dev);
+
+	dss6->data.dispc_ops = &dispc6_ops;
+	dss6->data.dispc = dispc;
+
+	return 0;
+err_free:
+	kfree(dispc);
+	return r;
+}
+
+static void dispc6_unbind(struct device *dev, struct device *master,
+			  void *data)
+{
+	struct dispc_device *dispc = dev_get_drvdata(dev);
+	struct dss6_device *dss6 = dispc->dss6;
+
+	dss6->data.dispc_ops = NULL;
+	dss6->data.dispc = NULL;
+
+	pm_runtime_disable(dev);
+
+	kfree(dispc);
+}
+
+static const struct component_ops dispc6_component_ops = {
+	.bind	= dispc6_bind,
+	.unbind	= dispc6_unbind,
+};
+
+static int dispc6_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &dispc6_component_ops);
+}
+
+static int dispc6_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dispc6_component_ops);
+	return 0;
+}
+
+static int dispc6_runtime_suspend(struct device *dev)
+{
+	struct dispc_device *dispc = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "suspend\n");
+
+	dispc->is_enabled = false;
+	/* ensure the dispc6_irq_handler sees the is_enabled value */
+	smp_wmb();
+	/* wait for current handler to finish before turning the DISPC off */
+	synchronize_irq(dispc->irq);
+
+	dispc6_save_context(dispc);
+
+	clk_disable_unprepare(dispc->fclk);
+
+	return 0;
+}
+
+static int dispc6_runtime_resume(struct device *dev)
+{
+	struct dispc_device *dispc = dev_get_drvdata(dev);
+
+	dev_dbg(dev, "resume\n");
+
+	clk_prepare_enable(dispc->fclk);
+
+	if (REG_GET(dispc, DISPC_SYSSTATUS, 0, 0) == 0)
+		dev_warn(dev, "DISPC FUNC RESET not done!\n");
+	if (REG_GET(dispc, DISPC_SYSSTATUS, 1, 1) == 0)
+		dev_warn(dev, "DISPC VP RESET not done!\n");
+
+	dispc6_initial_config(dispc);
+
+	dispc6_restore_context(dispc);
+
+	dispc6_restore_gamma_tables(dispc);
+
+	dispc->is_enabled = true;
+	/* ensure the dispc6_irq_handler sees the is_enabled value */
+	smp_wmb();
+
+	return 0;
+}
+
+static const struct dev_pm_ops dispc_pm_ops = {
+	.runtime_suspend = dispc6_runtime_suspend,
+	.runtime_resume = dispc6_runtime_resume,
+};
+
+static const struct of_device_id dispc6_of_match[] = {
+	{ .compatible = "ti,k2g-dispc", .data = &k2g_dispc_feats, },
+	{},
+};
+
+static struct platform_driver dispc6_driver = {
+	.probe		= dispc6_probe,
+	.remove         = dispc6_remove,
+	.driver         = {
+		.name   = "omap_dispc6",
+		.pm	= &dispc_pm_ops,
+		.of_match_table = dispc6_of_match,
+		.suppress_bind_attrs = true,
+	},
+};
+
+int __init dispc6_init_platform_driver(void)
+{
+	return platform_driver_register(&dispc6_driver);
+}
+
+void dispc6_uninit_platform_driver(void)
+{
+	platform_driver_unregister(&dispc6_driver);
+}
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc6.h b/drivers/gpu/drm/omapdrm/dss/dispc6.h
new file mode 100644
index 0000000..824fda4
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dispc6.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __OMAP2_DISPC6_REG_H
+#define __OMAP2_DISPC6_REG_H
+
+/* COMMON */
+
+#define DISPC_REVISION			0x000
+#define DISPC_SYSCONFIG			0x004
+#define DISPC_SYSSTATUS			0x008
+
+#define DISPC_IRQ_EOI			0x020
+#define DISPC_IRQSTATUS_RAW		0x024
+#define DISPC_IRQSTATUS			0x028
+#define DISPC_IRQENABLE_SET		0x02c
+#define DISPC_IRQENABLE_CLR		0x030
+#define DISPC_IRQWAKEEN			0x034
+
+#define DISPC_GLOBAL_MFLAG_ATTRIBUTE	0x040
+#define DISPC_GLOBAL_BUFFER		0x044
+#define DISPC_BA0_FLIPIMMEDIATE_EN	0x048
+
+#define DISPC_DBG_CONTROL		0x04c
+#define DISPC_DBG_STATUS		0x050
+
+#define DISPC_CLKGATING_DISABLE		0x054
+
+/* VID */
+
+#define DISPC_VID_ACCUH_0		0x0
+#define DISPC_VID_ACCUH_1		0x4
+#define DISPC_VID_ACCUH2_0		0x8
+#define DISPC_VID_ACCUH2_1		0xc
+
+#define DISPC_VID_ACCUV_0		0x10
+#define DISPC_VID_ACCUV_1		0x14
+#define DISPC_VID_ACCUV2_0		0x18
+#define DISPC_VID_ACCUV2_1		0x1c
+
+#define DISPC_VID_ATTRIBUTES		0x20
+#define DISPC_VID_ATTRIBUTES2		0x24
+
+#define DISPC_VID_BA_0			0x28
+#define DISPC_VID_BA_1			0x2c
+#define DISPC_VID_BA_UV_0		0x30
+#define DISPC_VID_BA_UV_1		0x34
+#define DISPC_VID_BUF_SIZE_STATUS	0x38
+#define DISPC_VID_BUF_THRESHOLD		0x3c
+
+#define DISPC_VID_CONV_COEF(n)		(0x40 + (n) * 4)
+
+#define DISPC_VID_FIRH			0x5c
+#define DISPC_VID_FIRH2			0x60
+#define DISPC_VID_FIRV			0x64
+#define DISPC_VID_FIRV2			0x68
+
+#define DISPC_VID_FIR_COEFS_H0		0x6c
+#define DISPC_VID_FIR_COEF_H0(phase)	(0x6c + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_H0_C	0x90
+#define DISPC_VID_FIR_COEF_H0_C(phase)	(0x90 + (phase) * 4)
+
+#define DISPC_VID_FIR_COEFS_H12		0xb4
+#define DISPC_VID_FIR_COEF_H12(phase)	(0xb4 + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_H12_C	0xf4
+#define DISPC_VID_FIR_COEF_H12_C(phase)	(0xf4 + (phase) * 4)
+
+#define DISPC_VID_FIR_COEFS_V0		0x134
+#define DISPC_VID_FIR_COEF_V0(phase)	(0x134 + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_V0_C	0x158
+#define DISPC_VID_FIR_COEF_V0_C(phase)	(0x158 + (phase) * 4)
+
+#define DISPC_VID_FIR_COEFS_V12		0x17c
+#define DISPC_VID_FIR_COEF_V12(phase)	(0x17c + (phase) * 4)
+#define DISPC_VID_FIR_COEFS_V12_C	0x1bc
+#define DISPC_VID_FIR_COEF_V12_C(phase)	(0x1bc + (phase) * 4)
+
+#define DISPC_VID_IRQENABLE		0x200
+#define DISPC_VID_IRQSTATUS		0x204
+
+#define DISPC_VID_MFLAG_THRESHOLD	0x208
+#define DISPC_VID_PICTURE_SIZE		0x20c
+#define DISPC_VID_PIXEL_INC		0x210
+#define DISPC_VID_POSITION		0x214
+#define DISPC_VID_PRELOAD		0x218
+#define DISPC_VID_ROW_INC		0x21c
+#define DISPC_VID_SIZE			0x220
+
+/* OVR */
+
+#define DISPC_OVR_DEFAULT_COLOR		0x08
+#define DISPC_OVR_DEFAULT_COLOR2	0x0c
+
+/* VP */
+
+#define DISPC_VP_CONFIG			0x00
+#define DISPC_VP_CONTROL		0x04
+#define DISPC_VP_GAMMA_TABLE		0x20
+#define DISPC_VP_IRQENABLE		0x3c
+#define DISPC_VP_IRQSTATUS		0x40
+#define DISPC_VP_POL_FREQ		0x4c
+#define DISPC_VP_SIZE_SCREEN		0x50
+#define DISPC_VP_TIMING_H		0x54
+#define DISPC_VP_TIMING_V		0x58
+
+#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/dpi6.c b/drivers/gpu/drm/omapdrm/dss/dpi6.c
new file mode 100644
index 0000000..458c8f3
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dpi6.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "omapdss.h"
+#include "dss6.h"
+
+struct dpi_data {
+	struct platform_device *pdev;
+
+	struct mutex lock;
+
+	struct videomode vm;
+	int data_lines;
+
+	struct omap_dss_device output;
+
+	bool port_initialized;
+
+	struct dss6_device *dss6;
+};
+
+static struct dpi_data *dpi6_get_data_from_dssdev(struct omap_dss_device *out)
+{
+	return container_of(out, struct dpi_data, output);
+}
+
+static void dpi6_config_lcd_manager(struct dpi_data *dpi)
+{
+	struct dss_lcd_mgr_config mgr_config = {
+		.io_pad_mode = DSS_IO_PAD_MODE_BYPASS,
+		.stallmode = false,
+		.fifohandcheck = false,
+		.video_port_width = dpi->data_lines,
+		.lcden_sig_polarity = 0,
+	};
+
+	dss_mgr_set_lcd_config(&dpi->output, &mgr_config);
+}
+
+static int dpi6_connect(struct omap_dss_device *out,
+			struct omap_dss_device *dst)
+{
+	struct dpi_data *dpi = dpi6_get_data_from_dssdev(out);
+	int r;
+
+	r = dss_mgr_connect(&dpi->output, out);
+	if (r)
+		return r;
+
+	r = omapdss_output_set_device(out, dst);
+	if (r) {
+		dev_err(&dpi->pdev->dev,
+			"failed to connect output to new device: %s\n",
+			dst->name);
+		dss_mgr_disconnect(&dpi->output, out);
+		return r;
+	}
+
+	return 0;
+}
+
+static void dpi6_disconnect(struct omap_dss_device *out,
+			    struct omap_dss_device *dst)
+{
+	struct dpi_data *dpi = dpi6_get_data_from_dssdev(out);
+
+	WARN_ON(dst != out->dst);
+
+	if (dst != out->dst)
+		return;
+
+	omapdss_output_unset_device(out);
+
+	dss_mgr_disconnect(&dpi->output, out);
+}
+
+static int dpi6_display_enable(struct omap_dss_device *out)
+{
+	struct dpi_data *dpi = dpi6_get_data_from_dssdev(out);
+	enum omap_channel channel = out->dispc_channel;
+	int r;
+
+	mutex_lock(&dpi->lock);
+
+	if (!out->dispc_channel_connected) {
+		dev_err(&dpi->pdev->dev, "failed to enable display: no output channel set\n");
+		r = -ENODEV;
+		goto err_no_out_mgr;
+	}
+
+	r = dispc6_runtime_get(dpi->dss6->data.dispc);
+	if (r)
+		goto err_get_dispc;
+
+	r = dispc6_vp_set_clk_rate(dpi->dss6->data.dispc, channel,
+				   dpi->vm.pixelclock);
+	if (r)
+		goto err_set_clk;
+
+	r = dispc6_vp_enable_clk(dpi->dss6->data.dispc, channel);
+	if (r)
+		goto err_enable_clk;
+
+	dpi6_config_lcd_manager(dpi);
+
+	r = dss_mgr_enable(&dpi->output);
+	if (r)
+		goto err_mgr_enable;
+
+	dss6_ungate_dpi_clk(&dpi->pdev->dev, out->port_num);
+
+	mutex_unlock(&dpi->lock);
+
+	return 0;
+
+err_mgr_enable:
+	dispc6_vp_disable_clk(dpi->dss6->data.dispc, channel);
+err_enable_clk:
+err_set_clk:
+	dispc6_runtime_put(dpi->dss6->data.dispc);
+err_get_dispc:
+err_no_out_mgr:
+	mutex_unlock(&dpi->lock);
+	return r;
+}
+
+static void dpi6_display_disable(struct omap_dss_device *out)
+{
+	struct dpi_data *dpi = dpi6_get_data_from_dssdev(out);
+	enum omap_channel channel = out->dispc_channel;
+
+	mutex_lock(&dpi->lock);
+
+	dss6_gate_dpi_clk(&dpi->pdev->dev, out->port_num);
+
+	dss_mgr_disable(&dpi->output);
+
+	dispc6_vp_disable_clk(dpi->dss6->data.dispc, channel);
+
+	dispc6_runtime_put(dpi->dss6->data.dispc);
+
+	mutex_unlock(&dpi->lock);
+}
+
+static int dpi6_check_timings(struct omap_dss_device *out,
+			      struct videomode *vm)
+{
+	struct dpi_data *dpi = dpi6_get_data_from_dssdev(out);
+	enum omap_channel channel = out->dispc_channel;
+
+	if (!dispc6_mgr_timings_ok(dpi->dss6->data.dispc, channel, vm))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void dpi6_set_timings(struct omap_dss_device *out,
+			     struct videomode *vm)
+{
+	struct dpi_data *dpi = dpi6_get_data_from_dssdev(out);
+
+	mutex_lock(&dpi->lock);
+
+	dpi->vm = *vm;
+
+	mutex_unlock(&dpi->lock);
+}
+
+static void dpi6_get_timings(struct omap_dss_device *out,
+			     struct videomode *vm)
+{
+	struct dpi_data *dpi = dpi6_get_data_from_dssdev(out);
+
+	mutex_lock(&dpi->lock);
+
+	*vm = dpi->vm;
+
+	mutex_unlock(&dpi->lock);
+}
+
+
+static const struct omapdss_dpi_ops dpi6_ops = {
+	.connect = dpi6_connect,
+	.disconnect = dpi6_disconnect,
+
+	.enable = dpi6_display_enable,
+	.disable = dpi6_display_disable,
+
+	.check_timings = dpi6_check_timings,
+	.set_timings = dpi6_set_timings,
+	.get_timings = dpi6_get_timings,
+};
+
+static void dpi6_setup_output_port(struct platform_device *pdev,
+				   struct device_node *port)
+{
+	struct dpi_data *dpi = port->data;
+	struct omap_dss_device *out = &dpi->output;
+	int r;
+	u32 port_num;
+
+	r = of_property_read_u32(port, "reg", &port_num);
+	if (r)
+		port_num = 0;
+
+	switch (port_num) {
+	case 0:
+	default:
+		out->name = "dpi.0";
+		break;
+	}
+
+	out->dev = &pdev->dev;
+	out->id = OMAP_DSS_OUTPUT_DPI;
+	out->output_type = OMAP_DISPLAY_TYPE_DPI;
+	out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
+	out->port_num = port_num;
+	out->ops.dpi = &dpi6_ops;
+	out->owner = THIS_MODULE;
+
+	omapdss_register_output(out);
+}
+
+int dpi6_init_port(struct platform_device *pdev, struct device_node *port)
+{
+	struct dss6_device *dss6 = dss6_get_device(&pdev->dev);
+	struct dpi_data *dpi;
+	struct device_node *ep;
+	u32 datalines;
+	int r;
+
+	dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
+	if (!dpi)
+		return -ENOMEM;
+
+	ep = of_get_next_child(port, NULL);
+	if (!ep)
+		return 0;
+
+	r = of_property_read_u32(ep, "data-lines", &datalines);
+	if (r) {
+		dev_err(&dpi->pdev->dev, "failed to parse datalines\n");
+		goto err_datalines;
+	}
+
+	dpi->data_lines = datalines;
+
+	of_node_put(ep);
+
+	dpi->pdev = pdev;
+	port->data = dpi;
+
+	mutex_init(&dpi->lock);
+
+	dpi6_setup_output_port(pdev, port);
+
+	dpi->dss6 = dss6;
+	dpi->port_initialized = true;
+
+	return 0;
+
+err_datalines:
+	of_node_put(ep);
+
+	return r;
+}
+
+void dpi6_uninit_port(struct device_node *port)
+{
+	struct dpi_data *dpi = port->data;
+
+	if (!dpi->port_initialized)
+		return;
+
+	omapdss_unregister_output(&dpi->output);
+}
diff --git a/drivers/gpu/drm/omapdrm/dss/dss6.c b/drivers/gpu/drm/omapdrm/dss/dss6.c
new file mode 100644
index 0000000..180fa69
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dss6.c
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+
+#include "omapdss.h"
+#include "dss6.h"
+
+#define DSS_REVISION	0x00
+#define DSS_SYSCONFIG	0x10
+#define DSS_SYSSTATUS	0x14
+#define DSS_RFBI_CTRL	0x18
+#define DSS_DPI_CTRL	0x1c
+#define DSS_DEBUG_CFG	0x40
+
+#define REG_GET(data, idx, start, end) \
+	FLD_GET(dss6_read(data, idx), start, end)
+
+#define REG_FLD_MOD(data, idx, val, start, end) \
+	dss6_write(data, idx, FLD_MOD(dss6_read(data, idx), val, start, end))
+
+struct dss_features {
+	int num_ports;
+};
+
+static const struct dss_features k2g_dss_feats = {
+	.num_ports = 1,
+};
+
+static const struct of_device_id dss6_of_match[];
+
+/* omapdrm device */
+
+static struct platform_device *omap_drm_device;
+
+static int initialize_omapdrm_device(void)
+{
+	omap_drm_device = platform_device_register_simple("omapdrm", 0, NULL, 0);
+	if (IS_ERR(omap_drm_device))
+		return PTR_ERR(omap_drm_device);
+
+	return 0;
+}
+
+/* omapdrm device end */
+
+static inline void dss6_write(struct dss6_device *dss6, u16 reg, u32 val)
+{
+	iowrite32(val, dss6->base + reg);
+}
+
+static inline u32 dss6_read(struct dss6_device *dss6, u16 reg)
+{
+	return ioread32(dss6->base + reg);
+}
+
+void dss6_ungate_dpi_clk(struct device *dev, int port)
+{
+	struct dss6_device *dss6 = dss6_get_device(dev);
+
+	REG_FLD_MOD(dss6, DSS_DPI_CTRL, 1, 1, 0);
+}
+
+void dss6_gate_dpi_clk(struct device *dev, int port)
+{
+	struct dss6_device *dss6 = dss6_get_device(dev);
+
+	REG_FLD_MOD(dss6, DSS_DPI_CTRL, 0, 1, 0);
+}
+
+static int dss6_init_features(struct platform_device *pdev)
+{
+	struct dss6_device *dss6 = dss6_get_device(&pdev->dev);
+	const struct of_device_id *match;
+
+	match = of_match_node(dss6_of_match, pdev->dev.of_node);
+	if (!match) {
+		dev_err(&pdev->dev, "Unsupported DSS version\n");
+		return -ENODEV;
+	}
+
+	dss6->feat = match->data;
+
+	return 0;
+}
+
+static int dss6_init_ports(struct platform_device *pdev)
+{
+	struct dss6_device *dss6 = dss6_get_device(&pdev->dev);
+	struct device_node *parent = pdev->dev.of_node;
+	struct device_node *port;
+	int i, ret;
+
+	for (i = 0; i < dss6->feat->num_ports; i++) {
+		port = of_graph_get_port_by_id(parent, i);
+		if (!port)
+			continue;
+
+		ret = dpi6_init_port(pdev, port);
+		of_node_put(port);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static void dss6_uninit_ports(struct platform_device *pdev)
+{
+	struct dss6_device *dss6 = dss6_get_device(&pdev->dev);
+	struct device_node *parent = pdev->dev.of_node;
+	struct device_node *port;
+	int i;
+
+	for (i = 0; i < dss6->feat->num_ports; i++) {
+		port = of_graph_get_port_by_id(parent, i);
+		if (!port)
+			continue;
+
+		dpi6_uninit_port(port);
+		of_node_put(port);
+	}
+}
+
+static int dss6_bind(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dss6_device *dss6;
+	struct resource *dss_mem;
+	int r;
+
+	dss6 = devm_kzalloc(dev, sizeof(*dss6), GFP_KERNEL);
+	if (!dss6)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, dss6);
+	dss6->pdev = pdev;
+
+	r = dss6_init_features(dss6->pdev);
+	if (r)
+		goto err_features;
+
+	dss_mem = platform_get_resource(dss6->pdev, IORESOURCE_MEM, 0);
+	if (!dss_mem) {
+		dev_err(dev, "Failed to get IORESOURCE_MEM\n");
+		r = -EINVAL;
+		goto err_resource;
+	}
+
+	dss6->base = devm_ioremap(&pdev->dev, dss_mem->start,
+					resource_size(dss_mem));
+	if (!dss6->base) {
+		dev_err(dev, "Failed to ioremap\n");
+		r = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	r = dss6_init_ports(pdev);
+	if (r)
+		goto err_init_ports;
+
+	dss6->fclk = devm_clk_get(dev, "fck");
+	if (IS_ERR(dss6->fclk)) {
+		dev_err(dev, "Failed to get fclk\n");
+		r = PTR_ERR(dss6->fclk);
+		goto err_clk_get;
+	}
+
+	dev_dbg(&pdev->dev, "DSS fclk %lu Hz\n", clk_get_rate(dss6->fclk));
+
+	pm_runtime_enable(&pdev->dev);
+
+	r = component_bind_all(&pdev->dev, NULL);
+	if (r)
+		goto err_component;
+
+	r = initialize_omapdrm_device();
+	if (r)
+		goto err_omapdrm_device;
+
+	omapdss_gather_components(dev);
+	omapdss_set_dss(&dss6->data);
+
+	return 0;
+
+err_omapdrm_device:
+	component_unbind_all(&pdev->dev, NULL);
+err_component:
+	pm_runtime_disable(&pdev->dev);
+err_clk_get:
+err_init_ports:
+err_ioremap:
+err_resource:
+err_features:
+	kfree(dss6);
+	return r;
+}
+
+static void dss6_unbind(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	omapdss_set_dss(NULL);
+
+	platform_device_unregister(omap_drm_device);
+
+	component_unbind_all(&pdev->dev, NULL);
+
+	dss6_uninit_ports(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+}
+
+static const struct component_master_ops dss6_component_ops = {
+	.bind = dss6_bind,
+	.unbind = dss6_unbind,
+};
+
+static int dss6_component_compare(struct device *dev, void *data)
+{
+	struct device *child = data;
+	return dev == child;
+}
+
+static int dss6_add_child_component(struct device *dev, void *data)
+{
+	struct component_match **match = data;
+
+	component_match_add(dev->parent, match, dss6_component_compare, dev);
+
+	return 0;
+}
+
+static int dss6_probe(struct platform_device *pdev)
+{
+	struct component_match *match = NULL;
+	int r;
+
+	/* add all the child devices as components */
+	device_for_each_child(&pdev->dev, &match, dss6_add_child_component);
+
+	if (!match) {
+		dev_err(&pdev->dev, "No submodules found\n");
+		return -EINVAL;
+	}
+
+	r = component_master_add_with_match(&pdev->dev, &dss6_component_ops, match);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+static int dss6_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &dss6_component_ops);
+	return 0;
+}
+
+static int dss6_runtime_suspend(struct device *dev)
+{
+	struct dss6_device *dss6 = dss6_get_device(dev);
+
+	clk_disable_unprepare(dss6->fclk);
+
+	return 0;
+}
+
+static int dss6_runtime_resume(struct device *dev)
+{
+	struct dss6_device *dss6 = dss6_get_device(dev);
+
+
+	clk_prepare_enable(dss6->fclk);
+
+	if (REG_GET(dss6, DSS_SYSSTATUS, 0, 0) == 0)
+		dev_warn(dev, "DSS FUNC RESET not done!\n");
+
+	return 0;
+}
+
+static const struct dev_pm_ops dss6_pm_ops = {
+	.runtime_suspend = dss6_runtime_suspend,
+	.runtime_resume = dss6_runtime_resume,
+};
+
+static const struct of_device_id dss6_of_match[] = {
+	{ .compatible = "ti,k2g-dss", .data = &k2g_dss_feats, },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, dss6_of_match);
+
+static struct platform_driver dss6_driver = {
+	.probe		= dss6_probe,
+	.remove		= dss6_remove,
+	.driver         = {
+		.name   = "omap_dss6",
+		.pm	= &dss6_pm_ops,
+		.of_match_table = dss6_of_match,
+		.suppress_bind_attrs = true,
+	},
+};
+
+static int __init omap_dss_init(void)
+{
+	int r;
+
+	r = platform_driver_register(&dss6_driver);
+	if (r)
+		return r;
+
+	r = dispc6_init_platform_driver();
+	if (r) {
+		platform_driver_unregister(&dss6_driver);
+		return r;
+	}
+
+	return 0;
+}
+
+static void __exit omap_dss_exit(void)
+{
+	dispc6_uninit_platform_driver();
+	platform_driver_unregister(&dss6_driver);
+}
+
+module_init(omap_dss_init);
+module_exit(omap_dss_exit);
+
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
+MODULE_DESCRIPTION("OMAP6 Display Subsystem");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/omapdrm/dss/dss6.h b/drivers/gpu/drm/omapdrm/dss/dss6.h
new file mode 100644
index 0000000..b581d71
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/dss6.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ */
+
+#ifndef __TI_DSS6_H
+#define __TI_DSS6_H
+
+#include "omapdss.h"
+
+struct dss6_device {
+	struct platform_device *pdev;
+	void __iomem *base;
+
+	struct clk *fclk;
+
+	const struct dss_features *feat;
+
+	struct dss_data data;
+};
+
+static inline struct dss6_device *dss6_get_device(struct device *dev)
+{
+	return dev_get_drvdata(dev);
+}
+
+/* DSS6 */
+void dss6_ungate_dpi_clk(struct device *dev, int port);
+void dss6_gate_dpi_clk(struct device *dev, int port);
+
+/* DISPC6 */
+int __init dispc6_init_platform_driver(void);
+void dispc6_uninit_platform_driver(void);
+
+int dispc6_runtime_get(struct dispc_device *dispc);
+void dispc6_runtime_put(struct dispc_device *dispc);
+
+bool dispc6_mgr_timings_ok(struct dispc_device *dispc,
+			   enum omap_channel channel,
+			   const struct videomode *vm);
+
+int dispc6_vp_set_clk_rate(struct dispc_device *dispc,
+			   enum omap_channel channel, unsigned long rate);
+int dispc6_vp_enable_clk(struct dispc_device *dispc,
+			 enum omap_channel channel);
+void dispc6_vp_disable_clk(struct dispc_device *dispc,
+			   enum omap_channel channel);
+
+/* DPI6 */
+int dpi6_init_port(struct platform_device *pdev, struct device_node *port);
+void dpi6_uninit_port(struct device_node *port);
+
+#endif /* __TI_DSS6_H */
