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_ops_register(struct exynos_hdmi_ops *ops)
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               if (hdmi_ops && hdmi_ops->disable)
-                       hdmi_ops->disable(ctx->hdmi_ctx->ctx);
-               break;
-       default:
-               DRM_DEBUG_KMS("unkown dps mode: %d\n", mode);
-               break;
+       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,
 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, zpos);
+               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, zpos);
+               mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
+
+       ctx->enabled[win] = false;
 }
 
 static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
        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);
        .driver         = {
                .name   = "exynos-drm-hdmi",
                .owner  = THIS_MODULE,
-               .pm = &hdmi_pm_ops,
        },
 };
 
 #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.
  *
        void (*get_max_resol)(void *ctx, unsigned int *width,
                                unsigned int *height);
        void (*commit)(void *ctx);
-       void (*disable)(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);
 
        /* overlay */
        void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
 
 struct hdmi_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
-       bool                            hpd_handle;
-       bool                            enabled;
+       bool                            hpd;
+       bool                            powered;
        bool                            is_v13;
+       struct mutex                    hdmi_mutex;
 
        struct resource                 *regs_res;
        void __iomem                    *regs;
-       unsigned int                    irq;
+       unsigned int                    external_irq;
+       unsigned int                    internal_irq;
 
        struct i2c_client               *ddc_port;
        struct i2c_client               *hdmiphy_port;
 static bool hdmi_is_connected(void *ctx)
 {
        struct hdmi_context *hdata = ctx;
-       u32 val = hdmi_reg_read(hdata, HDMI_HPD_STATUS);
 
-       if (val)
-               return true;
-
-       return false;
+       return hdata->hpd;
 }
 
 static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
                return hdmi_v14_check_timing(check_timing);
 }
 
-static int hdmi_display_power_on(void *ctx, int mode)
-{
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               DRM_DEBUG_KMS("hdmi [on]\n");
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-               break;
-       case DRM_MODE_DPMS_SUSPEND:
-               break;
-       case DRM_MODE_DPMS_OFF:
-               DRM_DEBUG_KMS("hdmi [off]\n");
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
 static void hdmi_set_acr(u32 freq, u8 *acr)
 {
        u32 n, cts;
 {
        u32 reg;
 
-       /* disable hpd handle for drm */
-       hdata->hpd_handle = false;
-
        if (hdata->is_v13)
                reg = HDMI_V13_CORE_RSTOUT;
        else
        mdelay(10);
        hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
        mdelay(10);
-
-       /* enable hpd handle for drm */
-       hdata->hpd_handle = true;
 }
 
 static void hdmi_conf_init(struct hdmi_context *hdata)
 {
-       /* disable hpd handle for drm */
-       hdata->hpd_handle = false;
-
        /* enable HPD interrupts */
        hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
                HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
                hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 2 << 5);
                hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
        }
-
-       /* enable hpd handle for drm */
-       hdata->hpd_handle = true;
 }
 
 static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
        hdmiphy_conf_reset(hdata);
        hdmiphy_conf_apply(hdata);
 
+       mutex_lock(&hdata->hdmi_mutex);
        hdmi_conf_reset(hdata);
        hdmi_conf_init(hdata);
+       mutex_unlock(&hdata->hdmi_mutex);
+
        hdmi_audio_init(hdata);
 
        /* setting core registers */
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
        hdmi_conf_apply(hdata);
