These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / exynos / exynos_hdmi.c
index 5eba971..57b6755 100644 (file)
 #include <drm/drmP.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 
 #include "regs-hdmi.h"
 
 #include <linux/kernel.h>
-#include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
 #include <linux/clk.h>
+#include <linux/gpio/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/io.h>
-#include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 #include <linux/hdmi.h>
 #include <linux/component.h>
 #include <linux/mfd/syscon.h>
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
-#include "exynos_mixer.h"
-
-#include <linux/gpio.h>
-#include <media/s5p_hdmi.h>
-
-#define ctx_from_connector(c)  container_of(c, struct hdmi_context, connector)
 
 #define HOTPLUG_DEBOUNCE_MS            1100
 
 enum hdmi_type {
        HDMI_TYPE13,
        HDMI_TYPE14,
+       HDMI_TYPE_COUNT
 };
 
-struct hdmi_driver_data {
-       unsigned int type;
-       const struct hdmiphy_config *phy_confs;
-       unsigned int phy_conf_count;
-       unsigned int is_apb_phy:1;
-};
+#define HDMI_MAPPED_BASE 0xffff0000
 
-struct hdmi_resources {
-       struct clk                      *hdmi;
-       struct clk                      *sclk_hdmi;
-       struct clk                      *sclk_pixel;
-       struct clk                      *sclk_hdmiphy;
-       struct clk                      *mout_hdmi;
-       struct regulator_bulk_data      *regul_bulk;
-       struct regulator                *reg_hdmi_en;
-       int                             regul_count;
-};
-
-struct hdmi_tg_regs {
-       u8 cmd[1];
-       u8 h_fsz[2];
-       u8 hact_st[2];
-       u8 hact_sz[2];
-       u8 v_fsz[2];
-       u8 vsync[2];
-       u8 vsync2[2];
-       u8 vact_st[2];
-       u8 vact_sz[2];
-       u8 field_chg[2];
-       u8 vact_st2[2];
-       u8 vact_st3[2];
-       u8 vact_st4[2];
-       u8 vsync_top_hdmi[2];
-       u8 vsync_bot_hdmi[2];
-       u8 field_top_hdmi[2];
-       u8 field_bot_hdmi[2];
-       u8 tg_3d[1];
-};
-
-struct hdmi_v13_core_regs {
-       u8 h_blank[2];
-       u8 v_blank[3];
-       u8 h_v_line[3];
-       u8 vsync_pol[1];
-       u8 int_pro_mode[1];
-       u8 v_blank_f[3];
-       u8 h_sync_gen[3];
-       u8 v_sync_gen1[3];
-       u8 v_sync_gen2[3];
-       u8 v_sync_gen3[3];
+enum hdmi_mapped_regs {
+       HDMI_PHY_STATUS = HDMI_MAPPED_BASE,
+       HDMI_PHY_RSTOUT,
+       HDMI_ACR_CON,
+       HDMI_ACR_MCTS0,
+       HDMI_ACR_CTS0,
+       HDMI_ACR_N0
 };
 
-struct hdmi_v14_core_regs {
-       u8 h_blank[2];
-       u8 v2_blank[2];
-       u8 v1_blank[2];
-       u8 v_line[2];
-       u8 h_line[2];
-       u8 hsync_pol[1];
-       u8 vsync_pol[1];
-       u8 int_pro_mode[1];
-       u8 v_blank_f0[2];
-       u8 v_blank_f1[2];
-       u8 h_sync_start[2];
-       u8 h_sync_end[2];
-       u8 v_sync_line_bef_2[2];
-       u8 v_sync_line_bef_1[2];
-       u8 v_sync_line_aft_2[2];
-       u8 v_sync_line_aft_1[2];
-       u8 v_sync_line_aft_pxl_2[2];
-       u8 v_sync_line_aft_pxl_1[2];
-       u8 v_blank_f2[2]; /* for 3D mode */
-       u8 v_blank_f3[2]; /* for 3D mode */
-       u8 v_blank_f4[2]; /* for 3D mode */
-       u8 v_blank_f5[2]; /* for 3D mode */
-       u8 v_sync_line_aft_3[2];
-       u8 v_sync_line_aft_4[2];
-       u8 v_sync_line_aft_5[2];
-       u8 v_sync_line_aft_6[2];
-       u8 v_sync_line_aft_pxl_3[2];
-       u8 v_sync_line_aft_pxl_4[2];
-       u8 v_sync_line_aft_pxl_5[2];
-       u8 v_sync_line_aft_pxl_6[2];
-       u8 vact_space_1[2];
-       u8 vact_space_2[2];
-       u8 vact_space_3[2];
-       u8 vact_space_4[2];
-       u8 vact_space_5[2];
-       u8 vact_space_6[2];
+static const u32 hdmi_reg_map[][HDMI_TYPE_COUNT] = {
+       { HDMI_V13_PHY_STATUS, HDMI_PHY_STATUS_0 },
+       { HDMI_V13_PHY_RSTOUT, HDMI_V14_PHY_RSTOUT },
+       { HDMI_V13_ACR_CON, HDMI_V14_ACR_CON },
+       { HDMI_V13_ACR_MCTS0, HDMI_V14_ACR_MCTS0 },
+       { HDMI_V13_ACR_CTS0, HDMI_V14_ACR_CTS0 },
+       { HDMI_V13_ACR_N0, HDMI_V14_ACR_N0 },
 };
 
-struct hdmi_v13_conf {
-       struct hdmi_v13_core_regs core;
-       struct hdmi_tg_regs tg;
+static const char * const supply[] = {
+       "vdd",
+       "vdd_osc",
+       "vdd_pll",
 };
 
-struct hdmi_v14_conf {
-       struct hdmi_v14_core_regs core;
-       struct hdmi_tg_regs tg;
-};
-
-struct hdmi_conf_regs {
-       int pixel_clock;
-       int cea_video_id;
-       enum hdmi_picture_aspect aspect_ratio;
-       union {
-               struct hdmi_v13_conf v13_conf;
-               struct hdmi_v14_conf v14_conf;
-       } conf;
+struct hdmi_driver_data {
+       unsigned int type;
+       const struct hdmiphy_config *phy_confs;
+       unsigned int phy_conf_count;
+       unsigned int is_apb_phy:1;
 };
 
 struct hdmi_context {
-       struct exynos_drm_display       display;
+       struct drm_encoder              encoder;
        struct device                   *dev;
        struct drm_device               *drm_dev;
        struct drm_connector            connector;
-       struct drm_encoder              *encoder;
-       bool                            hpd;
        bool                            powered;
        bool                            dvi_mode;
-       struct mutex                    hdmi_mutex;
-
-       void __iomem                    *regs;
-       int                             irq;
        struct delayed_work             hotplug_work;
-
-       struct i2c_adapter              *ddc_adpt;
-       struct i2c_client               *hdmiphy_port;
-
-       /* current hdmiphy conf regs */
        struct drm_display_mode         current_mode;
-       struct hdmi_conf_regs           mode_conf;
-
-       struct hdmi_resources           res;
+       u8                              cea_video_id;
+       const struct hdmi_driver_data   *drv_data;
 
-       int                             hpd_gpio;
+       void __iomem                    *regs;
        void __iomem                    *regs_hdmiphy;
-       const struct hdmiphy_config             *phy_confs;
-       unsigned int                    phy_conf_count;
-
+       struct i2c_client               *hdmiphy_port;
+       struct i2c_adapter              *ddc_adpt;
+       struct gpio_desc                *hpd_gpio;
+       int                             irq;
        struct regmap                   *pmureg;
-       enum hdmi_type                  type;
+       struct clk                      *hdmi;
+       struct clk                      *sclk_hdmi;
+       struct clk                      *sclk_pixel;
+       struct clk                      *sclk_hdmiphy;
+       struct clk                      *mout_hdmi;
+       struct regulator_bulk_data      regul_bulk[ARRAY_SIZE(supply)];
+       struct regulator                *reg_hdmi_en;
 };
 
-static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
+static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
+{
+       return container_of(e, struct hdmi_context, encoder);
+}
+
+static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c)
 {
-       return container_of(d, struct hdmi_context, display);
+       return container_of(c, struct hdmi_context, connector);
 }
 
 struct hdmiphy_config {
@@ -231,7 +148,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
                        0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
                        0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
                        0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
-                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
+                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
                },
        },
        {
@@ -240,7 +157,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
                        0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
                        0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
                        0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
-                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
+                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x80,
                },
        },
        {
@@ -249,7 +166,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
                        0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
                        0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
                        0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
-                       0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+                       0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
                },
        },
        {
@@ -258,7 +175,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
                        0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
                        0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
                        0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
-                       0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+                       0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
                },
        },
        {
@@ -267,7 +184,7 @@ static const struct hdmiphy_config hdmiphy_v13_configs[] = {
                        0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
                        0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
                        0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
-                       0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+                       0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
                },
        },
 };
