[PATCH v4 16/34] drm/exynos: Remove exynos_drm_hdmi shim

Sean Paul seanpaul at chromium.org
Thu Jan 30 13:19:15 PST 2014


This patch trims exynos_drm_hdmi out of the driver. The reason it
existed in the first place was to make up for the mixture of
display/overlay/manager ops being spread across hdmi and mixer. With
that code now rationalized, mixer and hdmi map directly to
exynos_drm_crtc and exynos_drm_encoder, respectively. Since there is a
1:1 mapping, we no longer need this layer.

Signed-off-by: Sean Paul <seanpaul at chromium.org>
---

Changes in v2:
 - hdmi/mixer ops now take display/manager instead of context
Changes in v3:
 - Moved removal of exynos_drm_hdmi.c file here
Changes in v4: None

 drivers/gpu/drm/exynos/Makefile          |   3 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |  13 -
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 416 -------------------------------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h |  69 -----
 drivers/gpu/drm/exynos/exynos_hdmi.c     | 162 +++++++-----
 drivers/gpu/drm/exynos/exynos_mixer.c    | 192 +++++++-------
 drivers/gpu/drm/exynos/exynos_mixer.h    |  20 ++
 7 files changed, 217 insertions(+), 658 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.c
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.h
 create mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 819961a..afbe499 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -11,8 +11,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o \
-					   exynos_drm_hdmi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_IPP)	+= exynos_drm_ipp.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 28e2cef..6143742 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -366,13 +366,6 @@ static int __init exynos_drm_init(void)
 	ret = platform_driver_register(&mixer_driver);
 	if (ret < 0)
 		goto out_mixer;
-	ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
-	if (ret < 0)
-		goto out_common_hdmi;
-
-	ret = exynos_platform_device_hdmi_register();
-	if (ret < 0)
-		goto out_common_hdmi_dev;
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_VIDI
@@ -465,10 +458,6 @@ out_vidi:
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-	exynos_platform_device_hdmi_unregister();
-out_common_hdmi_dev:
-	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
-out_common_hdmi:
 	platform_driver_unregister(&mixer_driver);
 out_mixer:
 	platform_driver_unregister(&hdmi_driver);
