All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/14] updated exynos-drm-next.
@ 2012-03-16  9:47 Inki Dae
  2012-03-16  9:47 ` [PATCH v2 01/14] drm/exynos: add HDMI version 1.4 support Inki Dae
                   ` (14 more replies)
  0 siblings, 15 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

Hi, Dave and all.

this update adds new features below:
- add HDMI version 1.4 and Audio support.
- add mode_fixup feature.
  . hdmi module would change current mode to driver desired mode properly.
- updated gem and buffer framework.
  . we can allocate physically continuous or non-continuous
    memory and also it creates scatterlist for iommu support so allocated
    memory region can be mapped to iommu page table using scatterlist.
- add dma address get/put interface.
  . this function would be used for drm based 2d acceleration driver
    to get/put dma address through gem handle.
    when exynos_drm_get_dma_address is called reference count of
    gem object would be increased not to be released by gem close and
    when exynos_drm_put_dma_address is called the reference count of
    this gem object would be decreased to be released.
- add virtual display driver.
  . this driver would be used for wireless display.
- add direct rendering based 2d graphics acceleration module.
  . exynos SoC chip has fimg2d named 2d graphics accelerator and this driver
    supports only exynos4x12 series.

Links to previous versions of the patchset:
v1: < http://permalink.gmane.org/gmane.comp.video.dri.devel/66247 >

Changelog v2:
- add HDMI Audio support.
- add descriptions for direct rendering based g2d driver and
  user application for it.
  . for user application, you can refer to this link below:
	http://www.spinics.net/lists/dri-devel/msg20014.html
- fix variable type Dave pointed out.
  . use __u64 __user * instead of void *
- code clean to exynos gem and buffer framework.
- add default pixel format for plane.

this patch set is based on git repository below:
	git://people.freedesktop.org/~airlied/linux.git drm-core-next
	commit-id: 8229c885fe361e521ac64de36b16011e54a30de0

and you can refer to our working git repository below:
	git://git.infradead.org/users/kmpark/linux-samsung exynos-drm-next

Thanks.

Eunchul Kim (1):
  drm/exynos: add default pixel format for plane

Inki Dae (4):
  drm/exynos: added mode_fixup feature and code clean.
  drm/exynos: update gem and buffer framework.
  drm/exynos: added new funtion to get/put dma address.
  drm/exynos: added virtual display driver.

Joonyoung Shim (8):
  drm/exynos: add HDMI version 1.4 support
  drm/exynos: release pending pageflip events when closed
  drm/exynos: remove module of exynos drm subdrv
  drm/exynos: add subdrv open/close functions
  drm/exynos: add is_local member in exynos_drm_subdrv struct
  drm/exynos: add G2D driver
  drm/exynos: remove exynos_mixer.h
  drm/exynos: cleanup exynos_hdmi.h

Seung-Woo Kim (1):
  drm/exynos: enable hdmi audio feature

 drivers/gpu/drm/exynos/Kconfig                |   20 +-
 drivers/gpu/drm/exynos/Makefile               |   12 +-
 drivers/gpu/drm/exynos/exynos_ddc.c           |    1 -
 drivers/gpu/drm/exynos/exynos_drm_buf.c       |  191 +++-
 drivers/gpu/drm/exynos/exynos_drm_buf.h       |   22 +-
 drivers/gpu/drm/exynos/exynos_drm_connector.c |   35 +-
 drivers/gpu/drm/exynos/exynos_drm_core.c      |  140 +--
 drivers/gpu/drm/exynos/exynos_drm_crtc.c      |   12 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c       |  125 +++-
 drivers/gpu/drm/exynos/exynos_drm_drv.h       |   51 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c   |   24 +-
 drivers/gpu/drm/exynos/exynos_drm_fb.c        |    6 -
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c     |   90 +--
 drivers/gpu/drm/exynos/exynos_drm_fimd.c      |   20 +-
 drivers/gpu/drm/exynos/exynos_drm_g2d.c       |  885 +++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_g2d.h       |   36 +
 drivers/gpu/drm/exynos/exynos_drm_gem.c       |  363 ++++++-
 drivers/gpu/drm/exynos/exynos_drm_gem.h       |   29 +-
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c      |  115 +--
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h      |    5 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c     |    8 +-
 drivers/gpu/drm/exynos/exynos_drm_vidi.c      |  676 ++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_vidi.h      |   36 +
 drivers/gpu/drm/exynos/exynos_hdmi.c          | 1437 +++++++++++++++++++++++--
 drivers/gpu/drm/exynos/exynos_hdmi.h          |   50 -
 drivers/gpu/drm/exynos/exynos_mixer.c         |   57 +-
 drivers/gpu/drm/exynos/exynos_mixer.h         |   92 --
 drivers/gpu/drm/exynos/regs-hdmi.h            |  488 ++++++++-
 include/drm/exynos_drm.h                      |   83 ++
 29 files changed, 4394 insertions(+), 715 deletions(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_g2d.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_g2d.h
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_vidi.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_vidi.h
 delete mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h

-- 
1.7.4.1

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 01/14] drm/exynos: add HDMI version 1.4 support
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 02/14] drm/exynos: added mode_fixup feature and code clean Inki Dae
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

Later Exynos series from Exynos4X12 support HDMI version 1.4. We will
distinguish to use which version via platform data. This patch supports
only default features of HDMI version 1.4(The 3D, sound and etc don't
support yet)

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_hdmi.c | 1152 +++++++++++++++++++++++++++++++---
 drivers/gpu/drm/exynos/exynos_hdmi.h |   10 +-
 drivers/gpu/drm/exynos/regs-hdmi.h   |  306 ++++++++--
 include/drm/exynos_drm.h             |    2 +
 4 files changed, 1325 insertions(+), 145 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 3429d3f..1cfe86e 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -43,42 +43,43 @@
 #define HDMI_OVERLAY_NUMBER	3
 #define get_hdmi_context(dev)	platform_get_drvdata(to_platform_device(dev))
 
