drm_connector)
 
 struct exynos_drm_connector {
-       struct drm_connector    drm_connector;
-       uint32_t                encoder_id;
-       struct exynos_drm_manager *manager;
+       struct drm_connector            drm_connector;
+       uint32_t                        encoder_id;
+       struct exynos_drm_display       *display;
 };
 
 static int exynos_drm_connector_get_modes(struct drm_connector *connector)
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_display_ops *display_ops = manager->display_ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        struct edid *edid = NULL;
        unsigned int count = 0;
        int ret;
 
-       if (!display_ops) {
-               DRM_DEBUG_KMS("display_ops is null.\n");
-               return 0;
-       }
-
        /*
         * if get_edid() exists then get_edid() callback of hdmi side
         * is called to get edid data through i2c interface else
         * P.S. in case of lcd panel, count is always 1 if success
         * because lcd panel has only one mode.
         */
-       if (display_ops->get_edid) {
-               edid = display_ops->get_edid(manager->dev, connector);
+       if (display->ops->get_edid) {
+               edid = display->ops->get_edid(display, connector);
                if (IS_ERR_OR_NULL(edid)) {
                        ret = PTR_ERR(edid);
                        edid = NULL;
                        return 0;
                }
 
-               if (display_ops->get_panel)
-                       panel = display_ops->get_panel(manager->dev);
+               if (display->ops->get_panel)
+                       panel = display->ops->get_panel(display);
                else {
                        drm_mode_destroy(connector->dev, mode);
                        return 0;
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_display_ops *display_ops = manager->display_ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        int ret = MODE_BAD;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (display_ops && display_ops->check_mode)
-               if (!display_ops->check_mode(manager->dev, mode))
+       if (display->ops->check_mode)
+               if (!display->ops->check_mode(display, mode))
                        ret = MODE_OK;
 
        return ret;
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_manager_ops *ops = manager->ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        unsigned int width, height;
 
        width = max_width;
         * if specific driver want to find desired_mode using maxmum
         * resolution then get max width and height from that driver.
         */
-       if (ops && ops->get_max_resol)
-               ops->get_max_resol(manager, &width, &height);
+       if (display->ops->get_max_resol)
+               display->ops->get_max_resol(display, &width, &height);
 
        return drm_helper_probe_single_connector_modes(connector, width,
                                                        height);
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_display_ops *display_ops =
-                                       manager->display_ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        enum drm_connector_status status = connector_status_disconnected;
 
-       if (display_ops && display_ops->is_connected) {
-               if (display_ops->is_connected(manager->dev))
+       if (display->ops->is_connected) {
+               if (display->ops->is_connected(display))
                        status = connector_status_connected;
                else
                        status = connector_status_disconnected;
                                                   struct drm_encoder *encoder)
 {
        struct exynos_drm_connector *exynos_connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        struct drm_connector *connector;
        int type;
        int err;
 
        connector = &exynos_connector->drm_connector;
 
-       switch (manager->display_ops->type) {
+       switch (display->type) {
        case EXYNOS_DISPLAY_TYPE_HDMI:
                type = DRM_MODE_CONNECTOR_HDMIA;
                connector->interlace_allowed = true;
                goto err_connector;
 
        exynos_connector->encoder_id = encoder->base.id;
-       exynos_connector->manager = manager;
+       exynos_connector->display = display;
        connector->dpms = DRM_MODE_DPMS_OFF;
        connector->encoder = encoder;
 
 
 
 #include <drm/drmP.h>
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_connector.h"
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
+static LIST_HEAD(exynos_drm_manager_list);
+static LIST_HEAD(exynos_drm_display_list);
 
 static int exynos_drm_create_enc_conn(struct drm_device *dev,
-                                       struct exynos_drm_subdrv *subdrv)
+                                       struct exynos_drm_display *display)
 {
        struct drm_encoder *encoder;
        struct drm_connector *connector;
+       struct exynos_drm_manager *manager;
        int ret;
+       unsigned long possible_crtcs = 0;
 
-       subdrv->manager->dev = subdrv->dev;
+       /* Find possible crtcs for this display */
+       list_for_each_entry(manager, &exynos_drm_manager_list, list)
+               if (manager->type == display->type)
+                       possible_crtcs |= 1 << manager->pipe;
 
        /* create and initialize a encoder for this sub driver. */
-       encoder = exynos_drm_encoder_create(dev, subdrv->manager,
-                       (1 << MAX_CRTC) - 1);
+       encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
        if (!encoder) {
                DRM_ERROR("failed to create encoder\n");
                return -EFAULT;
                goto err_destroy_encoder;
        }
 
-       subdrv->encoder = encoder;
-       subdrv->connector = connector;
+       display->encoder = encoder;
+       display->connector = connector;
 
        return 0;
 
        return ret;
 }
 
-static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
-{
-       if (subdrv->encoder) {
-               struct drm_encoder *encoder = subdrv->encoder;
-               encoder->funcs->destroy(encoder);
-               subdrv->encoder = NULL;
-       }
-
-       if (subdrv->connector) {
-               struct drm_connector *connector = subdrv->connector;
-               connector->funcs->destroy(connector);
-               subdrv->connector = NULL;
-       }
-}
-
 static int exynos_drm_subdrv_probe(struct drm_device *dev,
                                        struct exynos_drm_subdrv *subdrv)
 {
                subdrv->remove(dev, subdrv->dev);
 }
 
+int exynos_drm_initialize_managers(struct drm_device *dev)
+{
+       struct exynos_drm_manager *manager, *n;
+       int ret, pipe = 0;
+
+       list_for_each_entry(manager, &exynos_drm_manager_list, list) {
+               if (manager->ops->initialize) {
+                       ret = manager->ops->initialize(manager, dev, pipe);
+                       if (ret) {
+                               DRM_ERROR("Mgr init [%d] failed with %d\n",
+                                               manager->type, ret);
+                               goto err;
+                       }
+               }
+
+               manager->drm_dev = dev;
+               manager->pipe = pipe++;
+
+               ret = exynos_drm_crtc_create(manager);
+               if (ret) {
+                       DRM_ERROR("CRTC create [%d] failed with %d\n",
+                                       manager->type, ret);
+                       goto err;
+               }
+       }
+       return 0;
+
+err:
+       list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
+               if (pipe-- > 0)
+                       exynos_drm_manager_unregister(manager);
+               else
+                       list_del(&manager->list);
+       }
+       return ret;
+}
+
+void exynos_drm_remove_managers(struct drm_device *dev)
+{
+       struct exynos_drm_manager *manager, *n;
+
+       list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
+               exynos_drm_manager_unregister(manager);
+}
+
+int exynos_drm_initialize_displays(struct drm_device *dev)
+{
+       struct exynos_drm_display *display, *n;
+       int ret, initialized = 0;
+
+       list_for_each_entry(display, &exynos_drm_display_list, list) {
+               if (display->ops->initialize) {
+                       ret = display->ops->initialize(display, dev);
+                       if (ret) {
+                               DRM_ERROR("Display init [%d] failed with %d\n",
+                                               display->type, ret);
+                               goto err;
+                       }
+               }
+
+               initialized++;
+
+               ret = exynos_drm_create_enc_conn(dev, display);
+               if (ret) {
+                       DRM_ERROR("Encoder create [%d] failed with %d\n",
+                                       display->type, ret);
+                       goto err;
+               }
+       }
+       return 0;
+
+err:
+       list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
+               if (initialized-- > 0)
+                       exynos_drm_display_unregister(display);
+               else
+                       list_del(&display->list);
+       }
+       return ret;
+}
+
+void exynos_drm_remove_displays(struct drm_device *dev)
+{
+       struct exynos_drm_display *display, *n;
+
+       list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
+               exynos_drm_display_unregister(display);
+}
+
 int exynos_drm_device_register(struct drm_device *dev)
 {
        struct exynos_drm_subdrv *subdrv, *n;
-       unsigned int fine_cnt = 0;
        int err;
 
        if (!dev)
                        list_del(&subdrv->list);
                        continue;
                }
-
-               /*
-                * if manager is null then it means that this sub driver
-                * doesn't need encoder and connector.
-                */
-               if (!subdrv->manager) {
-                       fine_cnt++;
-                       continue;
-               }
-
-               err = exynos_drm_create_enc_conn(dev, subdrv);
-               if (err) {
-                       DRM_DEBUG("failed to create encoder and connector.\n");
-                       exynos_drm_subdrv_remove(dev, subdrv);
-                       list_del(&subdrv->list);
-                       continue;
-               }
-
-               fine_cnt++;
        }
 
-       if (!fine_cnt)
-               return -EINVAL;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_register);
 
        list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
                exynos_drm_subdrv_remove(dev, subdrv);
-               exynos_drm_destroy_enc_conn(subdrv);
        }
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
 
+int exynos_drm_manager_register(struct exynos_drm_manager *manager)
+{
+       BUG_ON(!manager->ops);
+       list_add_tail(&manager->list, &exynos_drm_manager_list);
+       return 0;
+}
+
+int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
+{
+       if (manager->ops->remove)
+               manager->ops->remove(manager);
+
+       list_del(&manager->list);
+       return 0;
+}
+
+int exynos_drm_display_register(struct exynos_drm_display *display)
+{
+       BUG_ON(!display->ops);
+       list_add_tail(&display->list, &exynos_drm_display_list);
+       return 0;
+}
+
+int exynos_drm_display_unregister(struct exynos_drm_display *display)
+{
+       if (display->ops->remove)
+               display->ops->remove(display);
+
+       list_del(&display->list);
+       return 0;
+}
+
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
        if (!subdrv)
 
  *
  * @drm_crtc: crtc object.
  * @drm_plane: pointer of private plane object for this crtc
+ * @manager: the manager associated with this crtc
  * @pipe: a crtc index created at load() with a new crtc object creation
  *     and the crtc object would be set to private->crtc array
  *     to get a crtc object corresponding to this pipe from private->crtc
 struct exynos_drm_crtc {
        struct drm_crtc                 drm_crtc;
        struct drm_plane                *plane;
+       struct exynos_drm_manager       *manager;
        unsigned int                    pipe;
        unsigned int                    dpms;
        enum exynos_crtc_mode           mode;
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
 
                drm_vblank_off(crtc->dev, exynos_crtc->pipe);
        }
 
-       exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
+       if (manager->ops->dpms)
+               manager->ops->dpms(manager, mode);
+
        exynos_crtc->dpms = mode;
 }
 
 static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
        exynos_plane_commit(exynos_crtc->plane);