@@ -510,8 +499,6 @@ static void __exit exynos_drm_exit(void)
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-	exynos_platform_device_hdmi_unregister();
-	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
 	platform_driver_unregister(&mixer_driver);
 	platform_driver_unregister(&hdmi_driver);
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
deleted file mode 100644
index b0b09b2..0000000
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- *	Inki Dae <inki.dae at samsung.com>
- *	Seung-Woo Kim <sw0312.kim at samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <drm/drmP.h>
-
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-
-#include <drm/exynos_drm.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
-
-/* platform device pointer for common drm hdmi device. */
-static struct platform_device *exynos_drm_hdmi_pdev;
-
-/* Common hdmi subdrv needs to access the hdmi and mixer though context.
-* These should be initialied by the repective drivers */
-static struct exynos_drm_hdmi_context *hdmi_ctx;
-static struct exynos_drm_hdmi_context *mixer_ctx;
-
-/* these callback points shoud be set by specific drivers. */
-static struct exynos_hdmi_ops *hdmi_ops;
-static struct exynos_mixer_ops *mixer_ops;
-
-struct drm_hdmi_context {
-	struct exynos_drm_hdmi_context	*hdmi_ctx;
-	struct exynos_drm_hdmi_context	*mixer_ctx;
-
-	bool	enabled[MIXER_WIN_NR];
-};
-
-int exynos_platform_device_hdmi_register(void)
-{
-	struct platform_device *pdev;
-
-	if (exynos_drm_hdmi_pdev)
-		return -EEXIST;
-
-	pdev = platform_device_register_simple(
-			"exynos-drm-hdmi", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	exynos_drm_hdmi_pdev = pdev;
-
-	return 0;
-}
-
-void exynos_platform_device_hdmi_unregister(void)
-{
-	if (exynos_drm_hdmi_pdev) {
-		platform_device_unregister(exynos_drm_hdmi_pdev);
-		exynos_drm_hdmi_pdev = NULL;
-	}
-}
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-	if (ctx)
-		hdmi_ctx = ctx;
-}
-
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-	if (ctx)
-		mixer_ctx = ctx;
-}
-
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
-{
-	if (ops)
-		hdmi_ops = ops;
-}
-
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
-{
-	if (ops)
-		mixer_ops = ops;
-}
-
-static int drm_hdmi_display_initialize(struct exynos_drm_display *display,
-		struct drm_device *drm_dev)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-
-	if (hdmi_ops && hdmi_ops->initialize)
-		return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
-
-	return 0;
-}
-
-
-static bool drm_hdmi_is_connected(struct exynos_drm_display *display)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-
-	if (hdmi_ops && hdmi_ops->is_connected)
-		return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
-
-	return false;
-}
-
-static struct edid *drm_hdmi_get_edid(struct exynos_drm_display *display,
-			struct drm_connector *connector)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-
-	if (hdmi_ops && hdmi_ops->get_edid)
-		return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
-
-	return NULL;
-}
-static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
-		struct drm_display_mode *mode)
-{
-	int ret = 0;
-
-	/*
-	* Both, mixer and hdmi should be able to handle the requested mode.
-	* If any of the two fails, return mode as BAD.
-	*/
-
-	if (mixer_ops && mixer_ops->check_mode)
-		ret = mixer_ops->check_mode(ctx->mixer_ctx->ctx, mode);
-
-	if (ret)
-		return ret;
-
-	if (hdmi_ops && hdmi_ops->check_mode)
-		return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode);
-
-	return 0;
-}
-
-static int drm_hdmi_check_mode(struct exynos_drm_display *display,
-		struct drm_display_mode *mode)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-
-	return drm_hdmi_check_mode_ctx(ctx, mode);
-}
-
-static void drm_hdmi_display_dpms(struct exynos_drm_display *display, int mode)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-
-	if (hdmi_ops && hdmi_ops->dpms)
-		hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_hdmi_mode_fixup(struct exynos_drm_display *display,
-				struct drm_connector *connector,
-				const struct drm_display_mode *mode,
-				struct drm_display_mode *adjusted_mode)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-	struct drm_display_mode *m;
-	int mode_ok;
-
-	drm_mode_set_crtcinfo(adjusted_mode, 0);
-
-	mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
-
-	/* just return if user desired mode exists. */
-	if (mode_ok == 0)
-		return;
-
-	/*
-	 * otherwise, find the most suitable mode among modes and change it
-	 * to adjusted_mode.
-	 */
-	list_for_each_entry(m, &connector->modes, head) {
-		mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
-
-		if (mode_ok == 0) {
-			struct drm_mode_object base;
-			struct list_head head;
-
-			DRM_INFO("desired mode doesn't exist so\n");
-			DRM_INFO("use the most suitable mode among modes.\n");
-
-			DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
-				m->hdisplay, m->vdisplay, m->vrefresh);
-
-			/* preserve display mode header while copying. */
-			head = adjusted_mode->head;
-			base = adjusted_mode->base;
-			memcpy(adjusted_mode, m, sizeof(*m));
-			adjusted_mode->head = head;
-			adjusted_mode->base = base;
-			break;
-		}
-	}
-}
-
-static void drm_hdmi_mode_set(struct exynos_drm_display *display,
-			struct drm_display_mode *mode)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-
-	if (hdmi_ops && hdmi_ops->mode_set)
-		hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_hdmi_get_max_resol(struct exynos_drm_display *display,
-				unsigned int *width, unsigned int *height)
-{
-	struct drm_hdmi_context *ctx = display->ctx;
-
-	if (hdmi_ops && hdmi_ops->get_max_resol)
-		hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
-}
-
-static struct exynos_drm_display_ops drm_hdmi_display_ops = {
-	.initialize = drm_hdmi_display_initialize,
-	.is_connected = drm_hdmi_is_connected,
-	.get_edid = drm_hdmi_get_edid,
-	.check_mode = drm_hdmi_check_mode,
-	.dpms = drm_hdmi_display_dpms,
-	.mode_fixup = drm_hdmi_mode_fixup,
-	.mode_set = drm_hdmi_mode_set,
-	.get_max_resol = drm_hdmi_get_max_resol,
-};
-
-static struct exynos_drm_display hdmi_display = {
-	.type = EXYNOS_DISPLAY_TYPE_HDMI,
-	.ops = &drm_hdmi_display_ops,
-};
-
-static int drm_hdmi_enable_vblank(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->enable_vblank)
-		return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx, mgr->pipe);
-
-	return 0;
-}
-
-static void drm_hdmi_disable_vblank(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->disable_vblank)
-		return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_wait_for_vblank(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->wait_for_vblank)
-		mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_commit(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (hdmi_ops && hdmi_ops->commit)
-		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static int drm_hdmi_mgr_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev, int pipe)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	int ret = 0;
-
-	if (!hdmi_ctx) {
-		DRM_ERROR("hdmi context not initialized.\n");
-		return -EFAULT;
-	}
-
-	if (!mixer_ctx) {
-		DRM_ERROR("mixer context not initialized.\n");
-		return -EFAULT;
-	}
-
-	ctx->hdmi_ctx = hdmi_ctx;
-	ctx->mixer_ctx = mixer_ctx;
-
-	if (mixer_ops && mixer_ops->initialize)
-		ret = mixer_ops->initialize(ctx->mixer_ctx->ctx, drm_dev);
-
-	if (mixer_ops->iommu_on)
-		mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
-
-	return ret;
-}
-
-static void drm_hdmi_mgr_remove(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops->iommu_on)
-		mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
-}
-
-static void drm_hdmi_dpms(struct exynos_drm_manager *mgr, int mode)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->dpms)
-		mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
-
-	if (hdmi_ops && hdmi_ops->dpms)
-		hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_mixer_win_mode_set(struct exynos_drm_manager *mgr,
-				struct exynos_drm_overlay *overlay)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->win_mode_set)
-		mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
-}
-
-static void drm_mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-	if (win < 0 || win >= MIXER_WIN_NR) {
-		DRM_ERROR("mixer window[%d] is wrong\n", win);
-		return;
-	}
-
-	if (mixer_ops && mixer_ops->win_commit)
-		mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
-
-	ctx->enabled[win] = true;
-}
-
-static void drm_mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-	if (win < 0 || win >= MIXER_WIN_NR) {
-		DRM_ERROR("mixer window[%d] is wrong\n", win);
-		return;
-	}
-
-	if (mixer_ops && mixer_ops->win_disable)
-		mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
-
-	ctx->enabled[win] = false;
-}
-
-static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
-	.initialize = drm_hdmi_mgr_initialize,
-	.remove = drm_hdmi_mgr_remove,
-	.dpms = drm_hdmi_dpms,
-	.enable_vblank = drm_hdmi_enable_vblank,
-	.disable_vblank = drm_hdmi_disable_vblank,
-	.wait_for_vblank = drm_hdmi_wait_for_vblank,
-	.commit = drm_hdmi_commit,
-	.win_mode_set = drm_mixer_win_mode_set,
-	.win_commit = drm_mixer_win_commit,
-	.win_disable = drm_mixer_win_disable,
-};
-
-static struct exynos_drm_manager hdmi_manager = {
-	.type		= EXYNOS_DISPLAY_TYPE_HDMI,
-	.ops		= &drm_hdmi_manager_ops,
-};
-
-static int exynos_drm_hdmi_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct drm_hdmi_context *ctx;
-
-	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
-
-	hdmi_manager.ctx = ctx;
-	hdmi_display.ctx = ctx;
-
-	exynos_drm_manager_register(&hdmi_manager);
-	exynos_drm_display_register(&hdmi_display);
-
-	return 0;
-}
-
-static int exynos_drm_hdmi_remove(struct platform_device *pdev)
-{
-	exynos_drm_display_unregister(&hdmi_display);
-	exynos_drm_manager_unregister(&hdmi_manager);
-
-	return 0;
-}
-
-struct platform_driver exynos_drm_common_hdmi_driver = {
-	.probe		= exynos_drm_hdmi_probe,
-	.remove		= exynos_drm_hdmi_remove,
-	.driver		= {
-		.name	= "exynos-drm-hdmi",
-		.owner	= THIS_MODULE,
-	},
-};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
deleted file mode 100644
index 37059ea..0000000
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* exynos_drm_hdmi.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authoer: Inki Dae <inki.dae at samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_HDMI_H_
-#define _EXYNOS_DRM_HDMI_H_
-
-#define MIXER_WIN_NR		3
-#define MIXER_DEFAULT_WIN	0
-
-/*
- * exynos hdmi common context structure.
- *
- * @drm_dev: pointer to drm_device.
- * @pipe: pipe for mixer
- * @ctx: pointer to the context of specific device driver.
- *	this context should be hdmi_context or mixer_context.
- */
-struct exynos_drm_hdmi_context {
-	int			pipe;
-	void			*ctx;
-};
-
-struct exynos_hdmi_ops {
-	/* display */
-	int (*initialize)(void *ctx, struct drm_device *drm_dev);
-	bool (*is_connected)(void *ctx);
-	struct edid *(*get_edid)(void *ctx,
-			struct drm_connector *connector);
-	int (*check_mode)(void *ctx, struct drm_display_mode *mode);
-	void (*dpms)(void *ctx, int mode);
-
-	/* manager */
-	void (*mode_set)(void *ctx, struct drm_display_mode *mode);
-	void (*get_max_resol)(void *ctx, unsigned int *width,
-				unsigned int *height);
-	void (*commit)(void *ctx);
-};
-
-struct exynos_mixer_ops {
-	/* manager */
-	int (*initialize)(void *ctx, struct drm_device *drm_dev);
-	int (*iommu_on)(void *ctx, bool enable);
-	int (*enable_vblank)(void *ctx, int pipe);
-	void (*disable_vblank)(void *ctx);
-	void (*wait_for_vblank)(void *ctx);
-	void (*dpms)(void *ctx, int mode);
-
-	/* overlay */
-	void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
-	void (*win_commit)(void *ctx, int zpos);
-	void (*win_disable)(void *ctx, int zpos);
-
-	/* display */
-	int (*check_mode)(void *ctx, struct drm_display_mode *mode);
-};
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx);
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops);
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops);
-#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 97a0e57..051aa76 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -39,14 +39,14 @@
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
+#include "exynos_mixer.h"
 
 #include <linux/gpio.h>
 #include <media/s5p_hdmi.h>
 
 #define MAX_WIDTH		1920
 #define MAX_HEIGHT		1080