-static const u8 hdmiphy_conf27[32] = {
+/* HDMI Version 1.3 */
+static const u8 hdmiphy_v13_conf27[32] = {
 	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,
 };
 
-static const u8 hdmiphy_conf27_027[32] = {
+static const u8 hdmiphy_v13_conf27_027[32] = {
 	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,
 };
 
-static const u8 hdmiphy_conf74_175[32] = {
+static const u8 hdmiphy_v13_conf74_175[32] = {
 	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,
 };
 
-static const u8 hdmiphy_conf74_25[32] = {
+static const u8 hdmiphy_v13_conf74_25[32] = {
 	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,
 };
 
-static const u8 hdmiphy_conf148_5[32] = {
+static const u8 hdmiphy_v13_conf148_5[32] = {
 	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,
 };
 
-struct hdmi_tg_regs {
+struct hdmi_v13_tg_regs {
 	u8 cmd;
 	u8 h_fsz_l;
 	u8 h_fsz_h;
@@ -110,7 +111,7 @@ struct hdmi_tg_regs {
 	u8 field_bot_hdmi_h;
 };
 
-struct hdmi_core_regs {
+struct hdmi_v13_core_regs {
 	u8 h_blank[2];
 	u8 v_blank[3];
 	u8 h_v_line[3];
@@ -123,12 +124,21 @@ struct hdmi_core_regs {
 	u8 v_sync_gen3[3];
 };
 
-struct hdmi_preset_conf {
-	struct hdmi_core_regs core;
-	struct hdmi_tg_regs tg;
+struct hdmi_v13_preset_conf {
+	struct hdmi_v13_core_regs core;
+	struct hdmi_v13_tg_regs tg;
+};
+
+struct hdmi_v13_conf {
+	int width;
+	int height;
+	int vrefresh;
+	bool interlace;
+	const u8 *hdmiphy_data;
+	const struct hdmi_v13_preset_conf *conf;
 };
 
-static const struct hdmi_preset_conf hdmi_conf_480p = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_480p = {
 	.core = {
 		.h_blank = {0x8a, 0x00},
 		.v_blank = {0x0d, 0x6a, 0x01},
@@ -154,7 +164,7 @@ static const struct hdmi_preset_conf hdmi_conf_480p = {
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_720p60 = {
 	.core = {
 		.h_blank = {0x72, 0x01},
 		.v_blank = {0xee, 0xf2, 0x00},
@@ -182,7 +192,7 @@ static const struct hdmi_preset_conf hdmi_conf_720p60 = {
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i50 = {
 	.core = {
 		.h_blank = {0xd0, 0x02},
 		.v_blank = {0x32, 0xB2, 0x00},
@@ -210,7 +220,7 @@ static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p50 = {
 	.core = {
 		.h_blank = {0xd0, 0x02},
 		.v_blank = {0x65, 0x6c, 0x01},
@@ -238,7 +248,7 @@ static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080i60 = {
 	.core = {
 		.h_blank = {0x18, 0x01},
 		.v_blank = {0x32, 0xB2, 0x00},
@@ -266,7 +276,7 @@ static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
 	},
 };
 
-static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+static const struct hdmi_v13_preset_conf hdmi_v13_conf_1080p60 = {
 	.core = {
 		.h_blank = {0x18, 0x01},
 		.v_blank = {0x65, 0x6c, 0x01},
@@ -294,13 +304,530 @@ static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
 	},
 };
 
+static const struct hdmi_v13_conf hdmi_v13_confs[] = {
+	{ 1280, 720, 60, false, hdmiphy_v13_conf74_25, &hdmi_v13_conf_720p60 },
+	{ 1280, 720, 50, false, hdmiphy_v13_conf74_25, &hdmi_v13_conf_720p60 },
+	{ 720, 480, 60, false, hdmiphy_v13_conf27_027, &hdmi_v13_conf_480p },
+	{ 1920, 1080, 50, true, hdmiphy_v13_conf74_25, &hdmi_v13_conf_1080i50 },
+	{ 1920, 1080, 50, false, hdmiphy_v13_conf148_5,
+				 &hdmi_v13_conf_1080p50 },
+	{ 1920, 1080, 60, true, hdmiphy_v13_conf74_25, &hdmi_v13_conf_1080i60 },
+	{ 1920, 1080, 60, false, hdmiphy_v13_conf148_5,
+				 &hdmi_v13_conf_1080p60 },
+};
+
+/* HDMI Version 1.4 */
+static const u8 hdmiphy_conf27_027[32] = {
+	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,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+	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,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+	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,
+};
+
+struct hdmi_tg_regs {
+	u8 cmd;
+	u8 h_fsz_l;
+	u8 h_fsz_h;
+	u8 hact_st_l;
+	u8 hact_st_h;
+	u8 hact_sz_l;
+	u8 hact_sz_h;
+	u8 v_fsz_l;
+	u8 v_fsz_h;
+	u8 vsync_l;
+	u8 vsync_h;
+	u8 vsync2_l;
+	u8 vsync2_h;
+	u8 vact_st_l;
+	u8 vact_st_h;
+	u8 vact_sz_l;
+	u8 vact_sz_h;
+	u8 field_chg_l;
+	u8 field_chg_h;
+	u8 vact_st2_l;
+	u8 vact_st2_h;
+	u8 vact_st3_l;
+	u8 vact_st3_h;
+	u8 vact_st4_l;
+	u8 vact_st4_h;
+	u8 vsync_top_hdmi_l;
+	u8 vsync_top_hdmi_h;
+	u8 vsync_bot_hdmi_l;
+	u8 vsync_bot_hdmi_h;
+	u8 field_top_hdmi_l;
+	u8 field_top_hdmi_h;
+	u8 field_bot_hdmi_l;
+	u8 field_bot_hdmi_h;
+	u8 tg_3d;
+};
+
+struct hdmi_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];
+};
+
+struct hdmi_preset_conf {
+	struct hdmi_core_regs core;
+	struct hdmi_tg_regs tg;
+};
+
+struct hdmi_conf {
+	int width;
+	int height;
+	int vrefresh;
+	bool interlace;
+	const u8 *hdmiphy_data;
+	const struct hdmi_preset_conf *conf;
+};
+
+static const struct hdmi_preset_conf hdmi_conf_480p60 = {
+	.core = {
+		.h_blank = {0x8a, 0x00},
+		.v2_blank = {0x0d, 0x02},
+		.v1_blank = {0x2d, 0x00},
+		.v_line = {0x0d, 0x02},
+		.h_line = {0x5a, 0x03},
+		.hsync_pol = {0x01},
+		.vsync_pol = {0x01},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x0e, 0x00},
+		.h_sync_end = {0x4c, 0x00},
+		.v_sync_line_bef_2 = {0x0f, 0x00},
+		.v_sync_line_bef_1 = {0x09, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x5a, 0x03, /* h_fsz */
+		0x8a, 0x00, 0xd0, 0x02, /* hact */
+		0x0d, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0xe0, 0x01, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50 = {
+	.core = {
+		.h_blank = {0xbc, 0x02},
+		.v2_blank = {0xee, 0x02},
+		.v1_blank = {0x1e, 0x00},
+		.v_line = {0xee, 0x02},
+		.h_line = {0xbc, 0x07},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0xb6, 0x01},
+		.h_sync_end = {0xde, 0x01},
+		.v_sync_line_bef_2 = {0x0a, 0x00},
+		.v_sync_line_bef_1 = {0x05, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0xbc, 0x07, /* h_fsz */
+		0xbc, 0x02, 0x00, 0x05, /* hact */
+		0xee, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x1e, 0x00, 0xd0, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+	.core = {
+		.h_blank = {0x72, 0x01},
+		.v2_blank = {0xee, 0x02},
+		.v1_blank = {0x1e, 0x00},
+		.v_line = {0xee, 0x02},
+		.h_line = {0x72, 0x06},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x6c, 0x00},
+		.h_sync_end = {0x94, 0x00},
+		.v_sync_line_bef_2 = {0x0a, 0x00},
+		.v_sync_line_bef_1 = {0x05, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x72, 0x06, /* h_fsz */
+		0x72, 0x01, 0x00, 0x05, /* hact */
+		0xee, 0x02, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x1e, 0x00, 0xd0, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
+	.core = {
+		.h_blank = {0xd0, 0x02},
+		.v2_blank = {0x32, 0x02},
+		.v1_blank = {0x16, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x50, 0x0a},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x01},
+		.v_blank_f0 = {0x49, 0x02},
+		.v_blank_f1 = {0x65, 0x04},
+		.h_sync_start = {0x0e, 0x02},
+		.h_sync_end = {0x3a, 0x02},
+		.v_sync_line_bef_2 = {0x07, 0x00},
+		.v_sync_line_bef_1 = {0x02, 0x00},
+		.v_sync_line_aft_2 = {0x39, 0x02},
+		.v_sync_line_aft_1 = {0x34, 0x02},
+		.v_sync_line_aft_pxl_2 = {0x38, 0x07},
+		.v_sync_line_aft_pxl_1 = {0x38, 0x07},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x50, 0x0a, /* h_fsz */
+		0xd0, 0x02, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x16, 0x00, 0x1c, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x49, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+	.core = {
+		.h_blank = {0x18, 0x01},
+		.v2_blank = {0x32, 0x02},
+		.v1_blank = {0x16, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x98, 0x08},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x01},
+		.v_blank_f0 = {0x49, 0x02},
+		.v_blank_f1 = {0x65, 0x04},
+		.h_sync_start = {0x56, 0x00},
+		.h_sync_end = {0x82, 0x00},
+		.v_sync_line_bef_2 = {0x07, 0x00},
+		.v_sync_line_bef_1 = {0x02, 0x00},
+		.v_sync_line_aft_2 = {0x39, 0x02},
+		.v_sync_line_aft_1 = {0x34, 0x02},
+		.v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+		.v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x98, 0x08, /* h_fsz */
+		0x18, 0x01, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x16, 0x00, 0x1c, 0x02, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x49, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+	.core = {
+		.h_blank = {0xd0, 0x02},
+		.v2_blank = {0x65, 0x04},
+		.v1_blank = {0x2d, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x50, 0x0a},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x0e, 0x02},
+		.h_sync_end = {0x3a, 0x02},
+		.v_sync_line_bef_2 = {0x09, 0x00},
+		.v_sync_line_bef_1 = {0x04, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		.vact_space_1 = {0xff, 0xff},
+		.vact_space_2 = {0xff, 0xff},
+		.vact_space_3 = {0xff, 0xff},
+		.vact_space_4 = {0xff, 0xff},
+		.vact_space_5 = {0xff, 0xff},
+		.vact_space_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x50, 0x0a, /* h_fsz */
+		0xd0, 0x02, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0x38, 0x04, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+	.core = {
+		.h_blank = {0x18, 0x01},
+		.v2_blank = {0x65, 0x04},
+		.v1_blank = {0x2d, 0x00},
+		.v_line = {0x65, 0x04},
+		.h_line = {0x98, 0x08},
+		.hsync_pol = {0x00},
+		.vsync_pol = {0x00},
+		.int_pro_mode = {0x00},
+		.v_blank_f0 = {0xff, 0xff},
+		.v_blank_f1 = {0xff, 0xff},
+		.h_sync_start = {0x56, 0x00},
+		.h_sync_end = {0x82, 0x00},
+		.v_sync_line_bef_2 = {0x09, 0x00},
+		.v_sync_line_bef_1 = {0x04, 0x00},
+		.v_sync_line_aft_2 = {0xff, 0xff},
+		.v_sync_line_aft_1 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_2 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_1 = {0xff, 0xff},
+		.v_blank_f2 = {0xff, 0xff},
+		.v_blank_f3 = {0xff, 0xff},
+		.v_blank_f4 = {0xff, 0xff},
+		.v_blank_f5 = {0xff, 0xff},
+		.v_sync_line_aft_3 = {0xff, 0xff},
+		.v_sync_line_aft_4 = {0xff, 0xff},
+		.v_sync_line_aft_5 = {0xff, 0xff},
+		.v_sync_line_aft_6 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_3 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_4 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_5 = {0xff, 0xff},
+		.v_sync_line_aft_pxl_6 = {0xff, 0xff},
+		/* other don't care */
+	},
+	.tg = {
+		0x00, /* cmd */
+		0x98, 0x08, /* h_fsz */
+		0x18, 0x01, 0x80, 0x07, /* hact */
+		0x65, 0x04, /* v_fsz */
+		0x01, 0x00, 0x33, 0x02, /* vsync */
+		0x2d, 0x00, 0x38, 0x04, /* vact */
+		0x33, 0x02, /* field_chg */
+		0x48, 0x02, /* vact_st2 */
+		0x00, 0x00, /* vact_st3 */
+		0x00, 0x00, /* vact_st4 */
+		0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+		0x01, 0x00, 0x33, 0x02, /* field top/bot */
+		0x00, /* 3d FP */
+	},
+};
+
 static const struct hdmi_conf hdmi_confs[] = {
+	{ 720, 480, 60, false, hdmiphy_conf27_027, &hdmi_conf_480p60 },
+	{ 1280, 720, 50, false, hdmiphy_conf74_25, &hdmi_conf_720p50 },
 	{ 1280, 720, 60, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
-	{ 1280, 720, 50, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
-	{ 720, 480, 60, false, hdmiphy_conf27_027, &hdmi_conf_480p },
 	{ 1920, 1080, 50, true, hdmiphy_conf74_25, &hdmi_conf_1080i50 },
-	{ 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
 	{ 1920, 1080, 60, true, hdmiphy_conf74_25, &hdmi_conf_1080i60 },
+	{ 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
 	{ 1920, 1080, 60, false, hdmiphy_conf148_5, &hdmi_conf_1080p60 },
 };
 
@@ -324,7 +851,7 @@ static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
 	writel(value, hdata->regs + reg_id);
 }
 
-static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
+static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix)
 {
 #define DUMPREG(reg_id) \
 	DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
@@ -333,6 +860,101 @@ static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
 	DUMPREG(HDMI_INTC_FLAG);
 	DUMPREG(HDMI_INTC_CON);
 	DUMPREG(HDMI_HPD_STATUS);
+	DUMPREG(HDMI_V13_PHY_RSTOUT);
+	DUMPREG(HDMI_V13_PHY_VPLL);
+	DUMPREG(HDMI_V13_PHY_CMU);
+	DUMPREG(HDMI_V13_CORE_RSTOUT);
+
+	DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_CON_0);
+	DUMPREG(HDMI_CON_1);
+	DUMPREG(HDMI_CON_2);
+	DUMPREG(HDMI_SYS_STATUS);
+	DUMPREG(HDMI_V13_PHY_STATUS);
+	DUMPREG(HDMI_STATUS_EN);
+	DUMPREG(HDMI_HPD);
+	DUMPREG(HDMI_MODE_SEL);
+	DUMPREG(HDMI_V13_HPD_GEN);
+	DUMPREG(HDMI_V13_DC_CONTROL);
+	DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN);
+
+	DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_H_BLANK_0);
+	DUMPREG(HDMI_H_BLANK_1);
+	DUMPREG(HDMI_V13_V_BLANK_0);
+	DUMPREG(HDMI_V13_V_BLANK_1);
+	DUMPREG(HDMI_V13_V_BLANK_2);
+	DUMPREG(HDMI_V13_H_V_LINE_0);
+	DUMPREG(HDMI_V13_H_V_LINE_1);
+	DUMPREG(HDMI_V13_H_V_LINE_2);
+	DUMPREG(HDMI_VSYNC_POL);
+	DUMPREG(HDMI_INT_PRO_MODE);
+	DUMPREG(HDMI_V13_V_BLANK_F_0);
+	DUMPREG(HDMI_V13_V_BLANK_F_1);
+	DUMPREG(HDMI_V13_V_BLANK_F_2);
+	DUMPREG(HDMI_V13_H_SYNC_GEN_0);
+	DUMPREG(HDMI_V13_H_SYNC_GEN_1);
+	DUMPREG(HDMI_V13_H_SYNC_GEN_2);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_1_0);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_1_1);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_1_2);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_2_0);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_2_1);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_2_2);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_3_0);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_3_1);
+	DUMPREG(HDMI_V13_V_SYNC_GEN_3_2);
+
+	DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_TG_CMD);
+	DUMPREG(HDMI_TG_H_FSZ_L);
+	DUMPREG(HDMI_TG_H_FSZ_H);
+	DUMPREG(HDMI_TG_HACT_ST_L);
+	DUMPREG(HDMI_TG_HACT_ST_H);
+	DUMPREG(HDMI_TG_HACT_SZ_L);
+	DUMPREG(HDMI_TG_HACT_SZ_H);
+	DUMPREG(HDMI_TG_V_FSZ_L);
+	DUMPREG(HDMI_TG_V_FSZ_H);
+	DUMPREG(HDMI_TG_VSYNC_L);
+	DUMPREG(HDMI_TG_VSYNC_H);
+	DUMPREG(HDMI_TG_VSYNC2_L);
+	DUMPREG(HDMI_TG_VSYNC2_H);
+	DUMPREG(HDMI_TG_VACT_ST_L);
+	DUMPREG(HDMI_TG_VACT_ST_H);
+	DUMPREG(HDMI_TG_VACT_SZ_L);
+	DUMPREG(HDMI_TG_VACT_SZ_H);
+	DUMPREG(HDMI_TG_FIELD_CHG_L);
+	DUMPREG(HDMI_TG_FIELD_CHG_H);
+	DUMPREG(HDMI_TG_VACT_ST2_L);
+	DUMPREG(HDMI_TG_VACT_ST2_H);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
+
+static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix)
+{
+	int i;
+
+#define DUMPREG(reg_id) \
+	DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \
+	readl(hdata->regs + reg_id))
+
+	DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_INTC_CON);
+	DUMPREG(HDMI_INTC_FLAG);
+	DUMPREG(HDMI_HPD_STATUS);
+	DUMPREG(HDMI_INTC_CON_1);
+	DUMPREG(HDMI_INTC_FLAG_1);
+	DUMPREG(HDMI_PHY_STATUS_0);
+	DUMPREG(HDMI_PHY_STATUS_PLL);
+	DUMPREG(HDMI_PHY_CON_0);
 	DUMPREG(HDMI_PHY_RSTOUT);
 	DUMPREG(HDMI_PHY_VPLL);
 	DUMPREG(HDMI_PHY_CMU);
@@ -343,40 +965,93 @@ static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
 	DUMPREG(HDMI_CON_1);
 	DUMPREG(HDMI_CON_2);
 	DUMPREG(HDMI_SYS_STATUS);
-	DUMPREG(HDMI_PHY_STATUS);
+	DUMPREG(HDMI_PHY_STATUS_0);
 	DUMPREG(HDMI_STATUS_EN);
 	DUMPREG(HDMI_HPD);
 	DUMPREG(HDMI_MODE_SEL);
-	DUMPREG(HDMI_HPD_GEN);
+	DUMPREG(HDMI_ENC_EN);
 	DUMPREG(HDMI_DC_CONTROL);
 	DUMPREG(HDMI_VIDEO_PATTERN_GEN);
 
 	DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix);
 	DUMPREG(HDMI_H_BLANK_0);
 	DUMPREG(HDMI_H_BLANK_1);
-	DUMPREG(HDMI_V_BLANK_0);
-	DUMPREG(HDMI_V_BLANK_1);
-	DUMPREG(HDMI_V_BLANK_2);
-	DUMPREG(HDMI_H_V_LINE_0);
-	DUMPREG(HDMI_H_V_LINE_1);
-	DUMPREG(HDMI_H_V_LINE_2);
+	DUMPREG(HDMI_V2_BLANK_0);
+	DUMPREG(HDMI_V2_BLANK_1);
+	DUMPREG(HDMI_V1_BLANK_0);
+	DUMPREG(HDMI_V1_BLANK_1);
+	DUMPREG(HDMI_V_LINE_0);
+	DUMPREG(HDMI_V_LINE_1);
+	DUMPREG(HDMI_H_LINE_0);
+	DUMPREG(HDMI_H_LINE_1);
+	DUMPREG(HDMI_HSYNC_POL);
+
 	DUMPREG(HDMI_VSYNC_POL);
 	DUMPREG(HDMI_INT_PRO_MODE);
-	DUMPREG(HDMI_V_BLANK_F_0);
-	DUMPREG(HDMI_V_BLANK_F_1);
-	DUMPREG(HDMI_V_BLANK_F_2);
-	DUMPREG(HDMI_H_SYNC_GEN_0);
-	DUMPREG(HDMI_H_SYNC_GEN_1);
-	DUMPREG(HDMI_H_SYNC_GEN_2);
-	DUMPREG(HDMI_V_SYNC_GEN_1_0);
-	DUMPREG(HDMI_V_SYNC_GEN_1_1);
-	DUMPREG(HDMI_V_SYNC_GEN_1_2);
-	DUMPREG(HDMI_V_SYNC_GEN_2_0);
-	DUMPREG(HDMI_V_SYNC_GEN_2_1);
-	DUMPREG(HDMI_V_SYNC_GEN_2_2);
-	DUMPREG(HDMI_V_SYNC_GEN_3_0);
-	DUMPREG(HDMI_V_SYNC_GEN_3_1);
-	DUMPREG(HDMI_V_SYNC_GEN_3_2);
+	DUMPREG(HDMI_V_BLANK_F0_0);
+	DUMPREG(HDMI_V_BLANK_F0_1);
+	DUMPREG(HDMI_V_BLANK_F1_0);
+	DUMPREG(HDMI_V_BLANK_F1_1);
+
+	DUMPREG(HDMI_H_SYNC_START_0);
+	DUMPREG(HDMI_H_SYNC_START_1);
+	DUMPREG(HDMI_H_SYNC_END_0);
+	DUMPREG(HDMI_H_SYNC_END_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
+	DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
+
+	DUMPREG(HDMI_V_BLANK_F2_0);
+	DUMPREG(HDMI_V_BLANK_F2_1);
+	DUMPREG(HDMI_V_BLANK_F3_0);
+	DUMPREG(HDMI_V_BLANK_F3_1);
+	DUMPREG(HDMI_V_BLANK_F4_0);
+	DUMPREG(HDMI_V_BLANK_F4_1);
+	DUMPREG(HDMI_V_BLANK_F5_0);
+	DUMPREG(HDMI_V_BLANK_F5_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
+
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
+	DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
+
+	DUMPREG(HDMI_VACT_SPACE_1_0);
+	DUMPREG(HDMI_VACT_SPACE_1_1);
+	DUMPREG(HDMI_VACT_SPACE_2_0);
+	DUMPREG(HDMI_VACT_SPACE_2_1);
+	DUMPREG(HDMI_VACT_SPACE_3_0);
+	DUMPREG(HDMI_VACT_SPACE_3_1);
+	DUMPREG(HDMI_VACT_SPACE_4_0);
+	DUMPREG(HDMI_VACT_SPACE_4_1);
+	DUMPREG(HDMI_VACT_SPACE_5_0);
+	DUMPREG(HDMI_VACT_SPACE_5_1);
+	DUMPREG(HDMI_VACT_SPACE_6_0);
+	DUMPREG(HDMI_VACT_SPACE_6_1);
 
 	DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix);
 	DUMPREG(HDMI_TG_CMD);
@@ -400,6 +1075,10 @@ static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
 	DUMPREG(HDMI_TG_FIELD_CHG_H);
 	DUMPREG(HDMI_TG_VACT_ST2_L);
 	DUMPREG(HDMI_TG_VACT_ST2_H);
+	DUMPREG(HDMI_TG_VACT_ST3_L);
+	DUMPREG(HDMI_TG_VACT_ST3_H);
+	DUMPREG(HDMI_TG_VACT_ST4_L);
+	DUMPREG(HDMI_TG_VACT_ST4_H);
 	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
 	DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
 	DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
@@ -408,10 +1087,49 @@ static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
 	DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
 	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
 	DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+	DUMPREG(HDMI_TG_3D);
+
+	DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix);
+	DUMPREG(HDMI_AVI_CON);
+	DUMPREG(HDMI_AVI_HEADER0);
+	DUMPREG(HDMI_AVI_HEADER1);
+	DUMPREG(HDMI_AVI_HEADER2);
+	DUMPREG(HDMI_AVI_CHECK_SUM);
+	DUMPREG(HDMI_VSI_CON);
+	DUMPREG(HDMI_VSI_HEADER0);
+	DUMPREG(HDMI_VSI_HEADER1);
+	DUMPREG(HDMI_VSI_HEADER2);
+	for (i = 0; i < 7; ++i)
+		DUMPREG(HDMI_VSI_DATA(i));
+
 #undef DUMPREG
 }
 
-static int hdmi_conf_index(struct drm_display_mode *mode)
+static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
+{
+	if (hdata->is_v13)
+		hdmi_v13_regs_dump(hdata, prefix);
+	else
+		hdmi_v14_regs_dump(hdata, prefix);
+}
+
+static int hdmi_v13_conf_index(struct drm_display_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
+		if (hdmi_v13_confs[i].width == mode->hdisplay &&
+				hdmi_v13_confs[i].height == mode->vdisplay &&
+				hdmi_v13_confs[i].vrefresh == mode->vrefresh &&
+				hdmi_v13_confs[i].interlace ==
+				((mode->flags & DRM_MODE_FLAG_INTERLACE) ?
+				 true : false))
+			return i;
+
+	return -1;
+}
+
+static int hdmi_v14_conf_index(struct drm_display_mode *mode)
 {
 	int i;
 
@@ -427,6 +1145,15 @@ static int hdmi_conf_index(struct drm_display_mode *mode)
 	return -1;
 }
 
+static int hdmi_conf_index(struct hdmi_context *hdata,
+			   struct drm_display_mode *mode)
+{
+	if (hdata->is_v13)
+		return hdmi_v13_conf_index(mode);
+	else
+		return hdmi_v14_conf_index(mode);
+}
+
 static bool hdmi_is_connected(void *ctx)
 {
 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
@@ -462,16 +1189,25 @@ static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
 	return 0;
 }
 
-static int hdmi_check_timing(void *ctx, void *timing)
+static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
 {
-	struct fb_videomode *check_timing = timing;
 	int i;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+	for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
+		if (hdmi_v13_confs[i].width == check_timing->xres &&
+			hdmi_v13_confs[i].height == check_timing->yres &&
+			hdmi_v13_confs[i].vrefresh == check_timing->refresh &&
+			hdmi_v13_confs[i].interlace ==
+			((check_timing->vmode & FB_VMODE_INTERLACED) ?
+			 true : false))
+			return 0;
 
-	DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", check_timing->xres,
-			check_timing->yres, check_timing->refresh,
-			check_timing->vmode);
+	return -EINVAL;
+}
+
+static int hdmi_v14_check_timing(struct fb_videomode *check_timing)
+{
+	int i;
 
 	for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
 		if (hdmi_confs[i].width == check_timing->xres &&
@@ -485,6 +1221,23 @@ static int hdmi_check_timing(void *ctx, void *timing)
 	return -EINVAL;
 }
 
+static int hdmi_check_timing(void *ctx, void *timing)
+{
+	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
+	struct fb_videomode *check_timing = timing;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", check_timing->xres,
+			check_timing->yres, check_timing->refresh,
+			check_timing->vmode);
+
+	if (hdata->is_v13)
+		return hdmi_v13_check_timing(check_timing);
+	else
+		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__);
@@ -516,13 +1269,20 @@ static struct exynos_hdmi_display_ops display_ops = {
 
 static void hdmi_conf_reset(struct hdmi_context *hdata)
 {
+	u32 reg;
+
 	/* disable hpd handle for drm */
 	hdata->hpd_handle = false;
 
+	if (hdata->is_v13)
+		reg = HDMI_V13_CORE_RSTOUT;
+	else
+		reg = HDMI_CORE_RSTOUT;
+
 	/* resetting HDMI core */
-	hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg,  0, HDMI_CORE_SW_RSTOUT);
 	mdelay(10);
-	hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
 	mdelay(10);
 
 	/* enable hpd handle for drm */
@@ -546,27 +1306,126 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
 		HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
 	/* disable bluescreen */
 	hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
-	/* choose bluescreen (fecal) color */
-	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_0, 0x12);
-	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_1, 0x34);
-	hdmi_reg_writeb(hdata, HDMI_BLUE_SCREEN_2, 0x56);
-	/* enable AVI packet every vsync, fixes purple line problem */
-	hdmi_reg_writeb(hdata, HDMI_AVI_CON, 0x02);
-	/* force RGB, look to CEA-861-D, table 7 for more detail */
-	hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(0), 0 << 5);
-	hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
-
-	hdmi_reg_writeb(hdata, HDMI_SPD_CON, 0x02);
-	hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
-	hdmi_reg_writeb(hdata, HDMI_ACR_CON, 0x04);
+
+	if (hdata->is_v13) {
+		/* choose bluescreen (fecal) color */
+		hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
+		hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
+		hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_2, 0x56);
+
+		/* enable AVI packet every vsync, fixes purple line problem */
+		hdmi_reg_writeb(hdata, HDMI_V13_AVI_CON, 0x02);
+		/* force RGB, look to CEA-861-D, table 7 for more detail */
+		hdmi_reg_writeb(hdata, HDMI_V13_AVI_BYTE(0), 0 << 5);
+		hdmi_reg_writemask(hdata, HDMI_CON_1, 0x10 << 5, 0x11 << 5);
+
+		hdmi_reg_writeb(hdata, HDMI_V13_SPD_CON, 0x02);
+		hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
+		hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
+	} else {
+		/* enable AVI packet every vsync, fixes purple line problem */
+		hdmi_reg_writeb(hdata, HDMI_AVI_CON, 0x02);
+		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_timing_apply(struct hdmi_context *hdata,
-				 const struct hdmi_preset_conf *conf)
+static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
 {
+	const struct hdmi_v13_preset_conf *conf =
+		hdmi_v13_confs[hdata->cur_conf].conf;
+	const struct hdmi_v13_core_regs *core = &conf->core;
+	const struct hdmi_v13_tg_regs *tg = &conf->tg;
+	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_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+
+	/* 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;
+		mdelay(1);
+	}
+	/* 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(hdata->res.sclk_hdmi);
+	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
+	clk_enable(hdata->res.sclk_hdmi);
+
+	/* enable HDMI and timing generator */
+	hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
+	if (core->int_pro_mode[0])
+		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN |
+				HDMI_FIELD_EN);
+	else
+		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
+}
+
+static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
+{
+	const struct hdmi_preset_conf *conf = hdmi_confs[hdata->cur_conf].conf;
 	const struct hdmi_core_regs *core = &conf->core;
 	const struct hdmi_tg_regs *tg = &conf->tg;
 	int tries;
@@ -574,29 +1433,102 @@ static void hdmi_timing_apply(struct hdmi_context *hdata,
 	/* 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_V_BLANK_0, core->v_blank[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_1, core->v_blank[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_2, core->v_blank[2]);
-	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_0, core->h_v_line[0]);
-	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_1, core->h_v_line[1]);
-	hdmi_reg_writeb(hdata, HDMI_H_V_LINE_2, core->h_v_line[2]);
+	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_F_0, core->v_blank_f[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
-	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
-	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
-	hdmi_reg_writeb(hdata, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
-	hdmi_reg_writeb(hdata, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+	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_l);
 	hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
@@ -618,6 +1550,10 @@ static void hdmi_timing_apply(struct hdmi_context *hdata,
 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
 	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4_l);
+	hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4_h);
 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
 	hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
@@ -626,10 +1562,11 @@ static void hdmi_timing_apply(struct hdmi_context *hdata,
 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
 	hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+	hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d);
 
 	/* waiting for HDMIPHY's PLL to get to steady state */
 	for (tries = 100; tries; --tries) {
-		u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS);
+		u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
 		if (val & HDMI_PHY_STATUS_READY)
 			break;
 		mdelay(1);
@@ -653,9 +1590,18 @@ static void hdmi_timing_apply(struct hdmi_context *hdata,
 		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
 }
 
+static void hdmi_timing_apply(struct hdmi_context *hdata)
+{
+	if (hdata->is_v13)
+		hdmi_v13_timing_apply(hdata);
+	else
+		hdmi_v14_timing_apply(hdata);
+}
+
 static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 {
 	u8 buffer[2];
+	u32 reg;
 
 	clk_disable(hdata->res.sclk_hdmi);
 	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
@@ -668,15 +1614,21 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 	if (hdata->hdmiphy_port)
 		i2c_master_send(hdata->hdmiphy_port, buffer, 2);
 
+	if (hdata->is_v13)
+		reg = HDMI_V13_PHY_RSTOUT;
+	else
+		reg = HDMI_PHY_RSTOUT;
+
 	/* reset hdmiphy */
-	hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
 	mdelay(10);
-	hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+	hdmi_reg_writemask(hdata, reg,  0, HDMI_PHY_SW_RSTOUT);
 	mdelay(10);
 }
 
 static void hdmiphy_conf_apply(struct hdmi_context *hdata)
 {
+	const u8 *hdmiphy_data;
 	u8 buffer[32];
 	u8 operation[2];
 	u8 read_buffer[32] = {0, };
@@ -689,7 +1641,12 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
 	}
 
 	/* pixel clock */
-	memcpy(buffer, hdmi_confs[hdata->cur_conf].hdmiphy_data, 32);
+	if (hdata->is_v13)
+		hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data;
+	else
+		hdmiphy_data = hdmi_confs[hdata->cur_conf].hdmiphy_data;
+
+	memcpy(buffer, hdmiphy_data, 32);
 	ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
 	if (ret != 32) {
 		DRM_ERROR("failed to configure HDMIPHY via I2C\n");
@@ -721,9 +1678,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
 
 static void hdmi_conf_apply(struct hdmi_context *hdata)
 {
-	const struct hdmi_preset_conf *conf =
-		  hdmi_confs[hdata->cur_conf].conf;
-
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
 	hdmiphy_conf_reset(hdata);
@@ -733,7 +1687,7 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
 	hdmi_conf_init(hdata);
 
 	/* setting core registers */
-	hdmi_timing_apply(hdata, conf);
+	hdmi_timing_apply(hdata);
 
 	hdmi_regs_dump(hdata, "start");
 }
@@ -745,8 +1699,8 @@ static void hdmi_mode_set(void *ctx, void *mode)
 
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-	conf_idx = hdmi_conf_index(mode);
-	if (conf_idx >= 0 && conf_idx < ARRAY_SIZE(hdmi_confs))
+	conf_idx = hdmi_conf_index(hdata, mode);
+	if (conf_idx >= 0)
 		hdata->cur_conf = conf_idx;
 	else
 		DRM_DEBUG_KMS("not supported mode\n");
@@ -926,7 +1880,6 @@ static void hdmi_resource_poweron(struct hdmi_context *hdata)
 	hdmiphy_conf_reset(hdata);
 	hdmi_conf_reset(hdata);
 	hdmi_conf_init(hdata);
-
 }
 
 static void hdmi_resource_poweroff(struct hdmi_context *hdata)
@@ -1022,6 +1975,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, drm_hdmi_ctx);
 
+	hdata->is_v13 = pdata->is_v13;
 	hdata->default_win = pdata->default_win;
 	hdata->default_timing = &pdata->timing;
 	hdata->default_bpp = pdata->bpp;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h b/drivers/gpu/drm/exynos/exynos_hdmi.h
index 31d6cf8..040ecad 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.h
@@ -28,15 +28,6 @@
 #ifndef _EXYNOS_HDMI_H_
 #define _EXYNOS_HDMI_H_
 
-struct hdmi_conf {
-	int width;
-	int height;
-	int vrefresh;
-	bool interlace;
-	const u8 *hdmiphy_data;
-	const struct hdmi_preset_conf *conf;
-};
-
 struct hdmi_resources {
 	struct clk *hdmi;
 	struct clk *sclk_hdmi;
@@ -51,6 +42,7 @@ struct hdmi_context {
 	struct device			*dev;
 	struct drm_device		*drm_dev;
 	struct fb_videomode		*default_timing;
+	unsigned int			is_v13:1;
 	unsigned int			default_win;
 	unsigned int			default_bpp;
 	bool				hpd_handle;
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index 72e6b52..6b28715 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -19,6 +19,7 @@
  * Register part
 */
 
+/* HDMI Version 1.3 & Common */
 #define HDMI_CTRL_BASE(x)		((x) + 0x00000000)
 #define HDMI_CORE_BASE(x)		((x) + 0x00010000)
 #define HDMI_TG_BASE(x)			((x) + 0x00050000)
@@ -27,56 +28,57 @@
 #define HDMI_INTC_CON			HDMI_CTRL_BASE(0x0000)
 #define HDMI_INTC_FLAG			HDMI_CTRL_BASE(0x0004)
 #define HDMI_HPD_STATUS			HDMI_CTRL_BASE(0x000C)
-#define HDMI_PHY_RSTOUT			HDMI_CTRL_BASE(0x0014)
-#define HDMI_PHY_VPLL			HDMI_CTRL_BASE(0x0018)
-#define HDMI_PHY_CMU			HDMI_CTRL_BASE(0x001C)
-#define HDMI_CORE_RSTOUT		HDMI_CTRL_BASE(0x0020)
+#define HDMI_V13_PHY_RSTOUT		HDMI_CTRL_BASE(0x0014)
+#define HDMI_V13_PHY_VPLL		HDMI_CTRL_BASE(0x0018)
+#define HDMI_V13_PHY_CMU		HDMI_CTRL_BASE(0x001C)
+#define HDMI_V13_CORE_RSTOUT		HDMI_CTRL_BASE(0x0020)
 
 /* Core registers */
 #define HDMI_CON_0			HDMI_CORE_BASE(0x0000)
 #define HDMI_CON_1			HDMI_CORE_BASE(0x0004)
 #define HDMI_CON_2			HDMI_CORE_BASE(0x0008)
 #define HDMI_SYS_STATUS			HDMI_CORE_BASE(0x0010)
-#define HDMI_PHY_STATUS			HDMI_CORE_BASE(0x0014)
+#define HDMI_V13_PHY_STATUS		HDMI_CORE_BASE(0x0014)
 #define HDMI_STATUS_EN			HDMI_CORE_BASE(0x0020)
 #define HDMI_HPD			HDMI_CORE_BASE(0x0030)
 #define HDMI_MODE_SEL			HDMI_CORE_BASE(0x0040)
-#define HDMI_BLUE_SCREEN_0		HDMI_CORE_BASE(0x0050)
-#define HDMI_BLUE_SCREEN_1		HDMI_CORE_BASE(0x0054)
-#define HDMI_BLUE_SCREEN_2		HDMI_CORE_BASE(0x0058)
+#define HDMI_ENC_EN			HDMI_CORE_BASE(0x0044)
+#define HDMI_V13_BLUE_SCREEN_0		HDMI_CORE_BASE(0x0050)
+#define HDMI_V13_BLUE_SCREEN_1		HDMI_CORE_BASE(0x0054)
+#define HDMI_V13_BLUE_SCREEN_2		HDMI_CORE_BASE(0x0058)
 #define HDMI_H_BLANK_0			HDMI_CORE_BASE(0x00A0)
 #define HDMI_H_BLANK_1			HDMI_CORE_BASE(0x00A4)
-#define HDMI_V_BLANK_0			HDMI_CORE_BASE(0x00B0)
-#define HDMI_V_BLANK_1			HDMI_CORE_BASE(0x00B4)
-#define HDMI_V_BLANK_2			HDMI_CORE_BASE(0x00B8)
-#define HDMI_H_V_LINE_0			HDMI_CORE_BASE(0x00C0)
-#define HDMI_H_V_LINE_1			HDMI_CORE_BASE(0x00C4)
-#define HDMI_H_V_LINE_2			HDMI_CORE_BASE(0x00C8)
+#define HDMI_V13_V_BLANK_0		HDMI_CORE_BASE(0x00B0)
+#define HDMI_V13_V_BLANK_1		HDMI_CORE_BASE(0x00B4)
+#define HDMI_V13_V_BLANK_2		HDMI_CORE_BASE(0x00B8)
+#define HDMI_V13_H_V_LINE_0		HDMI_CORE_BASE(0x00C0)
+#define HDMI_V13_H_V_LINE_1		HDMI_CORE_BASE(0x00C4)
+#define HDMI_V13_H_V_LINE_2		HDMI_CORE_BASE(0x00C8)
 #define HDMI_VSYNC_POL			HDMI_CORE_BASE(0x00E4)
 #define HDMI_INT_PRO_MODE		HDMI_CORE_BASE(0x00E8)
-#define HDMI_V_BLANK_F_0		HDMI_CORE_BASE(0x0110)
-#define HDMI_V_BLANK_F_1		HDMI_CORE_BASE(0x0114)
-#define HDMI_V_BLANK_F_2		HDMI_CORE_BASE(0x0118)
-#define HDMI_H_SYNC_GEN_0		HDMI_CORE_BASE(0x0120)
-#define HDMI_H_SYNC_GEN_1		HDMI_CORE_BASE(0x0124)
-#define HDMI_H_SYNC_GEN_2		HDMI_CORE_BASE(0x0128)
-#define HDMI_V_SYNC_GEN_1_0		HDMI_CORE_BASE(0x0130)
-#define HDMI_V_SYNC_GEN_1_1		HDMI_CORE_BASE(0x0134)
-#define HDMI_V_SYNC_GEN_1_2		HDMI_CORE_BASE(0x0138)
-#define HDMI_V_SYNC_GEN_2_0		HDMI_CORE_BASE(0x0140)
-#define HDMI_V_SYNC_GEN_2_1		HDMI_CORE_BASE(0x0144)
-#define HDMI_V_SYNC_GEN_2_2		HDMI_CORE_BASE(0x0148)
-#define HDMI_V_SYNC_GEN_3_0		HDMI_CORE_BASE(0x0150)
-#define HDMI_V_SYNC_GEN_3_1		HDMI_CORE_BASE(0x0154)
-#define HDMI_V_SYNC_GEN_3_2		HDMI_CORE_BASE(0x0158)
-#define HDMI_ACR_CON			HDMI_CORE_BASE(0x0180)
-#define HDMI_AVI_CON			HDMI_CORE_BASE(0x0300)
-#define HDMI_AVI_BYTE(n)		HDMI_CORE_BASE(0x0320 + 4 * (n))
-#define HDMI_DC_CONTROL			HDMI_CORE_BASE(0x05C0)
-#define HDMI_VIDEO_PATTERN_GEN		HDMI_CORE_BASE(0x05C4)
-#define HDMI_HPD_GEN			HDMI_CORE_BASE(0x05C8)
-#define HDMI_AUI_CON			HDMI_CORE_BASE(0x0360)
-#define HDMI_SPD_CON			HDMI_CORE_BASE(0x0400)
+#define HDMI_V13_V_BLANK_F_0		HDMI_CORE_BASE(0x0110)
+#define HDMI_V13_V_BLANK_F_1		HDMI_CORE_BASE(0x0114)
+#define HDMI_V13_V_BLANK_F_2		HDMI_CORE_BASE(0x0118)
+#define HDMI_V13_H_SYNC_GEN_0		HDMI_CORE_BASE(0x0120)
+#define HDMI_V13_H_SYNC_GEN_1		HDMI_CORE_BASE(0x0124)
+#define HDMI_V13_H_SYNC_GEN_2		HDMI_CORE_BASE(0x0128)
+#define HDMI_V13_V_SYNC_GEN_1_0		HDMI_CORE_BASE(0x0130)
+#define HDMI_V13_V_SYNC_GEN_1_1		HDMI_CORE_BASE(0x0134)
+#define HDMI_V13_V_SYNC_GEN_1_2		HDMI_CORE_BASE(0x0138)
+#define HDMI_V13_V_SYNC_GEN_2_0		HDMI_CORE_BASE(0x0140)
+#define HDMI_V13_V_SYNC_GEN_2_1		HDMI_CORE_BASE(0x0144)
+#define HDMI_V13_V_SYNC_GEN_2_2		HDMI_CORE_BASE(0x0148)
+#define HDMI_V13_V_SYNC_GEN_3_0		HDMI_CORE_BASE(0x0150)
+#define HDMI_V13_V_SYNC_GEN_3_1		HDMI_CORE_BASE(0x0154)
+#define HDMI_V13_V_SYNC_GEN_3_2		HDMI_CORE_BASE(0x0158)
+#define HDMI_V13_ACR_CON		HDMI_CORE_BASE(0x0180)
+#define HDMI_V13_AVI_CON		HDMI_CORE_BASE(0x0300)
+#define HDMI_V13_AVI_BYTE(n)		HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define HDMI_V13_DC_CONTROL		HDMI_CORE_BASE(0x05C0)
+#define HDMI_V13_VIDEO_PATTERN_GEN	HDMI_CORE_BASE(0x05C4)
+#define HDMI_V13_HPD_GEN		HDMI_CORE_BASE(0x05C8)
+#define HDMI_V13_AUI_CON		HDMI_CORE_BASE(0x0360)
+#define HDMI_V13_SPD_CON		HDMI_CORE_BASE(0x0400)
 
 /* Timing generator registers */
 #define HDMI_TG_CMD			HDMI_TG_BASE(0x0000)
@@ -144,4 +146,234 @@
 #define HDMI_TG_EN			(1 << 0)
 #define HDMI_FIELD_EN			(1 << 1)
 
+
+/* HDMI Version 1.4 */
+/* Control registers */
+/* #define HDMI_INTC_CON		HDMI_CTRL_BASE(0x0000) */
+/* #define HDMI_INTC_FLAG		HDMI_CTRL_BASE(0x0004) */
+#define HDMI_HDCP_KEY_LOAD		HDMI_CTRL_BASE(0x0008)
+/* #define HDMI_HPD_STATUS		HDMI_CTRL_BASE(0x000C) */
+#define HDMI_INTC_CON_1			HDMI_CTRL_BASE(0x0010)
+#define HDMI_INTC_FLAG_1		HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_STATUS_0		HDMI_CTRL_BASE(0x0020)
+#define HDMI_PHY_STATUS_CMU		HDMI_CTRL_BASE(0x0024)
+#define HDMI_PHY_STATUS_PLL		HDMI_CTRL_BASE(0x0028)
+#define HDMI_PHY_CON_0			HDMI_CTRL_BASE(0x0030)
+#define HDMI_HPD_CTRL			HDMI_CTRL_BASE(0x0040)
+#define HDMI_HPD_ST			HDMI_CTRL_BASE(0x0044)
+#define HDMI_HPD_TH_X			HDMI_CTRL_BASE(0x0050)
+#define HDMI_AUDIO_CLKSEL		HDMI_CTRL_BASE(0x0070)
+#define HDMI_PHY_RSTOUT			HDMI_CTRL_BASE(0x0074)
+#define HDMI_PHY_VPLL			HDMI_CTRL_BASE(0x0078)
+#define HDMI_PHY_CMU			HDMI_CTRL_BASE(0x007C)
+#define HDMI_CORE_RSTOUT		HDMI_CTRL_BASE(0x0080)
+
+/* Video related registers */
+#define HDMI_YMAX			HDMI_CORE_BASE(0x0060)
+#define HDMI_YMIN			HDMI_CORE_BASE(0x0064)
+#define HDMI_CMAX			HDMI_CORE_BASE(0x0068)
+#define HDMI_CMIN			HDMI_CORE_BASE(0x006C)
+
+#define HDMI_V2_BLANK_0			HDMI_CORE_BASE(0x00B0)
+#define HDMI_V2_BLANK_1			HDMI_CORE_BASE(0x00B4)
+#define HDMI_V1_BLANK_0			HDMI_CORE_BASE(0x00B8)
+#define HDMI_V1_BLANK_1			HDMI_CORE_BASE(0x00BC)
+
+#define HDMI_V_LINE_0			HDMI_CORE_BASE(0x00C0)
+#define HDMI_V_LINE_1			HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_LINE_0			HDMI_CORE_BASE(0x00C8)
+#define HDMI_H_LINE_1			HDMI_CORE_BASE(0x00CC)
+
+#define HDMI_HSYNC_POL			HDMI_CORE_BASE(0x00E0)
+
+#define HDMI_V_BLANK_F0_0		HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F0_1		HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F1_0		HDMI_CORE_BASE(0x0118)
+#define HDMI_V_BLANK_F1_1		HDMI_CORE_BASE(0x011C)
+
+#define HDMI_H_SYNC_START_0		HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_START_1		HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_END_0		HDMI_CORE_BASE(0x0128)
+#define HDMI_H_SYNC_END_1		HDMI_CORE_BASE(0x012C)
+
+#define HDMI_V_SYNC_LINE_BEF_2_0	HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_LINE_BEF_2_1	HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_LINE_BEF_1_0	HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_LINE_BEF_1_1	HDMI_CORE_BASE(0x013C)
+
+#define HDMI_V_SYNC_LINE_AFT_2_0	HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_LINE_AFT_2_1	HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_LINE_AFT_1_0	HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_LINE_AFT_1_1	HDMI_CORE_BASE(0x014C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_0	HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_1	HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_0	HDMI_CORE_BASE(0x0158)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_1	HDMI_CORE_BASE(0x015C)
+
+#define HDMI_V_BLANK_F2_0		HDMI_CORE_BASE(0x0160)
+#define HDMI_V_BLANK_F2_1		HDMI_CORE_BASE(0x0164)
+#define HDMI_V_BLANK_F3_0		HDMI_CORE_BASE(0x0168)
+#define HDMI_V_BLANK_F3_1		HDMI_CORE_BASE(0x016C)
+#define HDMI_V_BLANK_F4_0		HDMI_CORE_BASE(0x0170)
+#define HDMI_V_BLANK_F4_1		HDMI_CORE_BASE(0x0174)
+#define HDMI_V_BLANK_F5_0		HDMI_CORE_BASE(0x0178)
+#define HDMI_V_BLANK_F5_1		HDMI_CORE_BASE(0x017C)
+
+#define HDMI_V_SYNC_LINE_AFT_3_0	HDMI_CORE_BASE(0x0180)
+#define HDMI_V_SYNC_LINE_AFT_3_1	HDMI_CORE_BASE(0x0184)
+#define HDMI_V_SYNC_LINE_AFT_4_0	HDMI_CORE_BASE(0x0188)
+#define HDMI_V_SYNC_LINE_AFT_4_1	HDMI_CORE_BASE(0x018C)
+#define HDMI_V_SYNC_LINE_AFT_5_0	HDMI_CORE_BASE(0x0190)
+#define HDMI_V_SYNC_LINE_AFT_5_1	HDMI_CORE_BASE(0x0194)
+#define HDMI_V_SYNC_LINE_AFT_6_0	HDMI_CORE_BASE(0x0198)
+#define HDMI_V_SYNC_LINE_AFT_6_1	HDMI_CORE_BASE(0x019C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_0	HDMI_CORE_BASE(0x01A0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_1	HDMI_CORE_BASE(0x01A4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_0	HDMI_CORE_BASE(0x01A8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_1	HDMI_CORE_BASE(0x01AC)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_0	HDMI_CORE_BASE(0x01B0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_1	HDMI_CORE_BASE(0x01B4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_0	HDMI_CORE_BASE(0x01B8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_1	HDMI_CORE_BASE(0x01BC)
+
+#define HDMI_VACT_SPACE_1_0		HDMI_CORE_BASE(0x01C0)
+#define HDMI_VACT_SPACE_1_1		HDMI_CORE_BASE(0x01C4)
+#define HDMI_VACT_SPACE_2_0		HDMI_CORE_BASE(0x01C8)
+#define HDMI_VACT_SPACE_2_1		HDMI_CORE_BASE(0x01CC)
+#define HDMI_VACT_SPACE_3_0		HDMI_CORE_BASE(0x01D0)
+#define HDMI_VACT_SPACE_3_1		HDMI_CORE_BASE(0x01D4)
+#define HDMI_VACT_SPACE_4_0		HDMI_CORE_BASE(0x01D8)
+#define HDMI_VACT_SPACE_4_1		HDMI_CORE_BASE(0x01DC)
+#define HDMI_VACT_SPACE_5_0		HDMI_CORE_BASE(0x01E0)
+#define HDMI_VACT_SPACE_5_1		HDMI_CORE_BASE(0x01E4)
+#define HDMI_VACT_SPACE_6_0		HDMI_CORE_BASE(0x01E8)
+#define HDMI_VACT_SPACE_6_1		HDMI_CORE_BASE(0x01EC)
+
+#define HDMI_GCP_CON			HDMI_CORE_BASE(0x0200)
+#define HDMI_GCP_BYTE1			HDMI_CORE_BASE(0x0210)
+#define HDMI_GCP_BYTE2			HDMI_CORE_BASE(0x0214)
+#define HDMI_GCP_BYTE3			HDMI_CORE_BASE(0x0218)
+
+/* Audio related registers */
+#define HDMI_ASP_CON			HDMI_CORE_BASE(0x0300)
+#define HDMI_ASP_SP_FLAT		HDMI_CORE_BASE(0x0304)
+#define HDMI_ASP_CHCFG0			HDMI_CORE_BASE(0x0310)
+#define HDMI_ASP_CHCFG1			HDMI_CORE_BASE(0x0314)
+#define HDMI_ASP_CHCFG2			HDMI_CORE_BASE(0x0318)
+#define HDMI_ASP_CHCFG3			HDMI_CORE_BASE(0x031C)
+
+#define HDMI_ACR_CON			HDMI_CORE_BASE(0x0400)
+#define HDMI_ACR_MCTS0			HDMI_CORE_BASE(0x0410)
+#define HDMI_ACR_MCTS1			HDMI_CORE_BASE(0x0414)
+#define HDMI_ACR_MCTS2			HDMI_CORE_BASE(0x0418)
+#define HDMI_ACR_N0			HDMI_CORE_BASE(0x0430)
+#define HDMI_ACR_N1			HDMI_CORE_BASE(0x0434)
+#define HDMI_ACR_N2			HDMI_CORE_BASE(0x0438)
+
+/* Packet related registers */
+#define HDMI_ACP_CON			HDMI_CORE_BASE(0x0500)
+#define HDMI_ACP_TYPE			HDMI_CORE_BASE(0x0514)
+#define HDMI_ACP_DATA(n)		HDMI_CORE_BASE(0x0520 + 4 * (n))
+
+#define HDMI_ISRC_CON			HDMI_CORE_BASE(0x0600)
+#define HDMI_ISRC1_HEADER1		HDMI_CORE_BASE(0x0614)
+#define HDMI_ISRC1_DATA(n)		HDMI_CORE_BASE(0x0620 + 4 * (n))
+#define HDMI_ISRC2_DATA(n)		HDMI_CORE_BASE(0x06A0 + 4 * (n))
+
+#define HDMI_AVI_CON			HDMI_CORE_BASE(0x0700)
+#define HDMI_AVI_HEADER0		HDMI_CORE_BASE(0x0710)
+#define HDMI_AVI_HEADER1		HDMI_CORE_BASE(0x0714)
+#define HDMI_AVI_HEADER2		HDMI_CORE_BASE(0x0718)
+#define HDMI_AVI_CHECK_SUM		HDMI_CORE_BASE(0x071C)
+#define HDMI_AVI_BYTE(n)		HDMI_CORE_BASE(0x0720 + 4 * (n))
+
+#define HDMI_AUI_CON			HDMI_CORE_BASE(0x0800)
+#define HDMI_AUI_HEADER0		HDMI_CORE_BASE(0x0810)
+#define HDMI_AUI_HEADER1		HDMI_CORE_BASE(0x0814)
+#define HDMI_AUI_HEADER2		HDMI_CORE_BASE(0x0818)
+#define HDMI_AUI_CHECK_SUM		HDMI_CORE_BASE(0x081C)
+#define HDMI_AUI_BYTE(n)		HDMI_CORE_BASE(0x0820 + 4 * (n))
+
+#define HDMI_MPG_CON			HDMI_CORE_BASE(0x0900)
+#define HDMI_MPG_CHECK_SUM		HDMI_CORE_BASE(0x091C)
+#define HDMI_MPG_DATA(n)		HDMI_CORE_BASE(0x0920 + 4 * (n))
+
+#define HDMI_SPD_CON			HDMI_CORE_BASE(0x0A00)
+#define HDMI_SPD_HEADER0		HDMI_CORE_BASE(0x0A10)
+#define HDMI_SPD_HEADER1		HDMI_CORE_BASE(0x0A14)
+#define HDMI_SPD_HEADER2		HDMI_CORE_BASE(0x0A18)
+#define HDMI_SPD_DATA(n)		HDMI_CORE_BASE(0x0A20 + 4 * (n))
+
+#define HDMI_GAMUT_CON			HDMI_CORE_BASE(0x0B00)
+#define HDMI_GAMUT_HEADER0		HDMI_CORE_BASE(0x0B10)
+#define HDMI_GAMUT_HEADER1		HDMI_CORE_BASE(0x0B14)
+#define HDMI_GAMUT_HEADER2		HDMI_CORE_BASE(0x0B18)
+#define HDMI_GAMUT_METADATA(n)		HDMI_CORE_BASE(0x0B20 + 4 * (n))
+
+#define HDMI_VSI_CON			HDMI_CORE_BASE(0x0C00)
+#define HDMI_VSI_HEADER0		HDMI_CORE_BASE(0x0C10)
+#define HDMI_VSI_HEADER1		HDMI_CORE_BASE(0x0C14)
+#define HDMI_VSI_HEADER2		HDMI_CORE_BASE(0x0C18)
+#define HDMI_VSI_DATA(n)		HDMI_CORE_BASE(0x0C20 + 4 * (n))
+
+#define HDMI_DC_CONTROL			HDMI_CORE_BASE(0x0D00)
+#define HDMI_VIDEO_PATTERN_GEN		HDMI_CORE_BASE(0x0D04)
+
+#define HDMI_AN_SEED_SEL		HDMI_CORE_BASE(0x0E48)
+#define HDMI_AN_SEED_0			HDMI_CORE_BASE(0x0E58)
+#define HDMI_AN_SEED_1			HDMI_CORE_BASE(0x0E5C)
+#define HDMI_AN_SEED_2			HDMI_CORE_BASE(0x0E60)
+#define HDMI_AN_SEED_3			HDMI_CORE_BASE(0x0E64)
+
+/* HDCP related registers */
+#define HDMI_HDCP_SHA1(n)		HDMI_CORE_BASE(0x7000 + 4 * (n))
+#define HDMI_HDCP_KSV_LIST(n)		HDMI_CORE_BASE(0x7050 + 4 * (n))
+
+#define HDMI_HDCP_KSV_LIST_CON		HDMI_CORE_BASE(0x7064)
+#define HDMI_HDCP_SHA_RESULT		HDMI_CORE_BASE(0x7070)
+#define HDMI_HDCP_CTRL1			HDMI_CORE_BASE(0x7080)
+#define HDMI_HDCP_CTRL2			HDMI_CORE_BASE(0x7084)
+#define HDMI_HDCP_CHECK_RESULT		HDMI_CORE_BASE(0x7090)
+#define HDMI_HDCP_BKSV(n)		HDMI_CORE_BASE(0x70A0 + 4 * (n))
+#define HDMI_HDCP_AKSV(n)		HDMI_CORE_BASE(0x70C0 + 4 * (n))
+#define HDMI_HDCP_AN(n)			HDMI_CORE_BASE(0x70E0 + 4 * (n))
+
+#define HDMI_HDCP_BCAPS			HDMI_CORE_BASE(0x7100)
+#define HDMI_HDCP_BSTATUS_0		HDMI_CORE_BASE(0x7110)
+#define HDMI_HDCP_BSTATUS_1		HDMI_CORE_BASE(0x7114)
+#define HDMI_HDCP_RI_0			HDMI_CORE_BASE(0x7140)
+#define HDMI_HDCP_RI_1			HDMI_CORE_BASE(0x7144)
+#define HDMI_HDCP_I2C_INT		HDMI_CORE_BASE(0x7180)
+#define HDMI_HDCP_AN_INT		HDMI_CORE_BASE(0x7190)
+#define HDMI_HDCP_WDT_INT		HDMI_CORE_BASE(0x71A0)
+#define HDMI_HDCP_RI_INT		HDMI_CORE_BASE(0x71B0)
+#define HDMI_HDCP_RI_COMPARE_0		HDMI_CORE_BASE(0x71D0)
+#define HDMI_HDCP_RI_COMPARE_1		HDMI_CORE_BASE(0x71D4)
+#define HDMI_HDCP_FRAME_COUNT		HDMI_CORE_BASE(0x71E0)
+
+#define HDMI_RGB_ROUND_EN		HDMI_CORE_BASE(0xD500)
+#define HDMI_VACT_SPACE_R_0		HDMI_CORE_BASE(0xD504)
+#define HDMI_VACT_SPACE_R_1		HDMI_CORE_BASE(0xD508)
+#define HDMI_VACT_SPACE_G_0		HDMI_CORE_BASE(0xD50C)
+#define HDMI_VACT_SPACE_G_1		HDMI_CORE_BASE(0xD510)
+#define HDMI_VACT_SPACE_B_0		HDMI_CORE_BASE(0xD514)
+#define HDMI_VACT_SPACE_B_1		HDMI_CORE_BASE(0xD518)
+
+#define HDMI_BLUE_SCREEN_B_0		HDMI_CORE_BASE(0xD520)
+#define HDMI_BLUE_SCREEN_B_1		HDMI_CORE_BASE(0xD524)
+#define HDMI_BLUE_SCREEN_G_0		HDMI_CORE_BASE(0xD528)
+#define HDMI_BLUE_SCREEN_G_1		HDMI_CORE_BASE(0xD52C)
+#define HDMI_BLUE_SCREEN_R_0		HDMI_CORE_BASE(0xD530)
+#define HDMI_BLUE_SCREEN_R_1		HDMI_CORE_BASE(0xD534)
+
+/* Timing generator registers */
+/* TG configure/status registers */
+#define HDMI_TG_VACT_ST3_L		HDMI_TG_BASE(0x0068)
+#define HDMI_TG_VACT_ST3_H		HDMI_TG_BASE(0x006c)
+#define HDMI_TG_VACT_ST4_L		HDMI_TG_BASE(0x0070)
+#define HDMI_TG_VACT_ST4_H		HDMI_TG_BASE(0x0074)
+#define HDMI_TG_3D			HDMI_TG_BASE(0x00F0)
+
 #endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 1ed3aae..aff2313 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -147,11 +147,13 @@ struct exynos_drm_common_hdmi_pd {
  * @timing: default video mode for initializing
  * @default_win: default window layer number to be used for UI.
  * @bpp: default bit per pixel.
+ * @is_v13: set if hdmi version 13 is.
  */
 struct exynos_drm_hdmi_pdata {
 	struct fb_videomode		timing;
 	unsigned int			default_win;
 	unsigned int			bpp;
+	unsigned int			is_v13:1;
 };
 
 #endif	/* __KERNEL__ */
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 02/14] drm/exynos: added mode_fixup feature and code clean.
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
  2012-03-16  9:47 ` [PATCH v2 01/14] drm/exynos: add HDMI version 1.4 support Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 03/14] drm/exynos: update gem and buffer framework Inki Dae
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

this patch adds mode_fixup feature for hdmi module that
specific driver changes current mode to driver desired mode
properly.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_connector.c |   25 +++++++-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c      |    6 ++-
 drivers/gpu/drm/exynos/exynos_drm_drv.h       |    8 +++
 drivers/gpu/drm/exynos/exynos_drm_encoder.c   |   17 ++++-
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c      |   28 +++++++++
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h      |    5 ++
 drivers/gpu/drm/exynos/exynos_hdmi.c          |   81 ++++++++++++++++++++++--
 7 files changed, 157 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 618bd4d..ebdd71d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -225,6 +225,29 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
 	.best_encoder	= exynos_drm_best_encoder,
 };
 
+static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
+				unsigned int max_width, unsigned int max_height)
+{
+	struct exynos_drm_connector *exynos_connector =
+					to_exynos_connector(connector);
+	struct exynos_drm_manager *manager = exynos_connector->manager;
+	struct exynos_drm_manager_ops *ops = manager->ops;
+	unsigned int width, height;
+
+	width = max_width;
+	height = max_height;
+
+	/*
+	 * if specific driver want to find desired_mode using maxmum
+	 * resolution then get max width and height from that driver.
+	 */
+	if (ops && ops->get_max_resol)
+		ops->get_max_resol(manager->dev, &width, &height);
+
+	return drm_helper_probe_single_connector_modes(connector, width,
+							height);
+}
+
 /* get detection status of display device. */
 static enum drm_connector_status
 exynos_drm_connector_detect(struct drm_connector *connector, bool force)
@@ -262,7 +285,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector)
 
 static struct drm_connector_funcs exynos_connector_funcs = {
 	.dpms		= drm_helper_connector_dpms,
-	.fill_modes	= drm_helper_probe_single_connector_modes,
+	.fill_modes	= exynos_drm_connector_fill_modes,
 	.detect		= exynos_drm_connector_detect,
 	.destroy	= exynos_drm_connector_destroy,
 };
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index de81883..2d9a0e6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -249,7 +249,11 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 {
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	mode = adjusted_mode;
+	/*
+	 * copy the mode data adjusted by mode_fixup() into crtc->mode
+	 * so that hardware can be seet to proper mode.
+	 */
+	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
 	return exynos_drm_crtc_update(crtc);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 13540de..4115a9f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -155,8 +155,10 @@ struct exynos_drm_display_ops {
  *
  * @dpms: control device power.
  * @apply: set timing, vblank and overlay data to registers.
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
  * @mode_set: convert drm_display_mode to hw specific display mode and
  *	      would be called by encoder->mode_set().
+ * @get_max_resol: get maximum resolution to specific hardware.
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -164,7 +166,13 @@ struct exynos_drm_display_ops {
 struct exynos_drm_manager_ops {
 	void (*dpms)(struct device *subdrv_dev, int mode);
 	void (*apply)(struct device *subdrv_dev);
+	void (*mode_fixup)(struct device *subdrv_dev,
+				struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
 	void (*mode_set)(struct device *subdrv_dev, void *mode);
+	void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
+				unsigned int *height);
 	void (*commit)(struct device *subdrv_dev);
 	int (*enable_vblank)(struct device *subdrv_dev);
 	void (*disable_vblank)(struct device *subdrv_dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index ef4754f..45ca732 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -111,9 +111,19 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 			       struct drm_display_mode *mode,
 			       struct drm_display_mode *adjusted_mode)
 {
+	struct drm_device *dev = encoder->dev;
+	struct drm_connector *connector;
+	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+	struct exynos_drm_manager_ops *manager_ops = manager->ops;
+
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	/* drm framework doesn't check NULL. */
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->encoder == encoder)
+			if (manager_ops && manager_ops->mode_fixup)
+				manager_ops->mode_fixup(manager->dev, connector,
+							mode, adjusted_mode);
+	}
 
 	return true;
 }
@@ -132,12 +142,11 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	mode = adjusted_mode;
-
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->encoder == encoder) {
 			if (manager_ops && manager_ops->mode_set)
-				manager_ops->mode_set(manager->dev, mode);
+				manager_ops->mode_set(manager->dev,
+							adjusted_mode);
 
 			if (overlay_ops && overlay_ops->mode_set)
 				overlay_ops->mode_set(manager->dev, overlay);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index ed8a319e..ed86bdd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -155,6 +155,20 @@ static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
 		return hdmi_overlay_ops->disable_vblank(ctx->mixer_ctx->ctx);
 }
 
+static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
+				struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (hdmi_manager_ops && hdmi_manager_ops->mode_fixup)
+		hdmi_manager_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector,
+						mode, adjusted_mode);
+}
+
 static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -165,6 +179,18 @@ static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
 		hdmi_manager_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
 }
 
+static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
+				unsigned int *width, unsigned int *height)
+{
+	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (hdmi_manager_ops && hdmi_manager_ops->get_max_resol)
+		hdmi_manager_ops->get_max_resol(ctx->hdmi_ctx->ctx, width,
+							height);
+}
+
 static void drm_hdmi_commit(struct device *subdrv_dev)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -200,7 +226,9 @@ static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
 	.dpms = drm_hdmi_dpms,
 	.enable_vblank = drm_hdmi_enable_vblank,
 	.disable_vblank = drm_hdmi_disable_vblank,
+	.mode_fixup = drm_hdmi_mode_fixup,
 	.mode_set = drm_hdmi_mode_set,
+	.get_max_resol = drm_hdmi_get_max_resol,
 	.commit = drm_hdmi_commit,
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 3c29f79..44497cf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -47,7 +47,12 @@ struct exynos_hdmi_display_ops {
 };
 
 struct exynos_hdmi_manager_ops {
+	void (*mode_fixup)(void *ctx, struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
 	void (*mode_set)(void *ctx, void *mode);
+	void (*get_max_resol)(void *ctx, unsigned int *width,
+				unsigned int *height);
 	void (*commit)(void *ctx);
 	void (*disable)(void *ctx);
 };
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 1cfe86e..6fe1e89 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -41,6 +41,8 @@
 #include "exynos_hdmi.h"
 
 #define HDMI_OVERLAY_NUMBER	3
+#define MAX_WIDTH		1920
+#define MAX_HEIGHT		1080
 #define get_hdmi_context(dev)	platform_get_drvdata(to_platform_device(dev))
 
 /* HDMI Version 1.3 */
@@ -1126,7 +1128,7 @@ static int hdmi_v13_conf_index(struct drm_display_mode *mode)
 				 true : false))
 			return i;
 
-	return -1;
+	return -EINVAL;
 }
 
 static int hdmi_v14_conf_index(struct drm_display_mode *mode)
@@ -1142,7 +1144,7 @@ static int hdmi_v14_conf_index(struct drm_display_mode *mode)
 				 true : false))
 			return i;
 
-	return -1;
+	return -EINVAL;
 }
 
 static int hdmi_conf_index(struct hdmi_context *hdata,
@@ -1150,8 +1152,8 @@ static int hdmi_conf_index(struct hdmi_context *hdata,
 {
 	if (hdata->is_v13)
 		return hdmi_v13_conf_index(mode);
-	else
-		return hdmi_v14_conf_index(mode);
+
+	return hdmi_v14_conf_index(mode);
 }
 
 static bool hdmi_is_connected(void *ctx)
@@ -1193,6 +1195,11 @@ static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
 {
 	int i;
 
+	DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
+			check_timing->xres, check_timing->yres,
+			check_timing->refresh, (check_timing->vmode &
+			FB_VMODE_INTERLACED) ? true : false);
+
 	for (i = 0; i < ARRAY_SIZE(hdmi_v13_confs); ++i)
 		if (hdmi_v13_confs[i].width == check_timing->xres &&
 			hdmi_v13_confs[i].height == check_timing->yres &&
@@ -1200,7 +1207,9 @@ static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
 			hdmi_v13_confs[i].interlace ==
 			((check_timing->vmode & FB_VMODE_INTERLACED) ?
 			 true : false))
-			return 0;
+				return 0;
+
+	/* TODO */
 
 	return -EINVAL;
 }
@@ -1209,14 +1218,21 @@ static int hdmi_v14_check_timing(struct fb_videomode *check_timing)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i)
+	DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n",
+			check_timing->xres, check_timing->yres,
+			check_timing->refresh, (check_timing->vmode &
+			FB_VMODE_INTERLACED) ? true : false);
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_confs); i++)
 		if (hdmi_confs[i].width == check_timing->xres &&
 			hdmi_confs[i].height == check_timing->yres &&
 			hdmi_confs[i].vrefresh == check_timing->refresh &&
 			hdmi_confs[i].interlace ==
 			((check_timing->vmode & FB_VMODE_INTERLACED) ?
 			 true : false))
-			return 0;
+				return 0;
+
+	/* TODO */
 
 	return -EINVAL;
 }
@@ -1692,6 +1708,46 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
 	hdmi_regs_dump(hdata, "start");
 }
 
+static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector,
+				struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct drm_display_mode *m;
+	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
+	int index;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+	if (hdata->is_v13)
+		index = hdmi_v13_conf_index(adjusted_mode);
+	else
+		index = hdmi_v14_conf_index(adjusted_mode);
+
+	/* just return if user desired mode exists. */
+	if (index >= 0)
+		return;
+
+	/*
+	 * otherwise, find the most suitable mode among modes and change it
+	 * to adjusted_mode.
+	 */
+	list_for_each_entry(m, &connector->modes, head) {
+		if (hdata->is_v13)
+			index = hdmi_v13_conf_index(m);
+		else
+			index = hdmi_v14_conf_index(m);
+
+		if (index >= 0) {
+			DRM_INFO("desired mode doesn't exist so\n");
+			DRM_INFO("use the most suitable mode among modes.\n");
+			memcpy(adjusted_mode, m, sizeof(*m));
+			break;
+		}
+	}
+}
+
 static void hdmi_mode_set(void *ctx, void *mode)
 {
 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
@@ -1706,6 +1762,15 @@ static void hdmi_mode_set(void *ctx, void *mode)
 		DRM_DEBUG_KMS("not supported mode\n");
 }
 
+static void hdmi_get_max_resol(void *ctx, unsigned int *width,
+					unsigned int *height)
+{
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	*width = MAX_WIDTH;
+	*height = MAX_HEIGHT;
+}
+
 static void hdmi_commit(void *ctx)
 {
 	struct hdmi_context *hdata = (struct hdmi_context *)ctx;
@@ -1730,7 +1795,9 @@ static void hdmi_disable(void *ctx)
 }
 
 static struct exynos_hdmi_manager_ops manager_ops = {
+	.mode_fixup	= hdmi_mode_fixup,
 	.mode_set	= hdmi_mode_set,
+	.get_max_resol	= hdmi_get_max_resol,
 	.commit		= hdmi_commit,
 	.disable	= hdmi_disable,
 };
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 03/14] drm/exynos: update gem and buffer framework.
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
  2012-03-16  9:47 ` [PATCH v2 01/14] drm/exynos: add HDMI version 1.4 support Inki Dae
  2012-03-16  9:47 ` [PATCH v2 02/14] drm/exynos: added mode_fixup feature and code clean Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 04/14] drm/exynos: added new funtion to get/put dma address Inki Dae
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

with this patch, we can allocate physically continuous or non-continuous
memory and also it creates scatterlist for iommu support so allocated
memory region can be mapped to iommu page table using scatterlist.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_buf.c   |  191 +++++++++++++++----
 drivers/gpu/drm/exynos/exynos_drm_buf.h   |   22 ++-
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c |    4 +-
 drivers/gpu/drm/exynos/exynos_drm_gem.c   |  301 ++++++++++++++++++++++++++---
 drivers/gpu/drm/exynos/exynos_drm_gem.h   |   11 +-
 include/drm/exynos_drm.h                  |    6 +
 6 files changed, 463 insertions(+), 72 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 3cf785c..4a3a5f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -25,45 +25,161 @@
 
 #include "drmP.h"
 #include "drm.h"
+#include "exynos_drm.h"
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_buf.h"
 
 static int lowlevel_buffer_allocate(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer)
+		unsigned int flags, struct exynos_drm_gem_buf *buf)
 {
+	dma_addr_t start_addr, end_addr;
+	unsigned int npages, page_size, i = 0;
+	struct scatterlist *sgl;
+	int ret = 0;
+
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	buffer->kvaddr = dma_alloc_writecombine(dev->dev, buffer->size,
-			&buffer->dma_addr, GFP_KERNEL);
-	if (!buffer->kvaddr) {
-		DRM_ERROR("failed to allocate buffer.\n");
+	if (flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support allocation type.\n");
+		return -EINVAL;
+	}
+
+	if (buf->dma_addr) {
+		DRM_DEBUG_KMS("already allocated.\n");
+		return 0;
+	}
+
+	if (buf->size >= SZ_1M) {
+		npages = (buf->size >> SECTION_SHIFT) + 1;
+		page_size = SECTION_SIZE;
+	} else if (buf->size >= SZ_64K) {
+		npages = (buf->size >> 16) + 1;
+		page_size = SZ_64K;
+	} else {
+		npages = (buf->size >> PAGE_SHIFT) + 1;
+		page_size = PAGE_SIZE;
+	}
+
+	buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!buf->sgt) {
+		DRM_ERROR("failed to allocate sg table.\n");
 		return -ENOMEM;
 	}
 
-	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
-			(unsigned long)buffer->kvaddr,
-			(unsigned long)buffer->dma_addr,
-			buffer->size);
+	ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
+	if (ret < 0) {
+		DRM_ERROR("failed to initialize sg table.\n");
+		kfree(buf->sgt);
+		buf->sgt = NULL;
+		return -ENOMEM;
+	}
 
-	return 0;
+		buf->kvaddr = dma_alloc_writecombine(dev->dev, buf->size,
+				&buf->dma_addr, GFP_KERNEL);
+		if (!buf->kvaddr) {
+			DRM_ERROR("failed to allocate buffer.\n");
+			ret = -ENOMEM;
+			goto err1;
+		}
+
+		start_addr = buf->dma_addr;
+		end_addr = buf->dma_addr + buf->size;
+
+		buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
+		if (!buf->pages) {
+			DRM_ERROR("failed to allocate pages.\n");
+			ret = -ENOMEM;
+			goto err2;
+		}
+
+	start_addr = buf->dma_addr;
+	end_addr = buf->dma_addr + buf->size;
+
+	buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL);
+	if (!buf->pages) {
+		DRM_ERROR("failed to allocate pages.\n");
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	sgl = buf->sgt->sgl;
+
+	while (i < npages) {
+		buf->pages[i] = phys_to_page(start_addr);
+		sg_set_page(sgl, buf->pages[i], page_size, 0);
+		sg_dma_address(sgl) = start_addr;
+		start_addr += page_size;
+		if (end_addr - start_addr < page_size)
+			break;
+		sgl = sg_next(sgl);
+		i++;
+	}
+
+	buf->pages[i] = phys_to_page(start_addr);
+
+	sgl = sg_next(sgl);
+	sg_set_page(sgl, buf->pages[i+1], end_addr - start_addr, 0);
+
+	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
+			(unsigned long)buf->kvaddr,
+			(unsigned long)buf->dma_addr,
+			buf->size);
+
+	return ret;
+err2:
+	dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
+			(dma_addr_t)buf->dma_addr);
+	buf->dma_addr = (dma_addr_t)NULL;
+err1:
+	sg_free_table(buf->sgt);
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+
+	return ret;
 }
 
 static void lowlevel_buffer_deallocate(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer)
+		unsigned int flags, struct exynos_drm_gem_buf *buf)
 {
 	DRM_DEBUG_KMS("%s.\n", __FILE__);
 
-	if (buffer->dma_addr && buffer->size)
-		dma_free_writecombine(dev->dev, buffer->size, buffer->kvaddr,
-				(dma_addr_t)buffer->dma_addr);
-	else
-		DRM_DEBUG_KMS("buffer data are invalid.\n");
+	/*
+	 * release only physically continuous memory and
+	 * non-continuous memory would be released by exynos
+	 * gem framework.
+	 */
+	if (flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support allocation type.\n");
+		return;
+	}
+
+	if (!buf->dma_addr) {
+		DRM_DEBUG_KMS("dma_addr is invalid.\n");
+		return;
+	}
+
+	DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
+			(unsigned long)buf->kvaddr,
+			(unsigned long)buf->dma_addr,
+			buf->size);
+
+	sg_free_table(buf->sgt);
+
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+
+	kfree(buf->pages);
+	buf->pages = NULL;
+
+	dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
+				(dma_addr_t)buf->dma_addr);
+	buf->dma_addr = (dma_addr_t)NULL;
 }
 
-struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
-		unsigned int size)
+struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
+						unsigned int size)
 {
 	struct exynos_drm_gem_buf *buffer;
 
@@ -77,21 +193,11 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
 	}
 
 	buffer->size = size;
-
-	/*
-	 * allocate memory region with size and set the memory information
-	 * to vaddr and dma_addr of a buffer object.
-	 */
-	if (lowlevel_buffer_allocate(dev, buffer) < 0) {
-		kfree(buffer);
-		return NULL;
-	}
-
 	return buffer;
 }
 
-void exynos_drm_buf_destroy(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer)
+void exynos_drm_fini_buf(struct drm_device *dev,
+				struct exynos_drm_gem_buf *buffer)
 {
 	DRM_DEBUG_KMS("%s.\n", __FILE__);
 
@@ -100,12 +206,27 @@ void exynos_drm_buf_destroy(struct drm_device *dev,
 		return;
 	}
 
-	lowlevel_buffer_deallocate(dev, buffer);
-
 	kfree(buffer);
 	buffer = NULL;
 }
 
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Buffer Management Module");
-MODULE_LICENSE("GPL");
+int exynos_drm_alloc_buf(struct drm_device *dev,
+		struct exynos_drm_gem_buf *buf, unsigned int flags)
+{
+
+	/*
+	 * allocate memory region and set the memory information
+	 * to vaddr and dma_addr of a buffer object.
+	 */
+	if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void exynos_drm_free_buf(struct drm_device *dev,
+		unsigned int flags, struct exynos_drm_gem_buf *buffer)
+{
+
+	lowlevel_buffer_deallocate(dev, flags, buffer);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h
index c913f2b..3388e4e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h
@@ -26,12 +26,22 @@
 #ifndef _EXYNOS_DRM_BUF_H_
 #define _EXYNOS_DRM_BUF_H_
 
-/* allocate physical memory. */
-struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
-		unsigned int size);
+/* create and initialize buffer object. */
+struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
+						unsigned int size);
 
-/* remove allocated physical memory. */
-void exynos_drm_buf_destroy(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer);
+/* destroy buffer object. */
+void exynos_drm_fini_buf(struct drm_device *dev,
+				struct exynos_drm_gem_buf *buffer);
+
+/* allocate physical memory region and setup sgt and pages. */
+int exynos_drm_alloc_buf(struct drm_device *dev,
+				struct exynos_drm_gem_buf *buf,
+				unsigned int flags);
+
+/* release physical memory region, sgt and pages. */
+void exynos_drm_free_buf(struct drm_device *dev,
+				unsigned int flags,
+				struct exynos_drm_gem_buf *buffer);
 
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 54f8f07..b5dcd53 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -125,7 +125,9 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
 	}
 
 	size = mode_cmd.pitches[0] * mode_cmd.height;
-	exynos_gem_obj = exynos_drm_gem_create(dev, size);
+
+	/* 0 means to allocate physically continuous memory */
+	exynos_gem_obj = exynos_drm_gem_create(dev, 0, size);
 	if (IS_ERR(exynos_gem_obj)) {
 		ret = PTR_ERR(exynos_gem_obj);
 		goto out;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 6545251..730093f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -26,6 +26,7 @@
 #include "drmP.h"
 #include "drm.h"
 
+#include <linux/shmem_fs.h>
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
@@ -55,6 +56,178 @@ static unsigned int convert_to_vm_err_msg(int msg)
 	return out_msg;
 }
 
+static unsigned int mask_gem_flags(unsigned int flags)
+{
+	return flags &= EXYNOS_BO_NONCONTIG;
+}
+
+static struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
+						gfp_t gfpmask)
+{
+	struct inode *inode;
+	struct address_space *mapping;
+	struct page *p, **pages;
+	int i, npages;
+
+	/* This is the shared memory object that backs the GEM resource */
+	inode = obj->filp->f_path.dentry->d_inode;
+	mapping = inode->i_mapping;
+
+	npages = obj->size >> PAGE_SHIFT;
+
+	pages = drm_malloc_ab(npages, sizeof(struct page *));
+	if (pages == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	gfpmask |= mapping_gfp_mask(mapping);
+
+	for (i = 0; i < npages; i++) {
+		p = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
+		if (IS_ERR(p))
+			goto fail;
+		pages[i] = p;
+	}
+
+	return pages;
+
+fail:
+	while (i--)
+		page_cache_release(pages[i]);
+
+	drm_free_large(pages);
+	return ERR_PTR(PTR_ERR(p));
+}
+
+static void exynos_gem_put_pages(struct drm_gem_object *obj,
+					struct page **pages,
+					bool dirty, bool accessed)
+{
+	int i, npages;
+
+	npages = obj->size >> PAGE_SHIFT;
+
+	for (i = 0; i < npages; i++) {
+		if (dirty)
+			set_page_dirty(pages[i]);
+
+		if (accessed)
+			mark_page_accessed(pages[i]);
+
+		/* Undo the reference we took when populating the table */
+		page_cache_release(pages[i]);
+	}
+
+	drm_free_large(pages);
+}
+
+static int exynos_drm_gem_map_pages(struct drm_gem_object *obj,
+					struct vm_area_struct *vma,
+					unsigned long f_vaddr,
+					pgoff_t page_offset)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+	struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
+	unsigned long pfn;
+
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		unsigned long usize = buf->size;
+
+		if (!buf->pages)
+			return -EINTR;
+
+		while (usize > 0) {
+			pfn = page_to_pfn(buf->pages[page_offset++]);
+			vm_insert_mixed(vma, f_vaddr, pfn);
+			f_vaddr += PAGE_SIZE;
+			usize -= PAGE_SIZE;
+		}
+
+		return 0;
+	}
+
+	pfn = (buf->dma_addr >> PAGE_SHIFT) + page_offset;
+
+	return vm_insert_mixed(vma, f_vaddr, pfn);
+}
+
+static int exynos_drm_gem_get_pages(struct drm_gem_object *obj)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+	struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
+	struct scatterlist *sgl;
+	struct page **pages;
+	unsigned int npages, i = 0;
+	int ret;
+
+	if (buf->pages) {
+		DRM_DEBUG_KMS("already allocated.\n");
+		return -EINVAL;
+	}
+
+	pages = exynos_gem_get_pages(obj, GFP_KERNEL);
+	if (IS_ERR(pages)) {
+		DRM_ERROR("failed to get pages.\n");
+		return PTR_ERR(pages);
+	}
+
+	npages = obj->size >> PAGE_SHIFT;
+
+	buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!buf->sgt) {
+		DRM_ERROR("failed to allocate sg table.\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = sg_alloc_table(buf->sgt, npages, GFP_KERNEL);
+	if (ret < 0) {
+		DRM_ERROR("failed to initialize sg table.\n");
+		ret = -EFAULT;
+		goto err1;
+	}
+
+	sgl = buf->sgt->sgl;
+
+	/* set all pages to sg list. */
+	while (i < npages) {
+		sg_set_page(sgl, pages[i], PAGE_SIZE, 0);
+		sg_dma_address(sgl) = page_to_phys(pages[i]);
+		i++;
+		sgl = sg_next(sgl);
+	}
+
+	/* add some codes for UNCACHED type here. TODO */
+
+	buf->pages = pages;
+	return ret;
+err1:
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+err:
+	exynos_gem_put_pages(obj, pages, true, false);
+	return ret;
+
+}
+
+static void exynos_drm_gem_put_pages(struct drm_gem_object *obj)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+	struct exynos_drm_gem_buf *buf = exynos_gem_obj->buffer;
+
+	/*
+	 * if buffer typs is EXYNOS_BO_NONCONTIG then release all pages
+	 * allocated at gem fault handler.
+	 */
+	sg_free_table(buf->sgt);
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+
+	exynos_gem_put_pages(obj, buf->pages, true, false);
+	buf->pages = NULL;
+
+	/* add some codes for UNCACHED type here. TODO */
+}
+
 static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
 					struct drm_file *file_priv,
 					unsigned int *handle)
@@ -90,7 +263,15 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
 
 	DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&obj->handle_count));
 
-	exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->buffer);
+	if ((exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) &&
+			exynos_gem_obj->buffer->pages)
+		exynos_drm_gem_put_pages(obj);
+	else
+		exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags,
+					exynos_gem_obj->buffer);
+
+	exynos_drm_fini_buf(obj->dev, exynos_gem_obj->buffer);
+	exynos_gem_obj->buffer = NULL;
 
 	if (obj->map_list.map)
 		drm_gem_free_mmap_offset(obj);
@@ -99,6 +280,7 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
 	drm_gem_object_release(obj);
 
 	kfree(exynos_gem_obj);
+	exynos_gem_obj = NULL;
 }
 
 static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
@@ -114,6 +296,7 @@ static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
 		return NULL;
 	}
 
+	exynos_gem_obj->size = size;
 	obj = &exynos_gem_obj->base;
 
 	ret = drm_gem_object_init(dev, obj, size);
@@ -129,27 +312,55 @@ static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
 }
 
 struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
-						 unsigned long size)
+						unsigned int flags,
+						unsigned long size)
 {
-	struct exynos_drm_gem_buf *buffer;
 	struct exynos_drm_gem_obj *exynos_gem_obj;
+	struct exynos_drm_gem_buf *buf;
+	int ret;
 
 	size = roundup(size, PAGE_SIZE);
 	DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
 
-	buffer = exynos_drm_buf_create(dev, size);
-	if (!buffer)
+	flags = mask_gem_flags(flags);
+
+	buf = exynos_drm_init_buf(dev, size);
+	if (!buf)
 		return ERR_PTR(-ENOMEM);
 
 	exynos_gem_obj = exynos_drm_gem_init(dev, size);
 	if (!exynos_gem_obj) {
-		exynos_drm_buf_destroy(dev, buffer);
-		return ERR_PTR(-ENOMEM);
+		ret = -ENOMEM;
+		goto err;
 	}
 
-	exynos_gem_obj->buffer = buffer;
+	exynos_gem_obj->buffer = buf;
+
+	/* set memory type and cache attribute from user side. */
+	exynos_gem_obj->flags = flags;
+
+	/*
+	 * allocate all pages as desired size if user wants to allocate
+	 * physically non-continuous memory.
+	 */
+	if (flags & EXYNOS_BO_NONCONTIG) {
+		ret = exynos_drm_gem_get_pages(&exynos_gem_obj->base);
+		if (ret < 0) {
+			drm_gem_object_release(&exynos_gem_obj->base);
+			goto err;
+		}
+	} else {
+		ret = exynos_drm_alloc_buf(dev, buf, flags);
+		if (ret < 0) {
+			drm_gem_object_release(&exynos_gem_obj->base);
+			goto err;
+		}
+	}
 
 	return exynos_gem_obj;
+err:
+	exynos_drm_fini_buf(dev, buf);
+	return ERR_PTR(ret);
 }
 
 int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -161,7 +372,7 @@ int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
+	exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
 	if (IS_ERR(exynos_gem_obj))
 		return PTR_ERR(exynos_gem_obj);
 
@@ -200,7 +411,8 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
 	struct drm_gem_object *obj = filp->private_data;
 	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 	struct exynos_drm_gem_buf *buffer;
-	unsigned long pfn, vm_size;
+	unsigned long pfn, vm_size, usize, uaddr = vma->vm_start;
+	int ret;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -209,7 +421,8 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
 	/* in case of direct mapping, always having non-cachable attribute */
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
-	vm_size = vma->vm_end - vma->vm_start;
+	vm_size = usize = vma->vm_end - vma->vm_start;
+
 	/*
 	 * a buffer contains information to physically continuous memory
 	 * allocated by user request or at framebuffer creation.
@@ -220,18 +433,37 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
 	if (vm_size > buffer->size)
 		return -EINVAL;
 
-	/*
-	 * get page frame number to physical memory to be mapped
-	 * to user space.
-	 */
-	pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >> PAGE_SHIFT;
-
-	DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
-
-	if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
-				vma->vm_page_prot)) {
-		DRM_ERROR("failed to remap pfn range.\n");
-		return -EAGAIN;
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		int i = 0;
+
+		if (!buffer->pages)
+			return -EINVAL;
+
+		do {
+			ret = vm_insert_page(vma, uaddr, buffer->pages[i++]);
+			if (ret) {
+				DRM_ERROR("failed to remap user space.\n");
+				return ret;
+			}
+
+			uaddr += PAGE_SIZE;
+			usize -= PAGE_SIZE;
+		} while (usize > 0);
+	} else {
+		/*
+		 * get page frame number to physical memory to be mapped
+		 * to user space.
+		 */
+		pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
+								PAGE_SHIFT;
+
+		DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
+
+		if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
+					vma->vm_page_prot)) {
+			DRM_ERROR("failed to remap pfn range.\n");
+			return -EAGAIN;
+		}
 	}
 
 	return 0;
@@ -311,9 +543,9 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
 	 */
 
 	args->pitch = args->width * args->bpp >> 3;
-	args->size = args->pitch * args->height;
+	args->size = PAGE_ALIGN(args->pitch * args->height);
 
-	exynos_gem_obj = exynos_drm_gem_create(dev, args->size);
+	exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
 	if (IS_ERR(exynos_gem_obj))
 		return PTR_ERR(exynos_gem_obj);
 
@@ -397,20 +629,31 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 	struct drm_gem_object *obj = vma->vm_private_data;
 	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 	struct drm_device *dev = obj->dev;
-	unsigned long pfn;
+	unsigned long f_vaddr;
 	pgoff_t page_offset;
 	int ret;
 
 	page_offset = ((unsigned long)vmf->virtual_address -
 			vma->vm_start) >> PAGE_SHIFT;
+	f_vaddr = (unsigned long)vmf->virtual_address;
 
 	mutex_lock(&dev->struct_mutex);
 
-	pfn = (((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
-			PAGE_SHIFT) + page_offset;
+	/*
+	 * allocate all pages as desired size if user wants to allocate
+	 * physically non-continuous memory.
+	 */
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		ret = exynos_drm_gem_get_pages(obj);
+		if (ret < 0)
+			goto err;
+	}
 
-	ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
+	ret = exynos_drm_gem_map_pages(obj, vma, f_vaddr, page_offset);
+	if (ret < 0)
+		DRM_ERROR("failed to map pages.\n");
 
+err:
 	mutex_unlock(&dev->struct_mutex);
 
 	return convert_to_vm_err_msg(ret);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 67cdc91..096267d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -36,11 +36,15 @@
  * @dma_addr: bus address(accessed by dma) to allocated memory region.
  *	- this address could be physical address without IOMMU and
  *	device address with IOMMU.
+ * @sgt: sg table to transfer page data.
+ * @pages: contain all pages to allocated memory region.
  * @size: size of allocated memory region.
  */
 struct exynos_drm_gem_buf {
 	void __iomem		*kvaddr;
 	dma_addr_t		dma_addr;
+	struct sg_table		*sgt;
+	struct page		**pages;
 	unsigned long		size;
 };
 
@@ -55,6 +59,8 @@ struct exynos_drm_gem_buf {
  *	by user request or at framebuffer creation.
  *	continuous memory region allocated by user request
  *	or at framebuffer creation.
+ * @size: total memory size to physically non-continuous memory region.
+ * @flags: indicate memory type to allocated buffer and cache attruibute.
  *
  * P.S. this object would be transfered to user as kms_bo.handle so
  *	user can access the buffer through kms_bo.handle.
@@ -62,6 +68,8 @@ struct exynos_drm_gem_buf {
 struct exynos_drm_gem_obj {
 	struct drm_gem_object		base;
 	struct exynos_drm_gem_buf	*buffer;
+	unsigned long			size;
+	unsigned int			flags;
 };
 
 /* destroy a buffer with gem object */
@@ -69,7 +77,8 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
 
 /* create a new buffer with gem object */
 struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
-						 unsigned long size);
+						unsigned int flags,
+						unsigned long size);
 
 /*
  * request gem object creation and buffer allocation as the size
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index aff2313..81c9cb7 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -79,6 +79,12 @@ struct drm_exynos_plane_set_zpos {
 	__s32 zpos;
 };
 
+/* memory type definitions. */
+enum e_drm_exynos_gem_mem_type {
+	/* Physically Non-Continuous memory. */
+	EXYNOS_BO_NONCONTIG	= 1 << 0
+};
+
 #define DRM_EXYNOS_GEM_CREATE		0x00
 #define DRM_EXYNOS_GEM_MAP_OFFSET	0x01
 #define DRM_EXYNOS_GEM_MMAP		0x02
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 04/14] drm/exynos: added new funtion to get/put dma address.
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (2 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 03/14] drm/exynos: update gem and buffer framework Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 05/14] drm/exynos: release pending pageflip events when closed Inki Dae
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

this function would be used for drm based 2d acceleration driver
to get/put dma address through gem handle.
when exynos_drm_get_dma_address is called reference count of
gem object would be increased not to be released by gem close and
when exynos_drm_put_dma_address is called the reference count of
this gem object would be decreased to be released.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_gem.c |   58 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_gem.h |   18 +++++++++
 2 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 730093f..b5c6f3c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -386,6 +386,64 @@ int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
 	return 0;
 }
 
+void *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj;
+	struct drm_gem_object *obj;
+
+	obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	exynos_gem_obj = to_exynos_gem_obj(obj);
+
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support NONCONTIG type.\n");
+		drm_gem_object_unreference_unlocked(obj);
+
+		/* TODO */
+		return ERR_PTR(-EINVAL);
+	}
+
+	return &exynos_gem_obj->buffer->dma_addr;
+}
+
+void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv)
+{
+	struct exynos_drm_gem_obj *exynos_gem_obj;
+	struct drm_gem_object *obj;
+
+	obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		return;
+	}
+
+	exynos_gem_obj = to_exynos_gem_obj(obj);
+
+	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) {
+		DRM_DEBUG_KMS("not support NONCONTIG type.\n");
+		drm_gem_object_unreference_unlocked(obj);
+
+		/* TODO */
+		return;
+	}
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	/*
+	 * decrease obj->refcount one more time because we has already
+	 * increased it at exynos_drm_gem_get_dma_addr().
+	 */
+	drm_gem_object_unreference_unlocked(obj);
+}
+
 int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv)
 {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 096267d..e40fbad 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -88,6 +88,24 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
 int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
 
+/*
+ * get dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be increased.
+ */
+void *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv);
+
+/*
+ * put dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be decreased.
+ */
+void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *file_priv);
+
 /* get buffer offset to map to user space. */
 int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 05/14] drm/exynos: release pending pageflip events when closed
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (3 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 04/14] drm/exynos: added new funtion to get/put dma address Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 06/14] drm/exynos: remove module of exynos drm subdrv Inki Dae
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

We should release pending pageflip events when closed. If not, they will
be dangling events.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_drv.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 58820eb..d359cb4b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -147,8 +147,22 @@ static int exynos_drm_unload(struct drm_device *dev)
 static void exynos_drm_preclose(struct drm_device *dev,
 					struct drm_file *file)
 {
+	struct exynos_drm_private *private = dev->dev_private;
+	struct drm_pending_vblank_event *e, *t;
+	unsigned long flags;
+
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
+	/* release events of current file */
+	spin_lock_irqsave(&dev->event_lock, flags);
+	list_for_each_entry_safe(e, t, &private->pageflip_event_list,
+			base.link) {
+		if (e->base.file_priv == file) {
+			list_del(&e->base.link);
+			e->base.destroy(&e->base);
+		}
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
 static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 06/14] drm/exynos: remove module of exynos drm subdrv
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (4 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 05/14] drm/exynos: release pending pageflip events when closed Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 07/14] drm/exynos: add subdrv open/close functions Inki Dae
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

The exynos drm driver has several subdrv. They each can be module but it
causes unfixed probe order of exynodr drm driver and each subdrv. It
also needs some weird codes such as exynos_drm_fbdev_reinit and
exynos_drm_mode_group_reinit. This patch can remove weird codes and
clear codes through we doesn't modularity each subdrv.

Also this removes unnecessary codes related module.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/Kconfig                |    8 +--
 drivers/gpu/drm/exynos/Makefile               |   10 ++-
 drivers/gpu/drm/exynos/exynos_ddc.c           |    1 -
 drivers/gpu/drm/exynos/exynos_drm_connector.c |    6 --
 drivers/gpu/drm/exynos/exynos_drm_core.c      |  112 ++-----------------------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c      |    6 --
 drivers/gpu/drm/exynos/exynos_drm_drv.c       |   52 +++++++++++-
 drivers/gpu/drm/exynos/exynos_drm_drv.h       |   12 ++--
 drivers/gpu/drm/exynos/exynos_drm_encoder.c   |    6 --
 drivers/gpu/drm/exynos/exynos_drm_fb.c        |    6 --
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c     |   86 -------------------
 drivers/gpu/drm/exynos/exynos_drm_fimd.c      |   20 +----
 drivers/gpu/drm/exynos/exynos_drm_gem.c       |    4 -
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c      |   87 +------------------
 drivers/gpu/drm/exynos/exynos_hdmi.c          |    9 --
 drivers/gpu/drm/exynos/exynos_mixer.c         |    7 --
 16 files changed, 77 insertions(+), 355 deletions(-)

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index b9e5266..9a9850a 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -1,7 +1,6 @@
 config DRM_EXYNOS
 	tristate "DRM Support for Samsung SoC EXYNOS Series"
 	depends on DRM && PLAT_SAMSUNG
-	default	n
 	select DRM_KMS_HELPER
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
@@ -12,16 +11,13 @@ config DRM_EXYNOS
 	  If M is selected the module will be called exynosdrm.
 
 config DRM_EXYNOS_FIMD
-	tristate "Exynos DRM FIMD"
+	bool "Exynos DRM FIMD"
 	depends on DRM_EXYNOS && !FB_S3C
-	default n
 	help
 	  Choose this option if you want to use Exynos FIMD for DRM.
-	  If M is selected, the module will be called exynos_drm_fimd
 
 config DRM_EXYNOS_HDMI
-	tristate "Exynos DRM HDMI"
+	bool "Exynos DRM HDMI"
 	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
 	help
 	  Choose this option if you want to use Exynos HDMI for DRM.
-	  If M is selected, the module will be called exynos_drm_hdmi
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 395e69c..5331fa3 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -8,7 +8,9 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
 		exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
 		exynos_drm_plane.o
 
-obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
-obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
-obj-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynos_ddc.o \
-				 exynos_hdmiphy.o exynos_drm_hdmi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o \
+					   exynos_ddc.o exynos_hdmiphy.o \
+					   exynos_drm_hdmi.o
+
+obj-$(CONFIG_DRM_EXYNOS)		+= exynosdrm.o
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
index 84b614f..7e1051d 100644
--- a/drivers/gpu/drm/exynos/exynos_ddc.c
+++ b/drivers/gpu/drm/exynos/exynos_ddc.c
@@ -55,4 +55,3 @@ struct i2c_driver ddc_driver = {
 	.remove		= __devexit_p(s5p_ddc_remove),
 	.command		= NULL,
 };
-EXPORT_SYMBOL(ddc_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index ebdd71d..a5d6591 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -348,9 +348,3 @@ err_connector:
 	kfree(exynos_connector);
 	return NULL;
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Connector Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index d08a558..937b059 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -32,7 +32,6 @@
 #include "exynos_drm_connector.h"
 #include "exynos_drm_fbdev.h"
 
-static DEFINE_MUTEX(exynos_drm_mutex);
 static LIST_HEAD(exynos_drm_subdrv_list);
 static struct drm_device *drm_dev;
 
@@ -116,13 +115,10 @@ int exynos_drm_device_register(struct drm_device *dev)
 	if (!dev)
 		return -EINVAL;
 
-	if (drm_dev) {
-		DRM_ERROR("Already drm device were registered\n");
-		return -EBUSY;
-	}
+	drm_dev = dev;
 
-	mutex_lock(&exynos_drm_mutex);
 	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
+		subdrv->drm_dev = dev;
 		err = exynos_drm_subdrv_probe(dev, subdrv);
 		if (err) {
 			DRM_DEBUG("exynos drm subdrv probe failed.\n");
@@ -130,9 +126,6 @@ int exynos_drm_device_register(struct drm_device *dev)
 		}
 	}
 
-	drm_dev = dev;
-	mutex_unlock(&exynos_drm_mutex);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_register);
@@ -143,86 +136,28 @@ int exynos_drm_device_unregister(struct drm_device *dev)
 
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
-	if (!dev || dev != drm_dev) {
+	if (!dev) {
 		WARN(1, "Unexpected drm device unregister!\n");
 		return -EINVAL;
 	}
 
-	mutex_lock(&exynos_drm_mutex);
 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
 		exynos_drm_subdrv_remove(dev, subdrv);
 
 	drm_dev = NULL;
-	mutex_unlock(&exynos_drm_mutex);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
 
-static int exynos_drm_mode_group_reinit(struct drm_device *dev)
-{
-	struct drm_mode_group *group = &dev->primary->mode_group;
-	uint32_t *id_list = group->id_list;
-	int ret;
-
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
-	ret = drm_mode_group_init_legacy_group(dev, group);
-	if (ret < 0)
-		return ret;
-
-	kfree(id_list);
-	return 0;
-}
-
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
-	int err;
-
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
 	if (!subdrv)
 		return -EINVAL;
 
-	mutex_lock(&exynos_drm_mutex);
-	if (drm_dev) {
-		err = exynos_drm_subdrv_probe(drm_dev, subdrv);
-		if (err) {
-			DRM_ERROR("failed to probe exynos drm subdrv\n");
-			mutex_unlock(&exynos_drm_mutex);
-			return err;
-		}
-
-		/* setup possible_clones. */
-		exynos_drm_encoder_setup(drm_dev);
-
-		/*
-		 * if any specific driver such as fimd or hdmi driver called
-		 * exynos_drm_subdrv_register() later than drm_load(),
-		 * the fb helper should be re-initialized and re-configured.
-		 */
-		err = exynos_drm_fbdev_reinit(drm_dev);
-		if (err) {
-			DRM_ERROR("failed to reinitialize exynos drm fbdev\n");
-			exynos_drm_subdrv_remove(drm_dev, subdrv);
-			mutex_unlock(&exynos_drm_mutex);
-			return err;
-		}
-
-		err = exynos_drm_mode_group_reinit(drm_dev);
-		if (err) {
-			DRM_ERROR("failed to reinitialize mode group\n");
-			exynos_drm_fbdev_fini(drm_dev);
-			exynos_drm_subdrv_remove(drm_dev, subdrv);
-			mutex_unlock(&exynos_drm_mutex);
-			return err;
-		}
-	}
-
-	subdrv->drm_dev = drm_dev;
-
 	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
-	mutex_unlock(&exynos_drm_mutex);
 
 	return 0;
 }
@@ -230,46 +165,13 @@ EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
 
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
 {
-	int ret = -EFAULT;
-
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
-	if (!subdrv) {
-		DRM_DEBUG("Unexpected exynos drm subdrv unregister!\n");
-		return ret;
-	}
-
-	mutex_lock(&exynos_drm_mutex);
-	if (drm_dev) {
-		exynos_drm_subdrv_remove(drm_dev, subdrv);
-		list_del(&subdrv->list);
-
-		/*
-		 * fb helper should be updated once a sub driver is released
-		 * to re-configure crtc and connector and also to re-setup
-		 * drm framebuffer.
-		 */
-		ret = exynos_drm_fbdev_reinit(drm_dev);
-		if (ret < 0) {
-			DRM_ERROR("failed fb helper reinit.\n");
-			goto fail;
-		}
+	if (!subdrv)
+		return -EINVAL;
 
-		ret = exynos_drm_mode_group_reinit(drm_dev);
-		if (ret < 0) {
-			DRM_ERROR("failed drm mode group reinit.\n");
-			goto fail;
-		}
-	}
+	list_del(&subdrv->list);
 
-fail:
-	mutex_unlock(&exynos_drm_mutex);
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Core Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 2d9a0e6..3486ffe 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -430,9 +430,3 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
 	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
 			exynos_drm_disable_vblank);
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index d359cb4b..903fcf0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -266,9 +266,49 @@ static struct platform_driver exynos_drm_platform_driver = {
 
 static int __init exynos_drm_init(void)
 {
+	int ret;
+
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
-	return platform_driver_register(&exynos_drm_platform_driver);
+#ifdef CONFIG_DRM_EXYNOS_FIMD
+	ret = platform_driver_register(&fimd_driver);
+	if (ret < 0)
+		goto out_fimd;
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_HDMI
+	ret = platform_driver_register(&hdmi_driver);
+	if (ret < 0)
+		goto out_hdmi;
+	ret = platform_driver_register(&mixer_driver);
+	if (ret < 0)
+		goto out_mixer;
+	ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
+	if (ret < 0)
+		goto out_common_hdmi;
+#endif
+
+	ret = platform_driver_register(&exynos_drm_platform_driver);
+	if (ret < 0)
+		goto out;
+
+	return 0;
+
+out:
+#ifdef CONFIG_DRM_EXYNOS_HDMI
+	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
+out_common_hdmi:
+	platform_driver_unregister(&mixer_driver);
+out_mixer:
+	platform_driver_unregister(&hdmi_driver);
+out_hdmi:
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_FIMD
+	platform_driver_unregister(&fimd_driver);
+out_fimd:
+#endif
+	return ret;
 }
 
 static void __exit exynos_drm_exit(void)
@@ -276,6 +316,16 @@ static void __exit exynos_drm_exit(void)
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
 	platform_driver_unregister(&exynos_drm_platform_driver);
+
+#ifdef CONFIG_DRM_EXYNOS_HDMI
+	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
+	platform_driver_unregister(&mixer_driver);
+	platform_driver_unregister(&hdmi_driver);
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_FIMD
+	platform_driver_unregister(&fimd_driver);
+#endif
 }
 
 module_init(exynos_drm_init);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 4115a9f..f8bac0e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -262,15 +262,15 @@ int exynos_drm_device_unregister(struct drm_device *dev);
  * this function would be called by sub drivers such as display controller
  * or hdmi driver to register this sub driver object to exynos drm driver
  * and when a sub driver is registered to exynos drm driver a probe callback
- * of the sub driver is called and creates its own encoder and connector
- * and then fb helper and drm mode group would be re-initialized.
+ * of the sub driver is called and creates its own encoder and connector.
  */
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
 
-/*
- * this function removes subdrv list from exynos drm driver and fb helper
- * and drm mode group would be re-initialized.
- */
+/* this function removes subdrv list from exynos drm driver */
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
 
+extern struct platform_driver fimd_driver;
+extern struct platform_driver hdmi_driver;
+extern struct platform_driver mixer_driver;
+extern struct platform_driver exynos_drm_common_hdmi_driver;
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 45ca732..2278676 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -442,9 +442,3 @@ void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
 	if (overlay_ops && overlay_ops->disable)
 		overlay_ops->disable(manager->dev, zpos);
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Encoder Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 3733fe6..c38c8f4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -211,9 +211,3 @@ void exynos_drm_mode_config_init(struct drm_device *dev)
 
 	dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM FB Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index b5dcd53..d5586cc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -316,89 +316,3 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
 
 	drm_fb_helper_restore_fbdev_mode(private->fb_helper);
 }
-
-int exynos_drm_fbdev_reinit(struct drm_device *dev)
-{
-	struct exynos_drm_private *private = dev->dev_private;
-	struct drm_fb_helper *fb_helper;
-	int ret;
-
-	if (!private)
-		return -EINVAL;
-
-	/*
-	 * if all sub drivers were unloaded then num_connector is 0
-	 * so at this time, the framebuffers also should be destroyed.
-	 */
-	if (!dev->mode_config.num_connector) {
-		exynos_drm_fbdev_fini(dev);
-		return 0;
-	}
-
-	fb_helper = private->fb_helper;
-
-	if (fb_helper) {
-		struct list_head temp_list;
-
-		INIT_LIST_HEAD(&temp_list);
-
-		/*
-		 * fb_helper is reintialized but kernel fb is reused
-		 * so kernel_fb_list need to be backuped and restored
-		 */
-		if (!list_empty(&fb_helper->kernel_fb_list))
-			list_replace_init(&fb_helper->kernel_fb_list,
-					&temp_list);
-
-		drm_fb_helper_fini(fb_helper);
-
-		ret = drm_fb_helper_init(dev, fb_helper,
-				dev->mode_config.num_crtc, MAX_CONNECTOR);
-		if (ret < 0) {
-			DRM_ERROR("failed to initialize drm fb helper\n");
-			return ret;
-		}
-
-		if (!list_empty(&temp_list))
-			list_replace(&temp_list, &fb_helper->kernel_fb_list);
-
-		ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-		if (ret < 0) {
-			DRM_ERROR("failed to add fb helper to connectors\n");
-			goto err;
-		}
-
-		ret = drm_fb_helper_initial_config(fb_helper, PREFERRED_BPP);
-		if (ret < 0) {
-			DRM_ERROR("failed to set up hw configuration.\n");
-			goto err;
-		}
-	} else {
-		/*
-		 * if drm_load() failed whem drm load() was called prior
-		 * to specific drivers, fb_helper must be NULL and so
-		 * this fuction should be called again to re-initialize and
-		 * re-configure the fb helper. it means that this function
-		 * has been called by the specific drivers.
-		 */
-		ret = exynos_drm_fbdev_init(dev);
-	}
-
-	return ret;
-
-err:
-	/*
-	 * if drm_load() failed when drm load() was called prior
-	 * to specific drivers, the fb_helper must be NULL and so check it.
-	 */
-	if (fb_helper)
-		drm_fb_helper_fini(fb_helper);
-
-	return ret;
-}
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM FBDEV Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 360adf2..101d64c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -1012,7 +1012,7 @@ static const struct dev_pm_ops fimd_pm_ops = {
 	SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
 };
 
-static struct platform_driver fimd_driver = {
+struct platform_driver fimd_driver = {
 	.probe		= fimd_probe,
 	.remove		= __devexit_p(fimd_remove),
 	.driver		= {
@@ -1021,21 +1021,3 @@ static struct platform_driver fimd_driver = {
 		.pm	= &fimd_pm_ops,
 	},
 };
-
-static int __init fimd_init(void)
-{
-	return platform_driver_register(&fimd_driver);
-}
-
-static void __exit fimd_exit(void)
-{
-	platform_driver_unregister(&fimd_driver);
-}
-
-module_init(fimd_init);
-module_exit(fimd_exit);
-
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung DRM FIMD Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index b5c6f3c..fa1aa94 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -735,7 +735,3 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 
 	return ret;
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index ed86bdd..14eb26b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -38,7 +38,6 @@ struct drm_hdmi_context {
 	struct exynos_drm_subdrv	subdrv;
 	struct exynos_drm_hdmi_context	*hdmi_ctx;
 	struct exynos_drm_hdmi_context	*mixer_ctx;
-	struct work_struct		work;
 };
 
 void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
@@ -49,7 +48,6 @@ void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
 	if (display_ops)
 		hdmi_display_ops = display_ops;
 }
-EXPORT_SYMBOL(exynos_drm_display_ops_register);
 
 void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
 					*manager_ops)
@@ -59,7 +57,6 @@ void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
 	if (manager_ops)
 		hdmi_manager_ops = manager_ops;
 }
-EXPORT_SYMBOL(exynos_drm_manager_ops_register);
 
 void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
 					*overlay_ops)
@@ -69,7 +66,6 @@ void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
 	if (overlay_ops)
 		hdmi_overlay_ops = overlay_ops;
 }
-EXPORT_SYMBOL(exynos_drm_overlay_ops_register);
 
 static bool drm_hdmi_is_connected(struct device *dev)
 {
@@ -277,7 +273,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
 	struct drm_hdmi_context *ctx;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct exynos_drm_common_hdmi_pd *pd;
-	int ret;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -298,26 +293,13 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
 		return -EFAULT;
 	}
 
-	ret = platform_driver_register(&hdmi_driver);
-	if (ret) {
-		DRM_DEBUG_KMS("failed to register hdmi driver.\n");
-		return ret;
-	}
-
-	ret = platform_driver_register(&mixer_driver);
-	if (ret) {
-		DRM_DEBUG_KMS("failed to register mixer driver.\n");
-		goto err_hdmidrv;
-	}
-
 	ctx = get_ctx_from_subdrv(subdrv);
 
 	ctx->hdmi_ctx = (struct exynos_drm_hdmi_context *)
 				to_context(pd->hdmi_dev);
 	if (!ctx->hdmi_ctx) {
 		DRM_DEBUG_KMS("hdmi context is null.\n");
-		ret = -EFAULT;
-		goto err_mixerdrv;
+		return -EFAULT;
 	}
 
 	ctx->hdmi_ctx->drm_dev = drm_dev;
@@ -326,42 +308,12 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
 				to_context(pd->mixer_dev);
 	if (!ctx->mixer_ctx) {
 		DRM_DEBUG_KMS("mixer context is null.\n");
-		ret = -EFAULT;
-		goto err_mixerdrv;
+		return -EFAULT;
 	}
 
 	ctx->mixer_ctx->drm_dev = drm_dev;
 
 	return 0;
-
-err_mixerdrv:
-	platform_driver_unregister(&mixer_driver);
-err_hdmidrv:
-	platform_driver_unregister(&hdmi_driver);
-	return ret;
-}
-
-static void hdmi_subdrv_remove(struct drm_device *drm_dev)
-{
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	platform_driver_unregister(&hdmi_driver);
-	platform_driver_unregister(&mixer_driver);
-}
-
-static void exynos_drm_hdmi_late_probe(struct work_struct *work)
-{
-	struct drm_hdmi_context *ctx = container_of(work,
-				struct drm_hdmi_context, work);
-
-	/*
-	 * this function calls subdrv->probe() so this must be called
-	 * after probe context.
-	 *
-	 * PS. subdrv->probe() will call platform_driver_register() to probe
-	 * hdmi and mixer driver.
-	 */
-	exynos_drm_subdrv_register(&ctx->subdrv);
 }
 
 static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
@@ -381,7 +333,6 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
 	subdrv = &ctx->subdrv;
 
 	subdrv->probe = hdmi_subdrv_probe;
-	subdrv->remove = hdmi_subdrv_remove;
 	subdrv->manager.pipe = -1;
 	subdrv->manager.ops = &drm_hdmi_manager_ops;
 	subdrv->manager.overlay_ops = &drm_hdmi_overlay_ops;
@@ -390,9 +341,7 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, subdrv);
 
-	INIT_WORK(&ctx->work, exynos_drm_hdmi_late_probe);
-
-	schedule_work(&ctx->work);
+	exynos_drm_subdrv_register(subdrv);
 
 	return 0;
 }
@@ -428,7 +377,7 @@ static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_driver exynos_drm_common_hdmi_driver = {
+struct platform_driver exynos_drm_common_hdmi_driver = {
 	.probe		= exynos_drm_hdmi_probe,
 	.remove		= __devexit_p(exynos_drm_hdmi_remove),
 	.driver		= {
@@ -437,31 +386,3 @@ static struct platform_driver exynos_drm_common_hdmi_driver = {
 		.pm = &hdmi_pm_ops,
 	},
 };
-
-static int __init exynos_drm_hdmi_init(void)
-{
-	int ret;
-
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
-	if (ret) {
-		DRM_DEBUG_KMS("failed to register hdmi common driver.\n");
-		return ret;
-	}
-
-	return ret;
-}
-
-static void __exit exynos_drm_hdmi_exit(void)
-{
-	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
-}
-
-module_init(exynos_drm_hdmi_init);
-module_exit(exynos_drm_hdmi_exit);
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM HDMI Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 6fe1e89..3fe5b2e 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1998,14 +1998,12 @@ void hdmi_attach_ddc_client(struct i2c_client *ddc)
 	if (ddc)
 		hdmi_ddc = ddc;
 }
-EXPORT_SYMBOL(hdmi_attach_ddc_client);
 
 void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
 {
 	if (hdmiphy)
 		hdmi_hdmiphy = hdmiphy;
 }
-EXPORT_SYMBOL(hdmi_attach_hdmiphy_client);
 
 static int __devinit hdmi_probe(struct platform_device *pdev)
 {
@@ -2188,10 +2186,3 @@ struct platform_driver hdmi_driver = {
 		.pm = &hdmi_pm_ops,
 	},
 };
-EXPORT_SYMBOL(hdmi_driver);
-
-MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_DESCRIPTION("Samsung DRM HDMI core Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 93846e8..242cbcd 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -1066,10 +1066,3 @@ struct platform_driver mixer_driver = {
 	.probe = mixer_probe,
 	.remove = __devexit_p(mixer_remove),
 };
-EXPORT_SYMBOL(mixer_driver);
-
-MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_DESCRIPTION("Samsung DRM HDMI mixer Driver");
-MODULE_LICENSE("GPL");
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 07/14] drm/exynos: add subdrv open/close functions
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (5 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 06/14] drm/exynos: remove module of exynos drm subdrv Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 08/14] drm/exynos: add is_local member in exynos_drm_subdrv struct Inki Dae
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

Some subdrv need open and close functions call when open and close drm.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_core.c |   35 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |   10 ++++++++
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |    9 +++++++
 3 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 937b059..4e29c71 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -175,3 +175,38 @@ int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
+
+int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
+{
+	struct exynos_drm_subdrv *subdrv;
+	int ret;
+
+	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
+		if (subdrv->open) {
+			ret = subdrv->open(dev, subdrv->manager.dev, file);
+			if (ret)
+				goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
+		if (subdrv->close)
+			subdrv->close(dev, subdrv->manager.dev, file);
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
+
+void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
+{
+	struct exynos_drm_subdrv *subdrv;
+
+	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
+		if (subdrv->close)
+			subdrv->close(dev, subdrv->manager.dev, file);
+	}
+}
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 903fcf0..1d78e03 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -144,6 +144,13 @@ static int exynos_drm_unload(struct drm_device *dev)
 	return 0;
 }
 
+static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
+{
+	DRM_DEBUG_DRIVER("%s\n", __FILE__);
+
+	return exynos_drm_subdrv_open(dev, file);
+}
+
 static void exynos_drm_preclose(struct drm_device *dev,
 					struct drm_file *file)
 {
@@ -163,6 +170,8 @@ static void exynos_drm_preclose(struct drm_device *dev,
 		}
 	}
 	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	exynos_drm_subdrv_close(dev, file);
 }
 
 static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
@@ -216,6 +225,7 @@ static struct drm_driver exynos_drm_driver = {
 				  DRIVER_MODESET | DRIVER_GEM,
 	.load			= exynos_drm_load,
 	.unload			= exynos_drm_unload,
+	.open			= exynos_drm_open,
 	.preclose		= exynos_drm_preclose,
 	.lastclose		= exynos_drm_lastclose,
 	.postclose		= exynos_drm_postclose,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index f8bac0e..a412454 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -229,6 +229,8 @@ struct exynos_drm_private {
  *	subdrv is registered to it.
  * @remove: this callback is used to release resources created
  *	by probe callback.
+ * @open: this would be called with drm device file open.
+ * @close: this would be called with drm device file close.
  * @manager: subdrv has its own manager to control a hardware appropriately
  *	and we can access a hardware drawing on this manager.
  * @encoder: encoder object owned by this sub driver.
@@ -240,6 +242,10 @@ struct exynos_drm_subdrv {
 
 	int (*probe)(struct drm_device *drm_dev, struct device *dev);
 	void (*remove)(struct drm_device *dev);
+	int (*open)(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file);
+	void (*close)(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file);
 
 	struct exynos_drm_manager manager;
 	struct drm_encoder *encoder;
@@ -269,6 +275,9 @@ int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
 /* this function removes subdrv list from exynos drm driver */
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
 
+int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
+void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
+
 extern struct platform_driver fimd_driver;
 extern struct platform_driver hdmi_driver;
 extern struct platform_driver mixer_driver;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 08/14] drm/exynos: add is_local member in exynos_drm_subdrv struct
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (6 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 07/14] drm/exynos: add subdrv open/close functions Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 09/14] drm/exynos: add G2D driver Inki Dae
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

The is_local member indicates unused subdrv such connector and encoder
so doesn't make resources for them.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_core.c |    3 +++
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |    2 ++
 2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 4e29c71..411832e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -59,6 +59,9 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev,
 			return ret;
 	}
 
+	if (subdrv->is_local)
+		return 0;
+
 	/* create and initialize a encoder for this sub driver. */
 	encoder = exynos_drm_encoder_create(dev, &subdrv->manager,
 			(1 << MAX_CRTC) - 1);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index a412454..b26c2f4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -225,6 +225,7 @@ struct exynos_drm_private {
  * @list: sub driver has its own list object to register to exynos drm driver.
  * @drm_dev: pointer to drm_device and this pointer would be set
  *	when sub driver calls exynos_drm_subdrv_register().
+ * @is_local: appear encoder and connector disrelated device.
  * @probe: this callback would be called by exynos drm driver after
  *	subdrv is registered to it.
  * @remove: this callback is used to release resources created
@@ -239,6 +240,7 @@ struct exynos_drm_private {
 struct exynos_drm_subdrv {
 	struct list_head list;
 	struct drm_device *drm_dev;
+	bool is_local;
 
 	int (*probe)(struct drm_device *drm_dev, struct device *dev);
 	void (*remove)(struct drm_device *dev);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 09/14] drm/exynos: add G2D driver
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (7 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 08/14] drm/exynos: add is_local member in exynos_drm_subdrv struct Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-19 12:25   ` Dave Airlie
  2012-03-16  9:47 ` [PATCH v2 10/14] drm/exynos: added virtual display driver Inki Dae
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

The G2D is a 2D graphic accelerator that supports Bit Block Transfer.
This G2D driver is exynos drm specific and supports only G2D(version
4.1) of later Exynos series from Exynos4X12 because supporting DMA.

The G2D is performed by two tasks simply.
1. Configures the rendering parameters, such as foreground color and
   coordinates data by setting the drawing context registers.
2. Start the rendering process by setting thre relevant command
   registers accordingly.

The G2D version 4.1 supports DMA mode as host interface. User can make
command list to reduce HOST(ARM) loads. The contents of The command list
is setted to relevant registers of G2D by DMA.

The command list is composed Header and command sets and Tail.
- Header: The number of command set(4Bytes)
- Command set: Register offset(4Bytes) + Register data(4Bytes)
- Tail: Pointer of base address of the other command list(4Bytes)

By Tail field, the G2D can process many command lists without halt at
one go.

The G2D has following the rendering pipeline.
--> Primitive Drawing --> Rotation --> Clipping --> Bilinear Sampling
--> Color Key --> ROP --> Mask Operation --> Alpha Blending -->
Dithering --> FrameBuffer

And supports various operations from the rendering pipeline.
- copy
- fast solid color fill
- window clipping
- rotation
- flip
- 4 operand raster operation(ROP4)
- masking operation
- alpha blending
- color key
- dithering
- etc

User should make the command list to data and registers needed by
operation to use. The Exynos G2D driver only manages the command lists
received from user. Some registers needs memory base address(physical
address) of image. User doesn't know its physical address, so fills the
gem handle of that memory than address to command sets, then G2D driver
converts it to memory base address.

We adds three ioctls and one event for Exynos G2D.

- ioctls
DRM_EXYNOS_G2D_GET_VER: get the G2D hardware version
DRM_EXYNOS_G2D_SET_CMDLIST: set the command list from user to driver
DRM_EXYNOS_G2D_EXEC: execute the command lists setted to driver

- event
DRM_EXYNOS_G2D_EVENT: event to give notification completion of the
		      command list to user

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/Kconfig          |    6 +
 drivers/gpu/drm/exynos/Makefile         |    1 +
 drivers/gpu/drm/exynos/exynos_drm_drv.c |   31 ++
 drivers/gpu/drm/exynos/exynos_drm_drv.h |   13 +
 drivers/gpu/drm/exynos/exynos_drm_g2d.c |  885 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_g2d.h |   36 ++
 include/drm/exynos_drm.h                |   57 ++
 7 files changed, 1029 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_g2d.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_g2d.h

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 9a9850a..8493fe9 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -21,3 +21,9 @@ config DRM_EXYNOS_HDMI
 	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
 	help
 	  Choose this option if you want to use Exynos HDMI for DRM.
+
+config DRM_EXYNOS_G2D
+	bool "Exynos DRM G2D"
+	depends on DRM_EXYNOS
+	help
+	  Choose this option if you want to use Exynos G2D for DRM.
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 5331fa3..d6c1a3c 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -12,5 +12,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o \
 					   exynos_ddc.o exynos_hdmiphy.o \
 					   exynos_drm_hdmi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
 
 obj-$(CONFIG_DRM_EXYNOS)		+= exynosdrm.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 1d78e03..64ef4ce 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -37,6 +37,7 @@
 #include "exynos_drm_fbdev.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
+#include "exynos_drm_g2d.h"
 #include "exynos_drm_plane.h"
 
 #define DRIVER_NAME	"exynos"
@@ -146,8 +147,16 @@ static int exynos_drm_unload(struct drm_device *dev)
 
 static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 {
+	struct drm_exynos_file_private *file_priv;
+
 	DRM_DEBUG_DRIVER("%s\n", __FILE__);
 
+	file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
+	if (!file_priv)
+		return -ENOMEM;
+
+	file->driver_priv = file_priv;
+
 	return exynos_drm_subdrv_open(dev, file);
 }
 
@@ -208,6 +217,13 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
 			exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
 			DRM_UNLOCKED | DRM_AUTH),
+
+	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
+			exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
+			exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
+			exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
 };
 
 static const struct file_operations exynos_drm_driver_fops = {
@@ -298,6 +314,12 @@ static int __init exynos_drm_init(void)
 		goto out_common_hdmi;
 #endif
 
+#ifdef CONFIG_DRM_EXYNOS_G2D
+	ret = platform_driver_register(&g2d_driver);
+	if (ret < 0)
+		goto out_g2d;
+#endif
+
 	ret = platform_driver_register(&exynos_drm_platform_driver);
 	if (ret < 0)
 		goto out;
@@ -305,6 +327,11 @@ static int __init exynos_drm_init(void)
 	return 0;
 
 out:
+#ifdef CONFIG_DRM_EXYNOS_G2D
+	platform_driver_unregister(&g2d_driver);
+out_g2d:
+#endif
+
 #ifdef CONFIG_DRM_EXYNOS_HDMI
 	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
 out_common_hdmi:
@@ -327,6 +354,10 @@ static void __exit exynos_drm_exit(void)
 
 	platform_driver_unregister(&exynos_drm_platform_driver);
 
+#ifdef CONFIG_DRM_EXYNOS_G2D
+	platform_driver_unregister(&g2d_driver);
+#endif
+
 #ifdef CONFIG_DRM_EXYNOS_HDMI
 	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
 	platform_driver_unregister(&mixer_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index b26c2f4..750daa9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -203,6 +203,18 @@ struct exynos_drm_manager {
 	struct exynos_drm_display_ops *display_ops;
 };
 
+struct exynos_drm_g2d_private {
+	struct device		*dev;
+	struct list_head	inuse_cmdlist;
+	struct list_head	event_list;
+	struct list_head	gem_list;
+	unsigned int		gem_nr;
+};
+
+struct drm_exynos_file_private {
+	struct exynos_drm_g2d_private	*g2d_priv;
+};
+
 /*
  * Exynos drm private structure.
  */
@@ -284,4 +296,5 @@ extern struct platform_driver fimd_driver;
 extern struct platform_driver hdmi_driver;
 extern struct platform_driver mixer_driver;
 extern struct platform_driver exynos_drm_common_hdmi_driver;
+extern struct platform_driver g2d_driver;
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
new file mode 100644
index 0000000..bad7d624
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -0,0 +1,885 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Authors: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundationr
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include "drmP.h"
+#include "exynos_drm.h"
+#include "exynos_drm_drv.h"
+#include "exynos_drm_gem.h"
+
+#define G2D_HW_MAJOR_VER		4
+#define G2D_HW_MINOR_VER		1
+
+/* Registers */
+#define G2D_SOFT_RESET			0x0000
+#define G2D_INTEN			0x0004
+#define G2D_INTC_PEND			0x000C
+#define G2D_DMA_SFR_BASE_ADDR		0x0080
+#define G2D_DMA_COMMAND			0x0084
+#define G2D_DMA_STATUS			0x008C
+#define G2D_DMA_HOLD_CMD		0x0090
+#define G2D_BITBLT_START		0x0100
+#define G2D_SRC_BASE_ADDR		0x0304
+
+/* G2D_SOFT_RESET */
+#define G2D_SFRCLEAR			(1 << 1)
+#define G2D_R				(1 << 0)
+
+/* G2D_INTEN */
+#define G2D_INTEN_ACF			(1 << 3)
+#define G2D_INTEN_UCF			(1 << 2)
+#define G2D_INTEN_GCF			(1 << 1)
+#define G2D_INTEN_SCF			(1 << 0)
+
+/* G2D_INTC_PEND */
+#define G2D_INTP_ACMD_FIN		(1 << 3)
+#define G2D_INTP_UCMD_FIN		(1 << 2)
+#define G2D_INTP_GCMD_FIN		(1 << 1)
+#define G2D_INTP_SCMD_FIN		(1 << 0)
+
+/* G2D_DMA_COMMAND */
+#define G2D_DMA_HALT			(1 << 2)
+#define G2D_DMA_CONTINUE		(1 << 1)
+#define G2D_DMA_START			(1 << 0)
+
+/* G2D_DMA_STATUS */
+#define G2D_DMA_LIST_DONE_COUNT		(0xFF << 17)
+#define G2D_DMA_BITBLT_DONE_COUNT	(0xFFFF << 1)
+#define G2D_DMA_DONE			(1 << 0)
+#define G2D_DMA_LIST_DONE_COUNT_OFFSET	17
+
+/* G2D_DMA_HOLD_CMD */
+#define G2D_USET_HOLD			(1 << 2)
+#define G2D_LIST_HOLD			(1 << 1)
+#define G2D_BITBLT_HOLD			(1 << 0)
+
+/* G2D_BITBLT_START */
+#define G2D_START_CASESEL		(1 << 2)
+#define G2D_START_NHOLT			(1 << 1)
+#define G2D_START_BITBLT		(1 << 0)
+
+#define G2D_CMDLIST_SIZE		(PAGE_SIZE / 4)
+#define G2D_CMDLIST_NUM			64
+#define G2D_CMDLIST_POOL_SIZE		(G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
+#define G2D_CMDLIST_DATA_NUM		(G2D_CMDLIST_SIZE / sizeof(u32) - 2)
+
+/* cmdlist data structure */
+struct g2d_cmdlist {
+	u32	head;
+	u32	data[G2D_CMDLIST_DATA_NUM];
+	u32	last;	/* last data offset */
+};
+
+struct drm_exynos_pending_g2d_event {
+	struct drm_pending_event	base;
+	struct drm_exynos_g2d_event	event;
+};
+
+struct g2d_gem_node {
+	struct list_head	list;
+	unsigned int		handle;
+};
+
+struct g2d_cmdlist_node {
+	struct list_head	list;
+	struct g2d_cmdlist	*cmdlist;
+	unsigned int		gem_nr;
+	dma_addr_t		dma_addr;
+
+	struct drm_exynos_pending_g2d_event	*event;
+};
+
+struct g2d_runqueue_node {
+	struct list_head	list;
+	struct list_head	run_cmdlist;
+	struct list_head	event_list;
+	struct completion	complete;
+	int			async;
+};
+
+struct g2d_data {
+	struct device			*dev;
+	struct clk			*gate_clk;
+	struct resource			*regs_res;
+	void __iomem			*regs;
+	int				irq;
+	struct workqueue_struct		*g2d_workq;
+	struct work_struct		runqueue_work;
+	struct exynos_drm_subdrv	subdrv;
+	bool				suspended;
+
+	/* cmdlist */
+	struct g2d_cmdlist_node		*cmdlist_node;
+	struct list_head		free_cmdlist;
+	struct mutex			cmdlist_mutex;
+	dma_addr_t			cmdlist_pool;
+	void				*cmdlist_pool_virt;
+
+	/* runqueue*/
+	struct g2d_runqueue_node	*runqueue_node;
+	struct list_head		runqueue;
+	struct mutex			runqueue_mutex;
+	struct kmem_cache		*runqueue_slab;
+};
+
+/* cmdlist functions */
+static void g2d_print_cmdlist(struct device *dev, struct g2d_cmdlist_node *node)
+{
+	struct g2d_cmdlist *cmdlist = node->cmdlist;
+	int nr;
+	int index;
+
+	dev_dbg(dev, "Head: %d\n", cmdlist->head);
+	for (nr = 0, index = 0; nr < cmdlist->last; nr += 2) {
+		dev_dbg(dev, "%02d: [0x%08x] 0x%08x\n", index,
+				cmdlist->data[nr], cmdlist->data[nr + 1]);
+		index++;
+	}
+	dev_dbg(dev, "Tail: 0x%08x\n", cmdlist->data[cmdlist->last]);
+}
+
+static int g2d_init_cmdlist(struct g2d_data *g2d)
+{
+	struct device *dev = g2d->dev;
+	struct g2d_cmdlist_node *node = g2d->cmdlist_node;
+	int nr;
+	int ret;
+
+	g2d->cmdlist_pool_virt = dma_alloc_coherent(dev, G2D_CMDLIST_POOL_SIZE,
+						&g2d->cmdlist_pool, GFP_KERNEL);
+	if (!g2d->cmdlist_pool_virt) {
+		dev_err(dev, "failed to allocate dma memory\n");
+		return -ENOMEM;
+	}
+
+	node = kcalloc(G2D_CMDLIST_NUM, G2D_CMDLIST_NUM * sizeof(*node),
+			GFP_KERNEL);
+	if (!node) {
+		dev_err(dev, "failed to allocate memory\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) {
+		node[nr].cmdlist =
+			g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE;
+		node[nr].dma_addr =
+			g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE;
+
+		list_add_tail(&node[nr].list, &g2d->free_cmdlist);
+	}
+
+	return 0;
+
+err:
+	dma_free_coherent(dev, G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt,
+			g2d->cmdlist_pool);
+	return ret;
+}
+
+static void g2d_fini_cmdlist(struct g2d_data *g2d)
+{
+	struct device *dev = g2d->dev;
+
+	kfree(g2d->cmdlist_node);
+	dma_free_coherent(dev, G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt,
+			g2d->cmdlist_pool);
+}
+
+static struct g2d_cmdlist_node *g2d_get_cmdlist(struct g2d_data *g2d)
+{
+	struct device *dev = g2d->dev;
+	struct g2d_cmdlist_node *node;
+
+	mutex_lock(&g2d->cmdlist_mutex);
+	if (list_empty(&g2d->free_cmdlist)) {
+		dev_err(dev, "there is no free cmdlist\n");
+		mutex_unlock(&g2d->cmdlist_mutex);
+		return NULL;
+	}
+
+	node = list_first_entry(&g2d->free_cmdlist, struct g2d_cmdlist_node,
+				list);
+	list_del_init(&node->list);
+	mutex_unlock(&g2d->cmdlist_mutex);
+
+	return node;
+}
+
+static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node)
+{
+	mutex_lock(&g2d->cmdlist_mutex);
+	list_move_tail(&node->list, &g2d->free_cmdlist);
+	mutex_unlock(&g2d->cmdlist_mutex);
+}
+
+static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv,
+				     struct g2d_cmdlist_node *node)
+{
+	struct g2d_cmdlist_node *lnode;
+
+	if (list_empty(&g2d_priv->inuse_cmdlist))
+		goto add_to_list;
+
+	/* this links to base address of new cmdlist */
+	lnode = list_entry(g2d_priv->inuse_cmdlist.prev,
+				struct g2d_cmdlist_node, list);
+	lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr;
+
+add_to_list:
+	list_add_tail(&node->list, &g2d_priv->inuse_cmdlist);
+
+	if (node->event)
+		list_add_tail(&node->event->base.link, &g2d_priv->event_list);
+}
+
+static int g2d_get_cmdlist_gem(struct drm_device *drm_dev,
+			       struct drm_file *file,
+			       struct g2d_cmdlist_node *node)
+{
+	struct drm_exynos_file_private *file_priv = file->driver_priv;
+	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+	struct g2d_cmdlist *cmdlist = node->cmdlist;
+	dma_addr_t *addr;
+	int offset;
+	int i;
+
+	for (i = 0; i < node->gem_nr; i++) {
+		struct g2d_gem_node *gem_node;
+
+		gem_node = kzalloc(sizeof(*gem_node), GFP_KERNEL);
+		if (!gem_node) {
+			dev_err(g2d_priv->dev, "failed to allocate gem node\n");
+			return -ENOMEM;
+		}
+
+		offset = cmdlist->last - (i * 2 + 1);
+		gem_node->handle = cmdlist->data[offset];
+
+		addr = exynos_drm_gem_get_dma_addr(drm_dev, gem_node->handle,
+						   file);
+		if (IS_ERR(addr)) {
+			node->gem_nr = i;
+			kfree(gem_node);
+			return PTR_ERR(addr);
+		}
+
+		cmdlist->data[offset] = *addr;
+		list_add_tail(&gem_node->list, &g2d_priv->gem_list);
+		g2d_priv->gem_nr++;
+	}
+
+	return 0;
+}
+
+static void g2d_put_cmdlist_gem(struct drm_device *drm_dev,
+				struct drm_file *file,
+				unsigned int nr)
+{
+	struct drm_exynos_file_private *file_priv = file->driver_priv;
+	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+	struct g2d_gem_node *node, *n;
+
+	list_for_each_entry_safe_reverse(node, n, &g2d_priv->gem_list, list) {
+		if (!nr)
+			break;
+
+		exynos_drm_gem_put_dma_addr(drm_dev, node->handle, file);
+		list_del_init(&node->list);
+		kfree(node);
+		nr--;
+	}
+}
+
+static void g2d_dma_start(struct g2d_data *g2d,
+			  struct g2d_runqueue_node *runqueue_node)
+{
+	struct g2d_cmdlist_node *node =
+				list_first_entry(&runqueue_node->run_cmdlist,
+						struct g2d_cmdlist_node, list);
+
+	pm_runtime_get_sync(g2d->dev);
+	clk_enable(g2d->gate_clk);
+
+	/* interrupt enable */
+	writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF,
+			g2d->regs + G2D_INTEN);
+
+	writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
+	writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
+}
+
+static struct g2d_runqueue_node *g2d_get_runqueue_node(struct g2d_data *g2d)
+{
+	struct g2d_runqueue_node *runqueue_node;
+
+	if (list_empty(&g2d->runqueue))
+		return NULL;
+
+	runqueue_node = list_first_entry(&g2d->runqueue,
+					 struct g2d_runqueue_node, list);
+	list_del_init(&runqueue_node->list);
+	return runqueue_node;
+}
+
+static void g2d_free_runqueue_node(struct g2d_data *g2d,
+				   struct g2d_runqueue_node *runqueue_node)
+{
+	if (!runqueue_node)
+		return;
+
+	mutex_lock(&g2d->cmdlist_mutex);
+	list_splice_tail_init(&runqueue_node->run_cmdlist, &g2d->free_cmdlist);
+	mutex_unlock(&g2d->cmdlist_mutex);
+
+	kmem_cache_free(g2d->runqueue_slab, runqueue_node);
+}
+
+static void g2d_exec_runqueue(struct g2d_data *g2d)
+{
+	g2d->runqueue_node = g2d_get_runqueue_node(g2d);
+	if (g2d->runqueue_node)
+		g2d_dma_start(g2d, g2d->runqueue_node);
+}
+
+static void g2d_runqueue_worker(struct work_struct *work)
+{
+	struct g2d_data *g2d = container_of(work, struct g2d_data,
+					    runqueue_work);
+
+
+	mutex_lock(&g2d->runqueue_mutex);
+	clk_disable(g2d->gate_clk);
+	pm_runtime_put_sync(g2d->dev);
+
+	complete(&g2d->runqueue_node->complete);
+	if (g2d->runqueue_node->async)
+		g2d_free_runqueue_node(g2d, g2d->runqueue_node);
+
+	if (g2d->suspended)
+		g2d->runqueue_node = NULL;
+	else
+		g2d_exec_runqueue(g2d);
+	mutex_unlock(&g2d->runqueue_mutex);
+}
+
+static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
+{
+	struct drm_device *drm_dev = g2d->subdrv.drm_dev;
+	struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;
+	struct drm_exynos_pending_g2d_event *e;
+	struct timeval now;
+	unsigned long flags;
+
+	if (list_empty(&runqueue_node->event_list))
+		return;
+
+	e = list_first_entry(&runqueue_node->event_list,
+			     struct drm_exynos_pending_g2d_event, base.link);
+
+	do_gettimeofday(&now);
+	e->event.tv_sec = now.tv_sec;
+	e->event.tv_usec = now.tv_usec;
+	e->event.cmdlist_no = cmdlist_no;
+
+	spin_lock_irqsave(&drm_dev->event_lock, flags);
+	list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+	wake_up_interruptible(&e->base.file_priv->event_wait);
+	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+}
+
+static irqreturn_t g2d_irq_handler(int irq, void *dev_id)
+{
+	struct g2d_data *g2d = dev_id;
+	u32 pending;
+
+	pending = readl_relaxed(g2d->regs + G2D_INTC_PEND);
+	if (pending)
+		writel_relaxed(pending, g2d->regs + G2D_INTC_PEND);
+
+	if (pending & G2D_INTP_GCMD_FIN) {
+		u32 cmdlist_no = readl_relaxed(g2d->regs + G2D_DMA_STATUS);
+
+		cmdlist_no = (cmdlist_no & G2D_DMA_LIST_DONE_COUNT) >> 17;
+
+		g2d_finish_event(g2d, cmdlist_no);
+
+		writel_relaxed(0, g2d->regs + G2D_DMA_HOLD_CMD);
+		if (!(pending & G2D_INTP_ACMD_FIN)) {
+			writel_relaxed(G2D_DMA_CONTINUE,
+					g2d->regs + G2D_DMA_COMMAND);
+		}
+	}
+
+	if (pending & G2D_INTP_ACMD_FIN)
+		queue_work(g2d->g2d_workq, &g2d->runqueue_work);
+
+	return IRQ_HANDLED;
+}
+
+/* ioctl functions */
+int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data,
+			     struct drm_file *file)
+{
+	struct drm_exynos_g2d_get_ver *ver = data;
+
+	ver->major = G2D_HW_MAJOR_VER;
+	ver->minor = G2D_HW_MINOR_VER;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(exynos_g2d_get_ver_ioctl);
+
+int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
+				 struct drm_file *file)
+{
+	struct drm_exynos_file_private *file_priv = file->driver_priv;
+	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+	struct device *dev = g2d_priv->dev;
+	struct g2d_data *g2d;
+	struct drm_exynos_g2d_set_cmdlist *req = data;
+	struct drm_exynos_pending_g2d_event *e;
+	struct g2d_cmdlist_node *node;
+	struct g2d_cmdlist *cmdlist;
+	unsigned long flags;
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	g2d = dev_get_drvdata(dev);
+	if (!g2d)
+		return -EFAULT;
+
+	node = g2d_get_cmdlist(g2d);
+	if (!node)
+		return -ENOMEM;
+
+	node->event = NULL;
+
+	if (req->event_type != G2D_EVENT_NOT) {
+		spin_lock_irqsave(&drm_dev->event_lock, flags);
+		if (file->event_space < sizeof(e->event)) {
+			spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+			ret = -ENOMEM;
+			goto err;
+		}
+		file->event_space -= sizeof(e->event);
+		spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+
+		e = kzalloc(sizeof(*node->event), GFP_KERNEL);
+		if (!e) {
+			dev_err(dev, "failed to allocate event\n");
+
+			spin_lock_irqsave(&drm_dev->event_lock, flags);
+			file->event_space += sizeof(e->event);
+			spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		e->event.base.type = DRM_EXYNOS_G2D_EVENT;
+		e->event.base.length = sizeof(e->event);
+		e->event.user_data = req->user_data;
+		e->base.event = &e->event.base;
+		e->base.file_priv = file;
+		e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+		node->event = e;
+	}
+
+	cmdlist = node->cmdlist;
+
+	cmdlist->last = 0;
+
+	/* TODO: check cmdlist size */
+	/*
+	 * If don't clear SFR registers, the cmdlist is affected by register
+	 * values of previous cmdlist. G2D hw executes SFR clear command and
+	 * a next command at the same time then the next command is ignored and
+	 * is executed rightly from next next command, so needs a dummy command
+	 * to next command of SFR clear command.
+	 */
+	cmdlist->data[cmdlist->last++] = G2D_SOFT_RESET;
+	cmdlist->data[cmdlist->last++] = G2D_SFRCLEAR;
+	cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR;
+	cmdlist->data[cmdlist->last++] = 0;
+
+	if (node->event) {
+		cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD;
+		cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD;
+	}
+
+	if (copy_from_user(cmdlist->data + cmdlist->last,
+				(void __user *)req->cmd,
+				sizeof(*req->cmd) * req->cmd_nr)) {
+		ret = -EFAULT;
+		goto err_free_event;
+	}
+	cmdlist->last += req->cmd_nr * 2;
+
+	node->gem_nr = req->cmd_gem_nr;
+	if (req->cmd_gem_nr) {
+		struct drm_exynos_g2d_cmd *cmd_gem = req->cmd_gem;
+
+		if (copy_from_user(cmdlist->data + cmdlist->last,
+					(void __user *)cmd_gem,
+					sizeof(*cmd_gem) * req->cmd_gem_nr)) {
+			ret = -EFAULT;
+			goto err_free_event;
+		}
+		cmdlist->last += req->cmd_gem_nr * 2;
+
+		ret = g2d_get_cmdlist_gem(drm_dev, file, node);
+		if (ret < 0)
+			goto err_unmap;
+	}
+
+	cmdlist->data[cmdlist->last++] = G2D_BITBLT_START;
+	cmdlist->data[cmdlist->last++] = G2D_START_BITBLT;
+
+	/* head */
+	cmdlist->head = cmdlist->last / 2;
+
+	/* tail */
+	cmdlist->data[cmdlist->last] = 0;
+
+	g2d_add_cmdlist_to_inuse(g2d_priv, node);
+
+	return 0;
+
+err_unmap:
+	g2d_put_cmdlist_gem(drm_dev, file, node->gem_nr);
+err_free_event:
+	if (node->event) {
+		spin_lock_irqsave(&drm_dev->event_lock, flags);
+		file->event_space += sizeof(e->event);
+		spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+		kfree(node->event);
+	}
+err:
+	g2d_put_cmdlist(g2d, node);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(exynos_g2d_set_cmdlist_ioctl);
+
+int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
+			  struct drm_file *file)
+{
+	struct drm_exynos_file_private *file_priv = file->driver_priv;
+	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+	struct device *dev = g2d_priv->dev;
+	struct g2d_data *g2d;
+	struct drm_exynos_g2d_exec *req = data;
+	struct g2d_runqueue_node *runqueue_node;
+	struct list_head *run_cmdlist;
+	struct list_head *event_list;
+
+	if (!dev)
+		return -ENODEV;
+
+	g2d = dev_get_drvdata(dev);
+	if (!g2d)
+		return -EFAULT;
+
+	runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);
+	if (!runqueue_node) {
+		dev_err(dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+	run_cmdlist = &runqueue_node->run_cmdlist;
+	event_list = &runqueue_node->event_list;
+	INIT_LIST_HEAD(run_cmdlist);
+	INIT_LIST_HEAD(event_list);
+	init_completion(&runqueue_node->complete);
+	runqueue_node->async = req->async;
+
+	list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist);
+	list_splice_init(&g2d_priv->event_list, event_list);
+
+	if (list_empty(run_cmdlist)) {
+		dev_err(dev, "there is no inuse cmdlist\n");
+		kmem_cache_free(g2d->runqueue_slab, runqueue_node);
+		return -EPERM;
+	}
+
+	mutex_lock(&g2d->runqueue_mutex);
+	list_add_tail(&runqueue_node->list, &g2d->runqueue);
+	if (!g2d->runqueue_node)
+		g2d_exec_runqueue(g2d);
+	mutex_unlock(&g2d->runqueue_mutex);
+
+	if (runqueue_node->async)
+		goto out;
+
+	wait_for_completion(&runqueue_node->complete);
+	g2d_free_runqueue_node(g2d, runqueue_node);
+
+out:
+	return 0;
+}
+EXPORT_SYMBOL_GPL(exynos_g2d_exec_ioctl);
+
+static int g2d_open(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file)
+{
+	struct drm_exynos_file_private *file_priv = file->driver_priv;
+	struct exynos_drm_g2d_private *g2d_priv;
+
+	g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL);
+	if (!g2d_priv) {
+		dev_err(dev, "failed to allocate g2d private data\n");
+		return -ENOMEM;
+	}
+
+	g2d_priv->dev = dev;
+	file_priv->g2d_priv = g2d_priv;
+
+	INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist);
+	INIT_LIST_HEAD(&g2d_priv->event_list);
+	INIT_LIST_HEAD(&g2d_priv->gem_list);
+
+	return 0;
+}
+
+static void g2d_close(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file)
+{
+	struct drm_exynos_file_private *file_priv = file->driver_priv;
+	struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+	struct g2d_data *g2d;
+	struct g2d_cmdlist_node *node, *n;
+
+	if (!dev)
+		return;
+
+	g2d = dev_get_drvdata(dev);
+	if (!g2d)
+		return;
+
+	mutex_lock(&g2d->cmdlist_mutex);
+	list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list)
+		list_move_tail(&node->list, &g2d->free_cmdlist);
+	mutex_unlock(&g2d->cmdlist_mutex);
+
+	g2d_put_cmdlist_gem(drm_dev, file, g2d_priv->gem_nr);
+
+	kfree(file_priv->g2d_priv);
+}
+
+static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+{
+	return 0;
+}
+
+static int __devinit g2d_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct g2d_data *g2d;
+	struct exynos_drm_subdrv *subdrv;
+	int ret;
+
+	g2d = kzalloc(sizeof(*g2d), GFP_KERNEL);
+	if (!g2d) {
+		dev_err(dev, "failed to allocate driver data\n");
+		return -ENOMEM;
+	}
+
+	g2d->runqueue_slab = kmem_cache_create("g2d_runqueue_slab",
+			sizeof(struct g2d_runqueue_node), 0, 0, NULL);
+	if (!g2d->runqueue_slab) {
+		ret = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	g2d->dev = dev;
+
+	g2d->g2d_workq = create_singlethread_workqueue("g2d");
+	if (!g2d->g2d_workq) {
+		dev_err(dev, "failed to create workqueue\n");
+		ret = -EINVAL;
+		goto err_destroy_slab;
+	}
+
+	INIT_WORK(&g2d->runqueue_work, g2d_runqueue_worker);
+	INIT_LIST_HEAD(&g2d->free_cmdlist);
+	INIT_LIST_HEAD(&g2d->runqueue);
+
+	mutex_init(&g2d->cmdlist_mutex);
+	mutex_init(&g2d->runqueue_mutex);
+
+	ret = g2d_init_cmdlist(g2d);
+	if (ret < 0)
+		goto err_destroy_workqueue;
+
+	g2d->gate_clk = clk_get(dev, "fimg2d");
+	if (IS_ERR(g2d->gate_clk)) {
+		dev_err(dev, "failed to get gate clock\n");
+		ret = PTR_ERR(g2d->gate_clk);
+		goto err_fini_cmdlist;
+	}
+
+	pm_runtime_enable(dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "failed to get I/O memory\n");
+		ret = -ENOENT;
+		goto err_put_clk;
+	}
+
+	g2d->regs_res = request_mem_region(res->start, resource_size(res),
+					   dev_name(dev));
+	if (!g2d->regs_res) {
+		dev_err(dev, "failed to request I/O memory\n");
+		ret = -ENOENT;
+		goto err_put_clk;
+	}
+
+	g2d->regs = ioremap(res->start, resource_size(res));
+	if (!g2d->regs) {
+		dev_err(dev, "failed to remap I/O memory\n");
+		ret = -ENXIO;
+		goto err_release_res;
+	}
+
+	g2d->irq = platform_get_irq(pdev, 0);
+	if (g2d->irq < 0) {
+		dev_err(dev, "failed to get irq\n");
+		ret = g2d->irq;
+		goto err_unmap_base;
+	}
+
+	ret = request_irq(g2d->irq, g2d_irq_handler, 0, "drm_g2d", g2d);
+	if (ret < 0) {
+		dev_err(dev, "irq request failed\n");
+		goto err_unmap_base;
+	}
+
+	platform_set_drvdata(pdev, g2d);
+
+	subdrv = &g2d->subdrv;
+	subdrv->is_local = true;
+	subdrv->probe = g2d_subdrv_probe;
+	subdrv->open = g2d_open;
+	subdrv->close = g2d_close;
+	subdrv->manager.dev = dev;
+
+	ret = exynos_drm_subdrv_register(subdrv);
+	if (ret < 0) {
+		dev_err(dev, "failed to register drm g2d device\n");
+		goto err_free_irq;
+	}
+
+	dev_info(dev, "The exynos g2d(ver %d.%d) successfully probed\n",
+			G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER);
+
+	return 0;
+
+err_free_irq:
+	free_irq(g2d->irq, g2d);
+err_unmap_base:
+	iounmap(g2d->regs);
+err_release_res:
+	release_resource(g2d->regs_res);
+	kfree(g2d->regs_res);
+err_put_clk:
+	pm_runtime_disable(dev);
+	clk_put(g2d->gate_clk);
+err_fini_cmdlist:
+	g2d_fini_cmdlist(g2d);
+err_destroy_workqueue:
+	destroy_workqueue(g2d->g2d_workq);
+err_destroy_slab:
+	kmem_cache_destroy(g2d->runqueue_slab);
+err_free_mem:
+	kfree(g2d);
+	return ret;
+}
+
+static int __devexit g2d_remove(struct platform_device *pdev)
+{
+	struct g2d_data *g2d = platform_get_drvdata(pdev);
+
+	cancel_work_sync(&g2d->runqueue_work);
+	exynos_drm_subdrv_unregister(&g2d->subdrv);
+	free_irq(g2d->irq, g2d);
+
+	while (g2d->runqueue_node) {
+		g2d_free_runqueue_node(g2d, g2d->runqueue_node);
+		g2d->runqueue_node = g2d_get_runqueue_node(g2d);
+	}
+
+	iounmap(g2d->regs);
+	release_resource(g2d->regs_res);
+	kfree(g2d->regs_res);
+
+	pm_runtime_disable(&pdev->dev);
+	clk_put(g2d->gate_clk);
+
+	g2d_fini_cmdlist(g2d);
+	destroy_workqueue(g2d->g2d_workq);
+	kmem_cache_destroy(g2d->runqueue_slab);
+	kfree(g2d);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int g2d_suspend(struct device *dev)
+{
+	struct g2d_data *g2d = dev_get_drvdata(dev);
+
+	mutex_lock(&g2d->runqueue_mutex);
+	g2d->suspended = true;
+	mutex_unlock(&g2d->runqueue_mutex);
+
+	while (g2d->runqueue_node)
+		/* FIXME: good range? */
+		usleep_range(500, 1000);
+
+	flush_work_sync(&g2d->runqueue_work);
+
+	return 0;
+}
+
+static int g2d_resume(struct device *dev)
+{
+	struct g2d_data *g2d = dev_get_drvdata(dev);
+
+	g2d->suspended = false;
+	g2d_exec_runqueue(g2d);
+
+	return 0;
+}
+#endif
+
+SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);
+
+struct platform_driver g2d_driver = {
+	.probe		= g2d_probe,
+	.remove		= __devexit_p(g2d_remove),
+	.driver		= {
+		.name	= "s5p-g2d",
+		.owner	= THIS_MODULE,
+		.pm	= &g2d_pm_ops,
+	},
+};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.h b/drivers/gpu/drm/exynos/exynos_drm_g2d.h
new file mode 100644
index 0000000..1a9c7ca
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Authors: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundationr
+ */
+
+#ifdef CONFIG_DRM_EXYNOS_G2D
+extern int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_priv);
+extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data,
+					struct drm_file *file_priv);
+extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv);
+#else
+static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
+					   struct drm_file *file_priv)
+{
+	return -ENODEV;
+}
+
+static inline int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev,
+					       void *data,
+					       struct drm_file *file_priv)
+{
+	return -ENODEV;
+}
+
+static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
+					struct drm_file *file_priv)
+{
+	return -ENODEV;
+}
+#endif
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 81c9cb7..81bfd89 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -29,6 +29,8 @@
 #ifndef _EXYNOS_DRM_H_
 #define _EXYNOS_DRM_H_
 
+#include "drm.h"
+
 /**
  * User-desired buffer creation information structure.
  *
@@ -85,12 +87,48 @@ enum e_drm_exynos_gem_mem_type {
 	EXYNOS_BO_NONCONTIG	= 1 << 0
 };
 
+struct drm_exynos_g2d_get_ver {
+	__u32	major;
+	__u32	minor;
+};
+
+struct drm_exynos_g2d_cmd {
+	__u32	offset;
+	__u32	data;
+};
+
+enum drm_exynos_g2d_event_type {
+	G2D_EVENT_NOT,
+	G2D_EVENT_NONSTOP,
+	G2D_EVENT_STOP,		/* not yet */
+};
+
+struct drm_exynos_g2d_set_cmdlist {
+	struct drm_exynos_g2d_cmd		*cmd;
+	struct drm_exynos_g2d_cmd		*cmd_gem;
+	__u32					cmd_nr;
+	__u32					cmd_gem_nr;
+
+	/* for g2d event */
+	__u64					event_type;
+	__u64					user_data;
+};
+
+struct drm_exynos_g2d_exec {
+	__u64					async;
+};
+
 #define DRM_EXYNOS_GEM_CREATE		0x00
 #define DRM_EXYNOS_GEM_MAP_OFFSET	0x01
 #define DRM_EXYNOS_GEM_MMAP		0x02
 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
 #define DRM_EXYNOS_PLANE_SET_ZPOS	0x06
 
+/* G2D */
+#define DRM_EXYNOS_G2D_GET_VER		0x20
+#define DRM_EXYNOS_G2D_SET_CMDLIST	0x21
+#define DRM_EXYNOS_G2D_EXEC		0x22
+
 #define DRM_IOCTL_EXYNOS_GEM_CREATE		DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
 
@@ -103,6 +141,25 @@ enum e_drm_exynos_gem_mem_type {
 #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
 
+#define DRM_IOCTL_EXYNOS_G2D_GET_VER		DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver)
+#define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist)
+#define DRM_IOCTL_EXYNOS_G2D_EXEC		DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec)
+
+/* EXYNOS specific events */
+#define DRM_EXYNOS_G2D_EVENT		0x80000000
+
+struct drm_exynos_g2d_event {
+	struct drm_event	base;
+	__u64			user_data;
+	__u32			tv_sec;
+	__u32			tv_usec;
+	__u32			cmdlist_no;
+	__u32			reserved;
+};
+
 #ifdef __KERNEL__
 
 /**
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 10/14] drm/exynos: added virtual display driver.
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (8 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 09/14] drm/exynos: add G2D driver Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 11/14] drm/exynos: remove exynos_mixer.h Inki Dae
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

this driver would be used for wireless display. virtual display
driver has independent crtc, encoder and connector and to use
this driver, user application should send edid data to this driver
from wireless display.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/Kconfig                |    6 +
 drivers/gpu/drm/exynos/Makefile               |    1 +
 drivers/gpu/drm/exynos/exynos_drm_connector.c |    4 +
 drivers/gpu/drm/exynos/exynos_drm_drv.c       |   18 +
 drivers/gpu/drm/exynos/exynos_drm_drv.h       |    7 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c   |    1 +
 drivers/gpu/drm/exynos/exynos_drm_vidi.c      |  676 +++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_vidi.h      |   36 ++
 include/drm/exynos_drm.h                      |   18 +
 9 files changed, 765 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_vidi.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_drm_vidi.h

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 8493fe9..7b980cb 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -27,3 +27,9 @@ config DRM_EXYNOS_G2D
 	depends on DRM_EXYNOS
 	help
 	  Choose this option if you want to use Exynos G2D for DRM.
+
+config DRM_EXYNOS_VIDI
+	bool "Exynos DRM Virtual Display"
+	depends on DRM_EXYNOS
+	help
+	  Choose this option if you want to use Exynos VIDI for DRM.
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index d6c1a3c..a67ea9a 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -13,5 +13,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o \
 					   exynos_ddc.o exynos_hdmiphy.o \
 					   exynos_drm_hdmi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
 
 obj-$(CONFIG_DRM_EXYNOS)		+= exynosdrm.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index a5d6591..ee4ff74 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -315,6 +315,10 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 		connector->interlace_allowed = true;
 		connector->polled = DRM_CONNECTOR_POLL_HPD;
 		break;
+	case EXYNOS_DISPLAY_TYPE_VIDI:
+		type = DRM_MODE_CONNECTOR_VIRTUAL;
+		connector->polled = DRM_CONNECTOR_POLL_HPD;
+		break;
 	default:
 		type = DRM_MODE_CONNECTOR_Unknown;
 		break;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 64ef4ce..9af9dec2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -39,6 +39,7 @@
 #include "exynos_drm_gem.h"
 #include "exynos_drm_g2d.h"
 #include "exynos_drm_plane.h"
+#include "exynos_drm_vidi.h"
 
 #define DRIVER_NAME	"exynos"
 #define DRIVER_DESC	"Samsung SoC DRM"
@@ -217,6 +218,8 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
 			exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
 			DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
+			vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
 
 	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
 			exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
@@ -314,6 +317,12 @@ static int __init exynos_drm_init(void)
 		goto out_common_hdmi;
 #endif
 
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	ret = platform_driver_register(&vidi_driver);
+	if (ret < 0)
+		goto out_vidi;
+#endif
+
 #ifdef CONFIG_DRM_EXYNOS_G2D
 	ret = platform_driver_register(&g2d_driver);
 	if (ret < 0)
@@ -332,6 +341,11 @@ out:
 out_g2d:
 #endif
 
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	platform_driver_unregister(&vidi_driver);
+out_vidi:
+#endif
+
 #ifdef CONFIG_DRM_EXYNOS_HDMI
 	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
 out_common_hdmi:
@@ -358,6 +372,10 @@ static void __exit exynos_drm_exit(void)
 	platform_driver_unregister(&g2d_driver);
 #endif
 
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	platform_driver_unregister(&vidi_driver);
+#endif
+
 #ifdef CONFIG_DRM_EXYNOS_HDMI
 	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
 	platform_driver_unregister(&mixer_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 750daa9..168d296 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -32,9 +32,9 @@
 #include <linux/module.h>
 #include "drm.h"
 
-#define MAX_CRTC	2
+#define MAX_CRTC	3
 #define MAX_PLANE	5
-#define MAX_FB_BUFFER	3
+#define MAX_FB_BUFFER	4
 #define DEFAULT_ZPOS	-1
 
 struct drm_device;
@@ -50,6 +50,8 @@ enum exynos_drm_output_type {
 	EXYNOS_DISPLAY_TYPE_LCD,
 	/* HDMI Interface. */
 	EXYNOS_DISPLAY_TYPE_HDMI,
+	/* Virtual Display Interface. */
+	EXYNOS_DISPLAY_TYPE_VIDI,
 };
 
 /*
@@ -296,5 +298,6 @@ extern struct platform_driver fimd_driver;
 extern struct platform_driver hdmi_driver;
 extern struct platform_driver mixer_driver;
 extern struct platform_driver exynos_drm_common_hdmi_driver;
+extern struct platform_driver vidi_driver;
 extern struct platform_driver g2d_driver;
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 2278676..6e9ac7b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -218,6 +218,7 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
 		switch (display_ops->type) {
 		case EXYNOS_DISPLAY_TYPE_LCD:
 		case EXYNOS_DISPLAY_TYPE_HDMI:
+		case EXYNOS_DISPLAY_TYPE_VIDI:
 			clone_mask |= (1 << (cnt++));
 			break;
 		default:
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
new file mode 100644
index 0000000..8e1339f
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -0,0 +1,676 @@
+/* exynos_drm_vidi.c
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Authors:
+ *	Inki Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include "drmP.h"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <drm/exynos_drm.h>
+
+#include "drm_edid.h"
+#include "drm_crtc_helper.h"
+
+#include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
+#include "exynos_drm_encoder.h"
+
+/* vidi has totally three virtual windows. */
+#define WINDOWS_NR		3
+
+#define get_vidi_context(dev)	platform_get_drvdata(to_platform_device(dev))
+
+struct vidi_win_data {
+	unsigned int		offset_x;
+	unsigned int		offset_y;
+	unsigned int		ovl_width;
+	unsigned int		ovl_height;
+	unsigned int		fb_width;
+	unsigned int		fb_height;
+	unsigned int		bpp;
+	dma_addr_t		dma_addr;
+	void __iomem		*vaddr;
+	unsigned int		buf_offsize;
+	unsigned int		line_size;	/* bytes */
+	bool			enabled;
+};
+
+struct vidi_context {
+	struct exynos_drm_subdrv	subdrv;
+	struct drm_crtc			*crtc;
+	struct vidi_win_data		win_data[WINDOWS_NR];
+	struct edid			*raw_edid;
+	unsigned int			clkdiv;
+	unsigned int			default_win;
+	unsigned long			irq_flags;
+	unsigned int			connected;
+	bool				vblank_on;
+	bool				suspended;
+	struct work_struct		work;
+	struct mutex			lock;
+};
+
+static const char fake_edid_info[] = {
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
+	0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
+	0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
+	0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
+	0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
+	0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
+	0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
+	0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
+	0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
+	0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
+	0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
+	0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
+	0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
+	0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
+	0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
+	0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x06
+};
+
+static void vidi_fake_vblank_handler(struct work_struct *work);
+
+static bool vidi_display_is_connected(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/*
+	 * connection request would come from user side
+	 * to do hotplug through specific ioctl.
+	 */
+	return ctx->connected ? true : false;
+}
+
+static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
+				u8 *edid, int len)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct edid *raw_edid;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/*
+	 * the edid data comes from user side and it would be set
+	 * to ctx->raw_edid through specific ioctl.
+	 */
+	if (!ctx->raw_edid) {
+		DRM_DEBUG_KMS("raw_edid is null.\n");
+		return -EFAULT;
+	}
+
+	raw_edid = kzalloc(len, GFP_KERNEL);
+	if (!raw_edid) {
+		DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
+		return -ENOMEM;
+	}
+
+	memcpy(raw_edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
+						* EDID_LENGTH, len));
+
+	/* attach the edid data to connector. */
+	connector->display_info.raw_edid = (char *)raw_edid;
+
+	memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
+					* EDID_LENGTH, len));
+
+	return 0;
+}
+
+static void *vidi_get_panel(struct device *dev)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO. */
+
+	return NULL;
+}
+
+static int vidi_check_timing(struct device *dev, void *timing)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO. */
+
+	return 0;
+}
+
+static int vidi_display_power_on(struct device *dev, int mode)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO */
+
+	return 0;
+}
+
+static struct exynos_drm_display_ops vidi_display_ops = {
+	.type = EXYNOS_DISPLAY_TYPE_VIDI,
+	.is_connected = vidi_display_is_connected,
+	.get_edid = vidi_get_edid,
+	.get_panel = vidi_get_panel,
+	.check_timing = vidi_check_timing,
+	.power_on = vidi_display_power_on,
+};
+
+static void vidi_dpms(struct device *subdrv_dev, int mode)
+{
+	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+
+	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+	mutex_lock(&ctx->lock);
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		/* TODO. */
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		/* TODO. */
+		break;
+	default:
+		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+		break;
+	}
+
+	mutex_unlock(&ctx->lock);
+}
+
+static void vidi_apply(struct device *subdrv_dev)
+{
+	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+	struct exynos_drm_manager *mgr = &ctx->subdrv.manager;
+	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
+	struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
+	struct vidi_win_data *win_data;
+	int i;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		if (win_data->enabled && (ovl_ops && ovl_ops->commit))
+			ovl_ops->commit(subdrv_dev, i);
+	}
+
+	if (mgr_ops && mgr_ops->commit)
+		mgr_ops->commit(subdrv_dev);
+}
+
+static void vidi_commit(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return;
+}
+
+static int vidi_enable_vblank(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return -EPERM;
+
+	if (!test_and_set_bit(0, &ctx->irq_flags))
+		ctx->vblank_on = true;
+
+	return 0;
+}
+
+static void vidi_disable_vblank(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return;
+
+	if (test_and_clear_bit(0, &ctx->irq_flags))
+		ctx->vblank_on = false;
+}
+
+static struct exynos_drm_manager_ops vidi_manager_ops = {
+	.dpms = vidi_dpms,
+	.apply = vidi_apply,
+	.commit = vidi_commit,
+	.enable_vblank = vidi_enable_vblank,
+	.disable_vblank = vidi_disable_vblank,
+};
+
+static void vidi_win_mode_set(struct device *dev,
+			      struct exynos_drm_overlay *overlay)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_win_data *win_data;
+	int win;
+	unsigned long offset;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (!overlay) {
+		dev_err(dev, "overlay is NULL\n");
+		return;
+	}
+
+	win = overlay->zpos;
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win > WINDOWS_NR)
+		return;
+
+	offset = overlay->fb_x * (overlay->bpp >> 3);
+	offset += overlay->fb_y * overlay->pitch;
+
+	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+
+	win_data = &ctx->win_data[win];
+
+	win_data->offset_x = overlay->crtc_x;
+	win_data->offset_y = overlay->crtc_y;
+	win_data->ovl_width = overlay->crtc_width;
+	win_data->ovl_height = overlay->crtc_height;
+	win_data->fb_width = overlay->fb_width;
+	win_data->fb_height = overlay->fb_height;
+	win_data->dma_addr = overlay->dma_addr[0] + offset;
+	win_data->vaddr = overlay->vaddr[0] + offset;
+	win_data->bpp = overlay->bpp;
+	win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
+				(overlay->bpp >> 3);
+	win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+
+	/*
+	 * some parts of win_data should be transferred to user side
+	 * through specific ioctl.
+	 */
+
+	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+			win_data->offset_x, win_data->offset_y);
+	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+			win_data->ovl_width, win_data->ovl_height);
+	DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
+			(unsigned long)win_data->dma_addr,
+			(unsigned long)win_data->vaddr);
+	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
+			overlay->fb_width, overlay->crtc_width);
+}
+
+static void vidi_win_commit(struct device *dev, int zpos)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_win_data *win_data;
+	int win = zpos;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (ctx->suspended)
+		return;
+
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win > WINDOWS_NR)
+		return;
+
+	win_data = &ctx->win_data[win];
+
+	win_data->enabled = true;
+
+	DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
+
+	if (ctx->vblank_on)
+		schedule_work(&ctx->work);
+}
+
+static void vidi_win_disable(struct device *dev, int zpos)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_win_data *win_data;
+	int win = zpos;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win > WINDOWS_NR)
+		return;
+
+	win_data = &ctx->win_data[win];
+	win_data->enabled = false;
+
+	/* TODO. */
+}
+
+static struct exynos_drm_overlay_ops vidi_overlay_ops = {
+	.mode_set = vidi_win_mode_set,
+	.commit = vidi_win_commit,
+	.disable = vidi_win_disable,
+};
+
+static void vidi_finish_pageflip(struct drm_device *drm_dev, int crtc)
+{
+	struct exynos_drm_private *dev_priv = drm_dev->dev_private;
+	struct drm_pending_vblank_event *e, *t;
+	struct timeval now;
+	unsigned long flags;
+	bool is_checked = false;
+
+	spin_lock_irqsave(&drm_dev->event_lock, flags);
+
+	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
+			base.link) {
+		/* if event's pipe isn't same as crtc then ignore it. */
+		if (crtc != e->pipe)
+			continue;
+
+		is_checked = true;
+
+		do_gettimeofday(&now);
+		e->event.sequence = 0;
+		e->event.tv_sec = now.tv_sec;
+		e->event.tv_usec = now.tv_usec;
+
+		list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+		wake_up_interruptible(&e->base.file_priv->event_wait);
+	}
+
+	if (is_checked) {
+		/*
+		 * call drm_vblank_put only in case that drm_vblank_get was
+		 * called.
+		 */
+		if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
+			drm_vblank_put(drm_dev, crtc);
+
+		/*
+		 * don't off vblank if vblank_disable_allowed is 1,
+		 * because vblank would be off by timer handler.
+		 */
+		if (!drm_dev->vblank_disable_allowed)
+			drm_vblank_off(drm_dev, crtc);
+	}
+
+	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+}
+
+static void vidi_fake_vblank_handler(struct work_struct *work)
+{
+	struct vidi_context *ctx = container_of(work, struct vidi_context,
+					work);
+	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
+	struct exynos_drm_manager *manager = &subdrv->manager;
+
+	if (manager->pipe < 0)
+		return;
+
+	/* refresh rate is about 50Hz. */
+	usleep_range(16000, 20000);
+
+	drm_handle_vblank(subdrv->drm_dev, manager->pipe);
+	vidi_finish_pageflip(subdrv->drm_dev, manager->pipe);
+}
+
+static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/*
+	 * enable drm irq mode.
+	 * - with irq_enabled = 1, we can use the vblank feature.
+	 *
+	 * P.S. note that we wouldn't use drm irq handler but
+	 *	just specific driver own one instead because
+	 *	drm framework supports only one irq handler.
+	 */
+	drm_dev->irq_enabled = 1;
+
+	/*
+	 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+	 * by drm timer once a current process gives up ownership of
+	 * vblank event.(after drm_vblank_put function is called)
+	 */
+	drm_dev->vblank_disable_allowed = 1;
+
+	return 0;
+}
+
+static void vidi_subdrv_remove(struct drm_device *drm_dev)
+{
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/* TODO. */
+}
+
+static int vidi_power_on(struct vidi_context *ctx, bool enable)
+{
+	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
+	struct device *dev = subdrv->manager.dev;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (enable != false && enable != true)
+		return -EINVAL;
+
+	if (enable) {
+		ctx->suspended = false;
+
+		/* if vblank was enabled status, enable it again. */
+		if (test_and_clear_bit(0, &ctx->irq_flags))
+			vidi_enable_vblank(dev);
+
+		vidi_apply(dev);
+	} else {
+		ctx->suspended = true;
+	}
+
+	return 0;
+}
+
+static int vidi_show_connection(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int rc;
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	mutex_lock(&ctx->lock);
+
+	rc = sprintf(buf, "%d\n", ctx->connected);
+
+	mutex_unlock(&ctx->lock);
+
+	return rc;
+}
+
+static int vidi_store_connection(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t len)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+	int ret;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	ret = kstrtoint(buf, 0, &ctx->connected);
+	if (ret)
+		return ret;
+
+	if (ctx->connected > 1)
+		return -EINVAL;
+
+	DRM_DEBUG_KMS("requested connection.\n");
+
+	drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+
+	return len;
+}
+
+static DEVICE_ATTR(connection, 0644, vidi_show_connection,
+			vidi_store_connection);
+
+int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
+				struct drm_file *file_priv)
+{
+	struct vidi_context *ctx = NULL;
+	struct drm_encoder *encoder;
+	struct exynos_drm_manager *manager;
+	struct exynos_drm_display_ops *display_ops;
+	struct drm_exynos_vidi_connection *vidi = data;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (!vidi) {
+		DRM_DEBUG_KMS("user data for vidi is null.\n");
+		return -EINVAL;
+	}
+
+	if (!vidi->edid) {
+		DRM_DEBUG_KMS("edid data is null.\n");
+		return -EINVAL;
+	}
+
+	if (vidi->connection > 1) {
+		DRM_DEBUG_KMS("connection should be 0 or 1.\n");
+		return -EINVAL;
+	}
+
+	list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
+								head) {
+		manager = exynos_drm_get_manager(encoder);
+		display_ops = manager->display_ops;
+
+		if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) {
+			ctx = get_vidi_context(manager->dev);
+			break;
+		}
+	}
+
+	if (!ctx) {
+		DRM_DEBUG_KMS("not found virtual device type encoder.\n");
+		return -EINVAL;
+	}
+
+	if (ctx->connected == vidi->connection) {
+		DRM_DEBUG_KMS("same connection request.\n");
+		return -EINVAL;
+	}
+
+	if (vidi->connection)
+		ctx->raw_edid = (struct edid *)vidi->edid;
+
+	ctx->connected = vidi->connection;
+	drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+
+	return 0;
+}
+
+static int __devinit vidi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct vidi_context *ctx;
+	struct exynos_drm_subdrv *subdrv;
+	int ret;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->default_win = 0;
+
+	INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
+
+	/* for test */
+	ctx->raw_edid = (struct edid *)fake_edid_info;
+
+	subdrv = &ctx->subdrv;
+	subdrv->probe = vidi_subdrv_probe;
+	subdrv->remove = vidi_subdrv_remove;
+	subdrv->manager.pipe = -1;
+	subdrv->manager.ops = &vidi_manager_ops;
+	subdrv->manager.overlay_ops = &vidi_overlay_ops;
+	subdrv->manager.display_ops = &vidi_display_ops;
+	subdrv->manager.dev = dev;
+
+	mutex_init(&ctx->lock);
+
+	platform_set_drvdata(pdev, ctx);
+
+	ret = device_create_file(&pdev->dev, &dev_attr_connection);
+	if (ret < 0)
+		DRM_INFO("failed to create connection sysfs.\n");
+
+	exynos_drm_subdrv_register(subdrv);
+
+	return 0;
+}
+
+static int __devexit vidi_remove(struct platform_device *pdev)
+{
+	struct vidi_context *ctx = platform_get_drvdata(pdev);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	exynos_drm_subdrv_unregister(&ctx->subdrv);
+
+	kfree(ctx);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int vidi_suspend(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	return vidi_power_on(ctx, false);
+}
+
+static int vidi_resume(struct device *dev)
+{
+	struct vidi_context *ctx = get_vidi_context(dev);
+
+	return vidi_power_on(ctx, true);
+}
+#endif
+
+static const struct dev_pm_ops vidi_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume)
+};
+
+struct platform_driver vidi_driver = {
+	.probe		= vidi_probe,
+	.remove		= __devexit_p(vidi_remove),
+	.driver		= {
+		.name	= "exynos-drm-vidi",
+		.owner	= THIS_MODULE,
+		.pm	= &vidi_pm_ops,
+	},
+};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.h b/drivers/gpu/drm/exynos/exynos_drm_vidi.h
new file mode 100644
index 0000000..a4babe4
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.h
@@ -0,0 +1,36 @@
+/* exynos_drm_vidi.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Author: Inki Dae <inki.dae@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EXYNOS_DRM_VIDI_H_
+#define _EXYNOS_DRM_VIDI_H_
+
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
+				struct drm_file *file_priv);
+#else
+#define vidi_connection_ioctl	NULL
+#endif
+
+#endif
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 81bfd89..3cfa764 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -76,6 +76,20 @@ struct drm_exynos_gem_mmap {
 	uint64_t mapped;
 };
 
+/**
+ * A structure for user connection request of virtual display.
+ *
+ * @connection: indicate whether doing connetion or not by user.
+ * @extensions: if this value is 1 then the vidi driver would need additional
+ *	128bytes edid data.
+ * @edid: the edid data pointer from user side.
+ */
+struct drm_exynos_vidi_connection {
+	unsigned int connection;
+	unsigned int extensions;
+	__u64 __user *edid;
+};
+
 struct drm_exynos_plane_set_zpos {
 	__u32 plane_id;
 	__s32 zpos;
@@ -123,6 +137,7 @@ struct drm_exynos_g2d_exec {
 #define DRM_EXYNOS_GEM_MMAP		0x02
 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
 #define DRM_EXYNOS_PLANE_SET_ZPOS	0x06
+#define DRM_EXYNOS_VIDI_CONNECTION	0x07
 
 /* G2D */
 #define DRM_EXYNOS_G2D_GET_VER		0x20
@@ -141,6 +156,9 @@ struct drm_exynos_g2d_exec {
 #define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
 
+#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
+
 #define DRM_IOCTL_EXYNOS_G2D_GET_VER		DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver)
 #define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST	DRM_IOWR(DRM_COMMAND_BASE + \
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 11/14] drm/exynos: remove exynos_mixer.h
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (9 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 10/14] drm/exynos: added virtual display driver Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 12/14] drm/exynos: cleanup exynos_hdmi.h Inki Dae
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

The contents of exynos_mixer.h are used only in exynos_mixer.c, so
separated header is unnecessary.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_mixer.c |   49 +++++++++++++++++-
 drivers/gpu/drm/exynos/exynos_mixer.h |   92 ---------------------------------
 2 files changed, 48 insertions(+), 93 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h

diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 242cbcd..f42c437 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -37,10 +37,57 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_hdmi.h"
 #include "exynos_hdmi.h"
-#include "exynos_mixer.h"
+
+#define HDMI_OVERLAY_NUMBER	3
 
 #define get_mixer_context(dev)	platform_get_drvdata(to_platform_device(dev))
 
+struct hdmi_win_data {
+	dma_addr_t		dma_addr;
+	void __iomem		*vaddr;
+	dma_addr_t		chroma_dma_addr;
+	void __iomem		*chroma_vaddr;
+	uint32_t		pixel_format;
+	unsigned int		bpp;
+	unsigned int		crtc_x;
+	unsigned int		crtc_y;
+	unsigned int		crtc_width;
+	unsigned int		crtc_height;
+	unsigned int		fb_x;
+	unsigned int		fb_y;
+	unsigned int		fb_width;
+	unsigned int		fb_height;
+	unsigned int		mode_width;
+	unsigned int		mode_height;
+	unsigned int		scan_flags;
+};
+
+struct mixer_resources {
+	struct device		*dev;
+	int			irq;
+	void __iomem		*mixer_regs;
+	void __iomem		*vp_regs;
+	spinlock_t		reg_slock;
+	struct clk		*mixer;
+	struct clk		*vp;
+	struct clk		*sclk_mixer;
+	struct clk		*sclk_hdmi;
+	struct clk		*sclk_dac;
+};
+
+struct mixer_context {
+	struct fb_videomode	*default_timing;
+	unsigned int		default_win;
+	unsigned int		default_bpp;
+	unsigned int		irq;
+	int			pipe;
+	bool			interlace;
+	bool			vp_enabled;
+
+	struct mixer_resources	mixer_res;
+	struct hdmi_win_data	win_data[HDMI_OVERLAY_NUMBER];
+};
+
 static const u8 filter_y_horiz_tap8[] = {
 	0,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
 	-1,	-1,	-1,	-1,	-1,	0,	0,	0,
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
deleted file mode 100644
index cebacfe..0000000
--- a/drivers/gpu/drm/exynos/exynos_mixer.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *	Seung-Woo Kim <sw0312.kim@samsung.com>
- *	Inki Dae <inki.dae@samsung.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef _EXYNOS_MIXER_H_
-#define _EXYNOS_MIXER_H_
-
-#define HDMI_OVERLAY_NUMBER	3
-
-struct hdmi_win_data {
-	dma_addr_t		dma_addr;
-	void __iomem		*vaddr;
-	dma_addr_t		chroma_dma_addr;
-	void __iomem		*chroma_vaddr;
-	uint32_t		pixel_format;
-	unsigned int		bpp;
-	unsigned int		crtc_x;
-	unsigned int		crtc_y;
-	unsigned int		crtc_width;
-	unsigned int		crtc_height;
-	unsigned int		fb_x;
-	unsigned int		fb_y;
-	unsigned int		fb_width;
-	unsigned int		fb_height;
-	unsigned int		mode_width;
-	unsigned int		mode_height;
-	unsigned int		scan_flags;
-};
-
-struct mixer_resources {
-	struct device *dev;
-	/** interrupt index */
-	int irq;
-	/** pointer to Mixer registers */
-	void __iomem *mixer_regs;
-	/** pointer to Video Processor registers */
-	void __iomem *vp_regs;
-	/** spinlock for protection of registers */
-	spinlock_t reg_slock;
-	/** other resources */
-	struct clk *mixer;
-	struct clk *vp;
-	struct clk *sclk_mixer;
-	struct clk *sclk_hdmi;
-	struct clk *sclk_dac;
-};
-
-struct mixer_context {
-	unsigned int			default_win;
-	struct fb_videomode		*default_timing;
-	unsigned int			default_bpp;
-
-	/** mixer interrupt */
-	unsigned int irq;
-	/** current crtc pipe for vblank */
-	int pipe;
-	/** interlace scan mode */
-	bool interlace;
-	/** vp enabled status */
-	bool vp_enabled;
-
-	/** mixer and vp resources */
-	struct mixer_resources mixer_res;
-
-	/** overlay window data */
-	struct hdmi_win_data		win_data[HDMI_OVERLAY_NUMBER];
-};
-
-#endif
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 12/14] drm/exynos: cleanup exynos_hdmi.h
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (10 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 11/14] drm/exynos: remove exynos_mixer.h Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 13/14] drm/exynos: add default pixel format for plane Inki Dae
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Joonyoung Shim <jy0922.shim@samsung.com>

The some contents of the exynos_hdmi.h are used only in exynos_hdmi.c,
so move them to exynos_hdmi.c.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_hdmi.c  |   36 ++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_hdmi.h  |   42 ---------------------------------
 drivers/gpu/drm/exynos/exynos_mixer.c |    1 -
 3 files changed, 36 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 3fe5b2e..3583a7b 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -45,6 +45,42 @@
 #define MAX_HEIGHT		1080
 #define get_hdmi_context(dev)	platform_get_drvdata(to_platform_device(dev))
 
+struct hdmi_resources {
+	struct clk			*hdmi;
+	struct clk			*sclk_hdmi;
+	struct clk			*sclk_pixel;
+	struct clk			*sclk_hdmiphy;
+	struct clk			*hdmiphy;
+	struct regulator_bulk_data	*regul_bulk;
+	int				regul_count;
+};
+
+struct hdmi_context {
+	struct device			*dev;
+	struct drm_device		*drm_dev;
+	struct fb_videomode		*default_timing;
+	unsigned int			is_v13:1;
+	unsigned int			default_win;
+	unsigned int			default_bpp;
+	bool				hpd_handle;
+	bool				enabled;
+
+	struct resource			*regs_res;
+	void __iomem			*regs;
+	unsigned int			irq;
+	struct workqueue_struct		*wq;
+	struct work_struct		hotplug_work;
+
+	struct i2c_client		*ddc_port;
+	struct i2c_client		*hdmiphy_port;
+
+	/* current hdmiphy conf index */
+	int cur_conf;
+
+	struct hdmi_resources		res;
+	void				*parent_ctx;
+};
+
 /* HDMI Version 1.3 */
 static const u8 hdmiphy_v13_conf27[32] = {
 	0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h b/drivers/gpu/drm/exynos/exynos_hdmi.h
index 040ecad..1c3b6d8 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.h
@@ -28,48 +28,6 @@
 #ifndef _EXYNOS_HDMI_H_
 #define _EXYNOS_HDMI_H_
 
-struct hdmi_resources {
-	struct clk *hdmi;
-	struct clk *sclk_hdmi;
-	struct clk *sclk_pixel;
-	struct clk *sclk_hdmiphy;
-	struct clk *hdmiphy;
-	struct regulator_bulk_data *regul_bulk;
-	int regul_count;
-};
-
-struct hdmi_context {
-	struct device			*dev;
-	struct drm_device		*drm_dev;
-	struct fb_videomode		*default_timing;
-	unsigned int			is_v13:1;
-	unsigned int			default_win;
-	unsigned int			default_bpp;
-	bool				hpd_handle;
-	bool				enabled;
-
-	struct resource			*regs_res;
-	/** base address of HDMI registers */
-	void __iomem *regs;
-	/** HDMI hotplug interrupt */
-	unsigned int irq;
-	/** workqueue for delayed work */
-	struct workqueue_struct *wq;
-	/** hotplug handling work */
-	struct work_struct hotplug_work;
-
-	struct i2c_client *ddc_port;
-	struct i2c_client *hdmiphy_port;
-
-	/** current hdmiphy conf index */
-	int cur_conf;
-	/** other resources */
-	struct hdmi_resources res;
-
-	void *parent_ctx;
-};
-
-
 void hdmi_attach_ddc_client(struct i2c_client *ddc);
 void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index f42c437..4d5f41e 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -36,7 +36,6 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_hdmi.h"
-#include "exynos_hdmi.h"
 
 #define HDMI_OVERLAY_NUMBER	3
 
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 13/14] drm/exynos: add default pixel format for plane
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (11 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 12/14] drm/exynos: cleanup exynos_hdmi.h Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-16  9:47 ` [PATCH v2 14/14] drm/exynos: enable hdmi audio feature Inki Dae
  2012-03-20  9:49 ` [PATCH v2 00/14] updated exynos-drm-next Dave Airlie
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, Eunchul Kim, kyungmin.park, sw0312.kim

From: Eunchul Kim <chulspro.kim@samsung.com>

DRM checks whether the plane supports a pixel format of fb when plane is
updated. This adds a default pixel format supporting format exynos drm
plane.

Signed-off-by: Eunchul Kim <chulspro.kim@samsung.com>
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_plane.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index bdcf770..c277a3a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -22,6 +22,10 @@ struct exynos_plane {
 	bool				enabled;
 };
 
+static const uint32_t formats[] = {
+	DRM_FORMAT_XRGB8888,
+};
+
 static int
 exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -115,9 +119,9 @@ int exynos_plane_init(struct drm_device *dev, unsigned int nr)
 
 	exynos_plane->overlay.zpos = DEFAULT_ZPOS;
 
-	/* TODO: format */
 	return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
-			      &exynos_plane_funcs, NULL, 0, false);
+			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
+			      false);
 }
 
 int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 14/14] drm/exynos: enable hdmi audio feature
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (12 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 13/14] drm/exynos: add default pixel format for plane Inki Dae
@ 2012-03-16  9:47 ` Inki Dae
  2012-03-20  9:49 ` [PATCH v2 00/14] updated exynos-drm-next Dave Airlie
  14 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-16  9:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

From: Seung-Woo Kim <sw0312.kim@samsung.com>

This patch adds hdmi audio feature for exynos drm.
With this patch, i2s channel feeds audio data in hdmi when hdmi is connected.

Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_hdmi.c |  167 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/regs-hdmi.h   |  182 ++++++++++++++++++++++++++++++++++
 2 files changed, 349 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 3583a7b..575a8cb 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1319,6 +1319,169 @@ static struct exynos_hdmi_display_ops display_ops = {
 	.power_on	= hdmi_display_power_on,
 };
 
+static void hdmi_set_acr(u32 freq, u8 *acr)
+{
+	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;
+
+	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->is_v13)
+		hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
+	else
+		hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
+}
+
+static void hdmi_audio_init(struct hdmi_context *hdata)
+{
+	u32 sample_rate, bits_per_sample, frame_size_code;
+	u32 data_num, bit_ch, sample_frq;
+	u32 val;
+	u8 acr[7];
+
+	sample_rate = 44100;
+	bits_per_sample = 16;
+	frame_size_code = 0;
+
+	switch (bits_per_sample) {
+	case 20:
+		data_num = 2;
+		bit_ch  = 1;
+		break;
+	case 24:
+		data_num = 3;
+		bit_ch  = 1;
+		break;
+	default:
+		data_num = 1;
+		bit_ch  = 0;
+		break;
+	}
+
+	hdmi_set_acr(sample_rate, acr);
+	hdmi_reg_acr(hdata, acr);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CON, HDMI_I2S_IN_DISABLE
+				| HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
+				| HDMI_I2S_MUX_ENABLE);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CH, HDMI_I2S_CH0_EN
+			| HDMI_I2S_CH1_EN | HDMI_I2S_CH2_EN);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
+
+	sample_frq = (sample_rate == 44100) ? 0 :
+			(sample_rate == 48000) ? 2 :
+			(sample_rate == 32000) ? 3 :
+			(sample_rate == 96000) ? 0xa : 0x0;
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DIS);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_EN);
+
+	val = hdmi_reg_read(hdata, HDMI_I2S_DSD_CON) | 0x01;
+	hdmi_reg_writeb(hdata, HDMI_I2S_DSD_CON, val);
+
+	/* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
+			| HDMI_I2S_SEL_LRCK(6));
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
+			| HDMI_I2S_SEL_SDATA2(4));
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
+			| HDMI_I2S_SEL_SDATA2(2));
+	hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
+
+	/* I2S_CON_1 & 2 */
+	hdmi_reg_writeb(hdata, HDMI_I2S_CON_1, HDMI_I2S_SCLK_FALLING_EDGE
+			| HDMI_I2S_L_CH_LOW_POL);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CON_2, HDMI_I2S_MSB_FIRST_MODE
+			| HDMI_I2S_SET_BIT_CH(bit_ch)
+			| HDMI_I2S_SET_SDATA_BIT(data_num)
+			| HDMI_I2S_BASIC_FORMAT);
+
+	/* Configure register related to CUV information */
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_0, HDMI_I2S_CH_STATUS_MODE_0
+			| HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH
+			| HDMI_I2S_COPYRIGHT
+			| HDMI_I2S_LINEAR_PCM
+			| HDMI_I2S_CONSUMER_FORMAT);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_3, HDMI_I2S_CLK_ACCUR_LEVEL_2
+			| HDMI_I2S_SET_SMP_FREQ(sample_frq));
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_4,
+			HDMI_I2S_ORG_SMP_FREQ_44_1
+			| HDMI_I2S_WORD_LEN_MAX24_24BITS
+			| HDMI_I2S_WORD_LEN_MAX_24BITS);
+
+	hdmi_reg_writeb(hdata, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
+}
+
+static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
+{
+	u32 mod;
+
+	mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
+	if (mod & HDMI_DVI_MODE_EN)
+		return;
+
+	hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
+	hdmi_reg_writemask(hdata, HDMI_CON_0, onoff ?
+			HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
+}
+
 static void hdmi_conf_reset(struct hdmi_context *hdata)
 {
 	u32 reg;
@@ -1737,9 +1900,11 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
 
 	hdmi_conf_reset(hdata);
 	hdmi_conf_init(hdata);
+	hdmi_audio_init(hdata);
 
 	/* setting core registers */
 	hdmi_timing_apply(hdata);
+	hdmi_audio_control(hdata, true);
 
 	hdmi_regs_dump(hdata, "start");
 }
@@ -1825,6 +1990,7 @@ static void hdmi_disable(void *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);
 	}
@@ -1983,6 +2149,7 @@ static void hdmi_resource_poweron(struct hdmi_context *hdata)
 	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)
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index 6b28715..3c04bea 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -22,6 +22,7 @@
 /* HDMI Version 1.3 & Common */
 #define HDMI_CTRL_BASE(x)		((x) + 0x00000000)
 #define HDMI_CORE_BASE(x)		((x) + 0x00010000)
+#define HDMI_I2S_BASE(x)		((x) + 0x00040000)
 #define HDMI_TG_BASE(x)			((x) + 0x00050000)
 
 /* Control registers */
@@ -132,6 +133,9 @@
 
 /* HDMI_CON_0 */
 #define HDMI_BLUE_SCR_EN		(1 << 5)
+#define HDMI_ASP_EN			(1 << 2)
+#define HDMI_ASP_DIS			(0 << 2)
+#define HDMI_ASP_MASK			(1 << 2)
 #define HDMI_EN				(1 << 0)
 
 /* HDMI_PHY_STATUS */
@@ -140,6 +144,8 @@
 /* HDMI_MODE_SEL */
 #define HDMI_MODE_HDMI_EN		(1 << 1)
 #define HDMI_MODE_DVI_EN		(1 << 0)
+#define HDMI_DVI_MODE_EN		(1)
+#define HDMI_DVI_MODE_DIS		(0)
 #define HDMI_MODE_MASK			(3 << 0)
 
 /* HDMI_TG_CMD */
@@ -268,6 +274,9 @@
 #define HDMI_ACR_MCTS0			HDMI_CORE_BASE(0x0410)
 #define HDMI_ACR_MCTS1			HDMI_CORE_BASE(0x0414)
 #define HDMI_ACR_MCTS2			HDMI_CORE_BASE(0x0418)
+#define HDMI_ACR_CTS0			HDMI_CORE_BASE(0x0420)
+#define HDMI_ACR_CTS1			HDMI_CORE_BASE(0x0424)
+#define HDMI_ACR_CTS2			HDMI_CORE_BASE(0x0428)
 #define HDMI_ACR_N0			HDMI_CORE_BASE(0x0430)
 #define HDMI_ACR_N1			HDMI_CORE_BASE(0x0434)
 #define HDMI_ACR_N2			HDMI_CORE_BASE(0x0438)
@@ -368,6 +377,179 @@
 #define HDMI_BLUE_SCREEN_R_0		HDMI_CORE_BASE(0xD530)
 #define HDMI_BLUE_SCREEN_R_1		HDMI_CORE_BASE(0xD534)
 
+/* HDMI I2S register */
+#define HDMI_I2S_CLK_CON		HDMI_I2S_BASE(0x000)
+#define HDMI_I2S_CON_1			HDMI_I2S_BASE(0x004)
+#define HDMI_I2S_CON_2			HDMI_I2S_BASE(0x008)
+#define HDMI_I2S_PIN_SEL_0		HDMI_I2S_BASE(0x00c)
+#define HDMI_I2S_PIN_SEL_1		HDMI_I2S_BASE(0x010)
+#define HDMI_I2S_PIN_SEL_2		HDMI_I2S_BASE(0x014)
+#define HDMI_I2S_PIN_SEL_3		HDMI_I2S_BASE(0x018)
+#define HDMI_I2S_DSD_CON		HDMI_I2S_BASE(0x01c)
+#define HDMI_I2S_MUX_CON		HDMI_I2S_BASE(0x020)
+#define HDMI_I2S_CH_ST_CON		HDMI_I2S_BASE(0x024)
+#define HDMI_I2S_CH_ST_0		HDMI_I2S_BASE(0x028)
+#define HDMI_I2S_CH_ST_1		HDMI_I2S_BASE(0x02c)
+#define HDMI_I2S_CH_ST_2		HDMI_I2S_BASE(0x030)
+#define HDMI_I2S_CH_ST_3		HDMI_I2S_BASE(0x034)
+#define HDMI_I2S_CH_ST_4		HDMI_I2S_BASE(0x038)
+#define HDMI_I2S_CH_ST_SH_0		HDMI_I2S_BASE(0x03c)
+#define HDMI_I2S_CH_ST_SH_1		HDMI_I2S_BASE(0x040)
+#define HDMI_I2S_CH_ST_SH_2		HDMI_I2S_BASE(0x044)
+#define HDMI_I2S_CH_ST_SH_3		HDMI_I2S_BASE(0x048)
+#define HDMI_I2S_CH_ST_SH_4		HDMI_I2S_BASE(0x04c)
+#define HDMI_I2S_MUX_CH			HDMI_I2S_BASE(0x054)
+#define HDMI_I2S_MUX_CUV		HDMI_I2S_BASE(0x058)
+
+/* I2S bit definition */
+
+/* I2S_CLK_CON */
+#define HDMI_I2S_CLK_DIS		(0)
+#define HDMI_I2S_CLK_EN			(1)
+
+/* I2S_CON_1 */
+#define HDMI_I2S_SCLK_FALLING_EDGE	(0 << 1)
+#define HDMI_I2S_SCLK_RISING_EDGE	(1 << 1)
+#define HDMI_I2S_L_CH_LOW_POL		(0)
+#define HDMI_I2S_L_CH_HIGH_POL		(1)
+
+/* I2S_CON_2 */
+#define HDMI_I2S_MSB_FIRST_MODE		(0 << 6)
+#define HDMI_I2S_LSB_FIRST_MODE		(1 << 6)
+#define HDMI_I2S_BIT_CH_32FS		(0 << 4)
+#define HDMI_I2S_BIT_CH_48FS		(1 << 4)
+#define HDMI_I2S_BIT_CH_RESERVED	(2 << 4)
+#define HDMI_I2S_SDATA_16BIT		(1 << 2)
+#define HDMI_I2S_SDATA_20BIT		(2 << 2)
+#define HDMI_I2S_SDATA_24BIT		(3 << 2)
+#define HDMI_I2S_BASIC_FORMAT		(0)
+#define HDMI_I2S_L_JUST_FORMAT		(2)
+#define HDMI_I2S_R_JUST_FORMAT		(3)
+#define HDMI_I2S_CON_2_CLR		(~(0xFF))
+#define HDMI_I2S_SET_BIT_CH(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SET_SDATA_BIT(x)	(((x) & 0x7) << 2)
+
+/* I2S_PIN_SEL_0 */
+#define HDMI_I2S_SEL_SCLK(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_LRCK(x)		((x) & 0x7)
+
+/* I2S_PIN_SEL_1 */
+#define HDMI_I2S_SEL_SDATA1(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA2(x)		((x) & 0x7)
+
+/* I2S_PIN_SEL_2 */
+#define HDMI_I2S_SEL_SDATA3(x)		(((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA2(x)		((x) & 0x7)
+
+/* I2S_PIN_SEL_3 */
+#define HDMI_I2S_SEL_DSD(x)		((x) & 0x7)
+
+/* I2S_DSD_CON */
+#define HDMI_I2S_DSD_CLK_RI_EDGE	(1 << 1)
+#define HDMI_I2S_DSD_CLK_FA_EDGE	(0 << 1)
+#define HDMI_I2S_DSD_ENABLE		(1)
+#define HDMI_I2S_DSD_DISABLE		(0)
+
+/* I2S_MUX_CON */
+#define HDMI_I2S_NOISE_FILTER_ZERO	(0 << 5)
+#define HDMI_I2S_NOISE_FILTER_2_STAGE	(1 << 5)
+#define HDMI_I2S_NOISE_FILTER_3_STAGE	(2 << 5)
+#define HDMI_I2S_NOISE_FILTER_4_STAGE	(3 << 5)
+#define HDMI_I2S_NOISE_FILTER_5_STAGE	(4 << 5)
+#define HDMI_I2S_IN_DISABLE		(1 << 4)
+#define HDMI_I2S_IN_ENABLE		(0 << 4)
+#define HDMI_I2S_AUD_SPDIF		(0 << 2)
+#define HDMI_I2S_AUD_I2S		(1 << 2)
+#define HDMI_I2S_AUD_DSD		(2 << 2)
+#define HDMI_I2S_CUV_SPDIF_ENABLE	(0 << 1)
+#define HDMI_I2S_CUV_I2S_ENABLE		(1 << 1)
+#define HDMI_I2S_MUX_DISABLE		(0)
+#define HDMI_I2S_MUX_ENABLE		(1)
+#define HDMI_I2S_MUX_CON_CLR		(~(0xFF))
+
+/* I2S_CH_ST_CON */
+#define HDMI_I2S_CH_STATUS_RELOAD	(1)
+#define HDMI_I2S_CH_ST_CON_CLR		(~(1))
+
+/* I2S_CH_ST_0 / I2S_CH_ST_SH_0 */
+#define HDMI_I2S_CH_STATUS_MODE_0	(0 << 6)
+#define HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH	(0 << 3)
+#define HDMI_I2S_2AUD_CH_WITH_PREEMPH	(1 << 3)
+#define HDMI_I2S_DEFAULT_EMPHASIS	(0 << 3)
+#define HDMI_I2S_COPYRIGHT		(0 << 2)
+#define HDMI_I2S_NO_COPYRIGHT		(1 << 2)
+#define HDMI_I2S_LINEAR_PCM		(0 << 1)
+#define HDMI_I2S_NO_LINEAR_PCM		(1 << 1)
+#define HDMI_I2S_CONSUMER_FORMAT	(0)
+#define HDMI_I2S_PROF_FORMAT		(1)
+#define HDMI_I2S_CH_ST_0_CLR		(~(0xFF))
+
+/* I2S_CH_ST_1 / I2S_CH_ST_SH_1 */
+#define HDMI_I2S_CD_PLAYER		(0x00)
+#define HDMI_I2S_DAT_PLAYER		(0x03)
+#define HDMI_I2S_DCC_PLAYER		(0x43)
+#define HDMI_I2S_MINI_DISC_PLAYER	(0x49)
+
+/* I2S_CH_ST_2 / I2S_CH_ST_SH_2 */
+#define HDMI_I2S_CHANNEL_NUM_MASK	(0xF << 4)
+#define HDMI_I2S_SOURCE_NUM_MASK	(0xF)
+#define HDMI_I2S_SET_CHANNEL_NUM(x)	(((x) & (0xF)) << 4)
+#define HDMI_I2S_SET_SOURCE_NUM(x)	((x) & (0xF))
+
+/* I2S_CH_ST_3 / I2S_CH_ST_SH_3 */
+#define HDMI_I2S_CLK_ACCUR_LEVEL_1	(1 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_2	(0 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_3	(2 << 4)
+#define HDMI_I2S_SMP_FREQ_44_1		(0x0)
+#define HDMI_I2S_SMP_FREQ_48		(0x2)
+#define HDMI_I2S_SMP_FREQ_32		(0x3)
+#define HDMI_I2S_SMP_FREQ_96		(0xA)
+#define HDMI_I2S_SET_SMP_FREQ(x)	((x) & (0xF))
+
+/* I2S_CH_ST_4 / I2S_CH_ST_SH_4 */
+#define HDMI_I2S_ORG_SMP_FREQ_44_1	(0xF << 4)
+#define HDMI_I2S_ORG_SMP_FREQ_88_2	(0x7 << 4)
+#define HDMI_I2S_ORG_SMP_FREQ_22_05	(0xB << 4)
+#define HDMI_I2S_ORG_SMP_FREQ_176_4	(0x3 << 4)
+#define HDMI_I2S_WORD_LEN_NOT_DEFINE	(0x0 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_20BITS	(0x1 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_22BITS	(0x2 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_23BITS	(0x4 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_24BITS	(0x5 << 1)
+#define HDMI_I2S_WORD_LEN_MAX24_21BITS	(0x6 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_16BITS	(0x1 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_18BITS	(0x2 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_19BITS	(0x4 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_20BITS	(0x5 << 1)
+#define HDMI_I2S_WORD_LEN_MAX20_17BITS	(0x6 << 1)
+#define HDMI_I2S_WORD_LEN_MAX_24BITS	(1)
+#define HDMI_I2S_WORD_LEN_MAX_20BITS	(0)
+
+/* I2S_MUX_CH */
+#define HDMI_I2S_CH3_R_EN		(1 << 7)
+#define HDMI_I2S_CH3_L_EN		(1 << 6)
+#define HDMI_I2S_CH3_EN			(3 << 6)
+#define HDMI_I2S_CH2_R_EN		(1 << 5)
+#define HDMI_I2S_CH2_L_EN		(1 << 4)
+#define HDMI_I2S_CH2_EN			(3 << 4)
+#define HDMI_I2S_CH1_R_EN		(1 << 3)
+#define HDMI_I2S_CH1_L_EN		(1 << 2)
+#define HDMI_I2S_CH1_EN			(3 << 2)
+#define HDMI_I2S_CH0_R_EN		(1 << 1)
+#define HDMI_I2S_CH0_L_EN		(1)
+#define HDMI_I2S_CH0_EN			(3)
+#define HDMI_I2S_CH_ALL_EN		(0xFF)
+#define HDMI_I2S_MUX_CH_CLR		(~HDMI_I2S_CH_ALL_EN)
+
+/* I2S_MUX_CUV */
+#define HDMI_I2S_CUV_R_EN		(1 << 1)
+#define HDMI_I2S_CUV_L_EN		(1)
+#define HDMI_I2S_CUV_RL_EN		(0x03)
+
+/* I2S_CUV_L_R */
+#define HDMI_I2S_CUV_R_DATA_MASK	(0x7 << 4)
+#define HDMI_I2S_CUV_L_DATA_MASK	(0x7)
+
 /* Timing generator registers */
 /* TG configure/status registers */
 #define HDMI_TG_VACT_ST3_L		HDMI_TG_BASE(0x0068)
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 09/14] drm/exynos: add G2D driver
  2012-03-16  9:47 ` [PATCH v2 09/14] drm/exynos: add G2D driver Inki Dae
@ 2012-03-19 12:25   ` Dave Airlie
  2012-03-20  1:09     ` Joonyoung Shim
  0 siblings, 1 reply; 19+ messages in thread
From: Dave Airlie @ 2012-03-19 12:25 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin.park, sw0312.kim, dri-devel

On Fri, Mar 16, 2012 at 9:47 AM, Inki Dae <inki.dae@samsung.com> wrote:
> From: Joonyoung Shim <jy0922.shim@samsung.com>
>
> The G2D is a 2D graphic accelerator that supports Bit Block Transfer.
> This G2D driver is exynos drm specific and supports only G2D(version
> 4.1) of later Exynos series from Exynos4X12 because supporting DMA.

So just to make sure I understand, userspace generates two command
streams, one containing registers that don't need base addresses
and one containing registers that do contain it.

Now tell me how this address security wise, since non-root users have
the ability to use this interface.

can userspace put registers that require a base address into the first
command stream and specify any phy addr in the system? If not, please
explain in comments where this is blocked. Where is the list of
registers the first command stream and second command stream can
access specified?

I'm not really happy about this appearing so late on the radar for
3.4, you really want new major userspace security features to turn up
a lot earlier for review.

Dave.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 09/14] drm/exynos: add G2D driver
  2012-03-19 12:25   ` Dave Airlie
@ 2012-03-20  1:09     ` Joonyoung Shim
  0 siblings, 0 replies; 19+ messages in thread
From: Joonyoung Shim @ 2012-03-20  1:09 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Inki Dae, kyungmin.park, sw0312.kim, dri-devel

On 03/19/2012 09:25 PM, Dave Airlie wrote:
> On Fri, Mar 16, 2012 at 9:47 AM, Inki Dae<inki.dae@samsung.com>  wrote:
>> From: Joonyoung Shim<jy0922.shim@samsung.com>
>>
>> The G2D is a 2D graphic accelerator that supports Bit Block Transfer.
>> This G2D driver is exynos drm specific and supports only G2D(version
>> 4.1) of later Exynos series from Exynos4X12 because supporting DMA.
> So just to make sure I understand, userspace generates two command
> streams, one containing registers that don't need base addresses
> and one containing registers that do contain it.
>
> Now tell me how this address security wise, since non-root users have
> the ability to use this interface.
>
> can userspace put registers that require a base address into the first
> command stream and specify any phy addr in the system?

Right, it's possible scenario. I will add codes to check it.

> If not, please
> explain in comments where this is blocked. Where is the list of
> registers the first command stream and second command stream can
> access specified?
>
> I'm not really happy about this appearing so late on the radar for
> 3.4, you really want new major userspace security features to turn up
> a lot earlier for review.

I post the patch to get the review like this and i think time posting
patch can be open always. If the patch has serious problem, certainly
don't apply it. I don't want it too, but i will try to solve it and
resend updated patch.

Thanks.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 00/14] updated exynos-drm-next.
  2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
                   ` (13 preceding siblings ...)
  2012-03-16  9:47 ` [PATCH v2 14/14] drm/exynos: enable hdmi audio feature Inki Dae
@ 2012-03-20  9:49 ` Dave Airlie
  2012-03-21  1:47   ` Inki Dae
  14 siblings, 1 reply; 19+ messages in thread
From: Dave Airlie @ 2012-03-20  9:49 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin.park, sw0312.kim, dri-devel

On Fri, Mar 16, 2012 at 9:47 AM, Inki Dae <inki.dae@samsung.com> wrote:
> Hi, Dave and all.

Hi Inki,

I've taken most of these patches except for the G2D and Virtual drivers,

If you can make the virtual driver rebase without G2D I don't see an
issue with merging it, it didn't seem to apply cleanly here.

But I don't think G2D is close enough for this merge window
considering the security issues with exposing DMA engines without a
lot of review.

Dave.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [PATCH v2 00/14] updated exynos-drm-next.
  2012-03-20  9:49 ` [PATCH v2 00/14] updated exynos-drm-next Dave Airlie
@ 2012-03-21  1:47   ` Inki Dae
  0 siblings, 0 replies; 19+ messages in thread
From: Inki Dae @ 2012-03-21  1:47 UTC (permalink / raw)
  To: 'Dave Airlie'; +Cc: kyungmin.park, sw0312.kim, dri-devel

Hi Dave,

> -----Original Message-----
> From: Dave Airlie [mailto:airlied@gmail.com]
> Sent: Tuesday, March 20, 2012 6:49 PM
> To: Inki Dae
> Cc: airlied@linux.ie; dri-devel@lists.freedesktop.org;
> kyungmin.park@samsung.com; sw0312.kim@samsung.com
> Subject: Re: [PATCH v2 00/14] updated exynos-drm-next.
> 
> On Fri, Mar 16, 2012 at 9:47 AM, Inki Dae <inki.dae@samsung.com> wrote:
> > Hi, Dave and all.
> 
> Hi Inki,
> 
> I've taken most of these patches except for the G2D and Virtual drivers,
> 
> If you can make the virtual driver rebase without G2D I don't see an
> issue with merging it, it didn't seem to apply cleanly here.
> 
> But I don't think G2D is close enough for this merge window
> considering the security issues with exposing DMA engines without a
> lot of review.
> 
> Dave.

Ok, I will resend rebased Virtual Display Driver and we will consolidate the
security part of g2d for next time.

Thanks,
Inki Dae.

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2012-03-21  1:47 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-16  9:47 [PATCH v2 00/14] updated exynos-drm-next Inki Dae
2012-03-16  9:47 ` [PATCH v2 01/14] drm/exynos: add HDMI version 1.4 support Inki Dae
2012-03-16  9:47 ` [PATCH v2 02/14] drm/exynos: added mode_fixup feature and code clean Inki Dae
2012-03-16  9:47 ` [PATCH v2 03/14] drm/exynos: update gem and buffer framework Inki Dae
2012-03-16  9:47 ` [PATCH v2 04/14] drm/exynos: added new funtion to get/put dma address Inki Dae
2012-03-16  9:47 ` [PATCH v2 05/14] drm/exynos: release pending pageflip events when closed Inki Dae
2012-03-16  9:47 ` [PATCH v2 06/14] drm/exynos: remove module of exynos drm subdrv Inki Dae
2012-03-16  9:47 ` [PATCH v2 07/14] drm/exynos: add subdrv open/close functions Inki Dae
2012-03-16  9:47 ` [PATCH v2 08/14] drm/exynos: add is_local member in exynos_drm_subdrv struct Inki Dae
2012-03-16  9:47 ` [PATCH v2 09/14] drm/exynos: add G2D driver Inki Dae
2012-03-19 12:25   ` Dave Airlie
2012-03-20  1:09     ` Joonyoung Shim
2012-03-16  9:47 ` [PATCH v2 10/14] drm/exynos: added virtual display driver Inki Dae
2012-03-16  9:47 ` [PATCH v2 11/14] drm/exynos: remove exynos_mixer.h Inki Dae
2012-03-16  9:47 ` [PATCH v2 12/14] drm/exynos: cleanup exynos_hdmi.h Inki Dae
2012-03-16  9:47 ` [PATCH v2 13/14] drm/exynos: add default pixel format for plane Inki Dae
2012-03-16  9:47 ` [PATCH v2 14/14] drm/exynos: enable hdmi audio feature Inki Dae
2012-03-20  9:49 ` [PATCH v2 00/14] updated exynos-drm-next Dave Airlie
2012-03-21  1:47   ` Inki Dae

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.