+}
+
+static void hdmi_poweron(struct hdmi_context *hdata)
+{
+       struct hdmi_resources *res = &hdata->res;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       mutex_lock(&hdata->hdmi_mutex);
+       if (hdata->powered) {
+               mutex_unlock(&hdata->hdmi_mutex);
+               return;
+       }
 
-       hdata->enabled = true;
+       hdata->powered = true;
+
+       if (hdata->cfg_hpd)
+               hdata->cfg_hpd(true);
+       mutex_unlock(&hdata->hdmi_mutex);
+
+       pm_runtime_get_sync(hdata->dev);
+
+       regulator_bulk_enable(res->regul_count, res->regul_bulk);
+       clk_enable(res->hdmiphy);
+       clk_enable(res->hdmi);
+       clk_enable(res->sclk_hdmi);
+}
+
+static void hdmi_poweroff(struct hdmi_context *hdata)
+{
+       struct hdmi_resources *res = &hdata->res;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       mutex_lock(&hdata->hdmi_mutex);
+       if (!hdata->powered)
+               goto out;
+       mutex_unlock(&hdata->hdmi_mutex);
+
+       /*
+        * The TV power domain needs any condition of hdmiphy to turn off and
+        * its reset state seems to meet the condition.
+        */
+       hdmiphy_conf_reset(hdata);
+
+       clk_disable(res->sclk_hdmi);
+       clk_disable(res->hdmi);
+       clk_disable(res->hdmiphy);
+       regulator_bulk_disable(res->regul_count, res->regul_bulk);
+
+       pm_runtime_put_sync(hdata->dev);
+
+       mutex_lock(&hdata->hdmi_mutex);
+       if (hdata->cfg_hpd)
+               hdata->cfg_hpd(false);
+
+       hdata->powered = false;
+
+out:
+       mutex_unlock(&hdata->hdmi_mutex);
 }
 
-static void hdmi_disable(void *ctx)
+static void hdmi_dpms(void *ctx, int mode)
 {
        struct hdmi_context *hdata = ctx;
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       if (hdata->enabled) {
-               hdmi_audio_control(hdata, false);
-               hdmiphy_conf_reset(hdata);
-               hdmi_conf_reset(hdata);
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               hdmi_poweron(hdata);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               hdmi_poweroff(hdata);
+               break;
+       default:
+               DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
+               break;
        }
 }
 
        .is_connected   = hdmi_is_connected,
        .get_edid       = hdmi_get_edid,
        .check_timing   = hdmi_check_timing,
-       .power_on       = hdmi_display_power_on,
 
        /* manager */
        .mode_fixup     = hdmi_mode_fixup,
        .mode_set       = hdmi_mode_set,
        .get_max_resol  = hdmi_get_max_resol,
        .commit         = hdmi_commit,
-       .disable        = hdmi_disable,
+       .dpms           = hdmi_dpms,
 };
 
-static irqreturn_t hdmi_irq_thread(int irq, void *arg)
+static irqreturn_t hdmi_external_irq_thread(int irq, void *arg)
+{
+       struct exynos_drm_hdmi_context *ctx = arg;
+       struct hdmi_context *hdata = ctx->ctx;
+
+       if (!hdata->get_hpd)
+               goto out;
+
+       mutex_lock(&hdata->hdmi_mutex);
+       hdata->hpd = hdata->get_hpd();
+       mutex_unlock(&hdata->hdmi_mutex);
+
+       if (ctx->drm_dev)
+               drm_helper_hpd_irq_event(ctx->drm_dev);
+
+out:
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg)
 {
        struct exynos_drm_hdmi_context *ctx = arg;
        struct hdmi_context *hdata = ctx->ctx;
        intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
        /* clearing flags for HPD plug/unplug */
        if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
-               DRM_DEBUG_KMS("unplugged, handling:%d\n", hdata->hpd_handle);
+               DRM_DEBUG_KMS("unplugged\n");
                hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
                        HDMI_INTC_FLAG_HPD_UNPLUG);
        }
        if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
-               DRM_DEBUG_KMS("plugged, handling:%d\n", hdata->hpd_handle);
+               DRM_DEBUG_KMS("plugged\n");
                hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
                        HDMI_INTC_FLAG_HPD_PLUG);
        }
 
-       if (ctx->drm_dev && hdata->hpd_handle)
+       mutex_lock(&hdata->hdmi_mutex);
+       hdata->hpd = hdmi_reg_read(hdata, HDMI_HPD_STATUS);
+       if (hdata->powered && hdata->hpd) {
+               mutex_unlock(&hdata->hdmi_mutex);
+               goto out;
+       }
+       mutex_unlock(&hdata->hdmi_mutex);
+
+       if (ctx->drm_dev)
                drm_helper_hpd_irq_event(ctx->drm_dev);
 