-#define get_hdmi_context(dev)	platform_get_drvdata(to_platform_device(dev))
+#define get_hdmi_display(dev)	platform_get_drvdata(to_platform_device(dev))
 
 /* AVI header and aspect ratio */
 #define HDMI_AVI_VERSION		0x02
@@ -188,7 +188,6 @@ struct hdmi_context {
 	struct mutex			hdmi_mutex;
 
 	void __iomem			*regs;
-	void				*parent_ctx;
 	int				irq;
 
 	struct i2c_client		*ddc_port;
@@ -741,26 +740,28 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
 	}
 }
 
-static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
+static int hdmi_initialize(struct exynos_drm_display *display,
+			struct drm_device *drm_dev)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	hdata->drm_dev = drm_dev;
 
 	return 0;
 }
 
-static bool hdmi_is_connected(void *ctx)
+static bool hdmi_is_connected(struct exynos_drm_display *display)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	return hdata->hpd;
 }
 
-static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
+static struct edid *hdmi_get_edid(struct exynos_drm_display *display,
+			struct drm_connector *connector)
 {
 	struct edid *raw_edid;
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	if (!hdata->ddc_port)
 		return ERR_PTR(-ENODEV);
@@ -799,9 +800,10 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
 	return -EINVAL;
 }
 
