[1/4] drm/exynos: g2d: Convert to driver component API

Message ID 20180607133609.28397-2-m.szyprowski@samsung.com
State Superseded
Headers show
Series
  • Exynos DRM cleanup
Related show

Commit Message

Marek Szyprowski June 7, 2018, 1:36 p.m.
Exynos G2D driver is the last client of the custom Exynos 'sub-driver'
framework. In the current state it doesn't really resolve any of the
issues it has been designed for, as Exynos DRM is already built only
as a single kernel module. Remove the custom 'sub-driver' framework and
simply use generic component framework also in G2D driver.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

---
 drivers/gpu/drm/exynos/Makefile          |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_core.c | 119 -----------
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |  14 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |  47 +----
 drivers/gpu/drm/exynos/exynos_drm_g2d.c  | 257 +++++++++--------------
 drivers/gpu/drm/exynos/exynos_drm_g2d.h  |  11 +
 6 files changed, 115 insertions(+), 335 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_core.c

-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 3b323f1e0475..2ad146bbf4f5 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -4,7 +4,7 @@ 
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \
-		exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o
+		exynos_drm_gem.o exynos_drm_plane.o
 
 exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
deleted file mode 100644
index b0c0621fcdf7..000000000000
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ /dev/null
@@ -1,119 +0,0 @@ 
-/* exynos_drm_core.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Author:
- *	Inki Dae <inki.dae@samsung.com>
- *	Joonyoung Shim <jy0922.shim@samsung.com>
- *	Seung-Woo Kim <sw0312.kim@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 "exynos_drm_drv.h"
-#include "exynos_drm_crtc.h"
-
-static LIST_HEAD(exynos_drm_subdrv_list);
-
-int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
-
-	return 0;
-}
-
-int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_del(&subdrv->list);
-
-	return 0;
-}
-
-int exynos_drm_device_subdrv_probe(struct drm_device *dev)
-{
-	struct exynos_drm_subdrv *subdrv, *n;
-	int err;
-
-	if (!dev)
-		return -EINVAL;
-
-	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
-		if (subdrv->probe) {
-			subdrv->drm_dev = dev;
-
-			/*
-			 * this probe callback would be called by sub driver
-			 * after setting of all resources to this sub driver,
-			 * such as clock, irq and register map are done.
-			 */
-			err = subdrv->probe(dev, subdrv->dev);
-			if (err) {
-				DRM_DEBUG("exynos drm subdrv probe failed.\n");
-				list_del(&subdrv->list);
-				continue;
-			}
-		}
-	}
-
-	return 0;
-}
-
-int exynos_drm_device_subdrv_remove(struct drm_device *dev)
-{
-	struct exynos_drm_subdrv *subdrv;
-
-	if (!dev) {
-		WARN(1, "Unexpected drm device unregister!\n");
-		return -EINVAL;
-	}
-
-	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
-		if (subdrv->remove)
-			subdrv->remove(dev, subdrv->dev);
-	}
-
-	return 0;
-}
-
-int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
-{
-	struct exynos_drm_subdrv *subdrv;
-	int ret;
-
-	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
-		if (subdrv->open) {
-			ret = subdrv->open(dev, subdrv->dev, file);
-			if (ret)
-				goto err;
-		}
-	}
-
-	return 0;
-
-err:
-	list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) {
-		if (subdrv->close)
-			subdrv->close(dev, subdrv->dev, file);
-	}
-	return ret;
-}
-
-void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
-{
-	struct exynos_drm_subdrv *subdrv;
-
-	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
-		if (subdrv->close)
-			subdrv->close(dev, subdrv->dev, file);
-	}
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index a81b4a5e24a7..80d9c10146c3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -55,8 +55,7 @@  static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 		return -ENOMEM;
 
 	file->driver_priv = file_priv;
-
-	ret = exynos_drm_subdrv_open(dev, file);
+	ret = g2d_open(dev, file);
 	if (ret)
 		goto err_file_priv_free;
 
@@ -70,7 +69,7 @@  static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 
 static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
 {
-	exynos_drm_subdrv_close(dev, file);
+	g2d_close(dev, file);
 	kfree(file->driver_priv);
 	file->driver_priv = NULL;
 }