+out:
        return IRQ_HANDLED;
 }
 
        return 0;
 }
 
-static void hdmi_resource_poweron(struct hdmi_context *hdata)
-{
-       struct hdmi_resources *res = &hdata->res;
-
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       /* turn HDMI power on */
-       regulator_bulk_enable(res->regul_count, res->regul_bulk);
-       /* power-on hdmi physical interface */
-       clk_enable(res->hdmiphy);
-       /* turn clocks on */
-       clk_enable(res->hdmi);
-       clk_enable(res->sclk_hdmi);
-
-       hdmiphy_conf_reset(hdata);
-       hdmi_conf_reset(hdata);
-       hdmi_conf_init(hdata);
-       hdmi_audio_init(hdata);
-}
-
-static void hdmi_resource_poweroff(struct hdmi_context *hdata)
-{
-       struct hdmi_resources *res = &hdata->res;
-
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       /* turn clocks off */
-       clk_disable(res->sclk_hdmi);
-       clk_disable(res->hdmi);
-       /* power-off hdmiphy */
-       clk_disable(res->hdmiphy);
-       /* turn HDMI power off */
-       regulator_bulk_disable(res->regul_count, res->regul_bulk);
-}
-
-static int hdmi_runtime_suspend(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-
-       DRM_DEBUG_KMS("%s\n", __func__);
-
-       hdmi_resource_poweroff(ctx->ctx);
-
-       return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-
-       DRM_DEBUG_KMS("%s\n", __func__);
-
-       hdmi_resource_poweron(ctx->ctx);
-
-       return 0;
-}
-
-static const struct dev_pm_ops hdmi_pm_ops = {
-       .runtime_suspend = hdmi_runtime_suspend,
-       .runtime_resume  = hdmi_runtime_resume,
-};
-
 static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
 
 void hdmi_attach_ddc_client(struct i2c_client *ddc)
                return -ENOMEM;
        }
 
+       mutex_init(&hdata->hdmi_mutex);
+
        drm_hdmi_ctx->ctx = (void *)hdata;
        hdata->parent_ctx = (void *)drm_hdmi_ctx;
 
 
        hdata->hdmiphy_port = hdmi_hdmiphy;
 