+
+       if (manager->ops->commit)
+               manager->ops->commit(manager);
+
        exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
 }
 
        struct drm_plane *plane = exynos_crtc->plane;
        unsigned int crtc_w;
        unsigned int crtc_h;
-       int pipe = exynos_crtc->pipe;
        int ret;
 
        /*
        plane->crtc = crtc;
        plane->fb = crtc->fb;
 
-       exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
-
        return 0;
 }
 
        drm_object_attach_property(&crtc->base, prop, 0);
 }
 
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 {
        struct exynos_drm_crtc *exynos_crtc;
-       struct exynos_drm_private *private = dev->dev_private;
+       struct exynos_drm_private *private = manager->drm_dev->dev_private;
        struct drm_crtc *crtc;
 
        exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
        if (!exynos_crtc)
                return -ENOMEM;
 
-       exynos_crtc->pipe = nr;
-       exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
        init_waitqueue_head(&exynos_crtc->pending_flip_queue);
        atomic_set(&exynos_crtc->pending_flip, 0);
-       exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
+
+       exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
+       exynos_crtc->manager = manager;
+       exynos_crtc->pipe = manager->pipe;
+       exynos_crtc->plane = exynos_plane_init(manager->drm_dev,
+                               1 << manager->pipe, true);
        if (!exynos_crtc->plane) {
                kfree(exynos_crtc);
                return -ENOMEM;
 
        crtc = &exynos_crtc->drm_crtc;
 
-       private->crtc[nr] = crtc;
+       private->crtc[manager->pipe] = crtc;
 
-       drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
+       drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs);
        drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
        exynos_drm_crtc_attach_mode_property(crtc);
        return 0;
 }
 
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *private = dev->dev_private;
        struct exynos_drm_crtc *exynos_crtc =
-               to_exynos_crtc(private->crtc[crtc]);
+               to_exynos_crtc(private->crtc[pipe]);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
                return -EPERM;
 
-       exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
-                       exynos_drm_enable_vblank);
+       if (manager->ops->enable_vblank)
+               manager->ops->enable_vblank(manager);
 
        return 0;
 }
 
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *private = dev->dev_private;
        struct exynos_drm_crtc *exynos_crtc =
-               to_exynos_crtc(private->crtc[crtc]);
+               to_exynos_crtc(private->crtc[pipe]);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
                return;
 
-       exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
-                       exynos_drm_disable_vblank);
+       if (manager->ops->disable_vblank)
+               manager->ops->disable_vblank(manager);
 }
 
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *dev_priv = dev->dev_private;
        struct drm_pending_vblank_event *e, *t;
-       struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
+       struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
        unsigned long flags;
 
        list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
                        base.link) {
                /* if event's pipe isn't same as crtc then ignore it. */
-               if (crtc != e->pipe)
+               if (pipe != e->pipe)
                        continue;
 
                list_del(&e->base.link);
                drm_send_vblank_event(dev, -1, e);