@@ -240,6 +239,7 @@  static struct exynos_drm_driver_info exynos_drm_drivers[] = {
 		DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE
 	}, {
 		DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D),
+		DRM_COMPONENT_DRIVER
 	}, {
 		DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC),
 		DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE,
@@ -376,11 +376,6 @@  static int exynos_drm_bind(struct device *dev)
 	if (ret)
 		goto err_unbind_all;
 
-	/* Probe non kms sub drivers and virtual display driver. */
-	ret = exynos_drm_device_subdrv_probe(drm);
-	if (ret)
-		goto err_unbind_all;
-
 	drm_mode_config_reset(drm);
 
 	/*
@@ -411,7 +406,6 @@  static int exynos_drm_bind(struct device *dev)
 	exynos_drm_fbdev_fini(drm);
 err_cleanup_poll:
 	drm_kms_helper_poll_fini(drm);
-	exynos_drm_device_subdrv_remove(drm);
 err_unbind_all:
 	component_unbind_all(drm->dev, drm);
 err_mode_config_cleanup:
@@ -431,8 +425,6 @@  static void exynos_drm_unbind(struct device *dev)
 
 	drm_dev_unregister(drm);
 
-	exynos_drm_device_subdrv_remove(drm);
-
 	exynos_drm_fbdev_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 0f6d079a55c9..c737c4bd2c19 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -179,17 +179,13 @@  static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc,
 		crtc->pipe_clk->enable(crtc->pipe_clk, enable);
 }
 
-struct exynos_drm_g2d_private {
-	struct device		*dev;
+struct drm_exynos_file_private {
+	/* for g2d api */
 	struct list_head	inuse_cmdlist;
 	struct list_head	event_list;
 	struct list_head	userptr_list;
 };
 