@@ -297,7 +214,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
                        0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
                        0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
                        0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
-                       0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
                },
        },
        {
@@ -360,7 +277,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
                        0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
                        0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
                        0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
-                       0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+                       0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
                },
        },
        {
@@ -423,7 +340,7 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
                        0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
                        0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
                        0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
-                       0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
+                       0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
                },
        },
 };
@@ -605,50 +522,45 @@ static struct hdmi_driver_data exynos4210_hdmi_driver_data = {
        .is_apb_phy     = 0,
 };
 
-static struct hdmi_driver_data exynos5_hdmi_driver_data = {
-       .type           = HDMI_TYPE14,
-       .phy_confs      = hdmiphy_v13_configs,
-       .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs),
-       .is_apb_phy     = 0,
-};
+static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id)
+{
+       if ((reg_id & 0xffff0000) == HDMI_MAPPED_BASE)
+               return hdmi_reg_map[reg_id & 0xffff][hdata->drv_data->type];
+       return reg_id;
+}
 
 static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
 {
-       return readl(hdata->regs + reg_id);
+       return readl(hdata->regs + hdmi_map_reg(hdata, reg_id));
 }
 
 static inline void hdmi_reg_writeb(struct hdmi_context *hdata,
                                 u32 reg_id, u8 value)
 {
-       writeb(value, hdata->regs + reg_id);
+       writel(value, hdata->regs + hdmi_map_reg(hdata, reg_id));
 }
 
-static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
-                                u32 reg_id, u32 value, u32 mask)
+static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
+                                  int bytes, u32 val)
 {
-       u32 old = readl(hdata->regs + reg_id);
-       value = (value & mask) | (old & ~mask);
-       writel(value, hdata->regs + reg_id);
+       reg_id = hdmi_map_reg(hdata, reg_id);
+
+       while (--bytes >= 0) {
+               writel(val & 0xff, hdata->regs + reg_id);
+               val >>= 8;
+               reg_id += 4;
+       }
 }
 
-static int hdmiphy_reg_writeb(struct hdmi_context *hdata,
-                       u32 reg_offset, u8 value)
+static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
+                                u32 reg_id, u32 value, u32 mask)
 {
-       if (hdata->hdmiphy_port) {
-               u8 buffer[2];
-               int ret;
-
-               buffer[0] = reg_offset;
-               buffer[1] = value;
+       u32 old;
 
-               ret = i2c_master_send(hdata->hdmiphy_port, buffer, 2);
-               if (ret == 2)
-                       return 0;
-               return ret;
-       } else {
-               writeb(value, hdata->regs_hdmiphy + (reg_offset<<2));
-               return 0;
-       }
+       reg_id = hdmi_map_reg(hdata, reg_id);
+       old = readl(hdata->regs + reg_id);
+       value = (value & mask) | (old & ~mask);
+       writel(value, hdata->regs + reg_id);
 }
 
 static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
@@ -667,7 +579,7 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
        } else {
                int i;
                for (i = 0; i < len; i++)
-                       writeb(buf[i], hdata->regs_hdmiphy +
+                       writel(buf[i], hdata->regs_hdmiphy +
                                ((reg_offset + i)<<2));
                return 0;
        }
@@ -777,7 +689,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
        DUMPREG(HDMI_PHY_STATUS_0);
        DUMPREG(HDMI_PHY_STATUS_PLL);
        DUMPREG(HDMI_PHY_CON_0);
-       DUMPREG(HDMI_PHY_RSTOUT);
+       DUMPREG(HDMI_V14_PHY_RSTOUT);
        DUMPREG(HDMI_PHY_VPLL);
        DUMPREG(HDMI_PHY_CMU);
        DUMPREG(HDMI_CORE_RSTOUT);
@@ -929,7 +841,7 @@ static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
 
 static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
 {
-       if (hdata->type == HDMI_TYPE13)
+       if (hdata->drv_data->type == HDMI_TYPE13)
                hdmi_v13_regs_dump(hdata, prefix);
        else
                hdmi_v14_regs_dump(hdata, prefix);
@@ -956,7 +868,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
        u32 hdr_sum;
        u8 chksum;
        u32 mod;
-       u32 vic;
+       u8 ar;
 
        mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
        if (hdata->dvi_mode) {
@@ -987,27 +899,22 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
                 * Set the aspect ratio as per the mode, mentioned in
                 * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
                 */
-               switch (hdata->mode_conf.aspect_ratio) {
+               ar = hdata->current_mode.picture_aspect_ratio;
+               switch (ar) {
                case HDMI_PICTURE_ASPECT_4_3:
-                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
-                                       hdata->mode_conf.aspect_ratio |
-                                       AVI_4_3_CENTER_RATIO);
+                       ar |= AVI_4_3_CENTER_RATIO;
                        break;
                case HDMI_PICTURE_ASPECT_16_9:
-                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
-                                       hdata->mode_conf.aspect_ratio |
-                                       AVI_16_9_CENTER_RATIO);
+                       ar |= AVI_16_9_CENTER_RATIO;
                        break;
                case HDMI_PICTURE_ASPECT_NONE:
                default:
-                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
-                                       hdata->mode_conf.aspect_ratio |
-                                       AVI_SAME_AS_PIC_ASPECT_RATIO);
+                       ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
                        break;
                }
+               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
 
-               vic = hdata->mode_conf.cea_video_id;
-               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
+               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
 
                chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
                                        infoframe->any.length, hdr_sum);