-               drm_vblank_put(dev, crtc);
+               drm_vblank_put(dev, pipe);
                atomic_set(&exynos_crtc->pending_flip, 0);
                wake_up(&exynos_crtc->pending_flip_queue);
        }
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+                       struct exynos_drm_overlay *overlay)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_mode_set)
+               manager->ops->win_mode_set(manager, overlay);
+}
+
+void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_commit)
+               manager->ops->win_commit(manager, zpos);
+}
+
+void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_enable)
+               manager->ops->win_enable(manager, zpos);
+}
+
+void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_disable)
+               manager->ops->win_disable(manager, zpos);
+}
+
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
+{
+       struct exynos_drm_manager *manager;
+       struct drm_device *dev = fb->dev;
+       struct drm_crtc *crtc;
+
+       /*
+        * make sure that overlay data are updated to real hardware
+        * for all encoders.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               manager = to_exynos_crtc(crtc)->manager;
+
+               /*
+                * wait for vblank interrupt
+                * - this makes sure that overlay data are updated to
+                *      real hardware.
+                */
+               if (manager->ops->wait_for_vblank)
+                       manager->ops->wait_for_vblank(manager);
+       }
+}
 
 #ifndef _EXYNOS_DRM_CRTC_H_
 #define _EXYNOS_DRM_CRTC_H_
 
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc);
+struct drm_device;
+struct drm_crtc;
+struct exynos_drm_manager;
+struct exynos_drm_overlay;
+
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+                       struct exynos_drm_overlay *overlay);
+void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
+void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
+void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
 
 #endif
 
 
        exynos_drm_mode_config_init(dev);
 
-       /*
-        * EXYNOS4 is enough to have two CRTCs and each crtc would be used
-        * without dependency of hardware.
-        */
-       for (nr = 0; nr < MAX_CRTC; nr++) {
-               ret = exynos_drm_crtc_create(dev, nr);
-               if (ret)
-                       goto err_release_iommu_mapping;
-       }
+       ret = exynos_drm_initialize_managers(dev);
+       if (ret)
+               goto err_mode_config_cleanup;
 
        for (nr = 0; nr < MAX_PLANE; nr++) {
                struct drm_plane *plane;
 
                plane = exynos_plane_init(dev, possible_crtcs, false);
                if (!plane)
-                       goto err_release_iommu_mapping;
+                       goto err_manager_cleanup;
        }
 
+       ret = exynos_drm_initialize_displays(dev);
+       if (ret)
+               goto err_manager_cleanup;
+
        ret = drm_vblank_init(dev, MAX_CRTC);
        if (ret)
-               goto err_release_iommu_mapping;
+               goto err_display_cleanup;
 
        /*
         * probe sub drivers such as display controller and hdmi driver,
        exynos_drm_device_unregister(dev);
 err_vblank:
        drm_vblank_cleanup(dev);
-err_release_iommu_mapping:
+err_display_cleanup:
+       exynos_drm_remove_displays(dev);
+err_manager_cleanup:
+       exynos_drm_remove_managers(dev);
+err_mode_config_cleanup:
+       drm_mode_config_cleanup(dev);
        drm_release_iommu_mapping(dev);
 err_crtc:
        drm_mode_config_cleanup(dev);
        exynos_drm_device_unregister(dev);
        drm_vblank_cleanup(dev);
        drm_kms_helper_poll_fini(dev);
+       exynos_drm_remove_displays(dev);
+       exynos_drm_remove_managers(dev);
        drm_mode_config_cleanup(dev);
 
        drm_release_iommu_mapping(dev);
 
  * Exynos DRM Display Structure.
  *     - this structure is common to analog tv, digital tv and lcd panel.
  *
- * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
  * @initialize: initializes the display with drm_dev
+ * @remove: cleans up the display for removal
  * @is_connected: check for that display is connected or not.
+ * @get_max_resol: get maximum resolution to specific hardware.
  * @get_edid: get edid modes from display driver.
  * @get_panel: get panel object from display driver.
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
+ * @mode_set: convert drm_display_mode to hw specific display mode and
+ *           would be called by encoder->mode_set().
  * @check_mode: check if mode is valid or not.
  * @dpms: display device on or off.
+ * @commit: apply changes to hw
  */
+struct exynos_drm_display;
 struct exynos_drm_display_ops {
+       int (*initialize)(struct exynos_drm_display *display,
+                               struct drm_device *drm_dev);
+       void (*remove)(struct exynos_drm_display *display);
+       bool (*is_connected)(struct exynos_drm_display *display);
+       void (*get_max_resol)(struct exynos_drm_display *display,
+                               unsigned int *width,
+                               unsigned int *height);
+       struct edid *(*get_edid)(struct exynos_drm_display *display,
+                               struct drm_connector *connector);
+       void *(*get_panel)(struct exynos_drm_display *display);
+       void (*mode_fixup)(struct exynos_drm_display *display,
+                               struct drm_connector *connector,
+                               const struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode);
+       void (*mode_set)(struct exynos_drm_display *display,
+                               struct drm_display_mode *mode);
+       int (*check_mode)(struct exynos_drm_display *display,
+                               struct drm_display_mode *mode);
+       void (*dpms)(struct exynos_drm_display *display, int mode);
+       void (*commit)(struct exynos_drm_display *display);
+};
+
+/*
+ * Exynos drm display structure, maps 1:1 with an encoder/connector
+ *
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @encoder: encoder object this display maps to
+ * @connector: connector object this display maps to
+ * @ops: pointer to callbacks for exynos drm specific functionality
+ * @ctx: A pointer to the display's implementation specific context
+ */
+struct exynos_drm_display {
+       struct list_head list;
        enum exynos_drm_output_type type;
-       int (*initialize)(struct device *dev, struct drm_device *drm_dev);
-       bool (*is_connected)(struct device *dev);
-       struct edid *(*get_edid)(struct device *dev,
-                       struct drm_connector *connector);
-       void *(*get_panel)(struct device *dev);
-       int (*check_mode)(struct device *dev, struct drm_display_mode *mode);
-       int (*dpms)(struct device *dev, int mode);
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       struct exynos_drm_display_ops *ops;
+       void *ctx;
 };
 
 /*
  * Exynos drm manager ops
  *
  * @initialize: initializes the manager with drm_dev
+ * @remove: cleans up the manager for removal
  * @dpms: control device power.
- * @mode_fixup: fix mode data comparing to hw specific display mode.
- * @mode_set: convert drm_display_mode to hw specific display mode and
- *           would be called by encoder->mode_set().
- * @get_max_resol: get maximum resolution to specific hardware.
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
 struct exynos_drm_manager;
 struct exynos_drm_manager_ops {
        int (*initialize)(struct exynos_drm_manager *mgr,
-                               struct drm_device *drm_dev);
+                               struct drm_device *drm_dev, int pipe);
+       void (*remove)(struct exynos_drm_manager *mgr);
        void (*dpms)(struct exynos_drm_manager *mgr, int mode);
-       void (*mode_fixup)(struct exynos_drm_manager *mgr,
-                               struct drm_connector *connector,
-                               const struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode);
-       void (*mode_set)(struct exynos_drm_manager *mgr, void *mode);
-       void (*get_max_resol)(struct exynos_drm_manager *mgr,
-                               unsigned int *width, unsigned int *height);
        void (*commit)(struct exynos_drm_manager *mgr);
        int (*enable_vblank)(struct exynos_drm_manager *mgr);
        void (*disable_vblank)(struct exynos_drm_manager *mgr);
 };
 
 /*
- * Exynos drm common manager structure.
+ * Exynos drm common manager structure, maps 1:1 with a crtc
  *
- * @dev: pointer to device object for subdrv device driver.
- *     sub drivers such as display controller or hdmi driver,
- *     have their own device object.
- * @ops: pointer to callbacks for exynos drm specific framebuffer.
- *     these callbacks should be set by specific drivers such fimd
- *     or hdmi driver and are used to control hardware global registers.
- * @display: pointer to callbacks for exynos drm specific framebuffer.
- *     these callbacks should be set by specific drivers such fimd
- *     or hdmi driver and are used to control display devices such as
- *     analog tv, digital tv and lcd panel and also get timing data for them.
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @drm_dev: pointer to the drm device
+ * @pipe: the pipe number for this crtc/manager
+ * @ops: pointer to callbacks for exynos drm specific functionality
  * @ctx: A pointer to the manager's implementation specific context
  */
 struct exynos_drm_manager {
-       struct device *dev;
+       struct list_head list;
+       enum exynos_drm_output_type type;
+       struct drm_device *drm_dev;
        int pipe;
        struct exynos_drm_manager_ops *ops;
-       struct exynos_drm_display_ops *display_ops;
        void *ctx;
 };
 
  *     by probe callback.
  * @open: this would be called with drm device file open.
  * @close: this would be called with drm device file close.