-struct drm_exynos_file_private {
-	struct exynos_drm_g2d_private	*g2d_priv;
-};
-
 /*
  * Exynos drm private structure.
  *
@@ -201,6 +197,7 @@  struct exynos_drm_private {
 	struct drm_fb_helper *fb_helper;
 	struct drm_atomic_state *suspend_state;
 
+	struct device *g2d_dev;
 	struct device *dma_dev;
 	void *mapping;
 
@@ -217,44 +214,6 @@  static inline struct device *to_dma_dev(struct drm_device *dev)
 	return priv->dma_dev;
 }
 
-/*
- * Exynos drm sub driver structure.
- *
- * @list: sub driver has its own list object to register to exynos drm driver.
- * @dev: pointer to device object for subdrv device driver.
- * @drm_dev: pointer to drm_device and this pointer would be set
- *	when sub driver calls exynos_drm_subdrv_register().
- * @probe: this callback would be called by exynos drm driver after
- *     subdrv is registered to it.
- * @remove: this callback is used to release resources created
- *     by probe callback.
- * @open: this would be called with drm device file open.
- * @close: this would be called with drm device file close.
- */
-struct exynos_drm_subdrv {
-	struct list_head list;
-	struct device *dev;
-	struct drm_device *drm_dev;
-
-	int (*probe)(struct drm_device *drm_dev, struct device *dev);
-	void (*remove)(struct drm_device *drm_dev, struct device *dev);
-	int (*open)(struct drm_device *drm_dev, struct device *dev,
-			struct drm_file *file);
-	void (*close)(struct drm_device *drm_dev, struct device *dev,
-			struct drm_file *file);
-};
-
- /* This function would be called by non kms drivers such as g2d and ipp. */
-int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
-
-/* this function removes subdrv list from exynos drm driver */
-int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
-
-int exynos_drm_device_subdrv_probe(struct drm_device *dev);
-int exynos_drm_device_subdrv_remove(struct drm_device *dev);
-int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
-void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
-
 #ifdef CONFIG_DRM_EXYNOS_DPI
 struct drm_encoder *exynos_dpi_probe(struct device *dev);
 int exynos_dpi_remove(struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index f68ef1b3a28c..27b929757b43 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -9,6 +9,7 @@ 
 
 #include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/component.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -237,7 +238,7 @@  struct g2d_data {
 	int				irq;
 	struct workqueue_struct		*g2d_workq;
 	struct work_struct		runqueue_work;
-	struct exynos_drm_subdrv	subdrv;
+	struct drm_device		*drm_dev;
 	unsigned long			flags;
 
 	/* cmdlist */
@@ -268,14 +269,13 @@  static int g2d_init_cmdlist(struct g2d_data *g2d)
 {
 	struct device *dev = g2d->dev;
 	struct g2d_cmdlist_node *node = g2d->cmdlist_node;
-	struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
 	int nr;
 	int ret;
 	struct g2d_buf_info *buf_info;
 
 	g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE;
 
-	g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(subdrv->drm_dev),
+	g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(g2d->drm_dev),
 						G2D_CMDLIST_POOL_SIZE,
 						&g2d->cmdlist_pool, GFP_KERNEL,
 						g2d->cmdlist_dma_attrs);
@@ -308,7 +308,7 @@  static int g2d_init_cmdlist(struct g2d_data *g2d)
 	return 0;
 
 err:
-	dma_free_attrs(to_dma_dev(subdrv->drm_dev), G2D_CMDLIST_POOL_SIZE,
+	dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE,
 			g2d->cmdlist_pool_virt,
 			g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
 	return ret;
@@ -316,12 +316,10 @@  static int g2d_init_cmdlist(struct g2d_data *g2d)
 
 static void g2d_fini_cmdlist(struct g2d_data *g2d)
 {
-	struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
-
 	kfree(g2d->cmdlist_node);
 
 	if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) {
-		dma_free_attrs(to_dma_dev(subdrv->drm_dev),
+		dma_free_attrs(to_dma_dev(g2d->drm_dev),
 				G2D_CMDLIST_POOL_SIZE,
 				g2d->cmdlist_pool_virt,
 				g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
@@ -355,27 +353,27 @@  static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node)
 	mutex_unlock(&g2d->cmdlist_mutex);
 }
 
-static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv,
+static void g2d_add_cmdlist_to_inuse(struct drm_exynos_file_private *file_priv,
 				     struct g2d_cmdlist_node *node)
 {
 	struct g2d_cmdlist_node *lnode;
 
-	if (list_empty(&g2d_priv->inuse_cmdlist))
+	if (list_empty(&file_priv->inuse_cmdlist))
 		goto add_to_list;
 
 	/* this links to base address of new cmdlist */
-	lnode = list_entry(g2d_priv->inuse_cmdlist.prev,
+	lnode = list_entry(file_priv->inuse_cmdlist.prev,
 				struct g2d_cmdlist_node, list);
 	lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr;
 
 add_to_list:
-	list_add_tail(&node->list, &g2d_priv->inuse_cmdlist);
+	list_add_tail(&node->list, &file_priv->inuse_cmdlist);
 
 	if (node->event)
-		list_add_tail(&node->event->base.link, &g2d_priv->event_list);
+		list_add_tail(&node->event->base.link, &file_priv->event_list);
 }
 
-static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
+static void g2d_userptr_put_dma_addr(struct g2d_data *g2d,
 					unsigned long obj,
 					bool force)
 {
@@ -398,7 +396,7 @@  static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
 		return;
 
 out:
-	dma_unmap_sg(to_dma_dev(drm_dev), g2d_userptr->sgt->sgl,
+	dma_unmap_sg(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt->sgl,
 			g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL);
 
 	pages = frame_vector_pages(g2d_userptr->vec);
@@ -419,16 +417,14 @@  static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
 	kfree(g2d_userptr);
 }
 
-static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
+static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d,
 					unsigned long userptr,
 					unsigned long size,
 					struct drm_file *filp,
 					unsigned long *obj)
 {
 	struct drm_exynos_file_private *file_priv = filp->driver_priv;
-	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
 	struct g2d_cmdlist_userptr *g2d_userptr;
-	struct g2d_data *g2d;
 	struct sg_table	*sgt;
 	unsigned long start, end;
 	unsigned int npages, offset;
@@ -439,10 +435,8 @@  static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 		return ERR_PTR(-EINVAL);
 	}
 
-	g2d = dev_get_drvdata(g2d_priv->dev);
-
 	/* check if userptr already exists in userptr_list. */
-	list_for_each_entry(g2d_userptr, &g2d_priv->userptr_list, list) {
+	list_for_each_entry(g2d_userptr, &file_priv->userptr_list, list) {
 		if (g2d_userptr->userptr == userptr) {
 			/*
 			 * also check size because there could be same address
@@ -517,7 +511,7 @@  static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 
 	g2d_userptr->sgt = sgt;
 
-	if (!dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents,
+	if (!dma_map_sg(to_dma_dev(g2d->drm_dev), sgt->sgl, sgt->nents,
 				DMA_BIDIRECTIONAL)) {
 		DRM_ERROR("failed to map sgt with dma region.\n");
 		ret = -ENOMEM;
@@ -527,7 +521,7 @@  static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 	g2d_userptr->dma_addr = sgt->sgl[0].dma_address;
 	g2d_userptr->userptr = userptr;
 
-	list_add_tail(&g2d_userptr->list, &g2d_priv->userptr_list);
+	list_add_tail(&g2d_userptr->list, &file_priv->userptr_list);
 
 	if (g2d->current_pool + (npages << PAGE_SHIFT) < g2d->max_pool) {
 		g2d->current_pool += npages << PAGE_SHIFT;
@@ -556,17 +550,14 @@  static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 	return ERR_PTR(ret);
 }
 
-static void g2d_userptr_free_all(struct drm_device *drm_dev,
-					struct g2d_data *g2d,
-					struct drm_file *filp)
+static void g2d_userptr_free_all(struct g2d_data *g2d, struct drm_file *filp)
 {
 	struct drm_exynos_file_private *file_priv = filp->driver_priv;
-	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
 	struct g2d_cmdlist_userptr *g2d_userptr, *n;
 
-	list_for_each_entry_safe(g2d_userptr, n, &g2d_priv->userptr_list, list)
+	list_for_each_entry_safe(g2d_userptr, n, &file_priv->userptr_list, list)
 		if (g2d_userptr->in_pool)
-			g2d_userptr_put_dma_addr(drm_dev,
+			g2d_userptr_put_dma_addr(g2d,
 						(unsigned long)g2d_userptr,
 						true);
 
@@ -758,7 +749,7 @@  static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
 				goto err;
 			}
 
-			addr = g2d_userptr_get_dma_addr(drm_dev,
+			addr = g2d_userptr_get_dma_addr(g2d,
 							g2d_userptr.userptr,
 							g2d_userptr.size,
 							file,
@@ -785,7 +776,6 @@  static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
 				  struct g2d_cmdlist_node *node,
 				  struct drm_file *filp)
 {
-	struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
 	struct g2d_buf_info *buf_info = &node->buf_info;
 	int i;
 
@@ -800,11 +790,9 @@  static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
 		handle = buf_info->handles[reg_type];
 
 		if (buf_info->types[reg_type] == BUF_TYPE_GEM)
-			exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle,
-							filp);
+			exynos_drm_gem_put_dma_addr(g2d->drm_dev, handle, filp);
 		else
-			g2d_userptr_put_dma_addr(subdrv->drm_dev, handle,
-							false);
+			g2d_userptr_put_dma_addr(g2d, handle, false);
 
 		buf_info->reg_types[i] = REG_TYPE_NONE;
 		buf_info->handles[reg_type] = 0;
@@ -922,7 +910,7 @@  static void g2d_runqueue_worker(struct work_struct *work)
 
 static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
 {
-	struct drm_device *drm_dev = g2d->subdrv.drm_dev;
+	struct drm_device *drm_dev = g2d->drm_dev;
 	struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;
 	struct drm_exynos_pending_g2d_event *e;
 	struct timespec64 now;
@@ -1031,7 +1019,7 @@  static void g2d_wait_finish(struct g2d_data *g2d, struct drm_file *file)
 	mutex_unlock(&g2d->runqueue_mutex);
 }
 
-static int g2d_check_reg_offset(struct device *dev,
+static int g2d_check_reg_offset(struct g2d_data *g2d,
 				struct g2d_cmdlist_node *node,
 				int nr, bool for_addr)
 {
@@ -1131,7 +1119,7 @@  static int g2d_check_reg_offset(struct device *dev,
 	return 0;
 
 err:
-	dev_err(dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]);
+	dev_err(g2d->dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]);
 	return -EINVAL;
 }
 
@@ -1139,23 +1127,8 @@  static int g2d_check_reg_offset(struct device *dev,
 int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data,
 			     struct drm_file *file)
 {
-	struct drm_exynos_file_private *file_priv = file->driver_priv;
-	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
-	struct device *dev;
-	struct g2d_data *g2d;
 	struct drm_exynos_g2d_get_ver *ver = data;
 
-	if (!g2d_priv)
-		return -ENODEV;
-
-	dev = g2d_priv->dev;
-	if (!dev)
-		return -ENODEV;
-
-	g2d = dev_get_drvdata(dev);
-	if (!g2d)
-		return -EFAULT;
-
 	ver->major = G2D_HW_MAJOR_VER;
 	ver->minor = G2D_HW_MINOR_VER;
 
@@ -1166,9 +1139,8 @@  int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
 				 struct drm_file *file)
 {
 	struct drm_exynos_file_private *file_priv = file->driver_priv;
-	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
-	struct device *dev;
-	struct g2d_data *g2d;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
+	struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev);
 	struct drm_exynos_g2d_set_cmdlist *req = data;
 	struct drm_exynos_g2d_cmd *cmd;
 	struct drm_exynos_pending_g2d_event *e;
@@ -1177,17 +1149,6 @@  int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
 	int size;
 	int ret;
 
-	if (!g2d_priv)
-		return -ENODEV;
-
-	dev = g2d_priv->dev;
-	if (!dev)
-		return -ENODEV;
-
-	g2d = dev_get_drvdata(dev);
-	if (!g2d)
-		return -EFAULT;
-
 	node = g2d_get_cmdlist(g2d);
 	if (!node)
 		return -ENOMEM;
@@ -1199,7 +1160,7 @@  int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
 	 */
 	if (req->cmd_nr > G2D_CMDLIST_DATA_NUM ||
 	    req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) {
-		dev_err(dev, "number of submitted G2D commands exceeds limit\n");
+		dev_err(g2d->dev, "number of submitted G2D commands exceeds limit\n");
 		return -EINVAL;
 	}
 
@@ -1267,7 +1228,7 @@  int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
 	 */
 	size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2;
 	if (size > G2D_CMDLIST_DATA_NUM) {
-		dev_err(dev, "cmdlist size is too big\n");
+		dev_err(g2d->dev, "cmdlist size is too big\n");
 		ret = -EINVAL;
 		goto err_free_event;
 	}
@@ -1282,7 +1243,7 @@  int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
 	}
 	cmdlist->last += req->cmd_nr * 2;
 
-	ret = g2d_check_reg_offset(dev, node, req->cmd_nr, false);
+	ret = g2d_check_reg_offset(g2d, node, req->cmd_nr, false);
 	if (ret < 0)
 		goto err_free_event;
 
@@ -1301,7 +1262,7 @@  int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
 		}
 		cmdlist->last += req->cmd_buf_nr * 2;
 
-		ret = g2d_check_reg_offset(dev, node, req->cmd_buf_nr, true);
+		ret = g2d_check_reg_offset(g2d, node, req->cmd_buf_nr, true);
 		if (ret < 0)
 			goto err_free_event;
 
@@ -1319,7 +1280,7 @@  int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
 	/* tail */
 	cmdlist->data[cmdlist->last] = 0;
 
-	g2d_add_cmdlist_to_inuse(g2d_priv, node);
+	g2d_add_cmdlist_to_inuse(file_priv, node);
 
 	return 0;
 
@@ -1337,25 +1298,13 @@  int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
 			  struct drm_file *file)
 {
 	struct drm_exynos_file_private *file_priv = file->driver_priv;
-	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
-	struct device *dev;
-	struct g2d_data *g2d;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
+	struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev);
 	struct drm_exynos_g2d_exec *req = data;
 	struct g2d_runqueue_node *runqueue_node;
 	struct list_head *run_cmdlist;
 	struct list_head *event_list;
 
-	if (!g2d_priv)
-		return -ENODEV;
-
-	dev = g2d_priv->dev;
-	if (!dev)
-		return -ENODEV;
-
-	g2d = dev_get_drvdata(dev);
-	if (!g2d)
-		return -EFAULT;
-
 	runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);
 	if (!runqueue_node)
 		return -ENOMEM;
@@ -1367,11 +1316,11 @@  int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
 	init_completion(&runqueue_node->complete);
 	runqueue_node->async = req->async;
 
-	list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist);
-	list_splice_init(&g2d_priv->event_list, event_list);
+	list_splice_init(&file_priv->inuse_cmdlist, run_cmdlist);
+	list_splice_init(&file_priv->event_list, event_list);
 
 	if (list_empty(run_cmdlist)) {
-		dev_err(dev, "there is no inuse cmdlist\n");
+		dev_err(g2d->dev, "there is no inuse cmdlist\n");
 		kmem_cache_free(g2d->runqueue_slab, runqueue_node);
 		return -EPERM;
 	}
@@ -1395,71 +1344,28 @@  int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
 	return 0;
 }
 
-static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
-{
-	struct g2d_data *g2d;
-	int ret;
-
-	g2d = dev_get_drvdata(dev);
-	if (!g2d)
-		return -EFAULT;
-
-	/* allocate dma-aware cmdlist buffer. */
-	ret = g2d_init_cmdlist(g2d);
-	if (ret < 0) {
-		dev_err(dev, "cmdlist init failed\n");
-		return ret;
-	}
-
-	ret = drm_iommu_attach_device(drm_dev, dev);
-	if (ret < 0) {
-		dev_err(dev, "failed to enable iommu.\n");
-		g2d_fini_cmdlist(g2d);
-	}
-
-	return ret;
-
-}
-
-static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-	drm_iommu_detach_device(drm_dev, dev);
-}
-
-static int g2d_open(struct drm_device *drm_dev, struct device *dev,
-			struct drm_file *file)
+int g2d_open(struct drm_device *drm_dev, struct drm_file *file)
 {
 	struct drm_exynos_file_private *file_priv = file->driver_priv;
-	struct exynos_drm_g2d_private *g2d_priv;
-
-	g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL);
-	if (!g2d_priv)
-		return -ENOMEM;
-
-	g2d_priv->dev = dev;
-	file_priv->g2d_priv = g2d_priv;
 
