drm/exynos: Refactor manager/display/overlay
authorSean Paul <seanpaul@chromium.org>
Wed, 24 Oct 2012 21:28:49 +0000 (17:28 -0400)
committerGerrit <chrome-bot@google.com>
Tue, 13 Nov 2012 17:31:10 +0000 (09:31 -0800)
The exynos_drm_manager/display/overlay architecture wasn't really
serving its purpose. It attempted to split callbacks into logical
sections, but those sections didn't really make sense, and required us
to have a layer of abstraction such as exynos_drm_hdmi on top of the
controller and panel to call the appropriate functions.

This patch removes manager/display/overlay as well as exynos_drm_hdmi,
and adds a new abstraction which splits the callbacks to controller and
panel.

Right now, this just cleans things up, making the code a little more
readable. In the short term, it allows us to hook fimd into just
the controller side, and add dp/mipi as panel implementations. In the
long term, it removes all of the device pointers, so we should be able
to remove all of the various platform drivers more easily.

BUG=chrome-os-partner:11158,chrome-os-partner:10717
TEST=Tested on snow, hdmi hotplugged, booted with/without hdmi,
suspend/resume tested. No regressions detected.

Change-Id: Ia1bd6bbd67d49af2abecf36c43bfe765ae00f38d
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/36477
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
16 files changed:
drivers/gpu/drm/exynos/Makefile
drivers/gpu/drm/exynos/exynos_drm_connector.c
drivers/gpu/drm/exynos/exynos_drm_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_display.h [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_encoder.c
drivers/gpu/drm/exynos/exynos_drm_encoder.h
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_hdmi.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_hdmi.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_hdmi.h
drivers/gpu/drm/exynos/exynos_mixer.c

index 98cca4d..b8769d5 100644 (file)
@@ -11,8 +11,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
 exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)    += exynos_drm_fimd.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)    += exynos_hdmi.o exynos_mixer.o \
-                                          exynos_ddc.o exynos_hdmiphy.o \
-                                          exynos_drm_hdmi.o
+                                          exynos_ddc.o exynos_hdmiphy.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DP)      += exynos_dp_core.o exynos_dp_reg.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)    += exynos_drm_vidi.o
 
index ebecea6..911768e 100644 (file)
@@ -31,6 +31,7 @@
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
 #include "exynos_drm_encoder.h"
+#include "exynos_drm_display.h"
 
 #define MAX_EDID 256
 #define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
@@ -39,7 +40,7 @@
 struct exynos_drm_connector {
        struct drm_connector    drm_connector;
        uint32_t                encoder_id;
-       struct exynos_drm_manager *manager;
+       struct exynos_drm_display *display;
 };
 
 /* convert exynos_video_timings to drm_display_mode */
@@ -103,88 +104,114 @@ convert_to_video_timing(struct fb_videomode *timing,
                timing->vmode |= FB_VMODE_DOUBLE;
 }
 
-static int exynos_drm_connector_get_modes(struct drm_connector *connector)
+static struct exynos_drm_display *display_from_connector(
+               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;
-       unsigned int count;
+       return to_exynos_connector(connector)->display;
+}
 