-static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
+static int hdmi_check_mode(struct exynos_drm_display *display,
+			struct drm_display_mode *mode)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 	int ret;
 
 	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
@@ -809,12 +811,62 @@ static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
 		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
 		false, mode->clock * 1000);
 
+	ret = mixer_check_mode(mode);
+	if (ret)
+		return ret;
+
 	ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
 	if (ret < 0)
 		return ret;
 	return 0;
 }
 
+static void hdmi_mode_fixup(struct exynos_drm_display *display,
+				struct drm_connector *connector,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct drm_display_mode *m;
+	int mode_ok;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+	mode_ok = hdmi_check_mode(display, adjusted_mode);
+
+	/* just return if user desired mode exists. */
+	if (mode_ok == 0)
+		return;
+
+	/*
+	 * otherwise, find the most suitable mode among modes and change it
+	 * to adjusted_mode.
+	 */
+	list_for_each_entry(m, &connector->modes, head) {
+		mode_ok = hdmi_check_mode(display, m);
+
+		if (mode_ok == 0) {
+			struct drm_mode_object base;
+			struct list_head head;
+
+			DRM_INFO("desired mode doesn't exist so\n");
+			DRM_INFO("use the most suitable mode among modes.\n");
+
+			DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
+				m->hdisplay, m->vdisplay, m->vrefresh);
+
+			/* preserve display mode header while copying. */
+			head = adjusted_mode->head;
+			base = adjusted_mode->base;
+			memcpy(adjusted_mode, m, sizeof(*m));
+			adjusted_mode->head = head;
+			adjusted_mode->base = base;
+			break;
+		}
+	}
+}
+
 static void hdmi_set_acr(u32 freq, u8 *acr)
 {
 	u32 n, cts;
@@ -1640,9 +1692,10 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
 	hdmi_set_reg(tg->tg_3d, 1, 0x0);
 }
 