-	INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist);
-	INIT_LIST_HEAD(&g2d_priv->event_list);
-	INIT_LIST_HEAD(&g2d_priv->userptr_list);
+	INIT_LIST_HEAD(&file_priv->inuse_cmdlist);
+	INIT_LIST_HEAD(&file_priv->event_list);
+	INIT_LIST_HEAD(&file_priv->userptr_list);
 
 	return 0;
 }
 
-static void g2d_close(struct drm_device *drm_dev, struct device *dev,
-			struct drm_file *file)
+void g2d_close(struct drm_device *drm_dev, struct drm_file *file)
 {
 	struct drm_exynos_file_private *file_priv = file->driver_priv;
-	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
 	struct g2d_data *g2d;
 	struct g2d_cmdlist_node *node, *n;
 
-	if (!dev)
+	if (!priv->g2d_dev)
 		return;
 
-	g2d = dev_get_drvdata(dev);
-	if (!g2d)
-		return;
+	g2d = dev_get_drvdata(priv->g2d_dev);
 
 	/* Remove the runqueue nodes that belong to us. */
 	mutex_lock(&g2d->runqueue_mutex);
@@ -1480,24 +1386,70 @@  static void g2d_close(struct drm_device *drm_dev, struct device *dev,
 	 * Properly unmap these buffers here.
 	 */
 	mutex_lock(&g2d->cmdlist_mutex);
-	list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list) {
+	list_for_each_entry_safe(node, n, &file_priv->inuse_cmdlist, list) {
 		g2d_unmap_cmdlist_gem(g2d, node, file);
 		list_move_tail(&node->list, &g2d->free_cmdlist);
 	}
 	mutex_unlock(&g2d->cmdlist_mutex);
 
 	/* release all g2d_userptr in pool. */
-	g2d_userptr_free_all(drm_dev, g2d, file);
+	g2d_userptr_free_all(g2d, file);
+}
+
+static int g2d_bind(struct device *dev, struct device *master, void *data)
+{
+	struct g2d_data *g2d = dev_get_drvdata(dev);
+	struct drm_device *drm_dev = data;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
+	int ret;
+
+	g2d->drm_dev = drm_dev;
+
+	/* allocate dma-aware cmdlist buffer. */
+	ret = g2d_init_cmdlist(g2d);
+	if (ret < 0) {
+		dev_err(dev, "cmdlist init failed\n");
+		return ret;
+	}
+
+	ret = drm_iommu_attach_device(drm_dev, dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable iommu.\n");
+		g2d_fini_cmdlist(g2d);
+		return ret;
+	}
+	priv->g2d_dev = dev;
 
-	kfree(file_priv->g2d_priv);
+	dev_info(dev, "The Exynos G2D (ver %d.%d) successfully registered.\n",
+			G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER);
+	return 0;
 }
 
+static void g2d_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct g2d_data *g2d = dev_get_drvdata(dev);
+	struct drm_device *drm_dev = data;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
+
+	/* Suspend operation and wait for engine idle. */
+	set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
+	g2d_wait_finish(g2d, NULL);
+	priv->g2d_dev = NULL;
+
+	cancel_work_sync(&g2d->runqueue_work);
+	drm_iommu_detach_device(g2d->drm_dev, dev);
+}
+
+static const struct component_ops g2d_component_ops = {
+	.bind	= g2d_bind,
+	.unbind = g2d_unbind,
+};
+
 static int g2d_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct g2d_data *g2d;