-       DRM_DEBUG_KMS("%s\n", __FILE__);
+static int exynos_drm_connector_get_edid(struct drm_connector *connector)
+{
+       struct exynos_drm_display *display = display_from_connector(connector);
+       int ret;
+       void *edid;
 
-       if (!display_ops) {
-               DRM_DEBUG_KMS("display_ops is null.\n");
-               return 0;
+       if (!display->panel_ops->get_edid)
+               return -EINVAL;
+
+       edid = kzalloc(MAX_EDID, GFP_KERNEL);
+       if (!edid) {
+               DRM_ERROR("failed to allocate edid\n");
+               return -ENOMEM;
        }
 
-       /*
-        * if get_edid() exists then get_edid() callback of hdmi side
-        * is called to get edid data through i2c interface else
-        * get timing from the FIMD driver(display controller).
-        */
-       if (display_ops->get_edid) {
-               int ret;
-               void *edid;
-
-               edid = kzalloc(MAX_EDID, GFP_KERNEL);
-               if (!edid) {
-                       DRM_ERROR("failed to allocate edid\n");
-                       return 0;
-               }
-
-               ret = display_ops->get_edid(manager->dev, connector,
-                                               edid, MAX_EDID);
-               if (ret < 0) {
-                       DRM_ERROR("failed to get edid data.\n");
-                       kfree(edid);
-                       edid = NULL;
-                       return 0;
-               }
-
-               drm_mode_connector_update_edid_property(connector, edid);
-               count = drm_add_edid_modes(connector, edid);
-
-               kfree(connector->display_info.raw_edid);
-               connector->display_info.raw_edid = edid;
-       } else {
-               struct drm_display_mode *mode;
-               struct exynos_drm_panel_info *panel;
-
-               if (display_ops->get_panel)
-                       panel = display_ops->get_panel(manager->dev);
+       ret = display->panel_ops->get_edid(display->panel_ctx,
+                       connector, edid, MAX_EDID);
+       if (ret) {
+               DRM_ERROR("Panel operation get_edid failed %d\n", ret);
+               goto err;
+       }
+
+       ret = drm_mode_connector_update_edid_property(connector, edid);
+       if (ret) {
+               DRM_ERROR("update edid property failed(%d)\n", ret);
+               goto err;
+       }
+
+       ret = drm_add_edid_modes(connector, edid);
+       if (ret < 0) {
+               DRM_ERROR("Add edid modes failed %d\n", ret);
+               goto err;
+       }
+
+       kfree(connector->display_info.raw_edid);
+       connector->display_info.raw_edid = edid;
+
+       return ret;
+
+err:
+       kfree(edid);
+       return ret;
+}
+
+static int exynos_drm_connector_get_panel(struct drm_connector *connector)
+{
+       struct exynos_drm_display *display = display_from_connector(connector);
+       struct drm_display_mode *mode;
+       struct exynos_drm_panel_info *panel;
+       int ret;
+
+       if (!display->controller_ops->get_panel)
+               return -EINVAL;
+
+       panel = display->controller_ops->get_panel(
+                               display->controller_ctx);
+
+       for (ret = 0; panel && ret < MAX_NR_PANELS; ret++) {
+               if (panel[ret].timing.xres == -1 &&
+                   panel[ret].timing.yres == -1)
+                       break;
+
+               mode = drm_mode_create(connector->dev);
+               mode->type = DRM_MODE_TYPE_DRIVER;
+
+               /* Only the first panel is preferred mode */
+               if (ret)
+                       mode->type |= DRM_MODE_TYPE_PREFERRED;
                else
-                       return 0;
-
-               for (count = 0;count < MAX_NR_PANELS;count++) {
-                       if(panel[count].timing.xres == -1 && panel[count].timing.yres == -1) {
-                               DRM_DEBUG_KMS("panel %p count %d\n",panel,count);
-                               break;
-                       }
-                       mode = drm_mode_create(connector->dev);
-                       /* Only the first panel is preferred mode */
-                       mode->type = count ? DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_USERDEF:
-                               DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
-
-                       convert_to_display_mode(mode, &panel[count]);
-                       connector->display_info.width_mm = mode->width_mm;
-                       connector->display_info.height_mm = mode->height_mm;
-                       drm_mode_set_name(mode);
-                       drm_mode_probed_add(connector, mode);
-               }
+                       mode->type |= DRM_MODE_TYPE_USERDEF;
 
+               convert_to_display_mode(mode, &panel[ret]);
+               connector->display_info.width_mm = mode->width_mm;
+               connector->display_info.height_mm = mode->height_mm;
+               drm_mode_set_name(mode);
+               drm_mode_probed_add(connector, mode);
        }
 
-       return count;
+       return ret;
+}
+
+static int exynos_drm_connector_get_modes(struct drm_connector *connector)
+{
+       int ret;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       /*
+        * First try getting modes from EDID. If that doesn't yield any results,
+        * fall back to the panel call.
+        */
+       ret = exynos_drm_connector_get_edid(connector);
+       if (ret > 0)
+               return ret;
+
+       return exynos_drm_connector_get_panel(connector);
 }
 
 static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
                                            struct drm_display_mode *mode)
 {
-       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 = display_from_connector(connector);
        struct fb_videomode timing;
        int ret = MODE_BAD;
 
@@ -192,9 +219,11 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
 
        convert_to_video_timing(&timing, mode);
 
-       if (display_ops && display_ops->check_timing)
-               if (!display_ops->check_timing(manager->dev, (void *)&timing))
-                       ret = MODE_OK;
+       if (!display->panel_ops->check_timing)
+               return ret;
+
+       if (!display->panel_ops->check_timing(display->panel_ctx, &timing))
+               ret = MODE_OK;
 
        return ret;
 }
@@ -231,21 +260,19 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
                                unsigned int max_width, unsigned int max_height)
 {
-       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 = display_from_connector(connector);
        unsigned int width, height;
 
        width = max_width;
        height = max_height;
 
        /*
-        * if specific driver want to find desired_mode using maxmum
+        * If the specific driver wants to find desired_mode using maximum
         * resolution then get max width and height from that driver.
         */
-       if (ops && ops->get_max_resol)
-               ops->get_max_resol(manager->dev, &width, &height);
+       if (display->panel_ops->get_max_res)
+               display->panel_ops->get_max_res(display->panel_ctx, &width,
+                               &height);
 
        return drm_helper_probe_single_connector_modes(connector, width,
                                                        height);
@@ -255,21 +282,16 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
 static enum drm_connector_status
 exynos_drm_connector_detect(struct drm_connector *connector, bool force)
 {
-       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;
-       enum drm_connector_status status = connector_status_disconnected;
+       struct exynos_drm_display *display = display_from_connector(connector);
+       enum drm_connector_status status;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (display_ops && display_ops->is_connected) {
-               if (display_ops->is_connected(manager->dev))
-                       status = connector_status_connected;
-               else
-                       status = connector_status_disconnected;
-       }
+       if (display->panel_ops->is_connected &&
+           display->panel_ops->is_connected(display->panel_ctx))
+               status = connector_status_connected;
+       else
+               status = connector_status_disconnected;
 
        return status;
 }
@@ -297,7 +319,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
                                                   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;
@@ -312,17 +334,17 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 
        connector = &exynos_connector->drm_connector;
 
-       switch (manager->display_ops->type) {
-       case EXYNOS_DISPLAY_TYPE_HDMI:
+       switch (display->display_type) {
+       case EXYNOS_DRM_DISPLAY_TYPE_MIXER:
                type = DRM_MODE_CONNECTOR_HDMIA;
                connector->interlace_allowed = true;
                connector->polled = DRM_CONNECTOR_POLL_HPD;
                break;
-       case EXYNOS_DISPLAY_TYPE_VIDI:
+       case EXYNOS_DRM_DISPLAY_TYPE_VIDI:
                type = DRM_MODE_CONNECTOR_VIRTUAL;
                connector->polled = DRM_CONNECTOR_POLL_HPD;
                break;
-       case EXYNOS_DISPLAY_TYPE_LCD:
+       case EXYNOS_DRM_DISPLAY_TYPE_FIMD:
                type = DRM_MODE_CONNECTOR_eDP;
                break;
        default:
@@ -338,7 +360,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
                goto err_connector;
 
        exynos_connector->encoder_id = encoder->base.id;
-       exynos_connector->manager = manager;
+       exynos_connector->display = display;
        connector->encoder = encoder;
 
        err = drm_mode_connector_attach_encoder(connector, encoder);
index 0aa4290..88212f2 100644 (file)
@@ -31,6 +31,7 @@
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_connector.h"
 #include "exynos_drm_fbdev.h"
+#include "exynos_drm_display.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
 static struct drm_device *drm_dev;
@@ -57,18 +58,16 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev,
                 *
                 * P.S. note that this driver is considered for modularization.
                 */
-               ret = subdrv->probe(dev, subdrv->dev);
+               ret = subdrv->probe(dev, subdrv);
                if (ret)
                        return ret;
        }
 
-       if (!subdrv->manager)
+       if (!subdrv->display)
                return 0;
 
-       subdrv->manager->dev = subdrv->dev;
-
        /* create and initialize a encoder for this sub driver. */
-       encoder = exynos_drm_encoder_create(dev, subdrv->manager,
+       encoder = exynos_drm_encoder_create(dev, subdrv->display,
                        (1 << MAX_CRTC) - 1);
        if (!encoder) {
                DRM_ERROR("failed to create encoder\n");
index 0d15450..23ad023 100644 (file)
@@ -228,6 +228,12 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
        if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
                int mode = DRM_MODE_DPMS_ON;
 
+               /*
+                * TODO(seanpaul): This has the nasty habit of calling the
+                * underlying dpms/power callbacks twice on boot. This code
+                * needs to be cleaned up so this doesn't happen.
+                */
+
                /*
                 * enable hardware(power on) to all encoders hdmi connected
                 * to current crtc.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_display.h b/drivers/gpu/drm/exynos/exynos_drm_display.h
new file mode 100644 (file)
index 0000000..64e213e
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _EXYNOS_DRM_PANEL_H_
+#define _EXYNOS_DRM_PANEL_H_
+
+/*
+ * Callbacks used to manipulate the panel (DP/HDMI/MIPI)
+ *
+ * @subdrv_probe: Used to associate drm_dev with panel context
+ * @is_connected: Returns true if the panel is connected
+ * @get_edid: Fills in edid with mode data from the panel
+ * @check_timing: Returns 0 if the given timing is valid for the panel
+ * @power: Sets the panel's power to mode
+ * @dpms: Same as power, but called in different places. Best to avoid it
+ * @mode_fixup: Copies and optionally alters mode to adjusted_mode
+ * @mode_set: Sets the panel to output mode
+ * @commit: Commits changes to the panel from mode_set
+ * @apply: Same as commit in most cases
+ * @get_max_res: Returns the maximum resolution in width/height
+ */
+struct exynos_panel_ops {
+       int (*subdrv_probe)(void *ctx, struct drm_device *drm_dev);
+       bool (*is_connected)(void *ctx);
+       int (*get_edid)(void *ctx, struct drm_connector *connector,
+                       u8 *edid, int len);
+       int (*check_timing)(void *ctx, void *timing);
+       int (*power)(void *ctx, int mode);
+       int (*dpms)(void *ctx, int mode);
+       void (*mode_fixup)(void *ctx, struct drm_connector *connector,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode);
+       void (*mode_set)(void *ctx, void *mode);
+       void (*commit)(void *ctx);
+       void (*apply)(void *ctx);
+       void (*get_max_res)(void *ctx, unsigned int *width,
+                               unsigned int *height);
+};
+
+/*
+ * Callbacks used to manipulate the controller (FIMD/Mixer)
+ *
+ * @subdrv_probe: Used to associate drm_dev with the controller context
+ * @get_panel: If we're not using edid, return the panel info
+ * @enable_vblank: Enable the controller's vblank interrupt and set pipe
+ * @disable_vblank: Disable the controller's vblank interrupt
+ * @power: Sets the controller's power to mode
+ * @dpms: Same as power, but called in different places. Best to avoid it
+ * @mode_set: Sets the controller to output mode
+ * @page_flip: Updates the controller's dma pointer
+ * @commit: Applies controller level settings (as opposed to window level)
+ * @apply: Commits the changes on all of the controller's windows
+ * @win_commit: Commits the changes on only one window
+ * @win_disable: Disables one of the controller's windows
+ */
+struct exynos_controller_ops {
+       int (*subdrv_probe)(void *ctx, struct drm_device *drm_dev);
+       struct exynos_drm_panel_info *(*get_panel)(void *ctx);
+       int (*enable_vblank)(void *ctx, int pipe);
+       void (*disable_vblank)(void *ctx);
+       int (*power)(void *ctx, int mode);
+       int (*dpms)(void *ctx, int mode);
+       void (*mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
+       void (*page_flip)(void *ctx, struct exynos_drm_overlay *overlay);
+       void (*commit)(void *ctx);
+       void (*apply)(void *ctx);
+       void (*win_commit)(void *ctx, int zpos);
+       void (*win_disable)(void *ctx, int zpos);
+};
+
+enum exynos_drm_display_type {
+       EXYNOS_DRM_DISPLAY_TYPE_FIMD,
+       EXYNOS_DRM_DISPLAY_TYPE_MIXER,
+       EXYNOS_DRM_DISPLAY_TYPE_VIDI,
+       EXYNOS_DRM_DISPLAY_NUM_DISPLAYS,
+};
+
+/*
+ * The various bits we need to keep track of to manipulate the hardware from
+ * the connector/encoder/crtc drm callbacks.
+ *
+ * @display_type: The type of display, depends on which CONFIGs are enabled
+ * @subdrv: The exynos drm sub driver pointer
+ * @panel_ops: The panel callbacks to use
+ * @controller_ops: The controller callbacks to use
+ * @panel_ctx: The context pointer to pass to panel callbacks
+ * @controller_ctx: The context pointer to pass to controller callbacks
+ * @pipe: The current pipe number for this display
+ */
+struct exynos_drm_display {
+       enum exynos_drm_display_type display_type;
+       struct exynos_drm_subdrv *subdrv;
+       struct exynos_panel_ops *panel_ops;
+       struct exynos_controller_ops *controller_ops;
+       void *panel_ctx;
+       void *controller_ctx;
+       int pipe;
+};
+
+/*
+ * Used by the hardware drivers to attach panel and controller callbacks and
+ * contexts to a display.
+ */
+void exynos_display_attach_panel(enum exynos_drm_display_type type,
+               struct exynos_panel_ops *ops, void *ctx);
+void exynos_display_attach_controller(enum exynos_drm_display_type type,
+               struct exynos_controller_ops *ops, void *ctx);
+
+/* Initializes the given display to type */
+int exynos_display_init(struct exynos_drm_display *display,
+               enum exynos_drm_display_type type);
+
+/* Cleans up the given display */
+void exynos_display_remove(struct exynos_drm_display *display);
+
+#endif
index 69c7241..f7c9a43 100644 (file)
@@ -40,6 +40,7 @@
 #include "exynos_drm_plane.h"
 #include "exynos_drm_vidi.h"
 #include "exynos_drm_dmabuf.h"
+#include "exynos_drm_display.h"
 
 #define DRIVER_NAME    "exynos"
 #define DRIVER_DESC    "Samsung SoC DRM"
@@ -342,12 +343,116 @@ static struct platform_driver exynos_drm_platform_driver = {
        },
 };
 
-static int __init exynos_drm_init(void)
+/* TODO (seanpaul): Once we remove platform drivers, we'll be calling the
+ * various panel/controller init functions directly. These init functions will
+ * return to us the ops and context, so we can get rid of these attach
+ * functions. Once the attach functions are gone, we can move this array of
+ * display pointers into the drm device's platform data.
+ *
+ * For now, we'll use a global to keep track of things.
+ */
+static struct exynos_drm_display *displays[EXYNOS_DRM_DISPLAY_NUM_DISPLAYS];
+
+void exynos_display_attach_panel(enum exynos_drm_display_type type,
+               struct exynos_panel_ops *ops, void *ctx)
 {
+       int i;
+       for (i = 0; i < EXYNOS_DRM_DISPLAY_NUM_DISPLAYS; i++) {
+               if (displays[i]->display_type == type) {
+                       displays[i]->panel_ctx = ctx;
+                       displays[i]->panel_ops = ops;
+                       return;
+               }
+       }
+}
+
+void exynos_display_attach_controller(enum exynos_drm_display_type type,
+               struct exynos_controller_ops *ops, void *ctx)
+{
+       int i;
+       for (i = 0; i < EXYNOS_DRM_DISPLAY_NUM_DISPLAYS; i++) {
+               if (displays[i]->display_type == type) {
+                       displays[i]->controller_ctx = ctx;
+                       displays[i]->controller_ops = ops;
+                       return;
+               }
+       }
+}
+
+static int display_subdrv_probe(struct drm_device *drm_dev,
+               struct exynos_drm_subdrv *subdrv)
+{
+       struct exynos_drm_display *display = subdrv->display;
        int ret;
 
+       if (!display->controller_ops || !display->panel_ops)
+               return -EINVAL;
+
+       if (display->controller_ops->subdrv_probe) {
+               ret = display->controller_ops->subdrv_probe(
+                               display->controller_ctx, drm_dev);
+               if (ret)
+                       return ret;
+       }
+
+       if (display->panel_ops->subdrv_probe) {
+               ret = display->panel_ops->subdrv_probe(display->panel_ctx,
+                               drm_dev);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int exynos_display_init(struct exynos_drm_display *display,
+               enum exynos_drm_display_type type)
+{
+       struct exynos_drm_subdrv *subdrv;
+
+       subdrv = kzalloc(sizeof(*subdrv), GFP_KERNEL);
+       if (!subdrv) {
+               DRM_ERROR("Failed to allocate display subdrv\n");
+               return -ENOMEM;
+       }
+
+       display->display_type = type;
+       display->pipe = -1;
+       display->subdrv = subdrv;
+
+       subdrv->probe = display_subdrv_probe;
+       subdrv->display = display;
+       exynos_drm_subdrv_register(subdrv);
+
+       return 0;
+}
+
+void exynos_display_remove(struct exynos_drm_display *display)
+{
+       if (display->subdrv) {
+               exynos_drm_subdrv_unregister(display->subdrv);
+               kfree(display->subdrv);
+       }
+}
+
+static int __init exynos_drm_init(void)
+{
+       int ret, i;
+
        DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
+       for (i = 0; i < EXYNOS_DRM_DISPLAY_NUM_DISPLAYS; i++) {
+               displays[i] = kzalloc(sizeof(*displays[i]), GFP_KERNEL);
+               if (!displays[i]) {
+                       ret = -ENOMEM;
+                       goto out_display;
+               }
+
+               ret = exynos_display_init(displays[i], i);
+               if (ret)
+                       goto out_display;
+       }
+
 #ifdef CONFIG_DRM_EXYNOS_FIMD
        ret = platform_driver_register(&fimd_driver);
        if (ret < 0)
@@ -367,9 +472,6 @@ static int __init exynos_drm_init(void)
        ret = platform_driver_register(&mixer_driver);
        if (ret < 0)
                goto out_mixer;
-       ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
-       if (ret < 0)
-               goto out_common_hdmi;
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_VIDI
@@ -391,8 +493,6 @@ out_vidi:
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-       platform_driver_unregister(&exynos_drm_common_hdmi_driver);
-out_common_hdmi:
        platform_driver_unregister(&mixer_driver);
 out_mixer:
        platform_driver_unregister(&hdmi_driver);
@@ -405,17 +505,26 @@ out_dp_driver:
        platform_driver_unregister(&fimd_driver);
 out_fimd:
 #endif
+out_display:
+       for (i = 0; i < EXYNOS_DRM_DISPLAY_NUM_DISPLAYS; i++) {
+               if (!displays[i])
+                       continue;
+
+               exynos_display_remove(displays[i]);
+               kfree(displays[i]);
+       }
        return ret;
 }
 
 static void __exit exynos_drm_exit(void)
 {
+       int i;
+
        DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
        platform_driver_unregister(&exynos_drm_platform_driver);
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-       platform_driver_unregister(&exynos_drm_common_hdmi_driver);
        platform_driver_unregister(&mixer_driver);
        platform_driver_unregister(&hdmi_driver);
 #endif
@@ -428,6 +537,14 @@ static void __exit exynos_drm_exit(void)
 #ifdef CONFIG_DRM_EXYNOS_FIMD
        platform_driver_unregister(&fimd_driver);
 #endif
+
+       for (i = 0; i < EXYNOS_DRM_DISPLAY_NUM_DISPLAYS; i++) {
+               if (!displays[i])
+                       continue;
+
+               exynos_display_remove(displays[i]);
+               kfree(displays[i]);
+       }
 }
 
 module_init(exynos_drm_init);
index 62b6da6..ba49da7 100644 (file)
@@ -53,36 +53,10 @@ struct drm_device;
 struct exynos_drm_overlay;
 struct drm_connector;
 struct exynos_drm_gem_object;
+struct exynos_drm_display;
 
 extern unsigned int drm_vblank_offdelay;
 
-/* this enumerates display type. */
-enum exynos_drm_output_type {
-       EXYNOS_DISPLAY_TYPE_NONE,
-       /* RGB or CPU Interface. */
-       EXYNOS_DISPLAY_TYPE_LCD,
-       /* HDMI Interface. */
-       EXYNOS_DISPLAY_TYPE_HDMI,
-       /* Virtual Display Interface. */
-       EXYNOS_DISPLAY_TYPE_VIDI,
-};
-
-/*
- * Exynos drm overlay ops structure.
- *
- * @mode_set: copy drm overlay info to hw specific overlay info.
- * @commit: apply hardware specific overlay data to registers.
- * @disable: disable hardware specific overlay.
- */
-struct exynos_drm_overlay_ops {
-       void (*mode_set)(struct device *subdrv_dev,
-                        struct exynos_drm_overlay *overlay);
-       void (*page_flip)(struct device *subdrv_dev,
-                        struct exynos_drm_overlay *overlay);
-       void (*commit)(struct device *subdrv_dev, int zpos);
-       void (*disable)(struct device *subdrv_dev, int zpos);
-};
-
 /*
  * Exynos drm common overlay structure.
  *
@@ -147,80 +121,6 @@ struct exynos_drm_overlay {
        bool activated;
 };
 
-/*
- * 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.
- * @is_connected: check for that display is connected or not.
- * @get_edid: get edid modes from display driver.
- * @get_panel: get panel object from display driver.
- * @check_timing: check if timing is valid or not.
- * @power_on: display device on or off.
- */
-struct exynos_drm_display_ops {
-       enum exynos_drm_output_type type;
-       bool (*is_connected)(struct device *dev);
-       int (*get_edid)(struct device *dev, struct drm_connector *connector,
-                               u8 *edid, int len);
-       void *(*get_panel)(struct device *dev);
-       int (*check_timing)(struct device *dev, void *timing);
-       int (*power_on)(struct device *dev, int mode);
-};
-
-/*
- * Exynos drm manager ops
- *
- * @dpms: control device power.
- * @apply: set timing, vblank and overlay data to registers.
- * @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_ops {
-       void (*dpms)(struct device *subdrv_dev, int mode);
-       void (*apply)(struct device *subdrv_dev);
-       void (*mode_fixup)(struct device *subdrv_dev,
-                               struct drm_connector *connector,
-                               struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode);
-       void (*mode_set)(struct device *subdrv_dev, void *mode);
-       void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
-                               unsigned int *height);
-       void (*commit)(struct device *subdrv_dev);
-       int (*enable_vblank)(struct device *subdrv_dev);
-       void (*disable_vblank)(struct device *subdrv_dev);
-};
-
-/*
- * Exynos drm common manager structure.
- *
- * @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.
- * @overlay_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 overlay reigsters.
- * @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.
- */
-struct exynos_drm_manager {
-       struct device *dev;
-       int pipe;
-       struct exynos_drm_manager_ops *ops;
-       struct exynos_drm_overlay_ops *overlay_ops;
-       struct exynos_drm_display_ops *display_ops;
-};
-
 /*
  * Exynos drm private structure.
  */
@@ -254,8 +154,7 @@ struct exynos_drm_private {
  * @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().
- * @manager: subdrv has its own manager to control a hardware appropriately
- *     and we can access a hardware drawing on this manager.
+ * @display: A pointer to the display structure for this sub driver
  * @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
@@ -269,9 +168,10 @@ struct exynos_drm_subdrv {
        struct list_head list;
        struct device *dev;
        struct drm_device *drm_dev;
-       struct exynos_drm_manager *manager;
+       struct exynos_drm_display *display;
 
-       int (*probe)(struct drm_device *drm_dev, struct device *dev);
+       int (*probe)(struct drm_device *drm_dev,
+                       struct exynos_drm_subdrv *subdrv);
        void (*remove)(struct drm_device *dev);
        int (*open)(struct drm_device *drm_dev, struct device *dev,
                        struct drm_file *file);
index bf6e597..d203dda 100644 (file)
@@ -32,6 +32,7 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
+#include "exynos_drm_display.h"
 
 #define to_exynos_encoder(x)   container_of(x, struct exynos_drm_encoder,\
                                drm_encoder)
  * 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: specific encoder has its own display to control a hardware
+ *     appropriately and we can access a hardware drawing on this display.
  * @dpms: store the encoder dpms value.
  */
 struct exynos_drm_encoder {
-       struct drm_encoder              drm_encoder;
-       struct exynos_drm_manager       *manager;
+       struct drm_encoder drm_encoder;
+       struct exynos_drm_display *display;
        int dpms;
 };
 
@@ -54,19 +55,48 @@ static void exynos_drm_display_power(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       struct exynos_drm_display_ops *display_ops =
-                                                       manager->display_ops;
-
-                       DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
-                                       connector->base.id, mode);
-                       if (display_ops && display_ops->power_on)
-                               display_ops->power_on(manager->dev, mode);
+               if (connector->encoder != encoder)
+                       continue;
+
+               DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", connector->base.id,
+                               mode);
+
+               /* We want to make sure we order things correctly here. When
+                * turning on, start the controller, then the panel. When
+                * turning off, do the reverse.
+                */
+               switch (mode) {
+               case DRM_MODE_DPMS_ON:
+                       if (display->controller_ops->power)
+                               display->controller_ops->power(
+                                               display->controller_ctx, mode);
+
+                       if (display->panel_ops->power)
+                               display->panel_ops->power(display->panel_ctx,
+                                               mode);
+
                        exynos_encoder->dpms = mode;
+                       break;
+               case DRM_MODE_DPMS_STANDBY:
+               case DRM_MODE_DPMS_SUSPEND:
+               case DRM_MODE_DPMS_OFF:
+                       if (display->panel_ops->power)
+                               display->panel_ops->power(display->panel_ctx,
+                                               mode);
+
+                       if (display->controller_ops->power)
+                               display->controller_ops->power(
+                                               display->controller_ctx, mode);
+
+                       exynos_encoder->dpms = mode;
+                       break;
+               default:
+                       DRM_ERROR("Unknown dpms mode: %d\n", mode);
+                       break;
                }
        }
 }
@@ -74,8 +104,7 @@ static void exynos_drm_display_power(struct drm_encoder *encoder, int mode)
 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
        DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
@@ -90,8 +119,12 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
-               if (manager_ops && manager_ops->apply)
-                       manager_ops->apply(manager->dev);
+               if (display->controller_ops->apply)
+                       display->controller_ops->apply(display->controller_ctx);
+
+               if (display->panel_ops->apply)
+                       display->panel_ops->apply(display->panel_ctx);
+
                exynos_drm_display_power(encoder, mode);
                break;
        case DRM_MODE_DPMS_STANDBY:
@@ -114,16 +147,17 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        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->dev, connector,
-                                                       mode, adjusted_mode);
+               if (connector->encoder != encoder)
+                       continue;
+
+               if (display->panel_ops->mode_fixup)
+                       display->panel_ops->mode_fixup(display->panel_ctx,
+                                       connector, mode, adjusted_mode);
        }
 
        return true;
@@ -135,23 +169,23 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
 {
        struct drm_device *dev = encoder->dev;
        struct drm_connector *connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev,
                                                encoder->crtc);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       if (manager_ops && manager_ops->mode_set)
-                               manager_ops->mode_set(manager->dev,
-                                                       adjusted_mode);
+               if (connector->encoder != encoder)
+                       continue;
 
-                       if (overlay_ops && overlay_ops->mode_set)
-                               overlay_ops->mode_set(manager->dev, overlay);
-               }
+               if (display->panel_ops->mode_set)
+                       display->panel_ops->mode_set(display->panel_ctx,
+                                       adjusted_mode);
+
+               if (display->controller_ops->mode_set)
+                       display->controller_ops->mode_set(
+                                       display->controller_ctx, overlay);
        }
 }
 