-static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
+static void hdmi_mode_set(struct exynos_drm_display *display,
+			struct drm_display_mode *mode)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 	struct drm_display_mode *m = mode;
 
 	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
@@ -1656,16 +1709,16 @@ static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
 		hdmi_v14_mode_set(hdata, mode);
 }
 
-static void hdmi_get_max_resol(void *ctx, unsigned int *width,
-					unsigned int *height)
+static void hdmi_get_max_resol(struct exynos_drm_display *display,
+			unsigned int *width, unsigned int *height)
 {
 	*width = MAX_WIDTH;
 	*height = MAX_HEIGHT;
 }
 
-static void hdmi_commit(void *ctx)
+static void hdmi_commit(struct exynos_drm_display *display)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	mutex_lock(&hdata->hdmi_mutex);
 	if (!hdata->powered) {
@@ -1677,8 +1730,9 @@ static void hdmi_commit(void *ctx)
 	hdmi_conf_apply(hdata);
 }
 
-static void hdmi_poweron(struct hdmi_context *hdata)
+static void hdmi_poweron(struct exynos_drm_display *display)
 {
+	struct hdmi_context *hdata = display->ctx;
 	struct hdmi_resources *res = &hdata->res;
 
 	mutex_lock(&hdata->hdmi_mutex);
@@ -1699,11 +1753,12 @@ static void hdmi_poweron(struct hdmi_context *hdata)
 	clk_prepare_enable(res->sclk_hdmi);
 
 	hdmiphy_poweron(hdata);
-	hdmi_commit(hdata);
+	hdmi_commit(display);
 }
 
-static void hdmi_poweroff(struct hdmi_context *hdata)
+static void hdmi_poweroff(struct exynos_drm_display *display)
 {
+	struct hdmi_context *hdata = display->ctx;
 	struct hdmi_resources *res = &hdata->res;
 
 	mutex_lock(&hdata->hdmi_mutex);
@@ -1731,9 +1786,9 @@ out:
 	mutex_unlock(&hdata->hdmi_mutex);
 }
 
-static void hdmi_dpms(void *ctx, int mode)
+static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	DRM_DEBUG_KMS("mode %d\n", mode);
 
@@ -1754,24 +1809,26 @@ static void hdmi_dpms(void *ctx, int mode)
 	}
 }
 
-static struct exynos_hdmi_ops hdmi_ops = {
-	/* display */
+static struct exynos_drm_display_ops hdmi_display_ops = {
 	.initialize	= hdmi_initialize,
 	.is_connected	= hdmi_is_connected,
+	.get_max_resol	= hdmi_get_max_resol,
 	.get_edid	= hdmi_get_edid,
 	.check_mode	= hdmi_check_mode,
-	.dpms		= hdmi_dpms,
-
-	/* manager */
+	.mode_fixup	= hdmi_mode_fixup,
 	.mode_set	= hdmi_mode_set,
-	.get_max_resol	= hdmi_get_max_resol,
+	.dpms		= hdmi_dpms,
 	.commit		= hdmi_commit,
 };
 
+static struct exynos_drm_display hdmi_display = {
+	.type = EXYNOS_DISPLAY_TYPE_HDMI,
+	.ops = &hdmi_display_ops,
+};
+
 static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 {
-	struct exynos_drm_hdmi_context *ctx = arg;
-	struct hdmi_context *hdata = ctx->ctx;
+	struct hdmi_context *hdata = arg;
 
 	mutex_lock(&hdata->hdmi_mutex);
 	hdata->hpd = gpio_get_value(hdata->hpd_gpio);
@@ -1893,7 +1950,6 @@ static struct of_device_id hdmi_match_types[] = {
 static int hdmi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
 	struct hdmi_context *hdata;
 	struct s5p_hdmi_platform_data *pdata;
 	struct resource *res;
@@ -1908,20 +1964,13 @@ static int hdmi_probe(struct platform_device *pdev)
 	if (!pdata)
 		return -EINVAL;
 
-	drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
-	if (!drm_hdmi_ctx)
-		return -ENOMEM;
-
 	hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
 	if (!hdata)
 		return -ENOMEM;
 
 	mutex_init(&hdata->hdmi_mutex);
 
-	drm_hdmi_ctx->ctx = (void *)hdata;
-	hdata->parent_ctx = (void *)drm_hdmi_ctx;
-
-	platform_set_drvdata(pdev, drm_hdmi_ctx);
+	platform_set_drvdata(pdev, &hdmi_display);
 
 	match = of_match_node(hdmi_match_types, dev->of_node);
 	if (!match)
@@ -1986,17 +2035,14 @@ static int hdmi_probe(struct platform_device *pdev)
 	ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
 			hdmi_irq_thread, IRQF_TRIGGER_RISING |
 			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-			"hdmi", drm_hdmi_ctx);
+			"hdmi", hdata);
 	if (ret) {
 		DRM_ERROR("failed to register hdmi interrupt\n");
 		goto err_hdmiphy;
 	}
 
-	/* Attach HDMI Driver to common hdmi. */
-	exynos_hdmi_drv_attach(drm_hdmi_ctx);
-
-	/* register specific callbacks to common hdmi. */
-	exynos_hdmi_ops_register(&hdmi_ops);
+	hdmi_display.ctx = hdata;
+	exynos_drm_display_register(&hdmi_display);
 
 	pm_runtime_enable(dev);
 
@@ -2012,8 +2058,8 @@ err_ddc:
 static int hdmi_remove(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct hdmi_context *hdata = display->ctx;
 
 	pm_runtime_disable(dev);
 
@@ -2026,8 +2072,8 @@ static int hdmi_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int hdmi_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct hdmi_context *hdata = display->ctx;
 
 	disable_irq(hdata->irq);
 
@@ -2040,15 +2086,15 @@ static int hdmi_suspend(struct device *dev)
 		return 0;
 	}
 
-	hdmi_poweroff(hdata);
+	hdmi_poweroff(display);
 
 	return 0;
 }
 
 static int hdmi_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct hdmi_context *hdata = display->ctx;
 
 	hdata->hpd = gpio_get_value(hdata->hpd_gpio);
 