-	struct exynos_drm_subdrv *subdrv;
 	int ret;
 
 	g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL);
@@ -1564,22 +1516,12 @@  static int g2d_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, g2d);
 
-	subdrv = &g2d->subdrv;
-	subdrv->dev = dev;
-	subdrv->probe = g2d_subdrv_probe;
-	subdrv->remove = g2d_subdrv_remove;
-	subdrv->open = g2d_open;
-	subdrv->close = g2d_close;
-
-	ret = exynos_drm_subdrv_register(subdrv);
+	ret = component_add(dev, &g2d_component_ops);
 	if (ret < 0) {
 		dev_err(dev, "failed to register drm g2d device\n");
 		goto err_put_clk;
 	}
 
-	dev_info(dev, "The Exynos G2D (ver %d.%d) successfully probed.\n",
-			G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER);
-
 	return 0;
 
 err_put_clk:
@@ -1595,12 +1537,7 @@  static int g2d_remove(struct platform_device *pdev)
 {
 	struct g2d_data *g2d = platform_get_drvdata(pdev);
 
-	/* Suspend operation and wait for engine idle. */
-	set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
-	g2d_wait_finish(g2d, NULL);
-
-	cancel_work_sync(&g2d->runqueue_work);
-	exynos_drm_subdrv_unregister(&g2d->subdrv);
+	component_del(&pdev->dev, &g2d_component_ops);
 
 	/* There should be no locking needed here. */
 	g2d_remove_runqueue_nodes(g2d, NULL);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.h b/drivers/gpu/drm/exynos/exynos_drm_g2d.h
index 1a9c7ca8c15b..287b2ed8f178 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.h
@@ -14,6 +14,9 @@  extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data,
 					struct drm_file *file_priv);
 extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
 				 struct drm_file *file_priv);
+
+extern int g2d_open(struct drm_device *drm_dev, struct drm_file *file);
+extern void g2d_close(struct drm_device *drm_dev, struct drm_file *file);
 #else
 static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
 					   struct drm_file *file_priv)
@@ -33,4 +36,12 @@  static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
 {
 	return -ENODEV;
 }
+
+int g2d_open(struct drm_device *drm_dev, struct drm_file *file)
+{
+	return 0;
+}
+
+void g2d_close(struct drm_device *drm_dev, struct drm_file *file)
+{ }
 #endif