@@ -164,13 +198,14 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
 
 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 {
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
+       if (display->controller_ops->commit)
+               display->controller_ops->commit(display->controller_ctx);
 
-       if (manager_ops && manager_ops->commit)
-               manager_ops->commit(manager->dev);
+       if (display->panel_ops->commit)
+               display->panel_ops->commit(display->panel_ctx);
 }
 
 static struct drm_crtc *
@@ -190,12 +225,11 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
 
 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
 {
-       struct exynos_drm_encoder *exynos_encoder =
-               to_exynos_encoder(encoder);
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       exynos_encoder->manager->pipe = -1;
+       exynos_encoder->display->pipe = -1;
 
        drm_encoder_cleanup(encoder);
        kfree(exynos_encoder);
@@ -209,17 +243,15 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *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_drm_get_display(encoder);
        unsigned int clone_mask = 0;
        int cnt = 0;
 
        list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
-               switch (display_ops->type) {
-               case EXYNOS_DISPLAY_TYPE_LCD:
-               case EXYNOS_DISPLAY_TYPE_HDMI:
-               case EXYNOS_DISPLAY_TYPE_VIDI:
+               switch (display->display_type) {
+               case EXYNOS_DRM_DISPLAY_TYPE_FIMD:
+               case EXYNOS_DRM_DISPLAY_TYPE_MIXER:
+               case EXYNOS_DRM_DISPLAY_TYPE_VIDI:
                        clone_mask |= (1 << (cnt++));
                        break;
                default:
@@ -242,7 +274,7 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
 
 struct drm_encoder *
 exynos_drm_encoder_create(struct drm_device *dev,
-                          struct exynos_drm_manager *manager,
+                          struct exynos_drm_display *display,
                           unsigned int possible_crtcs)
 {
        struct drm_encoder *encoder;
@@ -250,10 +282,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (!manager || !possible_crtcs)
-               return NULL;
-
-       if (!manager->dev)
+       if (!display || !possible_crtcs)
                return NULL;
 
        exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
@@ -263,7 +292,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
        }
 
        exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
-       exynos_encoder->manager = manager;
+       exynos_encoder->display = display;
        encoder = &exynos_encoder->drm_encoder;
        encoder->possible_crtcs = possible_crtcs;
 
@@ -279,9 +308,9 @@ exynos_drm_encoder_create(struct drm_device *dev,
        return encoder;
 }
 
-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;
+       return to_exynos_encoder(encoder)->display;
 }
 
 void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
@@ -290,7 +319,7 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
        struct drm_device *dev = crtc->dev;
        struct drm_encoder *encoder;
        struct exynos_drm_private *private = dev->dev_private;
-       struct exynos_drm_manager *manager;
+       struct exynos_drm_display *display;
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                /*
@@ -298,13 +327,12 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
                 * 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)
+                       display = exynos_drm_get_display(encoder);
+                       if (display->pipe < 0 ||
+                                       private->crtc[display->pipe] != crtc)
                                continue;
+               } else if (encoder->crtc != crtc) {
+                       continue;
                }
 
                fn(encoder, data);
@@ -313,51 +341,56 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *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;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        int crtc = *(int *)data;
 
-       if (manager->pipe == -1)
-               manager->pipe = crtc;
+       if (display->pipe == -1)
+               display->pipe = crtc;
 
-       if (manager_ops->enable_vblank)
-               manager_ops->enable_vblank(manager->dev);
+       /* TODO(seanpaul): Fix the pipe interaction here */
+       if (display->controller_ops->enable_vblank)
+               display->controller_ops->enable_vblank(display->controller_ctx,
+                               display->pipe);
 }
 
 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;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        int crtc = *(int *)data;
 
-       if (manager->pipe == -1)
-               manager->pipe = crtc;
+       /*
+        * TODO(seanpaul): This seems like a hack. I don't think it's actually
+        * needed for 2 reasons:
+        *   (1) disable_vblank implies vblank has been enabled. If
+        *       enable_vblank hasn't already been called, that's a bug.
+        *   (2) Even if (1) isn't true, this function should just disable an
+        *       interrupt, and shouldn't affect pipe.
+        */
+       if (display->pipe == -1)
+               display->pipe = crtc;
 
-       if (manager_ops->disable_vblank)
-               manager_ops->disable_vblank(manager->dev);
+       if (display->controller_ops->disable_vblank)
+               display->controller_ops->disable_vblank(
+                               display->controller_ctx);
 }
 
 void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
                                          void *data)
 {
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        int zpos = DEFAULT_ZPOS;
 
        if (data)
                zpos = *(int *)data;
 
-       if (overlay_ops && overlay_ops->commit)
-               overlay_ops->commit(manager->dev, zpos);
+       if (display->controller_ops->win_commit)
+               display->controller_ops->win_commit(display->controller_ctx,
+                               zpos);
 }
 
 void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
 {
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        int crtc = *(int *)data;
        int zpos = DEFAULT_ZPOS;
 
@@ -365,9 +398,9 @@ void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
 
        /*
         * when crtc is detached from encoder, this pipe is used
-        * to select manager operation
+        * to select display operation
         */
-       manager->pipe = crtc;
+       display->pipe = crtc;
 
        exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
 }
@@ -385,15 +418,39 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
 {
        struct drm_device *dev = encoder->dev;
        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;
+       struct exynos_drm_display *display = exynos_encoder->display;
        struct drm_connector *connector;
        int mode = *(int *)data;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (manager_ops && manager_ops->dpms)
-               manager_ops->dpms(manager->dev, mode);
+       /* We want to make sure we order things correctly here. When turning on,
+        * start the controller, then the panel. When turning off, do the
+        * reverse.
+        */
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               if (display->controller_ops->dpms)
+                       display->controller_ops->dpms(display->controller_ctx,
+                                       mode);
+
+               if (display->panel_ops->dpms)
+                       display->panel_ops->dpms(display->panel_ctx, mode);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               if (display->panel_ops->dpms)
+                       display->panel_ops->dpms(display->panel_ctx, mode);
+
+               if (display->controller_ops->dpms)
+                       display->controller_ops->dpms(display->controller_ctx,
+                                       mode);
+               break;
+       default:
+               DRM_ERROR("Unknown dpms mode: %d\n", mode);
+               break;
+       }
 
        /*
         * set current dpms mode to the connector connected to
@@ -407,30 +464,27 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
        /*
         * 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.
+        * done, so clear pipe from display to prevent repeated call.
         */
        if (mode > DRM_MODE_DPMS_ON) {
                if (!encoder->crtc)
-                       manager->pipe = -1;
+                       display->pipe = -1;
        }
 }
 
 void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
 {
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        struct exynos_drm_overlay *overlay = data;
 
-       if (overlay_ops && overlay_ops->mode_set)
-               overlay_ops->mode_set(manager->dev, overlay);
+       if (display->controller_ops->mode_set)
+               display->controller_ops->mode_set(display->controller_ctx,
+                               overlay);
 }
 
 void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
 {
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        int zpos = DEFAULT_ZPOS;
 
        DRM_DEBUG_KMS("\n");
@@ -438,17 +492,17 @@ void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
        if (data)
                zpos = *(int *)data;
 
-       if (overlay_ops && overlay_ops->disable)
-               overlay_ops->disable(manager->dev, zpos);
+       if (display->controller_ops->win_disable)
+               display->controller_ops->win_disable(display->controller_ctx,
+                               zpos);
 }
 
 void exynos_drm_encoder_crtc_page_flip(struct drm_encoder *encoder, void *data)
 {
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        struct exynos_drm_overlay *overlay = data;
 
-       if (overlay_ops && overlay_ops->page_flip)
-               overlay_ops->page_flip(manager->dev, overlay);
+       if (display->controller_ops->page_flip)
+               display->controller_ops->page_flip(display->controller_ctx,
+                               overlay);
 }
index f206c20..af9b762 100644 (file)
 #ifndef _EXYNOS_DRM_ENCODER_H_
 #define _EXYNOS_DRM_ENCODER_H_
 
-struct exynos_drm_manager;
+struct exynos_drm_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 int possible_crtcs);
-struct exynos_drm_manager *
-exynos_drm_get_manager(struct drm_encoder *encoder);
+                       struct exynos_drm_display *display,
+                       unsigned int possible_crtcs);
+struct exynos_drm_display *exynos_drm_get_display(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);
index 09b1978..af5f824 100644 (file)
@@ -26,6 +26,7 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_fbdev.h"
+#include "exynos_drm_display.h"
 
 /*
  * FIMD is stand for Fully Interactive Mobile Display and
@@ -76,7 +77,9 @@ struct fimd_win_data {
 };
 
 struct fimd_context {
-       struct exynos_drm_subdrv        subdrv;
+       struct drm_device               *drm_dev;
+       enum disp_panel_type            panel_type;
+       int                             pipe;
        int                             irq;
        struct drm_crtc                 *crtc;
        struct clk                      *bus_clk;
@@ -105,7 +108,7 @@ void exynos_fimd_dp_attach(struct device *dev)
        dp_dev = dev;
 }
 
-static bool fimd_display_is_connected(struct device *dev)
+static bool fimd_display_is_connected(void *ctx)
 {
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -114,32 +117,31 @@ static bool fimd_display_is_connected(struct device *dev)
        return true;
 }
 
-static void *fimd_get_panel(struct device *dev)
+static struct exynos_drm_panel_info *fimd_get_panel(void *ctx)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       return ctx->panel;
+       return fimd_ctx->panel;
 }
 
-static int fimd_check_timing(struct device *dev, void *timing)
+static int fimd_check_timing(void *ctx, void *timing)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        struct fb_videomode *check_timing = timing;
        int i;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        for (i = 0;i< MAX_NR_PANELS;i++) {
-               if (ctx->panel[i].timing.xres == -1 &&
-                        ctx->panel[i].timing.yres == -1)
+               if (fimd_ctx->panel[i].timing.xres == -1 &&
+                   fimd_ctx->panel[i].timing.yres == -1)
                         break;
 
-               if (ctx->panel[i].timing.xres == check_timing->xres &&
-                        ctx->panel[i].timing.yres == check_timing->yres &&
-                       ctx->panel[i].timing.refresh == check_timing->refresh
-                       )
+               if (fimd_ctx->panel[i].timing.xres == check_timing->xres &&
+                   fimd_ctx->panel[i].timing.yres == check_timing->yres &&
+                   fimd_ctx->panel[i].timing.refresh == check_timing->refresh)
                        return 0;
        }
 
@@ -148,9 +150,9 @@ static int fimd_check_timing(struct device *dev, void *timing)
 
 static int fimd_power_on(struct fimd_context *ctx, bool enable);
 
-static int fimd_display_power_on(struct device *dev, int mode)
+static int fimd_power(void *ctx, int mode)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        bool enable;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -169,78 +171,50 @@ static int fimd_display_power_on(struct device *dev, int mode)
                return -EINVAL;
        }
 
-       fimd_power_on(ctx, enable);
+       fimd_power_on(fimd_ctx, enable);
 
        return 0;
 }
 
-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_timing = fimd_check_timing,
-       .power_on = fimd_display_power_on,
-};
-
-static void fimd_apply(struct device *subdrv_dev)
-{
-       struct fimd_context *ctx = get_fimd_context(subdrv_dev);
-       struct exynos_drm_manager *mgr = ctx->subdrv.manager;
-       struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-       struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
-       struct fimd_win_data *win_data;
-       int i;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled && (ovl_ops && ovl_ops->commit))
-                       ovl_ops->commit(subdrv_dev, i);
-       }
-
-       if (mgr_ops && mgr_ops->commit)
-               mgr_ops->commit(subdrv_dev);
-}
-
-static void fimd_commit(struct device *dev)
+static void fimd_commit(void *ctx)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
-       struct exynos_drm_panel_info *panel = &ctx->panel[ctx->idx];
+       struct fimd_context *fimd_ctx = ctx;
+       struct exynos_drm_panel_info *panel = &fimd_ctx->panel[fimd_ctx->idx];
        struct fb_videomode *timing = &panel->timing;
        u32 val;
 
-       if (ctx->suspended)
+       if (fimd_ctx->suspended)
                return;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        /* setup polarity values from machine code. */
-       writel(ctx->vidcon1, ctx->regs + VIDCON1);
+       writel(fimd_ctx->vidcon1, fimd_ctx->regs + VIDCON1);
 
        /* setup vertical timing values. */
        val = VIDTCON0_VBPD(timing->upper_margin - 1) |
               VIDTCON0_VFPD(timing->lower_margin - 1) |
               VIDTCON0_VSPW(timing->vsync_len - 1);