@@ -2059,7 +2105,7 @@ static int hdmi_resume(struct device *dev)
 		return 0;
 	}
 
-	hdmi_poweron(hdata);
+	hdmi_poweron(display);
 
 	return 0;
 }
@@ -2068,20 +2114,18 @@ static int hdmi_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int hdmi_runtime_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
 
-	hdmi_poweroff(hdata);
+	hdmi_poweroff(display);
 
 	return 0;
 }
 
 static int hdmi_runtime_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
 
-	hdmi_poweron(hdata);
+	hdmi_poweron(display);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 25a440a..d522857 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -36,10 +36,13 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
-#include "exynos_drm_hdmi.h"
 #include "exynos_drm_iommu.h"
+#include "exynos_mixer.h"
 
-#define get_mixer_context(dev)	platform_get_drvdata(to_platform_device(dev))
+#define get_mixer_manager(dev)	platform_get_drvdata(to_platform_device(dev))
+
+#define MIXER_WIN_NR		3
+#define MIXER_DEFAULT_WIN	0
 
 struct hdmi_win_data {
 	dma_addr_t		dma_addr;
@@ -95,7 +98,6 @@ struct mixer_context {
 	struct mixer_resources	mixer_res;
 	struct hdmi_win_data	win_data[MIXER_WIN_NR];
 	enum mixer_version_id	mxr_ver;
-	void			*parent_ctx;
 	wait_queue_head_t	wait_vsync_queue;
 	atomic_t		wait_vsync_event;
 };
@@ -827,12 +829,14 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
 	return 0;
 }
 
-static int mixer_initialize(void *ctx, struct drm_device *drm_dev)
+static int mixer_initialize(struct exynos_drm_manager *mgr,
+			struct drm_device *drm_dev, int pipe)
 {
 	int ret;
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
 	mixer_ctx->drm_dev = drm_dev;
+	mixer_ctx->pipe = pipe;
 
 	/* acquire resources: regs, irqs, clocks */
 	ret = mixer_resources_init(mixer_ctx);
@@ -850,29 +854,29 @@ static int mixer_initialize(void *ctx, struct drm_device *drm_dev)
 		}
 	}
 
-	return ret;
+	if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
+		return 0;
+
+	return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
-static int mixer_iommu_on(void *ctx, bool enable)
+static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mdata = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
-	if (is_drm_iommu_supported(mdata->drm_dev)) {
-		if (enable)
-			return drm_iommu_attach_device(mdata->drm_dev,
-					mdata->dev);
-
-		drm_iommu_detach_device(mdata->drm_dev, mdata->dev);
-	}
-	return 0;
+	if (is_drm_iommu_supported(mixer_ctx->drm_dev))
+		drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
-static int mixer_enable_vblank(void *ctx, int pipe)
+static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
-	mixer_ctx->pipe = pipe;
+	if (!mixer_ctx->powered) {
+		mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
+		return 0;
+	}
 
 	/* enable vsync interrupt */
 	mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