-       hdata->irq = platform_get_irq_byname(pdev, "internal_irq");
-       if (hdata->irq < 0) {
+       hdata->external_irq = platform_get_irq_byname(pdev, "external_irq");
+       if (hdata->external_irq < 0) {
                DRM_ERROR("failed to get platform irq\n");
-               ret = hdata->irq;
+               ret = hdata->external_irq;
                goto err_hdmiphy;
        }
 
-       /* register hpd interrupt */
-       ret = request_threaded_irq(hdata->irq, NULL, hdmi_irq_thread,
-                       IRQF_ONESHOT, "drm_hdmi", drm_hdmi_ctx);
+       hdata->internal_irq = platform_get_irq_byname(pdev, "internal_irq");
+       if (hdata->internal_irq < 0) {
+               DRM_ERROR("failed to get platform internal irq\n");
+               ret = hdata->internal_irq;
+               goto err_hdmiphy;
+       }
+
+       ret = request_threaded_irq(hdata->external_irq, NULL,
+                       hdmi_external_irq_thread, IRQF_TRIGGER_RISING |
+                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       "hdmi_external", drm_hdmi_ctx);
        if (ret) {
-               DRM_ERROR("request interrupt failed.\n");
+               DRM_ERROR("failed to register hdmi internal interrupt\n");
                goto err_hdmiphy;
        }
 
+       if (hdata->cfg_hpd)
+               hdata->cfg_hpd(false);
+
+       ret = request_threaded_irq(hdata->internal_irq, NULL,
+                       hdmi_internal_irq_thread, IRQF_ONESHOT,
+                       "hdmi_internal", drm_hdmi_ctx);
+       if (ret) {
+               DRM_ERROR("failed to register hdmi internal interrupt\n");
+               goto err_free_irq;
+       }
+
        /* register specific callbacks to common hdmi. */
        exynos_hdmi_ops_register(&hdmi_ops);
 
-       hdmi_resource_poweron(hdata);
+       pm_runtime_enable(dev);
 
        return 0;
 
+err_free_irq:
+       free_irq(hdata->external_irq, drm_hdmi_ctx);
 err_hdmiphy:
        i2c_del_driver(&hdmiphy_driver);
 err_ddc:
 
 static int __devexit hdmi_remove(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
        struct hdmi_context *hdata = ctx->ctx;
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       hdmi_resource_poweroff(hdata);
+       pm_runtime_disable(dev);
 
-       disable_irq(hdata->irq);
-       free_irq(hdata->irq, hdata);
+       free_irq(hdata->internal_irq, hdata);
 
        hdmi_resources_cleanup(hdata);
 
        .driver         = {
                .name   = "exynos4-hdmi",
                .owner  = THIS_MODULE,
-               .pm = &hdmi_pm_ops,
        },
 };
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_hdmi.h"
 
-#define MIXER_WIN_NR           3
-#define MIXER_DEFAULT_WIN      0
-
 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
 
 struct hdmi_win_data {
 };
 
 struct mixer_resources {
-       struct device           *dev;
        int                     irq;
        void __iomem            *mixer_regs;
        void __iomem            *vp_regs;
 };
 
 struct mixer_context {
-       unsigned int            irq;
+       struct device           *dev;
        int                     pipe;
        bool                    interlace;
+       bool                    powered;
+       u32                     int_en;
 
+       struct mutex            mixer_mutex;
        struct mixer_resources  mixer_res;
        struct hdmi_win_data    win_data[MIXER_WIN_NR];
 };
        WARN(tries == 0, "failed to reset Video Processor\n");
 }
 
+static void mixer_win_reset(struct mixer_context *ctx)
+{
+       struct mixer_resources *res = &ctx->mixer_res;
+       unsigned long flags;
+       u32 val; /* value stored to register */
+
+       spin_lock_irqsave(&res->reg_slock, flags);
+       mixer_vsync_set_update(ctx, false);
+
+       mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
+
+       /* set output in RGB888 mode */
+       mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
+
+       /* 16 beat burst in DMA */
+       mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
+               MXR_STATUS_BURST_MASK);
+
+       /* setting default layer priority: layer1 > layer0 > video
+        * because typical usage scenario would be
+        * layer1 - OSD
+        * layer0 - framebuffer
+        * video - video overlay
+        */
+       val = MXR_LAYER_CFG_GRP1_VAL(3);
+       val |= MXR_LAYER_CFG_GRP0_VAL(2);
+       val |= MXR_LAYER_CFG_VP_VAL(1);
+       mixer_reg_write(res, MXR_LAYER_CFG, val);
+
+       /* setting background color */
+       mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
+       mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
+       mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
+
+       /* setting graphical layers */
+
+       val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
+       val |= MXR_GRP_CFG_WIN_BLEND_EN;
+       val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+       /* the same configuration for both layers */
+       mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
+
+       val |= MXR_GRP_CFG_BLEND_PRE_MUL;
+       val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
+       mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
+
+       /* configuration of Video Processor Registers */
+       vp_win_reset(ctx);
+       vp_default_filter(res);
+
+       /* disable all layers */
+       mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
+       mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
+       mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
+
+       mixer_vsync_set_update(ctx, true);
+       spin_unlock_irqrestore(&res->reg_slock, flags);
+}
+
+static void mixer_poweron(struct mixer_context *ctx)
+{
+       struct mixer_resources *res = &ctx->mixer_res;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       mutex_lock(&ctx->mixer_mutex);
+       if (ctx->powered) {
+               mutex_unlock(&ctx->mixer_mutex);
+               return;
+       }
+       ctx->powered = true;
+       mutex_unlock(&ctx->mixer_mutex);
+
+       pm_runtime_get_sync(ctx->dev);
+
+       clk_enable(res->mixer);
+       clk_enable(res->vp);
+       clk_enable(res->sclk_mixer);
+
+       mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
+       mixer_win_reset(ctx);
+}
+
+static void mixer_poweroff(struct mixer_context *ctx)
+{
+       struct mixer_resources *res = &ctx->mixer_res;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       mutex_lock(&ctx->mixer_mutex);
+       if (!ctx->powered)
+               goto out;
+       mutex_unlock(&ctx->mixer_mutex);
+
+       ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
+
+       clk_disable(res->mixer);
+       clk_disable(res->vp);
+       clk_disable(res->sclk_mixer);
+
+       pm_runtime_put_sync(ctx->dev);
+
+       mutex_lock(&ctx->mixer_mutex);
+       ctx->powered = false;
+
+out:
+       mutex_unlock(&ctx->mixer_mutex);
+}
+
 static int mixer_enable_vblank(void *ctx, int pipe)
 {
        struct mixer_context *mixer_ctx = ctx;
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
+static void mixer_dpms(void *ctx, int mode)
+{
+       struct mixer_context *mixer_ctx = ctx;
+
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               mixer_poweron(mixer_ctx);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               mixer_poweroff(mixer_ctx);
+               break;
+       default:
+               DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
+               break;
+       }
+}
+
 static void mixer_win_mode_set(void *ctx,
                              struct exynos_drm_overlay *overlay)
 {
                win = MIXER_DEFAULT_WIN;
 
        if (win < 0 || win > MIXER_WIN_NR) {
-               DRM_ERROR("overlay plane[%d] is wrong\n", win);
+               DRM_ERROR("mixer window[%d] is wrong\n", win);
                return;
        }
 
        win_data->scan_flags = overlay->scan_flag;
 }
 