-       writel(val, ctx->regs + VIDTCON0);
+       writel(val, fimd_ctx->regs + VIDTCON0);
 
        /* setup horizontal timing values.  */
        val = VIDTCON1_HBPD(timing->left_margin - 1) |
               VIDTCON1_HFPD(timing->right_margin - 1) |
               VIDTCON1_HSPW(timing->hsync_len - 1);
-       writel(val, ctx->regs + VIDTCON1);
+       writel(val, fimd_ctx->regs + VIDTCON1);
 
        /* setup horizontal and vertical display size. */
        val = VIDTCON2_LINEVAL(timing->yres - 1) |
               VIDTCON2_HOZVAL(timing->xres - 1);
-       writel(val, ctx->regs + VIDTCON2);
+       writel(val, fimd_ctx->regs + VIDTCON2);
 
        /* setup clock source, clock divider, enable dma. */
-       val = ctx->vidcon0;
+       val = fimd_ctx->vidcon0;
        val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
 
-       if (ctx->clkdiv[ctx->idx] > 1)
-               val |= VIDCON0_CLKVAL_F(ctx->clkdiv[ctx->idx] - 1) | VIDCON0_CLKDIR;
+       if (fimd_ctx->clkdiv[fimd_ctx->idx] > 1)
+               val |= VIDCON0_CLKVAL_F(fimd_ctx->clkdiv[fimd_ctx->idx] - 1) |
+                       VIDCON0_CLKDIR;
        else
                val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
 
@@ -249,21 +223,28 @@ static void fimd_commit(struct device *dev)
         * at vsync(same as dma start)
         */
        val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
-       writel(val, ctx->regs + VIDCON0);
+       writel(val, fimd_ctx->regs + VIDCON0);
 }
 
-static int fimd_enable_vblank(struct device *dev)
+static struct exynos_panel_ops fimd_panel_ops = {
+       .is_connected = fimd_display_is_connected,
+       .check_timing = fimd_check_timing,
+};
+
+static int fimd_enable_vblank(void *ctx, int pipe)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        u32 val;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (ctx->suspended)
+       fimd_ctx->pipe = pipe;
+
+       if (fimd_ctx->suspended)
                return -EPERM;
 
-       if (!test_and_set_bit(0, &ctx->irq_flags)) {
-               val = readl(ctx->regs + VIDINTCON0);
+       if (!test_and_set_bit(0, &fimd_ctx->irq_flags)) {
+               val = readl(fimd_ctx->regs + VIDINTCON0);
 
                val |= VIDINTCON0_INT_ENABLE;
                val |= VIDINTCON0_INT_FRAME;
@@ -273,73 +254,69 @@ static int fimd_enable_vblank(struct device *dev)
                val &= ~VIDINTCON0_FRAMESEL1_MASK;
                val |= VIDINTCON0_FRAMESEL1_NONE;
 
-               writel(val, ctx->regs + VIDINTCON0);
+               writel(val, fimd_ctx->regs + VIDINTCON0);
        }
 
        return 0;
 }
 
-static void fimd_disable_vblank(struct device *dev)
+static void fimd_disable_vblank(void *ctx)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        u32 val;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (ctx->suspended)
+       if (fimd_ctx->suspended)
                return;
 
-       if (test_and_clear_bit(0, &ctx->irq_flags)) {
-               val = readl(ctx->regs + VIDINTCON0);
+       if (test_and_clear_bit(0, &fimd_ctx->irq_flags)) {
+               val = readl(fimd_ctx->regs + VIDINTCON0);
 
                val &= ~VIDINTCON0_INT_FRAME;
                val &= ~VIDINTCON0_INT_ENABLE;
 
-               writel(val, ctx->regs + VIDINTCON0);
+               writel(val, fimd_ctx->regs + VIDINTCON0);
        }
 }
 
-static struct exynos_drm_manager_ops fimd_manager_ops = {
-       .apply = fimd_apply,
-       .commit = fimd_commit,
-       .enable_vblank = fimd_enable_vblank,
-       .disable_vblank = fimd_disable_vblank,
-};
-
-static void fimd_win_mode_set(struct device *dev,
-                             struct exynos_drm_overlay *overlay)
+static void fimd_win_mode_set(void *ctx, struct exynos_drm_overlay *overlay)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        struct fimd_win_data *win_data;
-       int win;
+       int i, win;
        unsigned long offset;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (!overlay) {
-               dev_err(dev, "overlay is NULL\n");
+               DRM_ERROR("overlay is NULL\n");
                return;
        }
 
        win = overlay->zpos;
        if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+               win = fimd_ctx->default_win;
 
        if (win < 0 || win > WINDOWS_NR)
                return;
 
-       if(win == ctx->default_win) {
-               for(ctx->idx = 0;ctx->idx < MAX_NR_PANELS;ctx->idx++) {
-                       if (ctx->panel[ctx->idx].timing.xres == -1 &&
-                               ctx->panel[ctx->idx].timing.yres == -1) {
-                                       DRM_ERROR("Invalid panel parameters");
-                                       ctx->idx = 0; /* Reset to first panel index*/
-                                       break;
-                               }
-                       if (ctx->panel[ctx->idx].timing.xres == overlay->fb_width &&
-                               ctx->panel[ctx->idx].timing.yres == overlay->fb_height)
-                                       break;
+       if (win == fimd_ctx->default_win) {
+               for (i = 0; i < MAX_NR_PANELS; i++) {
+                       struct fb_videomode *timing;
+
+                       timing = &fimd_ctx->panel[i].timing;
+
+                       if (timing->xres == -1 && timing->yres == -1) {
+                               DRM_ERROR("Invalid panel parameters");
+                               i = 0; /* Reset to first panel index*/
+                               break;
+                       }
+                       if (timing->xres == overlay->fb_width &&
+                           timing->yres == overlay->fb_height)
+                               break;
                }
+               fimd_ctx->idx = i;
        }
 
        offset = overlay->fb_x * (overlay->bpp >> 3);
@@ -348,7 +325,7 @@ static void fimd_win_mode_set(struct device *dev,
        DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n",
                offset, overlay->fb_pitch);
 
-       win_data = &ctx->win_data[win];
+       win_data = &fimd_ctx->win_data[win];
 
        win_data->offset_x = overlay->crtc_x;
        win_data->offset_y = overlay->crtc_y;
@@ -375,10 +352,9 @@ static void fimd_win_mode_set(struct device *dev,
                        overlay->fb_width, overlay->crtc_width);
 }
 
-static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
+static void fimd_win_set_pixfmt(struct fimd_context *fimd_ctx, unsigned int win)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
-       struct fimd_win_data *win_data = &ctx->win_data[win];
+       struct fimd_win_data *win_data = &fimd_ctx->win_data[win];
        unsigned long val;
        unsigned long bytes;
 
@@ -446,12 +422,11 @@ static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
 
        DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
 
-       writel(val, ctx->regs + WINCON(win));
+       writel(val, fimd_ctx->regs + WINCON(win));
 }
 
-static void fimd_win_set_colkey(struct device *dev, unsigned int win)
+static void fimd_win_set_colkey(struct fimd_context *fimd_ctx, unsigned int win)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
        unsigned int keycon0 = 0, keycon1 = 0;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -461,8 +436,8 @@ static void fimd_win_set_colkey(struct device *dev, unsigned int win)
 
        keycon1 = WxKEYCON1_COLVAL(0xffffffff);
 
-       writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
-       writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
+       writel(keycon0, fimd_ctx->regs + WKEYCON0_BASE(win));
+       writel(keycon1, fimd_ctx->regs + WKEYCON1_BASE(win));
 }
 
 static void mie_set_6bit_dithering(struct fimd_context *ctx)
@@ -504,21 +479,20 @@ static void mie_set_6bit_dithering(struct fimd_context *ctx)
        }
 }
 
-static void fimd_win_page_flip(struct device *dev,
-                              struct exynos_drm_overlay *overlay)
+static void fimd_win_page_flip(void *ctx, struct exynos_drm_overlay *overlay)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        int win = overlay->zpos;
        struct fimd_win_data *win_data;
        unsigned long offset;
 
        if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+               win = fimd_ctx->default_win;
 
        if (win < 0 || win > WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       win_data = &fimd_ctx->win_data[win];
 
        offset = overlay->fb_x * (overlay->bpp >> 3);
        offset += overlay->fb_y * overlay->fb_pitch;
@@ -527,25 +501,25 @@ static void fimd_win_page_flip(struct device *dev,
        win_data->vaddr = overlay->vaddr[0] + offset;
 }
 
-static void fimd_win_commit(struct device *dev, int zpos)
+static void fimd_win_commit(void *ctx, int zpos)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        struct fimd_win_data *win_data;
        int win = zpos;
        unsigned long val, alpha, size;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (ctx->suspended)
+       if (fimd_ctx->suspended)
                return;
 
        if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+               win = fimd_ctx->default_win;
 
        if (win < 0 || win > WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       win_data = &fimd_ctx->win_data[win];
 
        /*
         * SHADOWCON register is used for enabling timing.
@@ -558,18 +532,18 @@ static void fimd_win_commit(struct device *dev, int zpos)
         */
 
        /* protect windows */
-       val = readl(ctx->regs + SHADOWCON);
+       val = readl(fimd_ctx->regs + SHADOWCON);
        val |= SHADOWCON_WINx_PROTECT(win);
-       writel(val, ctx->regs + SHADOWCON);
+       writel(val, fimd_ctx->regs + SHADOWCON);
 
        /* buffer start address */
        val = (unsigned long)win_data->dma_addr;
-       writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
+       writel(val, fimd_ctx->regs + VIDWx_BUF_START(win, 0));
 
        /* buffer end address */
        size = win_data->fb_height * win_data->fb_pitch;
        val = (unsigned long)(win_data->dma_addr + size);
-       writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
+       writel(val, fimd_ctx->regs + VIDWx_BUF_END(win, 0));
 
        DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
                        (unsigned long)win_data->dma_addr, val, size);
@@ -579,18 +553,18 @@ static void fimd_win_commit(struct device *dev, int zpos)
        /* buffer size */
        val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
                VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size);
-       writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
+       writel(val, fimd_ctx->regs + VIDWx_BUF_SIZE(win, 0));
 
        /* OSD position */
        val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
                VIDOSDxA_TOPLEFT_Y(win_data->offset_y);
-       writel(val, ctx->regs + VIDOSD_A(win));
+       writel(val, fimd_ctx->regs + VIDOSD_A(win));
 
        val = VIDOSDxB_BOTRIGHT_X(win_data->offset_x +
                                        win_data->ovl_width - 1) |
                VIDOSDxB_BOTRIGHT_Y(win_data->offset_y +
                                        win_data->ovl_height - 1);
-       writel(val, ctx->regs + VIDOSD_B(win));
+       writel(val, fimd_ctx->regs + VIDOSD_B(win));
 
        DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
                        win_data->offset_x, win_data->offset_y,
@@ -604,7 +578,7 @@ static void fimd_win_commit(struct device *dev, int zpos)
                        VIDISD14C_ALPHA1_G(0xf) |
                        VIDISD14C_ALPHA1_B(0xf);
 
-               writel(alpha, ctx->regs + VIDOSD_C(win));
+               writel(alpha, fimd_ctx->regs + VIDOSD_C(win));
        }
 
        /* OSD size */
@@ -613,112 +587,109 @@ static void fimd_win_commit(struct device *dev, int zpos)
                if (win == 0)
                        offset = VIDOSD_C_SIZE_W0;
                val = win_data->ovl_width * win_data->ovl_height;
-               writel(val, ctx->regs + offset);
+               writel(val, fimd_ctx->regs + offset);
 
                DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
        }
 
-       fimd_win_set_pixfmt(dev, win);
+       fimd_win_set_pixfmt(fimd_ctx, win);
 
        /* hardware window 0 doesn't support color key. */
        if (win != 0)
-               fimd_win_set_colkey(dev, win);
+               fimd_win_set_colkey(fimd_ctx, win);
 
        /* wincon */
-       val = readl(ctx->regs + WINCON(win));
+       val = readl(fimd_ctx->regs + WINCON(win));
        val |= WINCONx_ENWIN;
-       writel(val, ctx->regs + WINCON(win));
+       writel(val, fimd_ctx->regs + WINCON(win));
 
-       mie_set_6bit_dithering(ctx);
+       mie_set_6bit_dithering(fimd_ctx);
 
        /* Enable DMA channel and unprotect windows */
-       val = readl(ctx->regs + SHADOWCON);
+       val = readl(fimd_ctx->regs + SHADOWCON);
        val |= SHADOWCON_CHx_ENABLE(win);
        val &= ~SHADOWCON_WINx_PROTECT(win);
-       writel(val, ctx->regs + SHADOWCON);
+       writel(val, fimd_ctx->regs + SHADOWCON);
 
        win_data->enabled = true;
 }
 
-static void fimd_win_disable(struct device *dev, int zpos)
+static void fimd_win_disable(void *ctx, int zpos)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *fimd_ctx = ctx;
        struct fimd_win_data *win_data;
        int win = zpos;
        u32 val;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
-       if (ctx->suspended)
+       if (fimd_ctx->suspended)
                return;
 
        if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+               win = fimd_ctx->default_win;
 
        if (win < 0 || win > WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       win_data = &fimd_ctx->win_data[win];
 
        /* protect windows */
-       val = readl(ctx->regs + SHADOWCON);
+       val = readl(fimd_ctx->regs + SHADOWCON);
        val |= SHADOWCON_WINx_PROTECT(win);
-       writel(val, ctx->regs + SHADOWCON);
+       writel(val, fimd_ctx->regs + SHADOWCON);
 
        /* wincon */
-       val = readl(ctx->regs + WINCON(win));
+       val = readl(fimd_ctx->regs + WINCON(win));
        val &= ~WINCONx_ENWIN;
-       writel(val, ctx->regs + WINCON(win));
+       writel(val, fimd_ctx->regs + WINCON(win));
 
        /* unprotect windows */
-       val = readl(ctx->regs + SHADOWCON);
+       val = readl(fimd_ctx->regs + SHADOWCON);
        val &= ~SHADOWCON_CHx_ENABLE(win);
        val &= ~SHADOWCON_WINx_PROTECT(win);
-       writel(val, ctx->regs + SHADOWCON);
+       writel(val, fimd_ctx->regs + SHADOWCON);
 
        win_data->enabled = false;
 }
 
-static struct exynos_drm_overlay_ops fimd_overlay_ops = {
-       .mode_set = fimd_win_mode_set,
-       .page_flip = fimd_win_page_flip,
-       .commit = fimd_win_commit,
-       .disable = fimd_win_disable,
-};
+static void fimd_apply(void *ctx)
+{
+       struct fimd_context *fimd_ctx = ctx;
+       struct fimd_win_data *win_data;
+       int i;
 
-static struct exynos_drm_manager fimd_manager = {
-       .pipe           = -1,
-       .ops            = &fimd_manager_ops,
-       .overlay_ops    = &fimd_overlay_ops,
-       .display_ops    = &fimd_display_ops,
-};
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &fimd_ctx->win_data[i];
+               if (win_data->enabled)
+                       fimd_win_commit(ctx, i);
+       }
+}
 