- * @encoder: encoder object owned by this sub driver.
- * @connector: connector object owned by this sub driver.
  */
 struct exynos_drm_subdrv {
        struct list_head list;
        struct device *dev;
        struct drm_device *drm_dev;
-       struct exynos_drm_manager *manager;
 
        int (*probe)(struct drm_device *drm_dev, struct device *dev);
        void (*remove)(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);
-
-       struct drm_encoder *encoder;
-       struct drm_connector *connector;
 };
 
 /*
  */
 int exynos_drm_device_unregister(struct drm_device *dev);
 
+int exynos_drm_initialize_managers(struct drm_device *dev);
+void exynos_drm_remove_managers(struct drm_device *dev);
+int exynos_drm_initialize_displays(struct drm_device *dev);
+void exynos_drm_remove_displays(struct drm_device *dev);
+
+int exynos_drm_manager_register(struct exynos_drm_manager *manager);
+int exynos_drm_manager_unregister(struct exynos_drm_manager *manager);
+int exynos_drm_display_register(struct exynos_drm_display *display);
+int exynos_drm_display_unregister(struct exynos_drm_display *display);
+
 /*
  * this function would be called by sub drivers such as display controller
  * or hdmi driver to register this sub driver object to exynos drm driver
 
  * exynos specific encoder structure.
  *
  * @drm_encoder: encoder object.
- * @manager: specific encoder has its own manager to control a hardware
- *     appropriately and we can access a hardware drawing on this manager.
+ * @display: the display structure that maps to this encoder
  */
 struct exynos_drm_encoder {
        struct drm_crtc                 *old_crtc;
        struct drm_encoder              drm_encoder;
-       struct exynos_drm_manager       *manager;
+       struct exynos_drm_display       *display;
 };
 
 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_display_ops *display_ops = manager->display_ops;
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+       struct exynos_drm_display *display = exynos_encoder->display;
 
        DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
 
-       if (display_ops && display_ops->dpms)
-               display_ops->dpms(manager->ctx, mode);
+       if (display->ops->dpms)
+               display->ops->dpms(display, mode);
 }
 
 static bool
                               struct drm_display_mode *adjusted_mode)
 {
        struct drm_device *dev = encoder->dev;
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+       struct exynos_drm_display *display = exynos_encoder->display;
        struct drm_connector *connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder)
-                       if (manager_ops && manager_ops->mode_fixup)
-                               manager_ops->mode_fixup(manager, connector,
-                                                       mode, adjusted_mode);
+               if (connector->encoder != encoder)
+                       continue;
+
+               if (display->ops->mode_fixup)
+                       display->ops->mode_fixup(display, connector, mode,
+                                       adjusted_mode);
        }
 
        return true;
 {
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
-       struct exynos_drm_manager *manager;
-       struct exynos_drm_manager_ops *manager_ops;
+       struct exynos_drm_display *display;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                if (connector->encoder == encoder) {
                                                encoder->crtc);
                        }
 
-                       manager = exynos_drm_get_manager(encoder);
-                       manager_ops = manager->ops;
+                       display = exynos_encoder->display;
 
-                       if (manager_ops && manager_ops->mode_set)
-                               manager_ops->mode_set(manager, adjusted_mode);
+                       if (display->ops->mode_set)
+                               display->ops->mode_set(display,
+                                                       adjusted_mode);
 
                        exynos_encoder->old_crtc = encoder->crtc;
                }
 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 {
        struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_manager *manager = exynos_encoder->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-
-       if (manager_ops && manager_ops->commit)
-               manager_ops->commit(manager);
-}
+       struct exynos_drm_display *display = exynos_encoder->display;
 
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
-{
-       struct exynos_drm_encoder *exynos_encoder;
-       struct exynos_drm_manager_ops *ops;
-       struct drm_device *dev = fb->dev;
-       struct drm_encoder *encoder;
+       if (display->ops->dpms)
+               display->ops->dpms(display, DRM_MODE_DPMS_ON);
 
-       /*
-        * make sure that overlay data are updated to real hardware
-        * for all encoders.
-        */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               exynos_encoder = to_exynos_encoder(encoder);
-               ops = exynos_encoder->manager->ops;
-
-               /*
-                * wait for vblank interrupt
-                * - this makes sure that overlay data are updated to
-                *      real hardware.
-                */
-               if (ops->wait_for_vblank)
-                       ops->wait_for_vblank(exynos_encoder->manager);
-       }
+       if (display->ops->commit)
+               display->ops->commit(display);
 }
 