@@ -1035,12 +942,12 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
 static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
                                bool force)
 {
-       struct hdmi_context *hdata = ctx_from_connector(connector);
+       struct hdmi_context *hdata = connector_to_hdmi(connector);
 
-       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
+       if (gpiod_get_value(hdata->hpd_gpio))
+               return connector_status_connected;
 
-       return hdata->hpd ? connector_status_connected :
-                       connector_status_disconnected;
+       return connector_status_disconnected;
 }
 
 static void hdmi_connector_destroy(struct drm_connector *connector)
@@ -1050,16 +957,20 @@ static void hdmi_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs hdmi_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = drm_atomic_helper_connector_dpms,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .detect = hdmi_detect,
        .destroy = hdmi_connector_destroy,
+       .reset = drm_atomic_helper_connector_reset,
+       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
 static int hdmi_get_modes(struct drm_connector *connector)
 {
-       struct hdmi_context *hdata = ctx_from_connector(connector);
+       struct hdmi_context *hdata = connector_to_hdmi(connector);
        struct edid *edid;
+       int ret;
 
        if (!hdata->ddc_adpt)
                return -ENODEV;
@@ -1075,15 +986,19 @@ static int hdmi_get_modes(struct drm_connector *connector)
 
        drm_mode_connector_update_edid_property(connector, edid);
 
-       return drm_add_edid_modes(connector, edid);
+       ret = drm_add_edid_modes(connector, edid);
+
+       kfree(edid);
+
+       return ret;
 }
 
 static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
 {
        int i;
 
-       for (i = 0; i < hdata->phy_conf_count; i++)
-               if (hdata->phy_confs[i].pixel_clock == pixel_clock)
+       for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
+               if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
                        return i;
 
        DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
@@ -1093,7 +1008,7 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
 static int hdmi_mode_valid(struct drm_connector *connector,
                        struct drm_display_mode *mode)
 {
-       struct hdmi_context *hdata = ctx_from_connector(connector);
+       struct hdmi_context *hdata = connector_to_hdmi(connector);
        int ret;
 
        DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
@@ -1101,10 +1016,6 @@ static int hdmi_mode_valid(struct drm_connector *connector,
                (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
                false, mode->clock * 1000);
 
-       ret = mixer_check_mode(mode);
-       if (ret)
-               return MODE_BAD;
-
        ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
        if (ret < 0)
                return MODE_BAD;
@@ -1114,9 +1025,9 @@ static int hdmi_mode_valid(struct drm_connector *connector,
 
 static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
 {
-       struct hdmi_context *hdata = ctx_from_connector(connector);
+       struct hdmi_context *hdata = connector_to_hdmi(connector);
 
-       return hdata->encoder;
+       return &hdata->encoder;
 }
 
 static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
@@ -1125,14 +1036,12 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
        .best_encoder = hdmi_best_encoder,
 };
 
-static int hdmi_create_connector(struct exynos_drm_display *display,
-                       struct drm_encoder *encoder)
+static int hdmi_create_connector(struct drm_encoder *encoder)
 {
-       struct hdmi_context *hdata = display_to_hdmi(display);
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
        struct drm_connector *connector = &hdata->connector;
        int ret;
 
-       hdata->encoder = encoder;
        connector->interlace_allowed = true;
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -1150,23 +1059,30 @@ static int hdmi_create_connector(struct exynos_drm_display *display,
        return 0;
 }
 
-static void hdmi_mode_fixup(struct exynos_drm_display *display,
-                               struct drm_connector *connector,
-                               const struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode)
+static bool hdmi_mode_fixup(struct drm_encoder *encoder,
+                           const struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
 {
+       struct drm_device *dev = encoder->dev;
+       struct drm_connector *connector;
        struct drm_display_mode *m;
        int mode_ok;
 
-       DRM_DEBUG_KMS("%s\n", __FILE__);
-
        drm_mode_set_crtcinfo(adjusted_mode, 0);
 
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->encoder == encoder)
+                       break;
+       }
+
+       if (connector->encoder != encoder)
+               return true;
+
        mode_ok = hdmi_mode_valid(connector, adjusted_mode);
 
        /* just return if user desired mode exists. */
        if (mode_ok == MODE_OK)
-               return;
+               return true;
 
        /*
         * otherwise, find the most suitable mode among modes and change it
@@ -1186,72 +1102,21 @@ static void hdmi_mode_fixup(struct exynos_drm_display *display,
                        break;
                }
        }
+
+       return true;
 }
 
-static void hdmi_set_acr(u32 freq, u8 *acr)
+static void hdmi_reg_acr(struct hdmi_context *hdata, u32 freq)
 {
        u32 n, cts;
 
-       switch (freq) {
-       case 32000:
-               n = 4096;
-               cts = 27000;
-               break;
-       case 44100:
-               n = 6272;
-               cts = 30000;
-               break;
-       case 88200:
-               n = 12544;
-               cts = 30000;
-               break;
-       case 176400:
-               n = 25088;
-               cts = 30000;
-               break;
-       case 48000:
-               n = 6144;
-               cts = 27000;
-               break;
-       case 96000:
-               n = 12288;
-               cts = 27000;
-               break;
-       case 192000:
-               n = 24576;
-               cts = 27000;
-               break;
-       default:
-               n = 0;
-               cts = 0;
-               break;
-       }
-
-       acr[1] = cts >> 16;
-       acr[2] = cts >> 8 & 0xff;
-       acr[3] = cts & 0xff;
+       cts = (freq % 9) ? 27000 : 30000;
+       n = 128 * freq / (27000000 / cts);
 
-       acr[4] = n >> 16;
-       acr[5] = n >> 8 & 0xff;
-       acr[6] = n & 0xff;
-}
-
-static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
-{
-       hdmi_reg_writeb(hdata, HDMI_ACR_N0, acr[6]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_N1, acr[5]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_N2, acr[4]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_MCTS0, acr[3]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_MCTS1, acr[2]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_MCTS2, acr[1]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_CTS0, acr[3]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
-       hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
-
-       if (hdata->type == HDMI_TYPE13)
-               hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
-       else
-               hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
+       hdmi_reg_writev(hdata, HDMI_ACR_N0, 3, n);
+       hdmi_reg_writev(hdata, HDMI_ACR_MCTS0, 3, cts);
+       hdmi_reg_writev(hdata, HDMI_ACR_CTS0, 3, cts);
+       hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
 }
 
 static void hdmi_audio_init(struct hdmi_context *hdata)
@@ -1259,7 +1124,6 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
        u32 sample_rate, bits_per_sample;
        u32 data_num, bit_ch, sample_frq;
        u32 val;
-       u8 acr[7];
 
        sample_rate = 44100;
        bits_per_sample = 16;
@@ -1279,8 +1143,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
                break;
        }
 
-       hdmi_set_acr(sample_rate, acr);
-       hdmi_reg_acr(hdata, acr);
+       hdmi_reg_acr(hdata, sample_rate);
 
        hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
                                | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
@@ -1382,7 +1245,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
                                HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
        }
 
-       if (hdata->type == HDMI_TYPE13) {
+       if (hdata->drv_data->type == HDMI_TYPE13) {
                /* choose bluescreen (fecal) color */
                hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
                hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
@@ -1413,407 +1276,42 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
        }
 }
 
-static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
-{
-       const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
-       const struct hdmi_v13_core_regs *core =
-               &hdata->mode_conf.conf.v13_conf.core;
-       int tries;
-
-       /* setting core registers */
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
-       hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
-       hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
-       /* Timing generator registers */
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
-
-       /* waiting for HDMIPHY's PLL to get to steady state */
-       for (tries = 100; tries; --tries) {
-               u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
-               if (val & HDMI_PHY_STATUS_READY)
-                       break;
-               usleep_range(1000, 2000);
-       }
-       /* steady state not achieved */
-       if (tries == 0) {
-               DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
-               hdmi_regs_dump(hdata, "timing apply");
-       }
-
-       clk_disable_unprepare(hdata->res.sclk_hdmi);
-       clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
-       clk_prepare_enable(hdata->res.sclk_hdmi);
-
-       /* enable HDMI and timing generator */
-       hdmi_start(hdata, true);
-}
-
-static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
+static void hdmiphy_wait_for_pll(struct hdmi_context *hdata)
 {
-       const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
-       const struct hdmi_v14_core_regs *core =
-               &hdata->mode_conf.conf.v14_conf.core;
        int tries;
 
-       /* setting core registers */
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V2_BLANK_0, core->v2_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_V2_BLANK_1, core->v2_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V1_BLANK_0, core->v1_blank[0]);
-       hdmi_reg_writeb(hdata, HDMI_V1_BLANK_1, core->v1_blank[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_LINE_0, core->v_line[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_LINE_1, core->v_line[1]);
-       hdmi_reg_writeb(hdata, HDMI_H_LINE_0, core->h_line[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_LINE_1, core->h_line[1]);
-       hdmi_reg_writeb(hdata, HDMI_HSYNC_POL, core->hsync_pol[0]);
-       hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
-       hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
-       hdmi_reg_writeb(hdata, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_0,
-                       core->v_sync_line_bef_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_2_1,
-                       core->v_sync_line_bef_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_0,
-                       core->v_sync_line_bef_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_BEF_1_1,
-                       core->v_sync_line_bef_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_0,
-                       core->v_sync_line_aft_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_2_1,
-                       core->v_sync_line_aft_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_0,
-                       core->v_sync_line_aft_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_1_1,
-                       core->v_sync_line_aft_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
-                       core->v_sync_line_aft_pxl_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
-                       core->v_sync_line_aft_pxl_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
-                       core->v_sync_line_aft_pxl_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
-                       core->v_sync_line_aft_pxl_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_0,
-                       core->v_sync_line_aft_3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_3_1,
-                       core->v_sync_line_aft_3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_0,
-                       core->v_sync_line_aft_4[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_4_1,
-                       core->v_sync_line_aft_4[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_0,
-                       core->v_sync_line_aft_5[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_5_1,
-                       core->v_sync_line_aft_5[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_0,
-                       core->v_sync_line_aft_6[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_6_1,
-                       core->v_sync_line_aft_6[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
-                       core->v_sync_line_aft_pxl_3[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
-                       core->v_sync_line_aft_pxl_3[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
-                       core->v_sync_line_aft_pxl_4[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
-                       core->v_sync_line_aft_pxl_4[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
-                       core->v_sync_line_aft_pxl_5[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
-                       core->v_sync_line_aft_pxl_5[1]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
-                       core->v_sync_line_aft_pxl_6[0]);
-       hdmi_reg_writeb(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
-                       core->v_sync_line_aft_pxl_6[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
-       hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
-
-       /* Timing generator registers */
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
-       hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
-       hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]);
-
-       /* waiting for HDMIPHY's PLL to get to steady state */
-       for (tries = 100; tries; --tries) {
-               u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
-               if (val & HDMI_PHY_STATUS_READY)
-                       break;
-               usleep_range(1000, 2000);
-       }
-       /* steady state not achieved */
-       if (tries == 0) {
-               DRM_ERROR("hdmiphy's pll could not reach steady state.\n");
-               hdmi_regs_dump(hdata, "timing apply");
-       }
-
-       clk_disable_unprepare(hdata->res.sclk_hdmi);
-       clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
-       clk_prepare_enable(hdata->res.sclk_hdmi);
+       for (tries = 0; tries < 10; ++tries) {
+               u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
 
-       /* enable HDMI and timing generator */
-       hdmi_start(hdata, true);
-}
-
-static void hdmi_mode_apply(struct hdmi_context *hdata)
-{
-       if (hdata->type == HDMI_TYPE13)
-               hdmi_v13_mode_apply(hdata);
-       else
-               hdmi_v14_mode_apply(hdata);
-}
-
-static void hdmiphy_conf_reset(struct hdmi_context *hdata)
-{
-       u32 reg;
-
-       clk_disable_unprepare(hdata->res.sclk_hdmi);
-       clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
-       clk_prepare_enable(hdata->res.sclk_hdmi);
-
-       /* operation mode */
-       hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
-                               HDMI_PHY_ENABLE_MODE_SET);
-
-       if (hdata->type == HDMI_TYPE13)
-               reg = HDMI_V13_PHY_RSTOUT;
-       else
-               reg = HDMI_PHY_RSTOUT;
-
-       /* reset hdmiphy */
-       hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
-       usleep_range(10000, 12000);
-       hdmi_reg_writemask(hdata, reg,  0, HDMI_PHY_SW_RSTOUT);
-       usleep_range(10000, 12000);
-}
-
-static void hdmiphy_poweron(struct hdmi_context *hdata)
-{
-       if (hdata->type != HDMI_TYPE14)
-               return;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* For PHY Mode Setting */
-       hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
-                               HDMI_PHY_ENABLE_MODE_SET);
-       /* Phy Power On */
-       hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
-                               HDMI_PHY_POWER_ON);
-       /* For PHY Mode Setting */
-       hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
-                               HDMI_PHY_DISABLE_MODE_SET);
-       /* PHY SW Reset */
-       hdmiphy_conf_reset(hdata);
-}
-
-static void hdmiphy_poweroff(struct hdmi_context *hdata)
-{
-       if (hdata->type != HDMI_TYPE14)
-               return;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* PHY SW Reset */
-       hdmiphy_conf_reset(hdata);
-       /* For PHY Mode Setting */
-       hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
-                               HDMI_PHY_ENABLE_MODE_SET);
-
-       /* PHY Power Off */
-       hdmiphy_reg_writeb(hdata, HDMIPHY_POWER,
-                               HDMI_PHY_POWER_OFF);
-
-       /* For PHY Mode Setting */
-       hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
-                               HDMI_PHY_DISABLE_MODE_SET);
-}
-
-static void hdmiphy_conf_apply(struct hdmi_context *hdata)
-{
-       int ret;
-       int i;
-
-       /* pixel clock */
-       i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
-       if (i < 0) {
-               DRM_ERROR("failed to find hdmiphy conf\n");
-               return;
-       }
-
-       ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
-       if (ret) {
-               DRM_ERROR("failed to configure hdmiphy\n");
-               return;
-       }
-
-       usleep_range(10000, 12000);
-
-       ret = hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
-                               HDMI_PHY_DISABLE_MODE_SET);
-       if (ret) {
-               DRM_ERROR("failed to enable hdmiphy\n");
-               return;
+               if (val & HDMI_PHY_STATUS_READY) {
+                       DRM_DEBUG_KMS("PLL stabilized after %d tries\n", tries);
+                       return;
+               }
+               usleep_range(10, 20);
        }
 
+       DRM_ERROR("PLL could not reach steady state\n");
 }
 
-static void hdmi_conf_apply(struct hdmi_context *hdata)
-{
-       hdmiphy_conf_reset(hdata);
-       hdmiphy_conf_apply(hdata);
-
-       mutex_lock(&hdata->hdmi_mutex);
-       hdmi_start(hdata, false);
-       hdmi_conf_init(hdata);
-       mutex_unlock(&hdata->hdmi_mutex);
-
-       hdmi_audio_init(hdata);
-
-       /* setting core registers */
-       hdmi_mode_apply(hdata);
-       hdmi_audio_control(hdata, true);
-
-       hdmi_regs_dump(hdata, "start");
-}
-
-static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
-{
-       int i;
-       BUG_ON(num_bytes > 4);
-       for (i = 0; i < num_bytes; i++)
-               reg_pair[i] = (value >> (8 * i)) & 0xff;
-}
-
-static void hdmi_v13_mode_set(struct hdmi_context *hdata,
-                       struct drm_display_mode *m)
+static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
 {
-       struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
-       struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
+       struct drm_display_mode *m = &hdata->current_mode;
        unsigned int val;
 
-       hdata->mode_conf.cea_video_id =
-               drm_match_cea_mode((struct drm_display_mode *)m);
-       hdata->mode_conf.pixel_clock = m->clock * 1000;
-       hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
-
-       hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
+       hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
+                       (m->htotal << 12) | m->vtotal);
 
        val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
-       hdmi_set_reg(core->vsync_pol, 1, val);
+       hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
 
        val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
-       hdmi_set_reg(core->int_pro_mode, 1, val);
+       hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
 
        val = (m->hsync_start - m->hdisplay - 2);
        val |= ((m->hsync_end - m->hdisplay - 2) << 10);
        val |= ((m->flags & DRM_MODE_FLAG_NHSYNC)  ? 1 : 0)<<20;
-       hdmi_set_reg(core->h_sync_gen, 3, val);
+       hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
 
        /*
         * Quirk requirement for exynos HDMI IP design,
@@ -1826,86 +1324,78 @@ static void hdmi_v13_mode_set(struct hdmi_context *hdata,
                /* Interlaced Mode */
                val = ((m->vsync_end - m->vdisplay) / 2);
                val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
-               hdmi_set_reg(core->v_sync_gen1, 3, val);
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
 
                val = m->vtotal / 2;
                val |= ((m->vtotal - m->vdisplay) / 2) << 11;
-               hdmi_set_reg(core->v_blank, 3, val);
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
 
                val = (m->vtotal +
                        ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
                val |= m->vtotal << 11;
-               hdmi_set_reg(core->v_blank_f, 3, val);
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
 
                val = ((m->vtotal / 2) + 7);
                val |= ((m->vtotal / 2) + 2) << 12;
-               hdmi_set_reg(core->v_sync_gen2, 3, val);
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
 
                val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
                val |= ((m->htotal / 2) +
                        (m->hsync_start - m->hdisplay)) << 12;
-               hdmi_set_reg(core->v_sync_gen3, 3, val);
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
 
-               hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               (m->vtotal - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
 
-               hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
        } else {
                /* Progressive Mode */
 
                val = m->vtotal;
                val |= (m->vtotal - m->vdisplay) << 11;
-               hdmi_set_reg(core->v_blank, 3, val);
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
 
-               hdmi_set_reg(core->v_blank_f, 3, 0);
+               hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
 
                val = (m->vsync_end - m->vdisplay);
                val |= ((m->vsync_start - m->vdisplay) << 12);
-               hdmi_set_reg(core->v_sync_gen1, 3, val);
-
-               hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value  */
-               hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value  */
-               hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
-               hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
+
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
+               hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               m->vtotal - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
        }
 
        /* Timing generator registers */
-       hdmi_set_reg(tg->cmd, 1, 0x0);
-       hdmi_set_reg(tg->h_fsz, 2, m->htotal);
-       hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
-       hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
-       hdmi_set_reg(tg->vsync, 2, 0x1);
-       hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
+       hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
 }
 
-static void hdmi_v14_mode_set(struct hdmi_context *hdata,
-                       struct drm_display_mode *m)
+static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
 {
-       struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
-       struct hdmi_v14_core_regs *core =
-               &hdata->mode_conf.conf.v14_conf.core;
-
-       hdata->mode_conf.cea_video_id =
-               drm_match_cea_mode((struct drm_display_mode *)m);
-       hdata->mode_conf.pixel_clock = m->clock * 1000;
-       hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
-
-       hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(core->v_line, 2, m->vtotal);
-       hdmi_set_reg(core->h_line, 2, m->htotal);
-       hdmi_set_reg(core->hsync_pol, 1,
+       struct drm_display_mode *m = &hdata->current_mode;
+
+       hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal);
+       hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal);
+       hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1,
                        (m->flags & DRM_MODE_FLAG_NHSYNC)  ? 1 : 0);
-       hdmi_set_reg(core->vsync_pol, 1,
+       hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1,
                        (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
-       hdmi_set_reg(core->int_pro_mode, 1,
+       hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1,
                        (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
 
        /*
@@ -1917,229 +1407,255 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
        /* Following values & calculations differ for different type of modes */
        if (m->flags & DRM_MODE_FLAG_INTERLACE) {
                /* Interlaced Mode */
-               hdmi_set_reg(core->v_sync_line_bef_2, 2,
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
                        (m->vsync_end - m->vdisplay) / 2);
-               hdmi_set_reg(core->v_sync_line_bef_1, 2,
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
                        (m->vsync_start - m->vdisplay) / 2);
-               hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
-               hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
-               hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
-               hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
-               hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
-               hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
-               hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
+               hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal / 2);
+               hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
+                               (m->vtotal - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2,
+                               m->vtotal - m->vdisplay / 2);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, m->vtotal);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2,
+                               (m->vtotal / 2) + 7);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2,
+                               (m->vtotal / 2) + 2);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2,
                        (m->htotal / 2) + (m->hsync_start - m->hdisplay));
-               hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2,
                        (m->htotal / 2) + (m->hsync_start - m->hdisplay));
-               hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
-               hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
-               hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
-               hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
-               hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
-               hdmi_set_reg(tg->vact_st3, 2, 0x0);
-               hdmi_set_reg(tg->vact_st4, 2, 0x0);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               (m->vtotal - m->vdisplay) / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2,
+                               m->vtotal - m->vdisplay / 2);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2,
+                               (m->vtotal / 2) + 1);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2,
+                               (m->vtotal / 2) + 1);
+               hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2,
+                               (m->vtotal / 2) + 1);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0);
        } else {
                /* Progressive Mode */
-               hdmi_set_reg(core->v_sync_line_bef_2, 2,
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2,
                        m->vsync_end - m->vdisplay);
-               hdmi_set_reg(core->v_sync_line_bef_1, 2,
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2,
                        m->vsync_start - m->vdisplay);
-               hdmi_set_reg(core->v2_blank, 2, m->vtotal);
-               hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
-               hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
-               hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
-               hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
-               hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
-               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
-               hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
-               hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
-               hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
-               hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
-               hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
-               hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
+               hdmi_reg_writev(hdata, HDMI_V2_BLANK_0, 2, m->vtotal);
+               hdmi_reg_writev(hdata, HDMI_V1_BLANK_0, 2,
+                               m->vtotal - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F0_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_BLANK_F1_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_2_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_1_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_2_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_1_0, 2, 0xffff);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+                               m->vtotal - m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b);
+               hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
+               hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
+               hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
        }
 
        /* Following values & calculations are same irrespective of mode type */