-static void mixer_win_commit(void *ctx, int zpos)
+static void mixer_win_commit(void *ctx, int win)
 {
        struct mixer_context *mixer_ctx = ctx;
-       int win = zpos;
 
        DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
 
-       if (win == DEFAULT_ZPOS)
-               win = MIXER_DEFAULT_WIN;
-
-       if (win < 0 || win > MIXER_WIN_NR) {
-               DRM_ERROR("overlay plane[%d] is wrong\n", win);
-               return;
-       }
-
        if (win > 1)
                vp_video_buffer(mixer_ctx, win);
        else
                mixer_graph_buffer(mixer_ctx, win);
 }
 
-static void mixer_win_disable(void *ctx, int zpos)
+static void mixer_win_disable(void *ctx, int win)
 {
        struct mixer_context *mixer_ctx = ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
        unsigned long flags;
-       int win = zpos;
 
        DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
 
-       if (win == DEFAULT_ZPOS)
-               win = MIXER_DEFAULT_WIN;
-
-       if (win < 0 || win > MIXER_WIN_NR) {
-               DRM_ERROR("overlay plane[%d] is wrong\n", win);
-               return;
-       }
-
        spin_lock_irqsave(&res->reg_slock, flags);
        mixer_vsync_set_update(mixer_ctx, false);
 
        /* manager */
        .enable_vblank          = mixer_enable_vblank,
        .disable_vblank         = mixer_disable_vblank,
+       .dpms                   = mixer_dpms,
 
        /* overlay */
        .win_mode_set           = mixer_win_mode_set,
        return IRQ_HANDLED;
 }
 