-
 static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
 {
        struct drm_plane *plane;
 
 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
 {
-       struct exynos_drm_encoder *exynos_encoder =
-               to_exynos_encoder(encoder);
-
-       exynos_encoder->manager->pipe = -1;
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
        drm_encoder_cleanup(encoder);
        kfree(exynos_encoder);
        struct drm_encoder *clone;
        struct drm_device *dev = encoder->dev;
        struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_display_ops *display_ops =
-                               exynos_encoder->manager->display_ops;
+       struct exynos_drm_display *display = exynos_encoder->display;
        unsigned int clone_mask = 0;
        int cnt = 0;
 
        list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
-               switch (display_ops->type) {
+               switch (display->type) {
                case EXYNOS_DISPLAY_TYPE_LCD:
                case EXYNOS_DISPLAY_TYPE_HDMI:
                case EXYNOS_DISPLAY_TYPE_VIDI:
 
 struct drm_encoder *
 exynos_drm_encoder_create(struct drm_device *dev,
-                          struct exynos_drm_manager *manager,
+                          struct exynos_drm_display *display,
                           unsigned long possible_crtcs)
 {
        struct drm_encoder *encoder;
        struct exynos_drm_encoder *exynos_encoder;
-       int ret;
 
-       if (!manager || !possible_crtcs)
-               return NULL;
-
-       if (!manager->dev)
+       if (!possible_crtcs)
                return NULL;
 
        exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
        if (!exynos_encoder)
                return NULL;
 
-       exynos_encoder->manager = manager;
+       exynos_encoder->display = display;
        encoder = &exynos_encoder->drm_encoder;
        encoder->possible_crtcs = possible_crtcs;
 
 
        drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
 
-       if (manager->ops && manager->ops->initialize) {
-               ret = manager->ops->initialize(manager, dev);
-               if (ret) {
-                       DRM_ERROR("Manager initialize failed %d\n", ret);
-                       goto error;
-               }
-       }
-
-       if (manager->display_ops && manager->display_ops->initialize) {
-               ret = manager->display_ops->initialize(manager->dev, dev);
-               if (ret) {
-                       DRM_ERROR("Display initialize failed %d\n", ret);
-                       goto error;
-               }
-       }
-
        DRM_DEBUG_KMS("encoder has been created\n");
 
        return encoder;
-
-error:
-       exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
-       return NULL;
 }
 
-struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
 {
-       return to_exynos_encoder(encoder)->manager;
-}
-
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
-                           void (*fn)(struct drm_encoder *, void *))
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_encoder *encoder;
-       struct exynos_drm_private *private = dev->dev_private;
-       struct exynos_drm_manager *manager;
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               /*
-                * if crtc is detached from encoder, check pipe,
-                * otherwise check crtc attached to encoder
-                */
-               if (!encoder->crtc) {
-                       manager = to_exynos_encoder(encoder)->manager;
-                       if (manager->pipe < 0 ||
-                                       private->crtc[manager->pipe] != crtc)
-                               continue;
-               } else {
-                       if (encoder->crtc != crtc)
-                               continue;
-               }
-
-               fn(encoder, data);
-       }
-}
-
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int crtc = *(int *)data;
-
-       if (manager->pipe != crtc)
-               return;
-
-       if (manager_ops->enable_vblank)
-               manager_ops->enable_vblank(manager);
-}
-
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int crtc = *(int *)data;
-
-       if (manager->pipe != crtc)
-               return;
-
-       if (manager_ops->disable_vblank)
-               manager_ops->disable_vblank(manager);
-}
-
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_manager *manager = exynos_encoder->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int mode = *(int *)data;
-
-       if (manager_ops && manager_ops->dpms)
-               manager_ops->dpms(manager, mode);
-
-       /*
-        * if this condition is ok then it means that the crtc is already
-        * detached from encoder and last function for detaching is properly
-        * done, so clear pipe from manager to prevent repeated call.
-        */
-       if (mode > DRM_MODE_DPMS_ON) {
-               if (!encoder->crtc)
-                       manager->pipe = -1;
-       }
-}
-
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       int pipe = *(int *)data;
-
-       /*
-        * when crtc is detached from encoder, this pipe is used
-        * to select manager operation
-        */
-       manager->pipe = pipe;
-}
-
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       struct exynos_drm_overlay *overlay = data;
-
-       if (manager_ops && manager_ops->win_mode_set)
-               manager_ops->win_mode_set(manager, overlay);
-}
-
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int zpos = DEFAULT_ZPOS;
-
-       if (data)
-               zpos = *(int *)data;
-
-       if (manager_ops && manager_ops->win_commit)
-               manager_ops->win_commit(manager, zpos);
-}
-
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int zpos = DEFAULT_ZPOS;
-
-       if (data)
-               zpos = *(int *)data;
-
-       if (manager_ops && manager_ops->win_enable)
-               manager_ops->win_enable(manager, zpos);
-}
-
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int zpos = DEFAULT_ZPOS;
-
-       if (data)
-               zpos = *(int *)data;
-
-       if (manager_ops && manager_ops->win_disable)
-               manager_ops->win_disable(manager, zpos);
+       return to_exynos_encoder(encoder)->display;
 }
 
 
 void exynos_drm_encoder_setup(struct drm_device *dev);
 struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
-                                              struct exynos_drm_manager *mgr,
-                                              unsigned long possible_crtcs);
-struct exynos_drm_manager *
-exynos_drm_get_manager(struct drm_encoder *encoder);
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
-                           void (*fn)(struct drm_encoder *, void *));
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
+                       struct exynos_drm_display *mgr,
+                       unsigned long possible_crtcs);
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
 
 #endif
 
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_iommu.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
 
 #define to_exynos_fb(x)        container_of(x, struct exynos_drm_fb, fb)
 
        unsigned int i;
 
        /* make sure that overlay data are updated before relesing fb. */
-       exynos_drm_encoder_complete_scanout(fb);
+       exynos_drm_crtc_complete_scanout(fb);
 
        drm_framebuffer_cleanup(fb);
 
 
 };
 
 struct fimd_context {
-       struct exynos_drm_subdrv        subdrv;
        struct device                   *dev;
        struct drm_device               *drm_dev;
        int                             irq;
        u32                             vidcon0;
        u32                             vidcon1;
        bool                            suspended;
+       int                             pipe;
        struct mutex                    lock;
        wait_queue_head_t               wait_vsync_queue;
        atomic_t                        wait_vsync_event;
        return (struct fimd_driver_data *)of_id->data;
 }
 
-static bool fimd_display_is_connected(struct device *dev)
+static bool fimd_display_is_connected(struct exynos_drm_display *display)
 {
        /* TODO. */
 
        return true;
 }
 
-static void *fimd_get_panel(struct device *dev)
+static void *fimd_get_panel(struct exynos_drm_display *display)
 {
-       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
-       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_context *ctx = display->ctx;
 
        return &ctx->panel;
 }
 
-static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
+static int fimd_check_mode(struct exynos_drm_display *display,
+                       struct drm_display_mode *mode)
 {
        /* TODO. */
 
 }
 
 static struct exynos_drm_display_ops fimd_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_LCD,
        .is_connected = fimd_display_is_connected,
        .get_panel = fimd_get_panel,
        .check_mode = fimd_check_mode,
 };
 
+static struct exynos_drm_display fimd_display = {
+       .type = EXYNOS_DISPLAY_TYPE_LCD,
+       .ops = &fimd_display_ops,
+};
+
 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