-       hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
-       hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
-       hdmi_set_reg(core->vact_space_1, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_2, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_3, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_4, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_5, 2, 0xffff);
-       hdmi_set_reg(core->vact_space_6, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f5, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2,
+                       m->hsync_start - m->hdisplay - 2);
+       hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2,
+                       m->hsync_end - m->hdisplay - 2);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_1_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_2_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_VACT_SPACE_6_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F2_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_BLANK_F5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_6_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_3_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_4_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff);
+       hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff);
 
        /* Timing generator registers */
-       hdmi_set_reg(tg->cmd, 1, 0x0);
-       hdmi_set_reg(tg->h_fsz, 2, m->htotal);
-       hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
-       hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
-       hdmi_set_reg(tg->vsync, 2, 0x1);
-       hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
-       hdmi_set_reg(tg->tg_3d, 1, 0x0);
+       hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
+       hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
+       hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
+       hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0);
 }
 
-static void hdmi_mode_set(struct exynos_drm_display *display,
-                       struct drm_display_mode *mode)
+static void hdmi_mode_apply(struct hdmi_context *hdata)
 {
-       struct hdmi_context *hdata = display_to_hdmi(display);
-       struct drm_display_mode *m = mode;
+       if (hdata->drv_data->type == HDMI_TYPE13)
+               hdmi_v13_mode_apply(hdata);
+       else
+               hdmi_v14_mode_apply(hdata);
 
-       DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
-               m->hdisplay, m->vdisplay,
-               m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
-               "INTERLACED" : "PROGRESSIVE");
+       hdmiphy_wait_for_pll(hdata);
 