-static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
+static irqreturn_t fimd_irq_handler(int irq, void *arg)
 {
-       struct fimd_context *ctx = (struct fimd_context *)dev_id;
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct drm_device *drm_dev = subdrv->drm_dev;
-       struct exynos_drm_manager *manager = subdrv->manager;
+       struct fimd_context *fimd_ctx = (struct fimd_context *)arg;
        u32 val;
 
-       val = readl(ctx->regs + VIDINTCON1);
+       val = readl(fimd_ctx->regs + VIDINTCON1);
 
        if (val & VIDINTCON1_INT_FRAME)
                /* VSYNC interrupt */
-               writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
+               writel(VIDINTCON1_INT_FRAME, fimd_ctx->regs + VIDINTCON1);
 
        /* check the crtc is detached already from encoder */
-       if (manager->pipe < 0)
+       if (fimd_ctx->pipe < 0)
                goto out;
 
-       drm_handle_vblank(drm_dev, manager->pipe);
-       exynos_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
+       drm_handle_vblank(fimd_ctx->drm_dev, fimd_ctx->pipe);
+       exynos_drm_crtc_finish_pageflip(fimd_ctx->drm_dev, fimd_ctx->pipe);
 
 out:
        return IRQ_HANDLED;
 }
 
-static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+static int fimd_subdrv_probe(void *ctx, struct drm_device *drm_dev)
 {
+       struct fimd_context *fimd_ctx = ctx;
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        /*
@@ -738,15 +709,24 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
         */
        drm_dev->vblank_disable_allowed = 1;
 
+       fimd_ctx->drm_dev = drm_dev;
+
        return 0;
 }
 
-static void fimd_subdrv_remove(struct drm_device *drm_dev)
-{
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       /* TODO. */
-}
+static struct exynos_controller_ops fimd_controller_ops = {
+       .subdrv_probe = fimd_subdrv_probe,
+       .get_panel = fimd_get_panel,
+       .enable_vblank = fimd_enable_vblank,
+       .disable_vblank = fimd_disable_vblank,
+       .power = fimd_power,
+       .mode_set = fimd_win_mode_set,
+       .page_flip = fimd_win_page_flip,
+       .commit = fimd_commit,
+       .apply = fimd_apply,
+       .win_commit = fimd_win_commit,
+       .win_disable = fimd_win_disable,
+};
 
 static int fimd_calc_clkdiv(struct fimd_context *ctx,
                            struct fb_videomode *timing)
@@ -813,72 +793,67 @@ static void fimd_clear_win(struct fimd_context *ctx, int win)
 /*
  * Disables all windows for suspend, keeps track of which ones were enabled.
  */
-static void fimd_window_suspend(struct device *dev)
+static void fimd_window_suspend(struct fimd_context *fimd_ctx)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
        struct fimd_win_data *win_data;
        int i;
 
        for(i = 0; i < WINDOWS_NR; i++)
        {
-               win_data = &ctx->win_data[i];
+               win_data = &fimd_ctx->win_data[i];
                win_data->win_suspended = win_data->enabled;
-               fimd_win_disable(dev, i);
+               fimd_win_disable(fimd_ctx, i);
        }
 }
 
 /*
  * Resumes the suspended windows.
  */
-static void fimd_window_resume(struct device *dev)
+static void fimd_window_resume(struct fimd_context *fimd_ctx)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
        struct fimd_win_data *win_data;
        int i;
 
        for(i = 0; i < WINDOWS_NR; i++)
        {
-               win_data = &ctx->win_data[i];
+               win_data = &fimd_ctx->win_data[i];
                if (win_data->win_suspended) {
-                       fimd_win_commit(dev, i);
+                       fimd_win_commit(fimd_ctx, i);
                        win_data->win_suspended = false;
                }
        }
 }
 
-static int fimd_power_on(struct fimd_context *ctx, bool enable)
+static int fimd_power_on(struct fimd_context *fimd_ctx, bool enable)
 {
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct device *dev = subdrv->dev;
-       struct exynos_drm_fimd_pdata *pdata = dev->platform_data;
-
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (enable) {
                int ret;
 
-               ret = clk_enable(ctx->bus_clk);
+               ret = clk_enable(fimd_ctx->bus_clk);
                if (ret < 0)
                        return ret;
 
-               ret = clk_enable(ctx->lcd_clk);
+               ret = clk_enable(fimd_ctx->lcd_clk);
                if  (ret < 0) {
-                       clk_disable(ctx->bus_clk);
+                       clk_disable(fimd_ctx->bus_clk);
                        return ret;
                }
 
-               ctx->suspended = false;
+               fimd_ctx->suspended = false;
 
                /* if vblank was enabled status, enable it again. */
-               if (test_and_clear_bit(0, &ctx->irq_flags))
-                       fimd_enable_vblank(dev);
+               if (test_and_clear_bit(0, &fimd_ctx->irq_flags))
+                       fimd_enable_vblank(fimd_ctx, fimd_ctx->pipe);
 
-               fimd_apply(dev);
+               fimd_apply(fimd_ctx);
+               fimd_commit(fimd_ctx);
 
-               if (pdata->panel_type == DP_LCD)
-                       writel(MIE_CLK_ENABLE, ctx->regs + DPCLKCON);
+               if (fimd_ctx->panel_type == DP_LCD)
+                       writel(MIE_CLK_ENABLE, fimd_ctx->regs + DPCLKCON);
 
-               fimd_window_resume(dev);
+               fimd_window_resume(fimd_ctx);
 
                if (dp_dev)
                        exynos_dp_resume(dp_dev);
@@ -891,15 +866,15 @@ static int fimd_power_on(struct fimd_context *ctx, bool enable)
                 * suspend that connector. Otherwise we might try to scan from
                 * a destroyed buffer later.
                 */
-               fimd_window_suspend(dev);
+               fimd_window_suspend(fimd_ctx);
 
-               if (pdata->panel_type == DP_LCD)
-                       writel(0, ctx->regs + DPCLKCON);
+               if (fimd_ctx->panel_type == DP_LCD)
+                       writel(0, fimd_ctx->regs + DPCLKCON);
 
-               clk_disable(ctx->lcd_clk);
-               clk_disable(ctx->bus_clk);
+               clk_disable(fimd_ctx->lcd_clk);
+               clk_disable(fimd_ctx->bus_clk);
 
-               ctx->suspended = true;
+               fimd_ctx->suspended = true;
        }
 
        return 0;
@@ -948,8 +923,7 @@ static void iommu_deinit(struct platform_device *pdev)
 static int __devinit fimd_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct fimd_context *ctx;
-       struct exynos_drm_subdrv *subdrv;
+       struct fimd_context *fimd_ctx;
        struct exynos_drm_fimd_pdata *pdata;
        struct exynos_drm_panel_info *panel;
        struct resource *res;
@@ -978,21 +952,24 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
+       fimd_ctx = kzalloc(sizeof(*fimd_ctx), GFP_KERNEL);
+       if (!fimd_ctx)
                return -ENOMEM;
 
-       ctx->bus_clk = clk_get(dev, "fimd");
-       if (IS_ERR(ctx->bus_clk)) {
+       fimd_ctx->panel_type = pdata->panel_type;
+       fimd_ctx->pipe = -1;
+
+       fimd_ctx->bus_clk = clk_get(dev, "fimd");
+       if (IS_ERR(fimd_ctx->bus_clk)) {
                dev_err(dev, "failed to get bus clock\n");
-               ret = PTR_ERR(ctx->bus_clk);
+               ret = PTR_ERR(fimd_ctx->bus_clk);
                goto err_clk_get;
        }
 
-       ctx->lcd_clk = clk_get(dev, "sclk_fimd");
-       if (IS_ERR(ctx->lcd_clk)) {
+       fimd_ctx->lcd_clk = clk_get(dev, "sclk_fimd");
+       if (IS_ERR(fimd_ctx->lcd_clk)) {
                dev_err(dev, "failed to get lcd clock\n");
-               ret = PTR_ERR(ctx->lcd_clk);
+               ret = PTR_ERR(fimd_ctx->lcd_clk);
                goto err_bus_clk;
        }
 
@@ -1002,13 +979,13 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       if (clk_set_parent(ctx->lcd_clk, clk_parent)) {
-               ret = PTR_ERR(ctx->lcd_clk);
+       if (clk_set_parent(fimd_ctx->lcd_clk, clk_parent)) {
+               ret = PTR_ERR(fimd_ctx->lcd_clk);
                goto err_clk;
        }
 
-       if (clk_set_rate(ctx->lcd_clk, pdata->clock_rate)) {
-               ret = PTR_ERR(ctx->lcd_clk);
+       if (clk_set_rate(fimd_ctx->lcd_clk, pdata->clock_rate)) {
+               ret = PTR_ERR(fimd_ctx->lcd_clk);
                goto err_clk;
        }
 
@@ -1021,23 +998,23 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       ctx->regs_res = request_mem_region(res->start, resource_size(res),
+       fimd_ctx->regs_res = request_mem_region(res->start, resource_size(res),
                                           dev_name(dev));
-       if (!ctx->regs_res) {
+       if (!fimd_ctx->regs_res) {
                dev_err(dev, "failed to claim register region\n");
                ret = -ENOENT;
                goto err_clk;
        }
 
-       ctx->regs = ioremap(res->start, resource_size(res));
-       if (!ctx->regs) {
+       fimd_ctx->regs = ioremap(res->start, resource_size(res));
+       if (!fimd_ctx->regs) {
                dev_err(dev, "failed to map registers\n");
                ret = -ENXIO;
                goto err_req_region_io;
        }
 
-       ctx->regs_mie = ioremap(MIE_BASE_ADDRESS, 0x400);
-       if (!ctx->regs_mie) {
+       fimd_ctx->regs_mie = ioremap(MIE_BASE_ADDRESS, 0x400);
+       if (!fimd_ctx->regs_mie) {
                dev_err(dev, "failed to map registers\n");
                ret = -ENXIO;
                goto err_req_region_io_mie;
@@ -1049,29 +1026,23 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                goto err_req_region_irq;
        }
 
-       ctx->irq = res->start;
+       fimd_ctx->irq = res->start;
 
-       ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
+       ret = request_irq(fimd_ctx->irq, fimd_irq_handler, 0, "drm_fimd",
+                       fimd_ctx);
        if (ret < 0) {
                dev_err(dev, "irq request failed.\n");
                goto err_req_irq;
        }
 
-       ctx->vidcon0 = pdata->vidcon0;
-       ctx->vidcon1 = pdata->vidcon1;
-       ctx->default_win = pdata->default_win;
-       ctx->panel = panel;
-
-       subdrv = &ctx->subdrv;
+       fimd_ctx->vidcon0 = pdata->vidcon0;
+       fimd_ctx->vidcon1 = pdata->vidcon1;
+       fimd_ctx->default_win = pdata->default_win;
+       fimd_ctx->panel = panel;
 
-       subdrv->dev = dev;
-       subdrv->manager = &fimd_manager;
-       subdrv->probe = fimd_subdrv_probe;
-       subdrv->remove = fimd_subdrv_remove;
+       mutex_init(&fimd_ctx->lock);
 
-       mutex_init(&ctx->lock);
-
-       platform_set_drvdata(pdev, ctx);
+       platform_set_drvdata(pdev, fimd_ctx);
 
        pm_runtime_enable(dev);
        pm_runtime_get_sync(dev);
@@ -1080,46 +1051,52 @@ static int __devinit fimd_probe(struct platform_device *pdev)
                if(panel[i].timing.xres == -1 && panel[i].timing.yres == -1)
                        break;
 
-               ctx->clkdiv[i] = fimd_calc_clkdiv(ctx, &panel[i].timing);
-               panel[i].timing.pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv[i];
+               fimd_ctx->clkdiv[i] = fimd_calc_clkdiv(fimd_ctx,
+                                       &panel[i].timing);
+               panel[i].timing.pixclock = clk_get_rate(fimd_ctx->lcd_clk) /
+                                               fimd_ctx->clkdiv[i];
                DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n for panel[%d]",
-                               panel[i].timing.pixclock, ctx->clkdiv[i],i);
+                               panel[i].timing.pixclock,
+                               fimd_ctx->clkdiv[i], i);
        }
 
        for (win = 0; win < WINDOWS_NR; win++)
-               fimd_clear_win(ctx, win);
+               fimd_clear_win(fimd_ctx, win);
 
-       if (pdata->panel_type == DP_LCD)
-               writel(MIE_CLK_ENABLE, ctx->regs + DPCLKCON);
+       if (fimd_ctx->panel_type == DP_LCD)
+               writel(MIE_CLK_ENABLE, fimd_ctx->regs + DPCLKCON);
 
-       exynos_drm_subdrv_register(subdrv);
+       exynos_display_attach_controller(EXYNOS_DRM_DISPLAY_TYPE_FIMD,
+                       &fimd_controller_ops, fimd_ctx);
+       exynos_display_attach_panel(EXYNOS_DRM_DISPLAY_TYPE_FIMD,
+                       &fimd_panel_ops, fimd_ctx);
 
        return 0;
 
 err_req_irq:
 err_req_region_irq:
-       iounmap(ctx->regs_mie);
+       iounmap(fimd_ctx->regs_mie);
 
 err_req_region_io_mie:
-       iounmap(ctx->regs);
+       iounmap(fimd_ctx->regs);
 
 err_req_region_io:
-       release_resource(ctx->regs_res);
-       kfree(ctx->regs_res);
+       release_resource(fimd_ctx->regs_res);
+       kfree(fimd_ctx->regs_res);
 
 err_clk:
-       clk_disable(ctx->lcd_clk);
-       clk_put(ctx->lcd_clk);
+       clk_disable(fimd_ctx->lcd_clk);
+       clk_put(fimd_ctx->lcd_clk);
 
 err_bus_clk:
-       clk_disable(ctx->bus_clk);
-       clk_put(ctx->bus_clk);
+       clk_disable(fimd_ctx->bus_clk);
+       clk_put(fimd_ctx->bus_clk);
 
 err_clk_get:
 #ifdef CONFIG_EXYNOS_IOMMU
        iommu_deinit(pdev);
 #endif
-       kfree(ctx);
+       kfree(fimd_ctx);
        return ret;
 }
 
@@ -1130,8 +1107,6 @@ static int __devexit fimd_remove(struct platform_device *pdev)
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
-
        if (ctx->suspended)
                goto out;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
deleted file mode 100644 (file)
index ff5c789..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- *     Inki Dae <inki.dae@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 "drmP.h"
-
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-
-#include <drm/exynos_drm.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
-
-#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);
-
-/* Common hdmi subdrv needs to access the hdmi and mixer though context.
-* These should be initialied by the repective drivers */
-static struct exynos_drm_hdmi_context *hdmi_ctx;
-static struct exynos_drm_hdmi_context *mixer_ctx;
-
-/* these callback points shoud be set by specific drivers. */
-static struct exynos_hdmi_ops *hdmi_ops;
-static struct exynos_mixer_ops *mixer_ops;
-
-struct drm_hdmi_context {
-       struct exynos_drm_subdrv        subdrv;
-       struct exynos_drm_hdmi_context  *hdmi_ctx;
-       struct exynos_drm_hdmi_context  *mixer_ctx;
-       bool    enabled[MIXER_WIN_NR];
-};
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-       DRM_DEBUG_KMS("%s. %s.\n", __FILE__, __func__);
-       hdmi_ctx = ctx;
-}
-
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-       DRM_DEBUG_KMS("%s. %s.\n", __FILE__, __func__);
-       mixer_ctx = ctx;
-}
-
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
-{
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (ops)
-               hdmi_ops = ops;
-}
-
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
-{
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (ops)
-               mixer_ops = ops;
-}
-
-enum exynos_mixer_mode_type exynos_mixer_get_mode_type(int width, int height)
-{
-       if (width >= 464 && width <= 720 && height <= 480)
-               return EXYNOS_MIXER_MODE_SD_NTSC;
-       else if (width >= 464 && width <= 720 && height <= 576)
-               return EXYNOS_MIXER_MODE_SD_PAL;
-       else if (width >= 1024 && width <= 1280 && height <= 720)
-               return EXYNOS_MIXER_MODE_HD_720;
-       else if ((width == 1440 && height == 900) ||
-               (width == 800 && height == 600) ||
-               (width >= 1664 && width <= 1920 && height <= 1080))
-               return EXYNOS_MIXER_MODE_HD_1080;
-       else
-               return EXYNOS_MIXER_MODE_INVALID;
-}
-
-static bool drm_hdmi_is_connected(struct device *dev)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (hdmi_ops && hdmi_ops->is_connected)
-               return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
-
-       return false;
-}
-
-static int drm_hdmi_get_edid(struct device *dev,
-               struct drm_connector *connector, u8 *edid, int len)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (hdmi_ops && hdmi_ops->get_edid)
-               return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector, edid,
-                                         len);
-
-       return 0;
-}
-
-static int drm_hdmi_check_timing(struct device *dev, void *timing)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (hdmi_ops && hdmi_ops->check_timing)
-               return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
-
-       return 0;
-}
-
-static int drm_hdmi_power_on(struct device *dev, int mode)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (mixer_ops && mixer_ops->power_on) {
-               if (mixer_ops->power_on(ctx->mixer_ctx->ctx, mode))
-                       return -EINVAL;
-       }
-
-       if (hdmi_ops && hdmi_ops->power_on)
-               return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
-
-       return 0;
-}
-
-static struct exynos_drm_display_ops drm_hdmi_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_HDMI,
-       .is_connected = drm_hdmi_is_connected,
-       .get_edid = drm_hdmi_get_edid,
-       .check_timing = drm_hdmi_check_timing,
-       .power_on = drm_hdmi_power_on,
-};
-
-static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct exynos_drm_manager *manager = subdrv->manager;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       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 device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (mixer_ops && mixer_ops->disable_vblank)
-               return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
-                               struct drm_connector *connector,
-                               struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (hdmi_ops && hdmi_ops->mode_fixup)
-               hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode,
-                                    adjusted_mode);
-}
-
-static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (hdmi_ops && hdmi_ops->mode_set)
-               hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
-                               unsigned int *width, unsigned int *height)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (hdmi_ops && hdmi_ops->get_max_resol)
-               hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
-}
-
-static void drm_hdmi_commit(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (hdmi_ops && hdmi_ops->commit)
-               hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (mixer_ops && mixer_ops->dpms)
-               mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
-
-       if (hdmi_ops && hdmi_ops->dpms)
-               hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_hdmi_apply(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       int i;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       for (i = 0; i < MIXER_WIN_NR; i++) {
-               if (!ctx->enabled[i])
-                       continue;
-               if (mixer_ops && mixer_ops->win_commit)
-                       mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
-       }
-
-       if (hdmi_ops && hdmi_ops->commit)
-               hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
-       .dpms = drm_hdmi_dpms,
-       .apply = drm_hdmi_apply,
-       .enable_vblank = drm_hdmi_enable_vblank,
-       .disable_vblank = drm_hdmi_disable_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,
-};
-
-static void drm_mixer_mode_set(struct device *subdrv_dev,
-               struct exynos_drm_overlay *overlay)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (mixer_ops && mixer_ops->win_mode_set)
-               mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
-}
-
-static void drm_mixer_page_flip(struct device *subdrv_dev,
-               struct exynos_drm_overlay *overlay)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (mixer_ops && mixer_ops->win_page_flip)
-               mixer_ops->win_page_flip(ctx->mixer_ctx->ctx, overlay);
-}
-
-static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (win < 0 || win > MIXER_WIN_NR) {
-               DRM_ERROR("mixer window[%d] is wrong\n", win);
-               return;
-       }
-
-       if (mixer_ops && mixer_ops->win_commit)
-               mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
-
-       ctx->enabled[win] = true;
-}
-
-static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (win < 0 || win > MIXER_WIN_NR) {
-               DRM_ERROR("mixer window[%d] is wrong\n", win);
-               return;
-       }
-
-       if (mixer_ops && mixer_ops->win_disable)
-               mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
-
-       ctx->enabled[win] = false;
-}
-
-static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
-       .mode_set = drm_mixer_mode_set,
-       .page_flip = drm_mixer_page_flip,
-       .commit = drm_mixer_commit,
-       .disable = drm_mixer_disable,
-};
-
-static struct exynos_drm_manager hdmi_manager = {
-       .pipe           = -1,
-       .ops            = &drm_hdmi_manager_ops,
-       .overlay_ops    = &drm_hdmi_overlay_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;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       if (!hdmi_ctx) {
-               DRM_DEBUG_KMS("hdmi context is null.\n");
-               return -EFAULT;
-       }
-
-       if (!mixer_ctx) {
-               DRM_DEBUG_KMS("mixer context is null.\n");
-               return -EFAULT;
-       }
-
-       ctx = get_ctx_from_subdrv(subdrv);
-
-       ctx->hdmi_ctx = hdmi_ctx;
-       ctx->mixer_ctx = mixer_ctx;
-
-       ctx->hdmi_ctx->drm_dev = drm_dev;
-
-       ctx->mixer_ctx->drm_dev = drm_dev;
-
-       return 0;
-}
-
-static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct exynos_drm_subdrv *subdrv;
-       struct drm_hdmi_context *ctx;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx) {
-               DRM_LOG_KMS("failed to alloc common hdmi context.\n");
-               return -ENOMEM;
-       }
-
-       subdrv = &ctx->subdrv;
-
-       subdrv->dev = dev;
-       subdrv->manager = &hdmi_manager;
-       subdrv->probe = hdmi_subdrv_probe;
-
-       platform_set_drvdata(pdev, subdrv);
-
-       exynos_drm_subdrv_register(subdrv);
-
-       return 0;
-}
-
-static int hdmi_runtime_suspend(struct device *dev)
-{
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       return 0;
-}
-
-static const struct dev_pm_ops hdmi_pm_ops = {
-       .runtime_suspend = hdmi_runtime_suspend,
-       .runtime_resume  = hdmi_runtime_resume,
-};
-
-static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
-{
-       struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
-       kfree(ctx);
-
-       return 0;
-}
-
-struct platform_driver exynos_drm_common_hdmi_driver = {
-       .probe          = exynos_drm_hdmi_probe,
-       .remove         = __devexit_p(exynos_drm_hdmi_remove),
-       .driver         = {
-               .name   = "exynos-drm-hdmi",
-               .owner  = THIS_MODULE,
-               .pm = &hdmi_pm_ops,
-       },
-};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
deleted file mode 100644 (file)
index 607f91e..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* exynos_drm_hdmi.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authoer: Inki Dae <inki.dae@samsung.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _EXYNOS_DRM_HDMI_H_
-#define _EXYNOS_DRM_HDMI_H_
-
-#define MIXER_WIN_NR           3
-#define MIXER_DEFAULT_WIN      0
-
-/*
- * exynos hdmi common context structure.
- *
- * @drm_dev: pointer to drm_device.
- * @ctx: pointer to the context of specific device driver.
- *     this context should be hdmi_context or mixer_context.
- */
-struct exynos_drm_hdmi_context {
-       struct drm_device       *drm_dev;
-       void                    *ctx;
-};
-
-struct exynos_hdmi_ops {
-       /* display */
-       bool (*is_connected)(void *ctx);
-       int (*get_edid)(void *ctx, struct drm_connector *connector,
-                       u8 *edid, int len);
-       int (*check_timing)(void *ctx, void *timing);
-       int (*power_on)(void *ctx, int mode);
-
-       /* manager */
-       void (*mode_fixup)(void *ctx, struct drm_connector *connector,
-                               struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode);
-       void (*mode_set)(void *ctx, void *mode);
-       void (*get_max_resol)(void *ctx, unsigned int *width,
-                               unsigned int *height);
-       void (*commit)(void *ctx);
-       void (*dpms)(void *ctx, int mode);
-};
-
-struct exynos_mixer_ops {
-       /* manager */
-       int (*enable_vblank)(void *ctx, int pipe);
-       void (*disable_vblank)(void *ctx);
-       void (*dpms)(void *ctx, int mode);
-       int (*power_on)(void *ctx, int mode);
-
-       /* overlay */
-       void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
-       void (*win_page_flip)(void *ctx, struct exynos_drm_overlay *overlay);
-       void (*win_commit)(void *ctx, int zpos);
-       void (*win_disable)(void *ctx, int zpos);
-};
-
-enum exynos_mixer_mode_type {
-       EXYNOS_MIXER_MODE_INVALID,
-       EXYNOS_MIXER_MODE_SD_NTSC,
-       EXYNOS_MIXER_MODE_SD_PAL,
-       EXYNOS_MIXER_MODE_HD_720,
-       EXYNOS_MIXER_MODE_HD_1080,
-};
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx);
-
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops);
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops);
-
-enum exynos_mixer_mode_type exynos_mixer_get_mode_type(int width, int height);
-
-#endif
index 26ab772..5fdaaf9 100644 (file)
@@ -24,6 +24,7 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
+#include "exynos_drm_display.h"
 
 /* vidi has totally three virtual windows. */
 #define WINDOWS_NR             3
