Merge tag 'topic/drm-misc-2015-02-06' of git://anongit.freedesktop.org/drm-intel...
authorDave Airlie <airlied@redhat.com>
Wed, 11 Feb 2015 05:33:02 +0000 (15:33 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 11 Feb 2015 05:33:02 +0000 (15:33 +1000)
Flushing out my drm-misc queue with a few oddball things all over.

* tag 'topic/drm-misc-2015-02-06' of git://anongit.freedesktop.org/drm-intel:
  drm: Use static attribute groups for managing connector sysfs entries
  drm: remove DRM_FORMAT_NV12MT
  drm/modes: Print the mode status in human readable form
  drm/irq: Don't disable vblank interrupts when already disabled

1  2 
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_mixer.c

index 358cff67e5cef86bf5415f5fd45b11a1f6a99bd0,92d75a4eabd75c1393d3c4f1d587661941650113..2f43a3c4f7b7bb1362ede6d4acb0e3f35e46f37c
  #include <drm/drmP.h>
  
  #include <drm/exynos_drm.h>
 +#include <drm/drm_plane_helper.h>
  #include "exynos_drm_drv.h"
  #include "exynos_drm_crtc.h"
  #include "exynos_drm_fb.h"
  #include "exynos_drm_gem.h"
  #include "exynos_drm_plane.h"
  
 -#define to_exynos_plane(x)    container_of(x, struct exynos_plane, base)
 -
 -struct exynos_plane {
 -      struct drm_plane                base;
 -      struct exynos_drm_overlay       overlay;
 -      bool                            enabled;
 -};
 -
  static const uint32_t formats[] = {
        DRM_FORMAT_XRGB8888,
        DRM_FORMAT_ARGB8888,
        DRM_FORMAT_NV12,
-       DRM_FORMAT_NV12MT,
  };
  
  /*
@@@ -62,9 -68,16 +61,9 @@@ static int exynos_plane_get_size(int st
        return size;
  }
  
 -int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
 -                        struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 -                        unsigned int crtc_w, unsigned int crtc_h,
 -                        uint32_t src_x, uint32_t src_y,
 -                        uint32_t src_w, uint32_t src_h)
 +int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb)
  {
 -      struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 -      struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 -      unsigned int actual_w;
 -      unsigned int actual_h;
 +      struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
        int nr;
        int i;
  
                        return -EFAULT;
                }
  
 -              overlay->dma_addr[i] = buffer->dma_addr;
 +              exynos_plane->dma_addr[i] = buffer->dma_addr;
  
                DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
 -                              i, (unsigned long)overlay->dma_addr[i]);
 +                              i, (unsigned long)exynos_plane->dma_addr[i]);
        }
  
 +      return 0;
 +}
 +
 +void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
 +                        struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 +                        unsigned int crtc_w, unsigned int crtc_h,
 +                        uint32_t src_x, uint32_t src_y,
 +                        uint32_t src_w, uint32_t src_h)
 +{
 +      struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
 +      struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 +      unsigned int actual_w;
 +      unsigned int actual_h;
 +
        actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
        actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
  
        }
  
        /* set drm framebuffer data. */
 -      overlay->fb_x = src_x;
 -      overlay->fb_y = src_y;
 -      overlay->fb_width = fb->width;
 -      overlay->fb_height = fb->height;
 -      overlay->src_width = src_w;
 -      overlay->src_height = src_h;
 -      overlay->bpp = fb->bits_per_pixel;
 -      overlay->pitch = fb->pitches[0];
 -      overlay->pixel_format = fb->pixel_format;
 -
 -      /* set overlay range to be displayed. */
 -      overlay->crtc_x = crtc_x;
 -      overlay->crtc_y = crtc_y;
 -      overlay->crtc_width = actual_w;
 -      overlay->crtc_height = actual_h;
 +      exynos_plane->fb_x = src_x;
 +      exynos_plane->fb_y = src_y;
 +      exynos_plane->fb_width = fb->width;
 +      exynos_plane->fb_height = fb->height;
 +      exynos_plane->src_width = src_w;
 +      exynos_plane->src_height = src_h;
 +      exynos_plane->bpp = fb->bits_per_pixel;
 +      exynos_plane->pitch = fb->pitches[0];
 +      exynos_plane->pixel_format = fb->pixel_format;
 +
 +      /* set plane range to be displayed. */
 +      exynos_plane->crtc_x = crtc_x;
 +      exynos_plane->crtc_y = crtc_y;
 +      exynos_plane->crtc_width = actual_w;
 +      exynos_plane->crtc_height = actual_h;
  
        /* set drm mode data. */
 -      overlay->mode_width = crtc->mode.hdisplay;
 -      overlay->mode_height = crtc->mode.vdisplay;
 -      overlay->refresh = crtc->mode.vrefresh;
 -      overlay->scan_flag = crtc->mode.flags;
 +      exynos_plane->mode_width = crtc->mode.hdisplay;
 +      exynos_plane->mode_height = crtc->mode.vdisplay;
 +      exynos_plane->refresh = crtc->mode.vrefresh;
 +      exynos_plane->scan_flag = crtc->mode.flags;
  
 -      DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
 -                      overlay->crtc_x, overlay->crtc_y,
 -                      overlay->crtc_width, overlay->crtc_height);
 +      DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
 +                      exynos_plane->crtc_x, exynos_plane->crtc_y,
 +                      exynos_plane->crtc_width, exynos_plane->crtc_height);
  
        plane->crtc = crtc;
  
 -      exynos_drm_crtc_plane_mode_set(crtc, overlay);
 -
 -      return 0;
 -}
 -
 -void exynos_plane_commit(struct drm_plane *plane)
 -{
 -      struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 -      struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 -
 -      exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
 +      if (exynos_crtc->ops->win_mode_set)
 +              exynos_crtc->ops->win_mode_set(exynos_crtc, exynos_plane);
  }
  
  void exynos_plane_dpms(struct drm_plane *plane, int mode)
  {
 -      struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 -      struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 +      struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
 +      struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
  
        if (mode == DRM_MODE_DPMS_ON) {
                if (exynos_plane->enabled)
                        return;
  
 -              exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
 +              if (exynos_crtc->ops->win_enable)
 +                      exynos_crtc->ops->win_enable(exynos_crtc,
 +                                                   exynos_plane->zpos);
 +
                exynos_plane->enabled = true;
        } else {
                if (!exynos_plane->enabled)
                        return;
  
 -              exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
 +              if (exynos_crtc->ops->win_disable)
 +                      exynos_crtc->ops->win_disable(exynos_crtc,
 +                                                    exynos_plane->zpos);
 +
                exynos_plane->enabled = false;
        }
  }
  
 -static int
 +int
  exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
                     unsigned int crtc_w, unsigned int crtc_h,
                     uint32_t src_x, uint32_t src_y,
                     uint32_t src_w, uint32_t src_h)
  {
 +
 +      struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 +      struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
        int ret;
  
 -      ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
 -                      crtc_w, crtc_h, src_x >> 16, src_y >> 16,
 -                      src_w >> 16, src_h >> 16);
 +      ret = exynos_check_plane(plane, fb);
        if (ret < 0)
                return ret;
  
 -      exynos_plane_commit(plane);
 -      exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
 +      exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
 +                            crtc_w, crtc_h, src_x >> 16, src_y >> 16,
 +                            src_w >> 16, src_h >> 16);
 +
 +      if (exynos_crtc->ops->win_commit)
 +              exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
  
        return 0;
  }