-       /* preserve mode information for later use. */
-       drm_mode_copy(&hdata->current_mode, mode);
+       clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy);
 
-       if (hdata->type == HDMI_TYPE13)
-               hdmi_v13_mode_set(hdata, mode);
-       else
-               hdmi_v14_mode_set(hdata, mode);
+       /* enable HDMI and timing generator */
+       hdmi_start(hdata, true);
+}
+
+static void hdmiphy_conf_reset(struct hdmi_context *hdata)
+{
+       clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
+
+       /* reset hdmiphy */
+       hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+       usleep_range(10000, 12000);
+       hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+       usleep_range(10000, 12000);
 }
 
-static void hdmi_commit(struct exynos_drm_display *display)
+static void hdmiphy_conf_apply(struct hdmi_context *hdata)
 {
-       struct hdmi_context *hdata = display_to_hdmi(display);
+       int ret;
+       int i;
 
-       mutex_lock(&hdata->hdmi_mutex);
-       if (!hdata->powered) {
-               mutex_unlock(&hdata->hdmi_mutex);
+       /* pixel clock */
+       i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
+       if (i < 0) {
+               DRM_ERROR("failed to find hdmiphy conf\n");
                return;
        }
-       mutex_unlock(&hdata->hdmi_mutex);
 
-       hdmi_conf_apply(hdata);
+       ret = hdmiphy_reg_write_buf(hdata, 0,
+                       hdata->drv_data->phy_confs[i].conf, 32);
+       if (ret) {
+               DRM_ERROR("failed to configure hdmiphy\n");
+               return;
+       }
+
+       usleep_range(10000, 12000);
+}
+
+static void hdmi_conf_apply(struct hdmi_context *hdata)
+{
+       hdmiphy_conf_reset(hdata);
+       hdmiphy_conf_apply(hdata);
+
+       hdmi_start(hdata, false);
+       hdmi_conf_init(hdata);
+
+       hdmi_audio_init(hdata);
+
+       /* setting core registers */
+       hdmi_mode_apply(hdata);
+       hdmi_audio_control(hdata, true);
+
+       hdmi_regs_dump(hdata, "start");
 }
 
-static void hdmi_poweron(struct hdmi_context *hdata)
+static void hdmi_mode_set(struct drm_encoder *encoder,
+                         struct drm_display_mode *mode,
+                         struct drm_display_mode *adjusted_mode)
 {
-       struct hdmi_resources *res = &hdata->res;
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
+       struct drm_display_mode *m = adjusted_mode;
 
-       mutex_lock(&hdata->hdmi_mutex);
-       if (hdata->powered) {
-               mutex_unlock(&hdata->hdmi_mutex);
+       DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
+               m->hdisplay, m->vdisplay,
+               m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
+               "INTERLACED" : "PROGRESSIVE");
+
+       drm_mode_copy(&hdata->current_mode, m);
+       hdata->cea_video_id = drm_match_cea_mode(mode);
+}
+
+static void hdmi_enable(struct drm_encoder *encoder)
+{
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
+
+       if (hdata->powered)
                return;
-       }
 
        hdata->powered = true;
 
-       mutex_unlock(&hdata->hdmi_mutex);
-
        pm_runtime_get_sync(hdata->dev);
 
-       if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
+       if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk))
                DRM_DEBUG_KMS("failed to enable regulator bulk\n");
 
        /* set pmu hdmiphy control bit to enable hdmiphy */
        regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
                        PMU_HDMI_PHY_ENABLE_BIT, 1);
 