@@ -881,19 +885,19 @@ static int mixer_enable_vblank(void *ctx, int pipe)
 	return 0;
 }
 
-static void mixer_disable_vblank(void *ctx)
+static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
 	/* disable vsync interrupt */
 	mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
-static void mixer_win_mode_set(void *ctx,
-			      struct exynos_drm_overlay *overlay)
+static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
+			struct exynos_drm_overlay *overlay)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct hdmi_win_data *win_data;
 	int win;
 
@@ -942,9 +946,10 @@ static void mixer_win_mode_set(void *ctx,
 	win_data->scan_flags = overlay->scan_flag;
 }
 
-static void mixer_win_commit(void *ctx, int win)
+static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
+	int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 
 	DRM_DEBUG_KMS("win: %d\n", win);
 
@@ -963,10 +968,11 @@ static void mixer_win_commit(void *ctx, int win)
 	mixer_ctx->win_data[win].enabled = true;
 }
 
-static void mixer_win_disable(void *ctx, int win)
+static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
+	int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 	unsigned long flags;
 
 	DRM_DEBUG_KMS("win: %d\n", win);
@@ -990,32 +996,9 @@ static void mixer_win_disable(void *ctx, int win)
 	mixer_ctx->win_data[win].enabled = false;
 }
 
-static int mixer_check_mode(void *ctx, struct drm_display_mode *mode)
-{
-	struct mixer_context *mixer_ctx = ctx;
-	u32 w, h;
-
-	w = mode->hdisplay;
-	h = mode->vdisplay;
-
-	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
-		mode->hdisplay, mode->vdisplay, mode->vrefresh,
-		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
-
-	if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 ||
-		mixer_ctx->mxr_ver == MXR_VER_128_0_0_184)
-		return 0;
-
-	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
-		(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
-		(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
-		return 0;
-
-	return -EINVAL;
-}
-static void mixer_wait_for_vblank(void *ctx)
+static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
 	mutex_lock(&mixer_ctx->mixer_mutex);
 	if (!mixer_ctx->powered) {
@@ -1036,21 +1019,23 @@ static void mixer_wait_for_vblank(void *ctx)
 		DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
-static void mixer_window_suspend(struct mixer_context *ctx)
+static void mixer_window_suspend(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct hdmi_win_data *win_data;
 	int i;
 
 	for (i = 0; i < MIXER_WIN_NR; i++) {
 		win_data = &ctx->win_data[i];
 		win_data->resume = win_data->enabled;
-		mixer_win_disable(ctx, i);
+		mixer_win_disable(mgr, i);
 	}
-	mixer_wait_for_vblank(ctx);
+	mixer_wait_for_vblank(mgr);
 }
 
-static void mixer_window_resume(struct mixer_context *ctx)
+static void mixer_window_resume(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct hdmi_win_data *win_data;
 	int i;
 
@@ -1059,12 +1044,13 @@ static void mixer_window_resume(struct mixer_context *ctx)
 		win_data->enabled = win_data->resume;
 		win_data->resume = false;
 		if (win_data->enabled)
-			mixer_win_commit(ctx, i);
+			mixer_win_commit(mgr, i);
 	}
 }
 
-static void mixer_poweron(struct mixer_context *ctx)
+static void mixer_poweron(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct mixer_resources *res = &ctx->mixer_res;
 
 	mutex_lock(&ctx->mixer_mutex);
@@ -1084,11 +1070,12 @@ static void mixer_poweron(struct mixer_context *ctx)
 	mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
 	mixer_win_reset(ctx);
 
-	mixer_window_resume(ctx);
+	mixer_window_resume(mgr);
 }
 
-static void mixer_poweroff(struct mixer_context *ctx)
+static void mixer_poweroff(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct mixer_resources *res = &ctx->mixer_res;
 
 	mutex_lock(&ctx->mixer_mutex);
@@ -1096,7 +1083,7 @@ static void mixer_poweroff(struct mixer_context *ctx)
 		goto out;
 	mutex_unlock(&ctx->mixer_mutex);
 
-	mixer_window_suspend(ctx);
+	mixer_window_suspend(mgr);
 
 	ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
 
@@ -1113,9 +1100,9 @@ out:
 	mutex_unlock(&ctx->mixer_mutex);
 }
 
-static void mixer_dpms(void *ctx, int mode)
+static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
@@ -1134,20 +1121,41 @@ static void mixer_dpms(void *ctx, int mode)
 	}
 }
 