@@ -46,7 +47,7 @@ struct vidi_win_data {
 };
 
 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;
@@ -58,6 +59,7 @@ struct vidi_context {
        bool                            suspended;
        struct work_struct              work;
        struct mutex                    lock;
+       int                             pipe;
 };
 
 static const char fake_edid_info[] = {
@@ -87,9 +89,9 @@ static const char fake_edid_info[] = {
 
 static void vidi_fake_vblank_handler(struct work_struct *work);
 
-static bool vidi_display_is_connected(struct device *dev)
+static bool vidi_display_is_connected(void *ctx)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *vidi_ctx = ctx;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -97,22 +99,22 @@ static bool vidi_display_is_connected(struct device *dev)
         * connection request would come from user side
         * to do hotplug through specific ioctl.
         */
-       return ctx->connected ? true : false;
+       return vidi_ctx->connected ? true : false;
 }
 
-static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
+static int vidi_get_edid(void *ctx, struct drm_connector *connector,
                                u8 *edid, int len)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *vidi_ctx = ctx;
        struct edid *raw_edid;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        /*
         * the edid data comes from user side and it would be set
-        * to ctx->raw_edid through specific ioctl.
+        * to vidi_ctx->raw_edid through specific ioctl.
         */
-       if (!ctx->raw_edid) {
+       if (!vidi_ctx->raw_edid) {
                DRM_DEBUG_KMS("raw_edid is null.\n");
                return -EFAULT;
        }
@@ -123,19 +125,19 @@ static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
                return -ENOMEM;
        }
 
-       memcpy(raw_edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
-                                               * EDID_LENGTH, len));
+       memcpy(raw_edid, vidi_ctx->raw_edid,
+               min((1 + vidi_ctx->raw_edid->extensions) * EDID_LENGTH, len));
 
        /* attach the edid data to connector. */
        connector->display_info.raw_edid = (char *)raw_edid;
 
-       memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
-                                       * EDID_LENGTH, len));
+       memcpy(edid, vidi_ctx->raw_edid,
+               min((1 + vidi_ctx->raw_edid->extensions) * EDID_LENGTH, len));
 
        return 0;
 }
 
-static void *vidi_get_panel(struct device *dev)
+static struct exynos_drm_panel_info *vidi_get_panel(void *ctx)
 {
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -144,7 +146,7 @@ static void *vidi_get_panel(struct device *dev)
        return NULL;
 }
 
-static int vidi_check_timing(struct device *dev, void *timing)
+static int vidi_check_timing(void *ctx, void *timing)
 {
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -153,7 +155,7 @@ static int vidi_check_timing(struct device *dev, void *timing)
        return 0;
 }
 
-static int vidi_display_power_on(struct device *dev, int mode)
+static int vidi_display_power(void *ctx, int mode)
 {
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -162,22 +164,31 @@ static int vidi_display_power_on(struct device *dev, int mode)
        return 0;
 }
 
-static struct exynos_drm_display_ops vidi_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_VIDI,
+static void vidi_commit(void *ctx)
+{
+       struct vidi_context *vidi_ctx = ctx;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (vidi_ctx->suspended)
+               return;
+}
+
+static struct exynos_panel_ops vidi_panel_ops = {
        .is_connected = vidi_display_is_connected,
        .get_edid = vidi_get_edid,
-       .get_panel = vidi_get_panel,
        .check_timing = vidi_check_timing,
-       .power_on = vidi_display_power_on,
+       .power = vidi_display_power,
+       .commit = vidi_commit,
 };
 
-static void vidi_dpms(struct device *subdrv_dev, int mode)
+static int vidi_dpms(void *ctx, int mode)
 {
-       struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+       struct vidi_context *vidi_ctx = ctx;
 
        DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
 
-       mutex_lock(&ctx->lock);
+       mutex_lock(&vidi_ctx->lock);
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
@@ -193,80 +204,44 @@ static void vidi_dpms(struct device *subdrv_dev, int mode)
                break;
        }
 