-                       struct drm_device *drm_dev)
+                       struct drm_device *drm_dev, int pipe)
 {
        struct fimd_context *ctx = mgr->ctx;
 
        ctx->drm_dev = drm_dev;
+       ctx->pipe = pipe;
 
-       return 0;
-}
-
-static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
-{
-       struct fimd_context *ctx = mgr->ctx;
-
-       DRM_DEBUG_KMS("%d\n", mode);
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = true, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler.
+        */
+       drm_dev->irq_enabled = true;
 
-       mutex_lock(&ctx->lock);
+       /*
+        * with vblank_disable_allowed = true, vblank interrupt will be disabled
+        * by drm timer once a current process gives up ownership of
+        * vblank event.(after drm_vblank_put function is called)
+        */
+       drm_dev->vblank_disable_allowed = true;
 
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               /*
-                * enable fimd hardware only if suspended status.
-                *
-                * P.S. fimd_dpms function would be called at booting time so
-                * clk_enable could be called double time.
-                */
-               if (ctx->suspended)
-                       pm_runtime_get_sync(ctx->dev);
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               if (!ctx->suspended)
-                       pm_runtime_put_sync(ctx->dev);
-               break;
-       default:
-               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
-               break;
-       }
+       /* attach this sub driver to iommu mapping if supported. */
+       if (is_drm_iommu_supported(ctx->drm_dev))
+               drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
 
-       mutex_unlock(&ctx->lock);
+       return 0;
 }
 
-static void fimd_apply(struct exynos_drm_manager *mgr)
+static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
 {
        struct fimd_context *ctx = mgr->ctx;
-       struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-       struct fimd_win_data *win_data;
-       int i;
 
-       for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
-                       mgr_ops->win_commit(mgr, i);
-       }
-
-       if (mgr_ops && mgr_ops->commit)
-               mgr_ops->commit(mgr);
+       /* detach this sub driver from iommu mapping if supported. */
+       if (is_drm_iommu_supported(ctx->drm_dev))
+               drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
 }
 
 static void fimd_commit(struct exynos_drm_manager *mgr)
        win_data->enabled = false;
 }
 
+static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
+{
+       struct fimd_context *ctx = mgr->ctx;
+
+       DRM_DEBUG_KMS("%d\n", mode);
+
+       mutex_lock(&ctx->lock);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               /*
+                * enable fimd hardware only if suspended status.
+                *
+                * P.S. fimd_dpms function would be called at booting time so
+                * clk_enable could be called double time.
+                */
+               if (ctx->suspended)
+                       pm_runtime_get_sync(ctx->dev);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               if (!ctx->suspended)
+                       pm_runtime_put_sync(ctx->dev);
+               break;
+       default:
+               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+               break;
+       }
+
+       mutex_unlock(&ctx->lock);
+}
+
 static struct exynos_drm_manager_ops fimd_manager_ops = {
        .initialize = fimd_mgr_initialize,
+       .remove = fimd_mgr_remove,
        .dpms = fimd_dpms,
        .commit = fimd_commit,
        .enable_vblank = fimd_enable_vblank,
 };
 
 static struct exynos_drm_manager fimd_manager = {
-       .pipe           = -1,
-       .ops            = &fimd_manager_ops,
-       .display_ops    = &fimd_display_ops,
+       .type = EXYNOS_DISPLAY_TYPE_LCD,
+       .ops = &fimd_manager_ops,
 };
 
 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 {
        struct fimd_context *ctx = (struct fimd_context *)dev_id;
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct exynos_drm_manager *manager = subdrv->manager;
        u32 val;
 
        val = readl(ctx->regs + VIDINTCON1);
                writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
 
        /* check the crtc is detached already from encoder */
-       if (manager->pipe < 0 || !ctx->drm_dev)
+       if (ctx->pipe < 0 || !ctx->drm_dev)
                goto out;
 
-       drm_handle_vblank(ctx->drm_dev, manager->pipe);
-       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
+       drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
 
        /* set wait vsync event to zero and wake up queue. */
        if (atomic_read(&ctx->wait_vsync_event)) {
        return IRQ_HANDLED;
 }
 
-static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
-{
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler.
-        */
-       drm_dev->irq_enabled = true;
-
-       /*
-        * with vblank_disable_allowed = true, vblank interrupt will be disabled
-        * by drm timer once a current process gives up ownership of
-        * vblank event.(after drm_vblank_put function is called)
-        */
-       drm_dev->vblank_disable_allowed = true;
-
-       /* attach this sub driver to iommu mapping if supported. */
-       if (is_drm_iommu_supported(drm_dev))
-               drm_iommu_attach_device(drm_dev, dev);
-
-       return 0;
-}
-
-static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-       /* detach this sub driver from iommu mapping if supported. */
-       if (is_drm_iommu_supported(drm_dev))
-               drm_iommu_detach_device(drm_dev, dev);
-}
-
 static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
 {
        struct videomode *vm = &ctx->panel.vm;
        return 0;
 }
 
-static void fimd_window_suspend(struct device *dev)
+static void fimd_window_suspend(struct exynos_drm_manager *mgr)
 {
-       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
        struct fimd_context *ctx = mgr->ctx;
        struct fimd_win_data *win_data;
        int i;
        fimd_wait_for_vblank(mgr);
 }
 
-static void fimd_window_resume(struct device *dev)
+static void fimd_window_resume(struct exynos_drm_manager *mgr)
 {
-       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
        struct fimd_context *ctx = mgr->ctx;
        struct fimd_win_data *win_data;
        int i;
        }
 }
 