@@@ -206,7 -203,7 +205,7 @@@ static int exynos_disable_plane(struct 
  
  static void exynos_plane_destroy(struct drm_plane *plane)
  {
 -      struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 +      struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
  
        exynos_disable_plane(plane);
        drm_plane_cleanup(plane);
@@@ -218,11 -215,11 +217,11 @@@ static int exynos_plane_set_property(st
                                     uint64_t val)
  {
        struct drm_device *dev = plane->dev;
 -      struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 +      struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
        struct exynos_drm_private *dev_priv = dev->dev_private;
  
        if (property == dev_priv->plane_zpos_property) {
 -              exynos_plane->overlay.zpos = val;
 +              exynos_plane->zpos = val;
                return 0;
        }
  
@@@ -259,10 -256,10 +258,10 @@@ struct drm_plane *exynos_plane_init(str
                                    unsigned long possible_crtcs,
                                    enum drm_plane_type type)
  {
 -      struct exynos_plane *exynos_plane;
 +      struct exynos_drm_plane *exynos_plane;
        int err;
  
 -      exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
 +      exynos_plane = kzalloc(sizeof(struct exynos_drm_plane), GFP_KERNEL);
        if (!exynos_plane)
                return ERR_PTR(-ENOMEM);
  
        }
  
        if (type == DRM_PLANE_TYPE_PRIMARY)
 -              exynos_plane->overlay.zpos = DEFAULT_ZPOS;
 +              exynos_plane->zpos = DEFAULT_ZPOS;
        else
                exynos_plane_attach_zpos_property(&exynos_plane->base);
  
index ed44cd4f01f7647c79eca3e3b40f79d19a82d8c9,5da28443342df272dd35d28cd2967dbb894be73c..2fd2e5d46142e0b9b41e0389866f1bff542039cb
@@@ -84,10 -84,10 +84,10 @@@ enum mixer_version_id 
  };
  
  struct mixer_context {
 -      struct exynos_drm_manager manager;
        struct platform_device *pdev;
        struct device           *dev;
        struct drm_device       *drm_dev;
 +      struct exynos_drm_crtc  *crtc;
        int                     pipe;
        bool                    interlace;
        bool                    powered;
        atomic_t                wait_vsync_event;
  };
  
 -static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr)
 -{
 -      return container_of(mgr, struct mixer_context, manager);
 -}
 -
  struct mixer_drv_data {
        enum mixer_version_id   version;
        bool                                    is_vp_enabled;
@@@ -412,8 -417,6 +412,6 @@@ static void vp_video_buffer(struct mixe
        win_data = &ctx->win_data[win];
  
        switch (win_data->pixel_format) {
-       case DRM_FORMAT_NV12MT:
-               tiled_mode = true;
        case DRM_FORMAT_NV12:
                crcb_mode = false;
                buf_num = 2;
@@@ -849,15 -852,16 +847,15 @@@ static int vp_resources_init(struct mix
        return 0;
  }
  
 -static int mixer_initialize(struct exynos_drm_manager *mgr,
 +static int mixer_initialize(struct mixer_context *mixer_ctx,
                        struct drm_device *drm_dev)
  {
        int ret;
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
        struct exynos_drm_private *priv;
        priv = drm_dev->dev_private;
  
 -      mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
 -      mgr->pipe = mixer_ctx->pipe = priv->pipe++;
 +      mixer_ctx->drm_dev = drm_dev;
 +      mixer_ctx->pipe = priv->pipe++;
  
        /* acquire resources: regs, irqs, clocks */
        ret = mixer_resources_init(mixer_ctx);
        return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
  }
  
 -static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
 +static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
  {
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 -
        if (is_drm_iommu_supported(mixer_ctx->drm_dev))
                drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
  }
  
 -static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
 +static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
  {
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
  
        if (!mixer_ctx->powered) {
        return 0;
  }
  
 -static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
 +static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
  {
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
  
        /* disable vsync interrupt */
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
  }
  
 -static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
 -                      struct exynos_drm_overlay *overlay)
 +static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
 +                      struct exynos_drm_plane *plane)
  {
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *mixer_ctx = crtc->ctx;
        struct hdmi_win_data *win_data;
        int win;
  
 -      if (!overlay) {
 -              DRM_ERROR("overlay is NULL\n");
 +      if (!plane) {
 +              DRM_ERROR("plane is NULL\n");
                return;
        }
  
        DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
 -                               overlay->fb_width, overlay->fb_height,
 -                               overlay->fb_x, overlay->fb_y,
 -                               overlay->crtc_width, overlay->crtc_height,
 -                               overlay->crtc_x, overlay->crtc_y);
 +                               plane->fb_width, plane->fb_height,
 +                               plane->fb_x, plane->fb_y,
 +                               plane->crtc_width, plane->crtc_height,
 +                               plane->crtc_x, plane->crtc_y);
  
 -      win = overlay->zpos;
 +      win = plane->zpos;
        if (win == DEFAULT_ZPOS)
                win = MIXER_DEFAULT_WIN;
  
  
        win_data = &mixer_ctx->win_data[win];
  
 -      win_data->dma_addr = overlay->dma_addr[0];
 -      win_data->chroma_dma_addr = overlay->dma_addr[1];
 -      win_data->pixel_format = overlay->pixel_format;
 -      win_data->bpp = overlay->bpp;
 +      win_data->dma_addr = plane->dma_addr[0];
 +      win_data->chroma_dma_addr = plane->dma_addr[1];
 +      win_data->pixel_format = plane->pixel_format;
 +      win_data->bpp = plane->bpp;
  
 -      win_data->crtc_x = overlay->crtc_x;
 -      win_data->crtc_y = overlay->crtc_y;
 -      win_data->crtc_width = overlay->crtc_width;
 -      win_data->crtc_height = overlay->crtc_height;
 +      win_data->crtc_x = plane->crtc_x;
 +      win_data->crtc_y = plane->crtc_y;
 +      win_data->crtc_width = plane->crtc_width;
 +      win_data->crtc_height = plane->crtc_height;
  
 -      win_data->fb_x = overlay->fb_x;
 -      win_data->fb_y = overlay->fb_y;
 -      win_data->fb_width = overlay->fb_width;
 -      win_data->fb_height = overlay->fb_height;
 -      win_data->src_width = overlay->src_width;
 -      win_data->src_height = overlay->src_height;
 +      win_data->fb_x = plane->fb_x;
 +      win_data->fb_y = plane->fb_y;
 +      win_data->fb_width = plane->fb_width;
 +      win_data->fb_height = plane->fb_height;
 +      win_data->src_width = plane->src_width;
 +      win_data->src_height = plane->src_height;
  
 -      win_data->mode_width = overlay->mode_width;
 -      win_data->mode_height = overlay->mode_height;
 +      win_data->mode_width = plane->mode_width;
 +      win_data->mode_height = plane->mode_height;
  
 -      win_data->scan_flags = overlay->scan_flag;
 +      win_data->scan_flags = plane->scan_flag;
  }
  
 -static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
 +static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
  {
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *mixer_ctx = crtc->ctx;
        int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
  
        DRM_DEBUG_KMS("win: %d\n", win);
        mixer_ctx->win_data[win].enabled = true;
  }
  
 -static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 +static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
  {
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *mixer_ctx = crtc->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
        int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
        unsigned long flags;
        mixer_ctx->win_data[win].enabled = false;
  }
  
 -static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 +static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
  {
 -      struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *mixer_ctx = crtc->ctx;
 +      int err;
  
        mutex_lock(&mixer_ctx->mixer_mutex);
        if (!mixer_ctx->powered) {
        }
        mutex_unlock(&mixer_ctx->mixer_mutex);
  
 -      drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
 +      err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
 +      if (err < 0) {
 +              DRM_DEBUG_KMS("failed to acquire vblank counter\n");
 +              return;
 +      }
  
        atomic_set(&mixer_ctx->wait_vsync_event, 1);
  
                                HZ/20))
                DRM_DEBUG_KMS("vblank wait timed out.\n");
  
 -      drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe);
 +      drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
  }
  
 -static void mixer_window_suspend(struct exynos_drm_manager *mgr)
 +static void mixer_window_suspend(struct exynos_drm_crtc *crtc)
  {
 -      struct mixer_context *ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *ctx = crtc->ctx;
        struct hdmi_win_data *win_data;
        int i;
  
        for (i = 0; i < MIXER_WIN_NR; i++) {
                win_data = &ctx->win_data[i];
                win_data->resume = win_data->enabled;
 -              mixer_win_disable(mgr, i);
 +              mixer_win_disable(crtc, i);
        }
 -      mixer_wait_for_vblank(mgr);
 +      mixer_wait_for_vblank(crtc);
  }
  
 -static void mixer_window_resume(struct exynos_drm_manager *mgr)
 +static void mixer_window_resume(struct exynos_drm_crtc *crtc)
  {
 -      struct mixer_context *ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *ctx = crtc->ctx;
        struct hdmi_win_data *win_data;
        int i;
  
                win_data->enabled = win_data->resume;
                win_data->resume = false;
                if (win_data->enabled)
 -                      mixer_win_commit(mgr, i);
 +                      mixer_win_commit(crtc, i);
        }
  }
  
 -static void mixer_poweron(struct exynos_drm_manager *mgr)
 +static void mixer_poweron(struct exynos_drm_crtc *crtc)
  {
 -      struct mixer_context *ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *ctx = crtc->ctx;
        struct mixer_resources *res = &ctx->mixer_res;
  
        mutex_lock(&ctx->mixer_mutex);
        mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
        mixer_win_reset(ctx);
  
 -      mixer_window_resume(mgr);
 +      mixer_window_resume(crtc);
  }
  
 -static void mixer_poweroff(struct exynos_drm_manager *mgr)
 +static void mixer_poweroff(struct exynos_drm_crtc *crtc)
  {
 -      struct mixer_context *ctx = mgr_to_mixer(mgr);
 +      struct mixer_context *ctx = crtc->ctx;
        struct mixer_resources *res = &ctx->mixer_res;
  
        mutex_lock(&ctx->mixer_mutex);
        mutex_unlock(&ctx->mixer_mutex);
  
        mixer_stop(ctx);
 -      mixer_window_suspend(mgr);
 +      mixer_window_suspend(crtc);
  
        ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
  
        pm_runtime_put_sync(ctx->dev);
  }
  
 -static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
 +static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
  {
        switch (mode) {
        case DRM_MODE_DPMS_ON:
 -              mixer_poweron(mgr);
 +              mixer_poweron(crtc);
                break;
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
 -              mixer_poweroff(mgr);
 +              mixer_poweroff(crtc);
                break;
        default:
                DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
@@@ -1178,7 -1179,7 +1176,7 @@@ int mixer_check_mode(struct drm_display
        return -EINVAL;
  }
  
 -static struct exynos_drm_manager_ops mixer_manager_ops = {
 +static struct exynos_drm_crtc_ops mixer_crtc_ops = {
        .dpms                   = mixer_dpms,
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
@@@ -1249,30 -1250,28 +1247,30 @@@ static int mixer_bind(struct device *de
        struct drm_device *drm_dev = data;
        int ret;
  
 -      ret = mixer_initialize(&ctx->manager, drm_dev);
 -      if (ret)
 -              return ret;
 -
 -      ret = exynos_drm_crtc_create(&ctx->manager);
 -      if (ret) {
 -              mixer_mgr_remove(&ctx->manager);
 -              return ret;
 +      ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
 +                                   EXYNOS_DISPLAY_TYPE_HDMI,
 +                                   &mixer_crtc_ops, ctx);
 +      if (IS_ERR(ctx->crtc)) {
 +              ret = PTR_ERR(ctx->crtc);
 +              goto free_ctx;
        }
  
 -      pm_runtime_enable(dev);
 +      ret = mixer_initialize(ctx, drm_dev);
 +      if (ret)
 +              goto free_ctx;
  
        return 0;
 +
 +free_ctx:
 +      devm_kfree(dev, ctx);
 +      return ret;
  }
  
  static void mixer_unbind(struct device *dev, struct device *master, void *data)
  {
        struct mixer_context *ctx = dev_get_drvdata(dev);
  
 -      mixer_mgr_remove(&ctx->manager);
 -
 -      pm_runtime_disable(dev);
 +      mixer_ctx_remove(ctx);
  }
  
  static const struct component_ops mixer_component_ops = {
@@@ -1295,6 -1294,9 +1293,6 @@@ static int mixer_probe(struct platform_
  
        mutex_init(&ctx->mixer_mutex);
  
 -      ctx->manager.type = EXYNOS_DISPLAY_TYPE_HDMI;
 -      ctx->manager.ops = &mixer_manager_ops;
 -
        if (dev->of_node) {
                const struct of_device_id *match;
  
        platform_set_drvdata(pdev, ctx);
  
        ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
 -                                      ctx->manager.type);
 +                                      EXYNOS_DISPLAY_TYPE_HDMI);
        if (ret)
                return ret;