-static struct exynos_mixer_ops mixer_ops = {
-	/* manager */
+/* Only valid for Mixer version 16.0.33.0 */
+int mixer_check_mode(struct drm_display_mode *mode)
+{
+	u32 w, h;
+
+	w = mode->hdisplay;
+	h = mode->vdisplay;
+
+	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
+		mode->hdisplay, mode->vdisplay, mode->vrefresh,
+		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
+
+	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
+		(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
+		(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
+		return 0;
+
+	return -EINVAL;
+}
+
+static struct exynos_drm_manager_ops mixer_manager_ops = {
 	.initialize		= mixer_initialize,
-	.iommu_on		= mixer_iommu_on,
+	.remove			= mixer_mgr_remove,
+	.dpms			= mixer_dpms,
 	.enable_vblank		= mixer_enable_vblank,
 	.disable_vblank		= mixer_disable_vblank,
 	.wait_for_vblank	= mixer_wait_for_vblank,
-	.dpms			= mixer_dpms,
 	.win_mode_set		= mixer_win_mode_set,
 	.win_commit		= mixer_win_commit,
 	.win_disable		= mixer_win_disable,
+};
 
-	/* display */
-	.check_mode		= mixer_check_mode,
+static struct exynos_drm_manager mixer_manager = {
+	.type			= EXYNOS_DISPLAY_TYPE_HDMI,
+	.ops			= &mixer_manager_ops,
 };
 
 static struct mixer_drv_data exynos5420_mxr_drv_data = {
@@ -1195,20 +1203,16 @@ static struct of_device_id mixer_match_types[] = {
 static int mixer_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
 	struct mixer_context *ctx;
 	struct mixer_drv_data *drv;
 
 	dev_info(dev, "probe start\n");
 
-	drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
-								GFP_KERNEL);
-	if (!drm_hdmi_ctx)
-		return -ENOMEM;
-
-	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		DRM_ERROR("failed to alloc mixer context.\n");
 		return -ENOMEM;
+	}
 
 	mutex_init(&ctx->mixer_mutex);
 
@@ -1223,20 +1227,14 @@ static int mixer_probe(struct platform_device *pdev)
 
 	ctx->pdev = pdev;
 	ctx->dev = dev;
-	ctx->parent_ctx = (void *)drm_hdmi_ctx;
-	drm_hdmi_ctx->ctx = (void *)ctx;
 	ctx->vp_enabled = drv->is_vp_enabled;
 	ctx->mxr_ver = drv->version;
 	init_waitqueue_head(&ctx->wait_vsync_queue);
 	atomic_set(&ctx->wait_vsync_event, 0);
 
-	platform_set_drvdata(pdev, drm_hdmi_ctx);
-
-	/* attach mixer driver to common hdmi. */
-	exynos_mixer_drv_attach(drm_hdmi_ctx);
-
-	/* register specific callback point to common hdmi. */
-	exynos_mixer_ops_register(&mixer_ops);
+	mixer_manager.ctx = ctx;
+	platform_set_drvdata(pdev, &mixer_manager);
+	exynos_drm_manager_register(&mixer_manager);
 
 	pm_runtime_enable(dev);
 
@@ -1255,30 +1253,28 @@ static int mixer_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int mixer_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
 	if (pm_runtime_suspended(dev)) {
 		DRM_DEBUG_KMS("Already suspended\n");
 		return 0;
 	}
 
-	mixer_poweroff(ctx);
+	mixer_poweroff(mgr);
 
 	return 0;
 }
 
 static int mixer_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
 	if (!pm_runtime_suspended(dev)) {
 		DRM_DEBUG_KMS("Already resumed\n");
 		return 0;
 	}
 
-	mixer_poweron(ctx);
+	mixer_poweron(mgr);
 
 	return 0;
 }
@@ -1287,20 +1283,18 @@ static int mixer_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int mixer_runtime_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
-	mixer_poweroff(ctx);
+	mixer_poweroff(mgr);
 
 	return 0;
 }
 
 static int mixer_runtime_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
-	mixer_poweron(ctx);
+	mixer_poweron(mgr);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
new file mode 100644
index 0000000..3811e41
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_mixer.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _EXYNOS_MIXER_H_
+#define _EXYNOS_MIXER_H_
+
+/* This function returns 0 if the given timing is valid for the mixer */
+int mixer_check_mode(struct drm_display_mode *mode);
+
+#endif
-- 
1.8.5.1



More information about the dri-devel mailing list