+static void fimd_apply(struct exynos_drm_manager *mgr)
+{
+       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_win_data *win_data;
+       int i;
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               if (win_data->enabled)
+                       fimd_win_commit(mgr, i);
+       }
+
+       fimd_commit(mgr);
+}
+
 static int fimd_activate(struct exynos_drm_manager *mgr, bool enable)
 {
        struct fimd_context *ctx = mgr->ctx;
-       struct device *dev = ctx->subdrv.dev;
 
        if (enable) {
                int ret;
                if (test_and_clear_bit(0, &ctx->irq_flags))
                        fimd_enable_vblank(mgr);
 
-               fimd_window_resume(dev);
+               fimd_window_resume(mgr);
 
                fimd_apply(mgr);
        } else {
-               fimd_window_suspend(dev);
+               fimd_window_suspend(mgr);
 
                fimd_clock(ctx, false);
                ctx->suspended = true;
 {
        struct device *dev = &pdev->dev;
        struct fimd_context *ctx;
-       struct exynos_drm_subdrv *subdrv;
        struct resource *res;
        int win;
        int ret = -EINVAL;
        init_waitqueue_head(&ctx->wait_vsync_queue);
        atomic_set(&ctx->wait_vsync_event, 0);
 
-       fimd_manager.ctx = ctx;
-
-       subdrv = &ctx->subdrv;
-
-       subdrv->dev = dev;
-       subdrv->manager = &fimd_manager;
-       subdrv->probe = fimd_subdrv_probe;
-       subdrv->remove = fimd_subdrv_remove;
-
        mutex_init(&ctx->lock);
 
        platform_set_drvdata(pdev, &fimd_manager);
 
+       fimd_manager.ctx = ctx;
+       exynos_drm_manager_register(&fimd_manager);
+
+       fimd_display.ctx = ctx;
+       exynos_drm_display_register(&fimd_display);
+
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
 
        for (win = 0; win < WINDOWS_NR; win++)
                fimd_clear_win(ctx, win);
 
-       exynos_drm_subdrv_register(subdrv);
-
        return 0;
 }
 
        struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
        struct fimd_context *ctx = mgr->ctx;
 
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
+       exynos_drm_display_unregister(&fimd_display);
+       exynos_drm_manager_unregister(&fimd_manager);
 
        if (ctx->suspended)
                goto out;
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_hdmi.h"
 
-#define to_context(dev)                platform_get_drvdata(to_platform_device(dev))
-#define to_subdrv(dev)         to_context(dev)
-#define get_ctx_from_subdrv(subdrv)    container_of(subdrv,\
-                                       struct drm_hdmi_context, subdrv);
-
 /* platform device pointer for common drm hdmi device. */
 static struct platform_device *exynos_drm_hdmi_pdev;
 
 static struct exynos_mixer_ops *mixer_ops;
 
 struct drm_hdmi_context {
-       struct exynos_drm_subdrv        subdrv;
        struct exynos_drm_hdmi_context  *hdmi_ctx;
        struct exynos_drm_hdmi_context  *mixer_ctx;
 
                mixer_ops = ops;
 }
 
-static int drm_hdmi_display_initialize(struct device *dev,
+static int drm_hdmi_display_initialize(struct exynos_drm_display *display,
                struct drm_device *drm_dev)
 {
-       struct drm_hdmi_context *ctx = to_context(dev);
+       struct drm_hdmi_context *ctx = display->ctx;
 
        if (hdmi_ops && hdmi_ops->initialize)
                return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
 }
 
 
-static bool drm_hdmi_is_connected(struct device *dev)
+static bool drm_hdmi_is_connected(struct exynos_drm_display *display)
 {
-       struct drm_hdmi_context *ctx = to_context(dev);
+       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 device *dev,
+static struct edid *drm_hdmi_get_edid(struct exynos_drm_display *display,
                        struct drm_connector *connector)
 {
-       struct drm_hdmi_context *ctx = to_context(dev);
+       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 0;
 }
 
-static int drm_hdmi_check_mode(struct device *dev,
+static int drm_hdmi_check_mode(struct exynos_drm_display *display,
                struct drm_display_mode *mode)
 {
-       struct drm_hdmi_context *ctx = to_context(dev);
+       struct drm_hdmi_context *ctx = display->ctx;
 
        return drm_hdmi_check_mode_ctx(ctx, mode);
 }
 
-static int drm_hdmi_display_dpms(struct device *dev, int mode)
+static void drm_hdmi_display_dpms(struct exynos_drm_display *display, int mode)
 {
-       struct drm_hdmi_context *ctx = to_context(dev);
+       struct drm_hdmi_context *ctx = display->ctx;
 
        if (hdmi_ops && hdmi_ops->dpms)
                hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-
-       return 0;
 }
 
-static struct exynos_drm_display_ops drm_hdmi_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_HDMI,
-       .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,
-};
-
-static int drm_hdmi_enable_vblank(struct exynos_drm_manager *mgr)
-{
-       struct drm_hdmi_context *ctx = mgr->ctx;
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct exynos_drm_manager *manager = subdrv->manager;
-
-       if (mixer_ops && mixer_ops->enable_vblank)
-               return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
-                                               manager->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_mode_fixup(struct exynos_drm_manager *mgr,
+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 = mgr->ctx;
+       struct drm_hdmi_context *ctx = display->ctx;
        struct drm_display_mode *m;
        int mode_ok;
 
        }
 }
 
-static void drm_hdmi_mode_set(struct exynos_drm_manager *mgr, void *mode)
+static void drm_hdmi_mode_set(struct exynos_drm_display *display,
+                       struct drm_display_mode *mode)
 {
-       struct drm_hdmi_context *ctx = mgr->ctx;
+       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_manager *mgr,
+static void drm_hdmi_get_max_resol(struct exynos_drm_display *display,
                                unsigned int *width, unsigned int *height)
 {
-       struct drm_hdmi_context *ctx = mgr->ctx;
+       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;
                hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
 
-static int drm_hdmi_mgr_initialize(struct exynos_drm_manager *mgr, struct drm_device *drm_dev)
+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);
 
        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;
 
 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,
-       .mode_fixup = drm_hdmi_mode_fixup,
-       .mode_set = drm_hdmi_mode_set,
-       .get_max_resol = drm_hdmi_get_max_resol,
        .commit = drm_hdmi_commit,
        .win_mode_set = drm_mixer_win_mode_set,
        .win_commit = drm_mixer_win_commit,
 };
 
 static struct exynos_drm_manager hdmi_manager = {
-       .pipe           = -1,
+       .type           = EXYNOS_DISPLAY_TYPE_HDMI,
        .ops            = &drm_hdmi_manager_ops,
-       .display_ops    = &drm_hdmi_display_ops,
 };
 
-static int hdmi_subdrv_probe(struct drm_device *drm_dev,
-               struct device *dev)
-{
-       struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
-       struct drm_hdmi_context *ctx;
-
-       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 = get_ctx_from_subdrv(subdrv);
-
-       if (!ctx) {
-               DRM_ERROR("no drm hdmi context.\n");
-               return -EFAULT;
-       }
-
-       ctx->hdmi_ctx = hdmi_ctx;
-       ctx->mixer_ctx = mixer_ctx;
-
-       return 0;
-}
-
-static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-       struct drm_hdmi_context *ctx;
-       struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
-
-       ctx = get_ctx_from_subdrv(subdrv);
-
-       if (mixer_ops->iommu_on)
-               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
-}
-
 static int exynos_drm_hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct exynos_drm_subdrv *subdrv;
        struct drm_hdmi_context *ctx;
 
        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
                return -ENOMEM;
 
        hdmi_manager.ctx = ctx;
+       hdmi_display.ctx = ctx;
 
-       subdrv = &ctx->subdrv;
-
-       subdrv->dev = dev;
-       subdrv->manager = &hdmi_manager;
-       subdrv->probe = hdmi_subdrv_probe;
-       subdrv->remove = hdmi_subdrv_remove;
-
-       platform_set_drvdata(pdev, subdrv);
-
-       exynos_drm_subdrv_register(subdrv);
+       exynos_drm_manager_register(&hdmi_manager);
+       exynos_drm_display_register(&hdmi_display);
 
        return 0;
 }
 
 static int exynos_drm_hdmi_remove(struct platform_device *pdev)
 {
-       struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
-
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
+       exynos_drm_display_unregister(&hdmi_display);
+       exynos_drm_manager_unregister(&hdmi_manager);
 
        return 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;
 };
 
 
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
                        overlay->crtc_x, overlay->crtc_y,
                        overlay->crtc_width, overlay->crtc_height);
 
-       exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
+       exynos_drm_crtc_plane_mode_set(crtc, overlay);
 
        return 0;
 }
        struct exynos_plane *exynos_plane = to_exynos_plane(plane);
        struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 