-       clk_prepare_enable(res->hdmi);
-       clk_prepare_enable(res->sclk_hdmi);
+       clk_prepare_enable(hdata->hdmi);
+       clk_prepare_enable(hdata->sclk_hdmi);
 
-       hdmiphy_poweron(hdata);
-       hdmi_commit(&hdata->display);
+       hdmi_conf_apply(hdata);
 }
 
-static void hdmi_poweroff(struct hdmi_context *hdata)
+static void hdmi_disable(struct drm_encoder *encoder)
 {
-       struct hdmi_resources *res = &hdata->res;
+       struct hdmi_context *hdata = encoder_to_hdmi(encoder);
+       struct drm_crtc *crtc = encoder->crtc;
+       const struct drm_crtc_helper_funcs *funcs = NULL;
 
-       mutex_lock(&hdata->hdmi_mutex);
        if (!hdata->powered)
-               goto out;
-       mutex_unlock(&hdata->hdmi_mutex);
+               return;
+
+       /*
+        * The SFRs of VP and Mixer are updated by Vertical Sync of
+        * Timing generator which is a part of HDMI so the sequence
+        * to disable TV Subsystem should be as following,
+        *      VP -> Mixer -> HDMI
+        *
+        * Below codes will try to disable Mixer and VP(if used)
+        * prior to disabling HDMI.
+        */
+       if (crtc)
+               funcs = crtc->helper_private;
+       if (funcs && funcs->disable)
+               (*funcs->disable)(crtc);
 
        /* HDMI System Disable */
        hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
 
-       hdmiphy_poweroff(hdata);
-
        cancel_delayed_work(&hdata->hotplug_work);
 
-       clk_disable_unprepare(res->sclk_hdmi);
-       clk_disable_unprepare(res->hdmi);
+       clk_disable_unprepare(hdata->sclk_hdmi);
+       clk_disable_unprepare(hdata->hdmi);
 
        /* reset pmu hdmiphy control bit to disable hdmiphy */
        regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL,
                        PMU_HDMI_PHY_ENABLE_BIT, 0);
 