-static void mixer_win_reset(struct mixer_context *ctx)
-{
-       struct mixer_resources *res = &ctx->mixer_res;
-       unsigned long flags;
-       u32 val; /* value stored to register */
-
-       spin_lock_irqsave(&res->reg_slock, flags);
-       mixer_vsync_set_update(ctx, false);
-
-       mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
-
-       /* set output in RGB888 mode */
-       mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
-
-       /* 16 beat burst in DMA */
-       mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
-               MXR_STATUS_BURST_MASK);
-
-       /* setting default layer priority: layer1 > layer0 > video
-        * because typical usage scenario would be
-        * layer1 - OSD
-        * layer0 - framebuffer
-        * video - video overlay
-        */
-       val = MXR_LAYER_CFG_GRP1_VAL(3);
-       val |= MXR_LAYER_CFG_GRP0_VAL(2);
-       val |= MXR_LAYER_CFG_VP_VAL(1);
-       mixer_reg_write(res, MXR_LAYER_CFG, val);
-
-       /* setting background color */
-       mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
-       mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
-       mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
-
-       /* setting graphical layers */
-
-       val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
-       val |= MXR_GRP_CFG_WIN_BLEND_EN;
-       val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
-
-       /* the same configuration for both layers */
-       mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
-
-       val |= MXR_GRP_CFG_BLEND_PRE_MUL;
-       val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
-       mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
-
-       /* configuration of Video Processor Registers */
-       vp_win_reset(ctx);
-       vp_default_filter(res);
-
-       /* disable all layers */
-       mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
-       mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
-       mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
-
-       mixer_vsync_set_update(ctx, true);
-       spin_unlock_irqrestore(&res->reg_slock, flags);
-}
-
-static void mixer_resource_poweron(struct mixer_context *ctx)
-{
-       struct mixer_resources *res = &ctx->mixer_res;
-
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       clk_enable(res->mixer);
-       clk_enable(res->vp);
-       clk_enable(res->sclk_mixer);
-
-       mixer_win_reset(ctx);
-}
-
-static void mixer_resource_poweroff(struct mixer_context *ctx)
-{
-       struct mixer_resources *res = &ctx->mixer_res;
-
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
-       clk_disable(res->mixer);
-       clk_disable(res->vp);
-       clk_disable(res->sclk_mixer);
-}
-
-static int mixer_runtime_resume(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-
-       DRM_DEBUG_KMS("resume - start\n");
-
-       mixer_resource_poweron(ctx->ctx);
-
-       return 0;
-}
-
-static int mixer_runtime_suspend(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-
-       DRM_DEBUG_KMS("suspend - start\n");
-
-       mixer_resource_poweroff(ctx->ctx);
-
-       return 0;
-}
-
-static const struct dev_pm_ops mixer_pm_ops = {
-       .runtime_suspend = mixer_runtime_suspend,
-       .runtime_resume  = mixer_runtime_resume,
-};
-
 static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
                                 struct platform_device *pdev)
 {
        struct resource *res;
        int ret;
 
-       mixer_res->dev = dev;
        spin_lock_init(&mixer_res->reg_slock);
 
        mixer_res->mixer = clk_get(dev, "mixer");
                clk_put(mixer_res->vp);
        if (!IS_ERR_OR_NULL(mixer_res->mixer))
                clk_put(mixer_res->mixer);
-       mixer_res->dev = NULL;
        return ret;
 }
 
 {
        struct mixer_resources *res = &ctx->mixer_res;
 
-       disable_irq(res->irq);
        free_irq(res->irq, ctx);
 
        iounmap(res->vp_regs);
                return -ENOMEM;
        }
 
+       mutex_init(&ctx->mixer_mutex);
+
+       ctx->dev = &pdev->dev;
        drm_hdmi_ctx->ctx = (void *)ctx;
 
        platform_set_drvdata(pdev, drm_hdmi_ctx);
        /* register specific callback point to common hdmi. */
        exynos_mixer_ops_register(&mixer_ops);
 
-       mixer_resource_poweron(ctx);
+       pm_runtime_enable(dev);
 
        return 0;
 
 
        dev_info(dev, "remove successful\n");
 
-       mixer_resource_poweroff(ctx);
+       pm_runtime_disable(&pdev->dev);
+
        mixer_resources_cleanup(ctx);
 
        return 0;
        .driver = {
                .name = "s5p-mixer",
                .owner = THIS_MODULE,
-               .pm = &mixer_pm_ops,
        },
        .probe = mixer_probe,
        .remove = __devexit_p(mixer_remove),