-       exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-                       exynos_drm_encoder_plane_commit);
+       exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
 }
 
 void exynos_plane_dpms(struct drm_plane *plane, int mode)
                if (exynos_plane->enabled)
                        return;
 
-               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-                               exynos_drm_encoder_plane_enable);
-
+               exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
                exynos_plane->enabled = true;
        } else {
                if (!exynos_plane->enabled)
                        return;
 
-               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-                               exynos_drm_encoder_plane_disable);
-
+               exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
                exynos_plane->enabled = false;
        }
 }
 
 };
 
 struct vidi_context {
-       struct exynos_drm_subdrv        subdrv;
+       struct drm_device               *drm_dev;
        struct drm_crtc                 *crtc;
        struct vidi_win_data            win_data[WINDOWS_NR];
        struct edid                     *raw_edid;
        bool                            direct_vblank;
        struct work_struct              work;
        struct mutex                    lock;
+       int                             pipe;
 };
 
 static const char fake_edid_info[] = {
        0x00, 0x00, 0x00, 0x06
 };
 
-static bool vidi_display_is_connected(struct device *dev)
+static bool vidi_display_is_connected(struct exynos_drm_display *display)
 {
-       struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = display->ctx;
 
        /*
         * connection request would come from user side
        return ctx->connected ? true : false;
 }
 
-static struct edid *vidi_get_edid(struct device *dev,
+static struct edid *vidi_get_edid(struct exynos_drm_display *display,
                        struct drm_connector *connector)
 {
-       struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
-       struct vidi_context *ctx = mgr->ctx;
+       struct vidi_context *ctx = display->ctx;
        struct edid *edid;
 
        /*
        return edid;
 }
 
-static void *vidi_get_panel(struct device *dev)
-{
-       /* TODO. */
-
-       return NULL;
-}
-
-static int vidi_check_mode(struct device *dev, struct drm_display_mode *mode)
+static int vidi_check_mode(struct exynos_drm_display *display,
+                       struct drm_display_mode *mode)
 {
        /* TODO. */
 
 }
 
 static struct exynos_drm_display_ops vidi_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_VIDI,
        .is_connected = vidi_display_is_connected,
        .get_edid = vidi_get_edid,
-       .get_panel = vidi_get_panel,
        .check_mode = vidi_check_mode,
 };
 
+static struct exynos_drm_display vidi_display = {
+       .type = EXYNOS_DISPLAY_TYPE_VIDI,
+       .ops = &vidi_display_ops,
+};
+
 static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
 {
        struct vidi_context *ctx = mgr->ctx;
        /* TODO. */
 }
 
+static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
+                       struct drm_device *drm_dev, int pipe)
+{
+       struct vidi_context *ctx = mgr->ctx;
+
+       DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe);
+
+       ctx->drm_dev = drm_dev;
+       ctx->pipe = pipe;
+
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = 1, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler.
+        */
+       drm_dev->irq_enabled = 1;
+
+       /*
+        * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+        * by drm timer once a current process gives up ownership of
+        * vblank event.(after drm_vblank_put function is called)
+        */
+       drm_dev->vblank_disable_allowed = 1;
+
+       return 0;
+}
+
 static struct exynos_drm_manager_ops vidi_manager_ops = {
+       .initialize = vidi_mgr_initialize,
        .dpms = vidi_dpms,
        .commit = vidi_commit,
        .enable_vblank = vidi_enable_vblank,
 };
 
 static struct exynos_drm_manager vidi_manager = {
-       .pipe           = -1,
-       .ops            = &vidi_manager_ops,
-       .display_ops    = &vidi_display_ops,
+       .type = EXYNOS_DISPLAY_TYPE_VIDI,
+       .ops = &vidi_manager_ops,
 };
 
 static void vidi_fake_vblank_handler(struct work_struct *work)
 {
        struct vidi_context *ctx = container_of(work, struct vidi_context,
                                        work);
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct exynos_drm_manager *manager = subdrv->manager;
 
-       if (manager->pipe < 0)
+       if (ctx->pipe < 0)
                return;
 
        /* refresh rate is about 50Hz. */
        mutex_lock(&ctx->lock);
 
        if (ctx->direct_vblank) {
-               drm_handle_vblank(subdrv->drm_dev, manager->pipe);
+               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
                ctx->direct_vblank = false;
                mutex_unlock(&ctx->lock);
                return;
 
        mutex_unlock(&ctx->lock);
 
-       exynos_drm_crtc_finish_pageflip(subdrv->drm_dev, manager->pipe);
-}
-
-static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
-{
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler.
-        */
-       drm_dev->irq_enabled = true;
-
-       /*
-        * with vblank_disable_allowed = true, vblank interrupt will be disabled
-        * by drm timer once a current process gives up ownership of
-        * vblank event.(after drm_vblank_put function is called)
-        */
-       drm_dev->vblank_disable_allowed = true;
-
-       return 0;
-}
-
-static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-       /* TODO. */
+       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
 }
 
 static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
 
        DRM_DEBUG_KMS("requested connection.\n");
 
-       drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+       drm_helper_hpd_irq_event(ctx->drm_dev);
 
        return len;
 }
 {
        struct vidi_context *ctx = NULL;
        struct drm_encoder *encoder;
-       struct exynos_drm_manager *manager;
-       struct exynos_drm_display_ops *display_ops;
+       struct exynos_drm_display *display;
        struct drm_exynos_vidi_connection *vidi = data;
 
        if (!vidi) {
 
        list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
                                                                head) {
-               manager = exynos_drm_get_manager(encoder);
-               display_ops = manager->display_ops;
+               display = exynos_drm_get_display(encoder);
 
-               if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) {
-                       ctx = manager->ctx;
+               if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
+                       ctx = display->ctx;
                        break;
                }
        }
        }
 
        ctx->connected = vidi->connection;
-       drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+       drm_helper_hpd_irq_event(ctx->drm_dev);
 
        return 0;
 }
 {
        struct device *dev = &pdev->dev;
        struct vidi_context *ctx;
-       struct exynos_drm_subdrv *subdrv;
        int ret;
 
        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
        INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
 
        vidi_manager.ctx = ctx;
-
-       subdrv = &ctx->subdrv;
-       subdrv->dev = dev;
-       subdrv->manager = &vidi_manager;
-       subdrv->probe = vidi_subdrv_probe;
-       subdrv->remove = vidi_subdrv_remove;
+       vidi_display.ctx = ctx;
 
        mutex_init(&ctx->lock);
 
        if (ret < 0)
                DRM_INFO("failed to create connection sysfs.\n");
 
-       exynos_drm_subdrv_register(subdrv);
+       exynos_drm_manager_register(&vidi_manager);
+       exynos_drm_display_register(&vidi_display);
 
        return 0;
 }
 {
        struct vidi_context *ctx = platform_get_drvdata(pdev);
 
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
+       exynos_drm_display_unregister(&vidi_display);
+       exynos_drm_manager_unregister(&vidi_manager);
 
        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
                kfree(ctx->raw_edid);