-       regulator_bulk_disable(res->regul_count, res->regul_bulk);
+       regulator_bulk_disable(ARRAY_SIZE(supply), hdata->regul_bulk);
 
        pm_runtime_put_sync(hdata->dev);
 
-       mutex_lock(&hdata->hdmi_mutex);
        hdata->powered = false;
-
-out:
-       mutex_unlock(&hdata->hdmi_mutex);
 }
 
-static void hdmi_dpms(struct exynos_drm_display *display, int mode)
-{
-       struct hdmi_context *hdata = display_to_hdmi(display);
-       struct drm_encoder *encoder = hdata->encoder;
-       struct drm_crtc *crtc = encoder->crtc;
-       const struct drm_crtc_helper_funcs *funcs = NULL;
-
-       DRM_DEBUG_KMS("mode %d\n", mode);
-
-       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:
-               /*
-                * The SFRs of VP and Mixer are updated by Vertical Sync of
-                * Timing generator which is a part of HDMI so the sequence
-                * to disable TV Subsystem should be as following,
-                *      VP -> Mixer -> HDMI
-                *
-                * Below codes will try to disable Mixer and VP(if used)
-                * prior to disabling HDMI.
-                */
-               if (crtc)
-                       funcs = crtc->helper_private;
-               if (funcs && funcs->dpms)
-                       (*funcs->dpms)(crtc, mode);
-
-               hdmi_poweroff(hdata);
-               break;
-       default:
-               DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
-               break;
-       }
-}
-
-static struct exynos_drm_display_ops hdmi_display_ops = {
-       .create_connector = hdmi_create_connector,
+static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
        .mode_fixup     = hdmi_mode_fixup,
        .mode_set       = hdmi_mode_set,
-       .dpms           = hdmi_dpms,
-       .commit         = hdmi_commit,
+       .enable         = hdmi_enable,
+       .disable        = hdmi_disable,
+};
+
+static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
 };
 
 static void hdmi_hotplug_work_func(struct work_struct *work)
@@ -2148,10 +1664,6 @@ static void hdmi_hotplug_work_func(struct work_struct *work)
 
        hdata = container_of(work, struct hdmi_context, hotplug_work.work);
 
-       mutex_lock(&hdata->hdmi_mutex);
-       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
-       mutex_unlock(&hdata->hdmi_mutex);
-
        if (hdata->drm_dev)
                drm_helper_hpd_irq_event(hdata->drm_dev);
 }