-       mutex_unlock(&ctx->lock);
-}
-
-static void vidi_apply(struct device *subdrv_dev)
-{
-       struct vidi_context *ctx = get_vidi_context(subdrv_dev);
-       struct exynos_drm_manager *mgr = ctx->subdrv.manager;
-       struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-       struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
-       struct vidi_win_data *win_data;
-       int i;
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled && (ovl_ops && ovl_ops->commit))
-                       ovl_ops->commit(subdrv_dev, i);
-       }
-
-       if (mgr_ops && mgr_ops->commit)
-               mgr_ops->commit(subdrv_dev);
-}
-
-static void vidi_commit(struct device *dev)
-{
-       struct vidi_context *ctx = get_vidi_context(dev);
-
-       DRM_DEBUG_KMS("%s\n", __FILE__);
+       mutex_unlock(&vidi_ctx->lock);
 
-       if (ctx->suspended)
-               return;
+       return 0;
 }
 
-static int vidi_enable_vblank(struct device *dev)
+static int vidi_enable_vblank(void *ctx, int pipe)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *vidi_ctx = ctx;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (ctx->suspended)
+       if (vidi_ctx->suspended)
                return -EPERM;
 
-       if (!test_and_set_bit(0, &ctx->irq_flags))
-               ctx->vblank_on = true;
+       if (!test_and_set_bit(0, &vidi_ctx->irq_flags))
+               vidi_ctx->vblank_on = true;
+
+       vidi_ctx->pipe = pipe;
 
        return 0;
 }
 
-static void vidi_disable_vblank(struct device *dev)
+static void vidi_disable_vblank(void *ctx)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *vidi_ctx = ctx;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (ctx->suspended)
+       if (vidi_ctx->suspended)
                return;
 
-       if (test_and_clear_bit(0, &ctx->irq_flags))
-               ctx->vblank_on = false;
+       if (test_and_clear_bit(0, &vidi_ctx->irq_flags))
+               vidi_ctx->vblank_on = false;
 }
 
-static struct exynos_drm_manager_ops vidi_manager_ops = {
-       .dpms = vidi_dpms,
-       .apply = vidi_apply,
-       .commit = vidi_commit,
-       .enable_vblank = vidi_enable_vblank,
-       .disable_vblank = vidi_disable_vblank,
-};
-
-static void vidi_win_mode_set(struct device *dev,
-                             struct exynos_drm_overlay *overlay)
+static void vidi_win_mode_set(void *ctx, struct exynos_drm_overlay *overlay)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *vidi_ctx = ctx;
        struct vidi_win_data *win_data;
        int win;
        unsigned long offset;
@@ -274,13 +249,13 @@ static void vidi_win_mode_set(struct device *dev,
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (!overlay) {
-               dev_err(dev, "overlay is NULL\n");
+               DRM_ERROR("overlay is NULL\n");
                return;
        }
 
        win = overlay->zpos;
        if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+               win = vidi_ctx->default_win;
 
        if (win < 0 || win > WINDOWS_NR)
                return;
@@ -291,7 +266,7 @@ static void vidi_win_mode_set(struct device *dev,
        DRM_DEBUG_KMS("offset = 0x%lx, fb_pitch = %x\n", offset,
                        overlay->fb_pitch);
 
-       win_data = &ctx->win_data[win];
+       win_data = &vidi_ctx->win_data[win];
 
        win_data->offset_x = overlay->crtc_x;
        win_data->offset_y = overlay->crtc_y;
@@ -322,85 +297,89 @@ static void vidi_win_mode_set(struct device *dev,
                        overlay->fb_width, overlay->crtc_width);
 }
 
-static void vidi_win_commit(struct device *dev, int zpos)
+static void vidi_win_commit(void *ctx, int zpos)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *vidi_ctx = ctx;
        struct vidi_win_data *win_data;
        int win = zpos;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (ctx->suspended)
+       if (vidi_ctx->suspended)
                return;
 
        if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+               win = vidi_ctx->default_win;
 
        if (win < 0 || win > WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       win_data = &vidi_ctx->win_data[win];
 
        win_data->enabled = true;
 
        DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
 
-       if (ctx->vblank_on)
-               schedule_work(&ctx->work);
+       if (vidi_ctx->vblank_on)
+               schedule_work(&vidi_ctx->work);
 }
 
-static void vidi_win_disable(struct device *dev, int zpos)
+static void vidi_apply(void *ctx)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *vidi_ctx = ctx;
+       struct vidi_win_data *win_data;
+       int i;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &vidi_ctx->win_data[i];
+               if (win_data->enabled)
+                       vidi_win_commit(ctx, i);
+       }
+
+       vidi_commit(ctx);
+}
+
+static void vidi_win_disable(void *ctx, int zpos)
+{
+       struct vidi_context *vidi_ctx = ctx;
        struct vidi_win_data *win_data;
        int win = zpos;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (win == DEFAULT_ZPOS)
-               win = ctx->default_win;
+               win = vidi_ctx->default_win;
 
        if (win < 0 || win > WINDOWS_NR)
                return;
 
-       win_data = &ctx->win_data[win];
+       win_data = &vidi_ctx->win_data[win];
        win_data->enabled = false;
 
        /* TODO. */
 }
 
-static struct exynos_drm_overlay_ops vidi_overlay_ops = {
-       .mode_set = vidi_win_mode_set,
-       .commit = vidi_win_commit,
-       .disable = vidi_win_disable,
-};
-
-static struct exynos_drm_manager vidi_manager = {
-       .pipe           = -1,
-       .ops            = &vidi_manager_ops,
-       .overlay_ops    = &vidi_overlay_ops,
-       .display_ops    = &vidi_display_ops,
-};
-
 static void vidi_fake_vblank_handler(struct work_struct *work)
 {
-       struct vidi_context *ctx = container_of(work, struct vidi_context,
+       struct vidi_context *vidi_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 (vidi_ctx->pipe < 0)
                return;
 
        /* refresh rate is about 50Hz. */
        usleep_range(16000, 20000);
 
-       drm_handle_vblank(subdrv->drm_dev, manager->pipe);
-       exynos_drm_crtc_finish_pageflip(subdrv->drm_dev, manager->pipe);
+       drm_handle_vblank(vidi_ctx->drm_dev, vidi_ctx->pipe);
+       exynos_drm_crtc_finish_pageflip(vidi_ctx->drm_dev, vidi_ctx->pipe);
 }
 
-static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+static int vidi_subdrv_probe(void *ctx, struct drm_device *drm_dev)
 {
+       struct vidi_context *vidi_ctx = ctx;
+
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        /*
@@ -420,36 +399,40 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
         */
        drm_dev->vblank_disable_allowed = 1;
 
+       vidi_ctx->drm_dev = drm_dev;
+
        return 0;
 }
 
-static void vidi_subdrv_remove(struct drm_device *drm_dev)
-{
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
-       /* TODO. */
-}
+static struct exynos_controller_ops vidi_controller_ops = {
+       .subdrv_probe = vidi_subdrv_probe,
+       .get_panel = vidi_get_panel,
+       .dpms = vidi_dpms,
+       .apply = vidi_apply,
+       .win_commit = vidi_win_commit,
+       .enable_vblank = vidi_enable_vblank,
+       .disable_vblank = vidi_disable_vblank,
+       .mode_set = vidi_win_mode_set,
+       .win_disable = vidi_win_disable,
+};
 
-static int vidi_power_on(struct vidi_context *ctx, bool enable)
+static int vidi_power_on(struct vidi_context *vidi_ctx, bool enable)
 {
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct device *dev = subdrv->dev;
-
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (enable != false && enable != true)
                return -EINVAL;
 
        if (enable) {
-               ctx->suspended = false;
+               vidi_ctx->suspended = false;
 
                /* if vblank was enabled status, enable it again. */
-               if (test_and_clear_bit(0, &ctx->irq_flags))
-                       vidi_enable_vblank(dev);
+               if (test_and_clear_bit(0, &vidi_ctx->irq_flags))
+                       vidi_enable_vblank(vidi_ctx, vidi_ctx->pipe);
 
-               vidi_apply(dev);
+               vidi_apply(vidi_ctx);
        } else {
-               ctx->suspended = true;
+               vidi_ctx->suspended = true;
        }
 
        return 0;
@@ -488,7 +471,7 @@ static int vidi_store_connection(struct device *dev,
 
        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;
 }
@@ -501,8 +484,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
 {
        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;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -524,11 +506,10 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
 
        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 = get_vidi_context(manager->dev);
+               if (display->display_type == EXYNOS_DRM_DISPLAY_TYPE_VIDI) {
+                       ctx = display->controller_ctx;
                        break;
                }
        }
@@ -547,16 +528,14 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
                ctx->raw_edid = (struct edid *)vidi->edid;
 
        ctx->connected = vidi->connection;
-       drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+       drm_helper_hpd_irq_event(ctx->drm_dev);
 
        return 0;
 }
 
 static int __devinit vidi_probe(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
        struct vidi_context *ctx;
-       struct exynos_drm_subdrv *subdrv;
        int ret;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -572,12 +551,6 @@ static int __devinit vidi_probe(struct platform_device *pdev)
        /* for test */
        ctx->raw_edid = (struct edid *)fake_edid_info;
 
-       subdrv = &ctx->subdrv;
-       subdrv->dev = dev;
-       subdrv->manager = &vidi_manager;
-       subdrv->probe = vidi_subdrv_probe;
-       subdrv->remove = vidi_subdrv_remove;
-
        mutex_init(&ctx->lock);
 
        platform_set_drvdata(pdev, ctx);
@@ -586,7 +559,11 @@ static int __devinit vidi_probe(struct platform_device *pdev)
        if (ret < 0)
                DRM_INFO("failed to create connection sysfs.\n");
 
-       exynos_drm_subdrv_register(subdrv);
+       exynos_display_attach_controller(EXYNOS_DRM_DISPLAY_TYPE_VIDI,
+                       &vidi_controller_ops, ctx);
+       exynos_display_attach_panel(EXYNOS_DRM_DISPLAY_TYPE_VIDI,
+                       &vidi_panel_ops, ctx);
+
 
        return 0;
 }
@@ -597,8 +574,6 @@ static int __devexit vidi_remove(struct platform_device *pdev)
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
-
        kfree(ctx);
 
        return 0;
index 3d372e0..2f5fe96 100644 (file)
@@ -40,7 +40,7 @@
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
+#include "exynos_drm_display.h"
 
 #include "exynos_hdmi.h"
 
@@ -153,7 +153,6 @@ struct hdmi_context {
        int cur_conf;
 
        struct hdmi_resources           res;
-       void                            *parent_ctx;
 };
 
 /* HDMI Version 1.3 */
@@ -1875,6 +1874,11 @@ static void hdmi_commit(void *ctx)
        hdata->enabled = true;
 }
 
+static void hdmi_apply(void *ctx)
+{
+       hdmi_commit(ctx);
+}
+
 static int hdmi_power_on(void *ctx, int mode)
 {
        struct hdmi_context *hdata = ctx;
@@ -1902,17 +1906,28 @@ static int hdmi_power_on(void *ctx, int mode)
        return 0;
 }
 
-static struct exynos_hdmi_ops hdmi_ops = {
+static int hdmi_subdrv_probe(void *ctx, struct drm_device *drm_dev)
+{
+       struct hdmi_context *hdata = ctx;
+
+       hdata->drm_dev = drm_dev;
+
+       return 0;
+}
+
+static struct exynos_panel_ops hdmi_ops = {
        /* display */
+       .subdrv_probe   = hdmi_subdrv_probe,
        .is_connected   = hdmi_is_connected,
        .get_edid       = hdmi_get_edid,
        .check_timing   = hdmi_check_timing,
-       .power_on       = hdmi_power_on,
+       .power          = hdmi_power_on,
 
        /* manager */
        .mode_fixup     = hdmi_mode_fixup,
        .mode_set       = hdmi_mode_set,
        .commit         = hdmi_commit,
+       .apply          = hdmi_apply,
 };
 
 /*
@@ -1922,16 +1937,13 @@ static void hdmi_hotplug_func(struct work_struct *work)
 {
        struct hdmi_context *hdata =
                container_of(work, struct hdmi_context, hotplug_work);
-       struct exynos_drm_hdmi_context *ctx =
-               (struct exynos_drm_hdmi_context *)hdata->parent_ctx;
 
-       drm_helper_hpd_irq_event(ctx->drm_dev);
+       drm_helper_hpd_irq_event(hdata->drm_dev);
 }
 
 static irqreturn_t hdmi_irq_handler(int irq, void *arg)
 {
-       struct exynos_drm_hdmi_context *ctx = arg;
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = arg;
        u32 intc_flag;
        if (hdata->is_hdmi_powered_on) {
                intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
@@ -1950,7 +1962,7 @@ static irqreturn_t hdmi_irq_handler(int irq, void *arg)
                }
        }
 
-       if (ctx->drm_dev && hdata->hpd_handle)
+       if (hdata->drm_dev && hdata->hpd_handle)
                queue_work(hdata->wq, &hdata->hotplug_work);
 
        return IRQ_HANDLED;
@@ -2194,8 +2206,7 @@ static void hdmi_resource_poweroff(struct hdmi_context *hdata)
 #ifdef CONFIG_PM_SLEEP
 static int hdmi_suspend(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = get_hdmi_context(dev);
 
        DRM_DEBUG_KMS("[hdmi] sleep suspend - start\n");
        if (pm_runtime_suspended(dev)) {
@@ -2210,8 +2221,7 @@ static int hdmi_suspend(struct device *dev)
 }
 static int hdmi_resume(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = get_hdmi_context(dev);
 
        DRM_DEBUG_KMS("[hdmi] sleep resume - start\n");
 
@@ -2227,8 +2237,7 @@ static int hdmi_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int hdmi_runtime_suspend(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = get_hdmi_context(dev);
 
        DRM_DEBUG_KMS("[hdmi] runtime suspend - start\n");
        hdmi_resource_poweroff(hdata);
@@ -2239,8 +2248,7 @@ static int hdmi_runtime_suspend(struct device *dev)
 
 static int hdmi_runtime_resume(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = get_hdmi_context(dev);
 
        DRM_DEBUG_KMS("[hdmi] runtime resume - start\n");
 
@@ -2273,8 +2281,7 @@ struct platform_device *hdmi_audio_device;
 
 int hdmi_register_audio_device(struct platform_device *pdev)
 {
-       struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = platform_get_drvdata(pdev);
        struct platform_device *audio_dev;
        int ret;
 
@@ -2319,7 +2326,6 @@ void hdmi_unregister_audio_device(void)
 static int __devinit hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx;
        struct hdmi_context *hdata;
        struct exynos_drm_hdmi_pdata *pdata;
        struct resource *res;
@@ -2334,23 +2340,13 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
-       if (!drm_hdmi_ctx) {
-               DRM_ERROR("failed to allocate common hdmi context.\n");
-               return -ENOMEM;
-       }
-
        hdata = kzalloc(sizeof(struct hdmi_context), GFP_KERNEL);
        if (!hdata) {
                DRM_ERROR("out of memory\n");
-               kfree(drm_hdmi_ctx);
                return -ENOMEM;
        }
 
-       drm_hdmi_ctx->ctx = (void *)hdata;
-       hdata->parent_ctx = (void *)drm_hdmi_ctx;
-
-       platform_set_drvdata(pdev, drm_hdmi_ctx);
+       platform_set_drvdata(pdev, hdata);
 
        hdata->is_v13 = pdata->is_v13;
        hdata->default_win = pdata->default_win;
@@ -2437,7 +2433,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
        INIT_WORK(&hdata->hotplug_work, hdmi_hotplug_func);
 
        ret = request_irq(hdata->internal_irq, hdmi_irq_handler,
-                       IRQF_SHARED, "int_hdmi", hdata->parent_ctx);
+                       IRQF_SHARED, "int_hdmi", hdata);
        if (ret) {
                DRM_ERROR("request int interrupt failed.\n");
                goto err_workqueue;
@@ -2446,7 +2442,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
 
        ret = request_irq(hdata->external_irq, hdmi_irq_handler,
                IRQ_TYPE_EDGE_BOTH | IRQF_SHARED, "ext_hdmi",
-               hdata->parent_ctx);
+               hdata);
        if (ret) {
                DRM_ERROR("request ext interrupt failed.\n");
                goto err_int_irq;
@@ -2462,11 +2458,6 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
                }
        }
 
-       /* Attach HDMI Driver to common hdmi. */
-       exynos_hdmi_drv_attach(drm_hdmi_ctx);
-
-       /* register specific callbacks to common hdmi. */
-       exynos_hdmi_ops_register(&hdmi_ops);
        hdmi_resource_poweron(hdata);
        pm_runtime_enable(dev);
 
@@ -2476,6 +2467,10 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
        } else {
                pm_runtime_get_sync(dev);
        }
+
+       exynos_display_attach_panel(EXYNOS_DRM_DISPLAY_TYPE_MIXER, &hdmi_ops,
+                       hdata);
+
        return 0;
 
 err_ext_irq:
@@ -2497,14 +2492,12 @@ err_resource:
        hdmi_resources_cleanup(hdata);
 err_data:
        kfree(hdata);
-       kfree(drm_hdmi_ctx);
        return ret;
 }
 
 static int __devexit hdmi_remove(struct platform_device *pdev)
 {
-       struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = platform_get_drvdata(pdev);
        struct hdmi_resources *res = &hdata->res;
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
index f80f40d..43ab75c 100644 (file)
@@ -58,4 +58,14 @@ void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
 extern struct i2c_driver hdmiphy_driver;
 extern struct i2c_driver ddc_driver;
 
+enum exynos_mixer_mode_type {
+       EXYNOS_MIXER_MODE_INVALID,
+       EXYNOS_MIXER_MODE_SD_NTSC,
+       EXYNOS_MIXER_MODE_SD_PAL,
+       EXYNOS_MIXER_MODE_HD_720,
+       EXYNOS_MIXER_MODE_HD_1080,
+};
+
+enum exynos_mixer_mode_type exynos_mixer_get_mode_type(int width, int height);
+
 #endif
index 190ef4b..1695670 100644 (file)
@@ -36,7 +36,9 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
-#include "exynos_drm_hdmi.h"
+#include "exynos_drm_display.h"
+
+#include "exynos_hdmi.h"
 
 #include <plat/map-base.h>
 #ifdef CONFIG_EXYNOS_IOMMU
@@ -47,6 +49,9 @@
 
 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
 
+#define MIXER_WIN_NR           3
+#define MIXER_DEFAULT_WIN      0
+
 struct hdmi_win_data {
        dma_addr_t              dma_addr;
        void __iomem            *vaddr;
@@ -85,10 +90,12 @@ struct mixer_resources {
 
 struct mixer_context {
        struct device           *dev;
+       struct drm_device       *drm_dev;
        unsigned int            irq;
        int                     pipe;
        bool                    interlace;
        bool                    is_mixer_powered_on;
+       bool                    enabled[MIXER_WIN_NR];
 
        struct mixer_resources  mixer_res;
        struct hdmi_win_data    win_data[MIXER_WIN_NR];
@@ -173,6 +180,22 @@ static inline void mixer_reg_writemask(struct mixer_resources *res,
        writel(val, res->mixer_regs + reg_id);
 }
 
+enum exynos_mixer_mode_type exynos_mixer_get_mode_type(int width, int height)
+{
+       if (width >= 464 && width <= 720 && height <= 480)
+               return EXYNOS_MIXER_MODE_SD_NTSC;
+       else if (width >= 464 && width <= 720 && height <= 576)
+               return EXYNOS_MIXER_MODE_SD_PAL;
+       else if (width >= 1024 && width <= 1280 && height <= 720)
+               return EXYNOS_MIXER_MODE_HD_720;
+       else if ((width == 1440 && height == 900) ||
+               (width == 800 && height == 600) ||
+               (width >= 1664 && width <= 1920 && height <= 1080))
+               return EXYNOS_MIXER_MODE_HD_1080;
+       else
+               return EXYNOS_MIXER_MODE_INVALID;
+}
+
 static void mixer_regs_dump(struct mixer_context *mctx)
 {
 #define DUMPREG(reg_id) \
@@ -517,6 +540,8 @@ static void vp_video_buffer(struct mixer_context *mctx, int win)
        spin_lock_irqsave(&res->reg_slock, flags);
        mixer_vsync_set_update(mctx, false);
 
+       mctx->enabled[win] = true;
+
        /* interlace or progressive scan mode */
        val = (mctx->interlace ? ~0 : 0);
        vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
@@ -633,6 +658,8 @@ static void mixer_graph_buffer(struct mixer_context *mctx, int win)
        spin_lock_irqsave(&res->reg_slock, flags);
        mixer_vsync_set_update(mctx, false);
 
+       mctx->enabled[win] = true;
+
        /* setup format */
        mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
                MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
@@ -794,8 +821,7 @@ static void mixer_win_mode_set(void *ctx,
        win_data->scan_flags = overlay->scan_flag;
 }
 
-static void mixer_win_page_flip(void *ctx,
-                             struct exynos_drm_overlay *overlay)
+static void mixer_win_page_flip(void *ctx, struct exynos_drm_overlay *overlay)
 {
        struct mixer_context *mixer_ctx = ctx;
        struct hdmi_win_data *win_data;
@@ -847,6 +873,19 @@ static void mixer_win_commit(void *ctx, int zpos)
                mixer_graph_buffer(mctx, win);
 }
 
+static void mixer_apply(void *ctx)
+{
+       struct mixer_context *mctx = ctx;
+       int i;
+
+       for (i = 0; i < MIXER_WIN_NR; i++) {
+               if (!mctx->enabled[i])
+                       continue;
+
+               mixer_win_commit(ctx, i);
+       }
+}
+
 static void mixer_win_disable(void *ctx, int zpos)
 {
        struct mixer_context *mctx = ctx;
@@ -869,6 +908,7 @@ static void mixer_win_disable(void *ctx, int zpos)
        spin_lock_irqsave(&res->reg_slock, flags);
        mixer_vsync_set_update(mctx, false);
 
+       mctx->enabled[win] = false;
        mixer_cfg_layer(mctx, win, false);
 
        mixer_vsync_set_update(mctx, true);
@@ -884,8 +924,7 @@ static void mixer_win_disable(void *ctx, int zpos)
 /* for pageflip event */
 static irqreturn_t mixer_irq_handler(int irq, void *arg)
 {
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
-       struct mixer_context *mctx = drm_hdmi_ctx->ctx;
+       struct mixer_context *mctx = arg;
        struct mixer_resources *res = &mctx->mixer_res;
        u32 val, base, shadow;
        int i;
@@ -910,7 +949,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
                                goto out;
                }
 
-               drm_handle_vblank(drm_hdmi_ctx->drm_dev, mctx->pipe);
+               drm_handle_vblank(mctx->drm_dev, mctx->pipe);
 
                /* Bail out if a layer update is pending */
                if (mixer_get_layer_update_count(mctx))
@@ -919,8 +958,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
                for (i = 0; i < MIXER_WIN_NR; i++)
                        mctx->win_data[i].updated = false;
 
-               exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
-                                               mctx->pipe);
+               exynos_drm_crtc_finish_pageflip(mctx->drm_dev, mctx->pipe);
 
                if (mctx->event_flags & MXR_EVENT_VSYNC) {
                        DRM_DEBUG_KMS("mctx->event_flags & MXR_EVENT_VSYNC");
@@ -1045,8 +1083,7 @@ static void mixer_resource_poweroff(struct mixer_context *mctx)
 #ifdef CONFIG_PM_SLEEP
 static int mixer_resume(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-       struct mixer_context *mctx = ctx->ctx;
+       struct mixer_context *mctx = get_mixer_context(dev);
 
        DRM_DEBUG_KMS("[mixer] sleep resume - start\n");
 
@@ -1061,8 +1098,7 @@ static int mixer_resume(struct device *dev)
 }
 static int mixer_suspend(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-       struct mixer_context *mctx = ctx->ctx;
+       struct mixer_context *mctx = get_mixer_context(dev);
 
        DRM_DEBUG_KMS("[mixer] suspend - start\n");
        if (pm_runtime_suspended(dev)) {
@@ -1078,8 +1114,7 @@ static int mixer_suspend(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int mixer_runtime_resume(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-       struct mixer_context *mctx = ctx->ctx;
+       struct mixer_context *mctx = get_mixer_context(dev);
 
        DRM_DEBUG_KMS("[mixer] runtime resume - start\n");
 
@@ -1091,8 +1126,7 @@ static int mixer_runtime_resume(struct device *dev)
 
 static int mixer_runtime_suspend(struct device *dev)
 {
-       struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-       struct mixer_context *mctx = ctx->ctx;
+       struct mixer_context *mctx = get_mixer_context(dev);
 
        DRM_DEBUG_KMS("[mixer] runtime suspend - start\n");
 
@@ -1103,7 +1137,7 @@ static int mixer_runtime_suspend(struct device *dev)
 
 #endif
 
-static int mixer_power_on(void *ctx, int mode)
+static int mixer_power(void *ctx, int mode)
 {
        struct mixer_context *mctx = ctx;
 
@@ -1134,15 +1168,26 @@ static int mixer_power_on(void *ctx, int mode)
        return 0;
 }
 
-static struct exynos_mixer_ops mixer_ops = {
+static int mixer_subdrv_probe(void *ctx, struct drm_device *drm_dev)
+{
+       struct mixer_context *mctx = ctx;
+
+       mctx->drm_dev = drm_dev;
+
+       return 0;
+}
+
+static struct exynos_controller_ops mixer_ops = {
        /* manager */
+       .subdrv_probe           = mixer_subdrv_probe,
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
-       .power_on               = mixer_power_on,
+       .power                  = mixer_power,
 
        /* overlay */
-       .win_mode_set           = mixer_win_mode_set,
-       .win_page_flip          = mixer_win_page_flip,
+       .mode_set               = mixer_win_mode_set,
+       .page_flip              = mixer_win_page_flip,
+       .apply                  = mixer_apply,
        .win_commit             = mixer_win_commit,
        .win_disable            = mixer_win_disable,
 };
@@ -1182,11 +1227,10 @@ static int iommu_init(struct platform_device *pdev)
 #endif
 
 static int __devinit mixer_resources_init_exynos(
-                       struct exynos_drm_hdmi_context *ctx,
+                       struct mixer_context *mctx,
                        struct platform_device *pdev,
                        int is_exynos5)
 {
-       struct mixer_context *mctx = ctx->ctx;
        struct device *dev = &pdev->dev;
        struct mixer_resources *mixer_res = &mctx->mixer_res;
        struct resource *res;
@@ -1285,7 +1329,7 @@ static int __devinit mixer_resources_init_exynos(
                }
        }
 
-       ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
+       ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", mctx);
        if (ret) {
                dev_err(dev, "request interrupt failed.\n");
                goto fail_mixer_regs;
@@ -1322,12 +1366,13 @@ fail:
        return ret;
 }
 
-static void mixer_resources_cleanup(struct mixer_context *mctx)
+static void mixer_resources_cleanup(struct device *dev,
+               struct mixer_context *mctx)
 {
        struct mixer_resources *res = &mctx->mixer_res;
 
        disable_irq(res->irq);
-       free_irq(res->irq, mctx);
+       free_irq(res->irq, dev);
 
        iounmap(res->vp_regs);
        iounmap(res->mixer_regs);
@@ -1336,49 +1381,37 @@ static void mixer_resources_cleanup(struct mixer_context *mctx)
 static int __devinit mixer_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx;
        struct exynos_drm_hdmi_pdata *pdata;
        struct mixer_context *mctx;
        int ret;
 
        dev_info(dev, "probe start\n");
 
-       drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
-       if (!drm_hdmi_ctx) {
-               DRM_ERROR("failed to allocate common hdmi context.\n");
-               return -ENOMEM;
-       }
-
        mctx = kzalloc(sizeof(*mctx), GFP_KERNEL);
        if (!mctx) {
                DRM_ERROR("failed to alloc mixer context.\n");
-               kfree(drm_hdmi_ctx);
                return -ENOMEM;
        }
 
-
        mctx->dev = &pdev->dev;
        mctx->pipe = -1;
-       drm_hdmi_ctx->ctx = (void *)mctx;
 
-       platform_set_drvdata(pdev, drm_hdmi_ctx);
+       platform_set_drvdata(pdev, mctx);
 
        /* Get from Platform soc deatils */
        pdata = pdev->dev.platform_data;
 
        /* acquire resources: regs, irqs, clocks */
-       ret = mixer_resources_init_exynos(drm_hdmi_ctx, pdev,pdata->is_soc_exynos5);
+       ret = mixer_resources_init_exynos(mctx, pdev, pdata->is_soc_exynos5);
        if (ret)
                goto fail;
 
-       /* attach mixer driver to common hdmi. */
-       exynos_mixer_drv_attach(drm_hdmi_ctx);
-
-       /* register specific callback point to common hdmi. */
-       exynos_mixer_ops_register(&mixer_ops);
        mctx->is_mixer_powered_on = false;
        pm_runtime_enable(dev);
 
+       exynos_display_attach_controller(EXYNOS_DRM_DISPLAY_TYPE_MIXER,
+                       &mixer_ops, mctx);
+
        return 0;
 
 
@@ -1390,17 +1423,14 @@ fail:
 static int mixer_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx =
-                                       platform_get_drvdata(pdev);
-       struct mixer_context *mctx = drm_hdmi_ctx->ctx;
+       struct mixer_context *mctx = platform_get_drvdata(pdev);
 
        dev_info(dev, "remove successful\n");
 
        mixer_resource_poweroff(mctx);
-       mixer_resources_cleanup(mctx);
+       mixer_resources_cleanup(dev, mctx);
 
        kfree(mctx);
-       kfree(drm_hdmi_ctx);
 
        return 0;
 }