@@ -2169,80 +1681,76 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 static int hdmi_resources_init(struct hdmi_context *hdata)
 {
        struct device *dev = hdata->dev;
-       struct hdmi_resources *res = &hdata->res;
-       static char *supply[] = {
-               "vdd",
-               "vdd_osc",
-               "vdd_pll",
-       };
        int i, ret;
 
        DRM_DEBUG_KMS("HDMI resource init\n");
 
+       hdata->hpd_gpio = devm_gpiod_get(dev, "hpd", GPIOD_IN);
+       if (IS_ERR(hdata->hpd_gpio)) {
+               DRM_ERROR("cannot get hpd gpio property\n");
+               return PTR_ERR(hdata->hpd_gpio);
+       }
+
+       hdata->irq = gpiod_to_irq(hdata->hpd_gpio);
+       if (hdata->irq < 0) {
+               DRM_ERROR("failed to get GPIO irq\n");
+               return  hdata->irq;
+       }
        /* get clocks, power */
-       res->hdmi = devm_clk_get(dev, "hdmi");
-       if (IS_ERR(res->hdmi)) {
+       hdata->hdmi = devm_clk_get(dev, "hdmi");
+       if (IS_ERR(hdata->hdmi)) {
                DRM_ERROR("failed to get clock 'hdmi'\n");
-               ret = PTR_ERR(res->hdmi);
+               ret = PTR_ERR(hdata->hdmi);
                goto fail;
        }
-       res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
-       if (IS_ERR(res->sclk_hdmi)) {
+       hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
+       if (IS_ERR(hdata->sclk_hdmi)) {
                DRM_ERROR("failed to get clock 'sclk_hdmi'\n");
-               ret = PTR_ERR(res->sclk_hdmi);
+               ret = PTR_ERR(hdata->sclk_hdmi);
                goto fail;
        }
-       res->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
-       if (IS_ERR(res->sclk_pixel)) {
+       hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel");
+       if (IS_ERR(hdata->sclk_pixel)) {
                DRM_ERROR("failed to get clock 'sclk_pixel'\n");
-               ret = PTR_ERR(res->sclk_pixel);
+               ret = PTR_ERR(hdata->sclk_pixel);
                goto fail;
        }
-       res->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
-       if (IS_ERR(res->sclk_hdmiphy)) {
+       hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy");
+       if (IS_ERR(hdata->sclk_hdmiphy)) {
                DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n");
-               ret = PTR_ERR(res->sclk_hdmiphy);
+               ret = PTR_ERR(hdata->sclk_hdmiphy);
                goto fail;
        }
-       res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
-       if (IS_ERR(res->mout_hdmi)) {
+       hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
+       if (IS_ERR(hdata->mout_hdmi)) {
                DRM_ERROR("failed to get clock 'mout_hdmi'\n");
-               ret = PTR_ERR(res->mout_hdmi);
+               ret = PTR_ERR(hdata->mout_hdmi);
                goto fail;
        }
 
-       clk_set_parent(res->mout_hdmi, res->sclk_pixel);
+       clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel);
 
-       res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
-               sizeof(res->regul_bulk[0]), GFP_KERNEL);
-       if (!res->regul_bulk) {
-               ret = -ENOMEM;
-               goto fail;
-       }
        for (i = 0; i < ARRAY_SIZE(supply); ++i) {
-               res->regul_bulk[i].supply = supply[i];
-               res->regul_bulk[i].consumer = NULL;
+               hdata->regul_bulk[i].supply = supply[i];
+               hdata->regul_bulk[i].consumer = NULL;
        }
-       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(supply), hdata->regul_bulk);
        if (ret) {
                DRM_ERROR("failed to get regulators\n");
                return ret;
        }
-       res->regul_count = ARRAY_SIZE(supply);
 
-       res->reg_hdmi_en = devm_regulator_get(dev, "hdmi-en");
-       if (IS_ERR(res->reg_hdmi_en) && PTR_ERR(res->reg_hdmi_en) != -ENOENT) {
-               DRM_ERROR("failed to get hdmi-en regulator\n");
-               return PTR_ERR(res->reg_hdmi_en);
-       }
-       if (!IS_ERR(res->reg_hdmi_en)) {
-               ret = regulator_enable(res->reg_hdmi_en);
-               if (ret) {
-                       DRM_ERROR("failed to enable hdmi-en regulator\n");
-                       return ret;
-               }
-       } else
-               res->reg_hdmi_en = NULL;
+       hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
+
+       if (PTR_ERR(hdata->reg_hdmi_en) == -ENODEV)
+               return 0;
+
+       if (IS_ERR(hdata->reg_hdmi_en))
+               return PTR_ERR(hdata->reg_hdmi_en);
+
+       ret = regulator_enable(hdata->reg_hdmi_en);
+       if (ret)
+               DRM_ERROR("failed to enable hdmi-en regulator\n");
 
        return ret;
 fail:
@@ -2250,35 +1758,8 @@ fail:
        return ret;
 }
 
-static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
-                                       (struct device *dev)
-{
-       struct device_node *np = dev->of_node;
-       struct s5p_hdmi_platform_data *pd;
-       u32 value;
-
-       pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
-       if (!pd)
-               goto err_data;
-
-       if (!of_find_property(np, "hpd-gpio", &value)) {
-               DRM_ERROR("no hpd gpio property found\n");
-               goto err_data;
-       }
-
-       pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
-
-       return pd;
-
-err_data:
-       return NULL;
-}
-
 static struct of_device_id hdmi_match_types[] = {
        {
-               .compatible = "samsung,exynos5-hdmi",
-               .data = &exynos5_hdmi_driver_data,
-       }, {
                .compatible = "samsung,exynos4210-hdmi",
                .data = &exynos4210_hdmi_driver_data,
        }, {
@@ -2297,10 +1778,33 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        struct drm_device *drm_dev = data;
        struct hdmi_context *hdata = dev_get_drvdata(dev);
+       struct drm_encoder *encoder = &hdata->encoder;
+       int ret, pipe;
 
        hdata->drm_dev = drm_dev;
 
-       return exynos_drm_create_enc_conn(drm_dev, &hdata->display);
+       pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
+                                                 EXYNOS_DISPLAY_TYPE_HDMI);
+       if (pipe < 0)
+               return pipe;
+
+       encoder->possible_crtcs = 1 << pipe;
+
+       DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+       drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+
+       drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
+
+       ret = hdmi_create_connector(encoder);
+       if (ret) {
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
+               drm_encoder_cleanup(encoder);
+               return ret;
+       }
+
+       return 0;
 }
 
 static void hdmi_unbind(struct device *dev, struct device *master, void *data)
@@ -2334,49 +1838,24 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev)
 static int hdmi_probe(struct platform_device *pdev)
 {
        struct device_node *ddc_node, *phy_node;
-       struct s5p_hdmi_platform_data *pdata;
-       struct hdmi_driver_data *drv_data;
        const struct of_device_id *match;
        struct device *dev = &pdev->dev;
        struct hdmi_context *hdata;
        struct resource *res;
        int ret;
 
-       if (!dev->of_node)
-               return -ENODEV;
-
-       pdata = drm_hdmi_dt_parse_pdata(dev);
-       if (!pdata)
-               return -EINVAL;
-
        hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
        if (!hdata)
                return -ENOMEM;
 
-       hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
-       hdata->display.ops = &hdmi_display_ops;
-
-       ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
-                                       hdata->display.type);
-       if (ret)
-               return ret;
+       match = of_match_device(hdmi_match_types, dev);
+       if (!match)
+               return -ENODEV;
 
-       mutex_init(&hdata->hdmi_mutex);
+       hdata->drv_data = match->data;
 
        platform_set_drvdata(pdev, hdata);
 
-       match = of_match_node(hdmi_match_types, dev->of_node);
-       if (!match) {
-               ret = -ENODEV;
-               goto err_del_component;
-       }
-
-       drv_data = (struct hdmi_driver_data *)match->data;
-       hdata->type = drv_data->type;
-       hdata->phy_confs = drv_data->phy_confs;
-       hdata->phy_conf_count = drv_data->phy_conf_count;
-
-       hdata->hpd_gpio = pdata->hpd_gpio;
        hdata->dev = dev;
 
        ret = hdmi_resources_init(hdata);
@@ -2389,13 +1868,7 @@ static int hdmi_probe(struct platform_device *pdev)
        hdata->regs = devm_ioremap_resource(dev, res);
        if (IS_ERR(hdata->regs)) {
                ret = PTR_ERR(hdata->regs);
-               goto err_del_component;
-       }
-
-       ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
-       if (ret) {
-               DRM_ERROR("failed to request HPD gpio\n");
-               goto err_del_component;
+               return ret;
        }
 
        ddc_node = hdmi_legacy_ddc_dt_binding(dev);
@@ -2406,8 +1879,7 @@ static int hdmi_probe(struct platform_device *pdev)
        ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
        if (!ddc_node) {
                DRM_ERROR("Failed to find ddc node in device tree\n");
-               ret = -ENODEV;
-               goto err_del_component;
+               return -ENODEV;
        }
 
 out_get_ddc_adpt:
@@ -2430,7 +1902,7 @@ out_get_ddc_adpt:
        }
 
 out_get_phy_port:
-       if (drv_data->is_apb_phy) {
+       if (hdata->drv_data->is_apb_phy) {
                hdata->regs_hdmiphy = of_iomap(phy_node, 0);
                if (!hdata->regs_hdmiphy) {
                        DRM_ERROR("failed to ioremap hdmi phy\n");
@@ -2446,15 +1918,6 @@ out_get_phy_port:
                }
        }
 
-       hdata->irq = gpio_to_irq(hdata->hpd_gpio);
-       if (hdata->irq < 0) {
-               DRM_ERROR("failed to get GPIO irq\n");
-               ret = hdata->irq;
-               goto err_hdmiphy;
-       }
-
-       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
-
        INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
 
        ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
@@ -2491,9 +1954,6 @@ err_hdmiphy:
 err_ddc:
        put_device(&hdata->ddc_adpt->dev);
 
-err_del_component:
-       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
-
        return ret;
 }
 
@@ -2503,17 +1963,18 @@ static int hdmi_remove(struct platform_device *pdev)
 
        cancel_delayed_work_sync(&hdata->hotplug_work);
 
-       if (hdata->res.reg_hdmi_en)
-               regulator_disable(hdata->res.reg_hdmi_en);
+       component_del(&pdev->dev, &hdmi_component_ops);
+
+       pm_runtime_disable(&pdev->dev);
+
+       if (!IS_ERR(hdata->reg_hdmi_en))
+               regulator_disable(hdata->reg_hdmi_en);
 
        if (hdata->hdmiphy_port)
                put_device(&hdata->hdmiphy_port->dev);
-       put_device(&hdata->ddc_adpt->dev);
 
-       pm_runtime_disable(&pdev->dev);
-       component_del(&pdev->dev, &hdmi_component_ops);
+       put_device(&hdata->ddc_adpt->dev);
 
-       exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
        return 0;
 }