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

Hi, Dave and all.

this patch set includes the following features.
- add HDMI version 1.4 support.
- add mode_fixup feature.
  . hdmi module would change current mode to driver desired mode properly.
- add buffer alloction type.
  . 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.


this patch set is based on git repository below:
git://git.infradead.org/users/kmpark/linux-samsung exynos-drm-fixes
commit-id: f6d69d1e77509d71c29f2a7b119214b8fdf86ae2

and exynos-drm-fixes is based on git repository below:
git://people.freedesktop.org/~airlied/linux.git drm-fixes
commit-id: 38aa4a568ba4c3ccba83e862a01e3e60e3b811ee

P.S.
drm-next doesn't reflect updated latest codes of mainline so this patch set
should be merged to drm-next after latest mainline codes are merged to
drm-next. now is just for review and if latest codes are merged to drm-next
then I will merge this patch set to exynos-drm-next for git pull request.

Thanks.

Inki Dae (5):
  drm/exynos: add HDMI version 1.4 support
  drm/exynos: added mode_fixup feature and code clean.
  drm/exynos: added buffer allocation type.
  drm/exynos: added new funtion to get/put dma address.
  drm/exynos: added virtual display driver.

Joonyoung Shim (5):
  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

 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       |  152 +++-
 drivers/gpu/drm/exynos/exynos_drm_buf.h       |    4 +-
 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       |   49 +-
 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       |  864 +++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_g2d.h       |   36 +
 drivers/gpu/drm/exynos/exynos_drm_gem.c       |  346 +++++++-
 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_vidi.c      |  677 ++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_vidi.h      |   36 +
 drivers/gpu/drm/exynos/exynos_hdmi.c          | 1234 ++++++++++++++++++++++---
 drivers/gpu/drm/exynos/exynos_hdmi.h          |   10 +-
 drivers/gpu/drm/exynos/exynos_mixer.c         |    7 -
 drivers/gpu/drm/exynos/regs-hdmi.h            |  306 ++++++-
 include/drm/exynos_drm.h                      |   84 ++
 27 files changed, 3879 insertions(+), 560 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

-- 
1.7.4.1

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

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

Later Exynos series from Exynos4X12 support HDMI version 1.4. We will
distinguish to use which version via platform data.

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] 28+ messages in thread

* [PATCH 02/10] drm/exynos: added mode_fixup feature and code clean.
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
  2012-03-13 14:46 ` [PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
@ 2012-03-13 14:46 ` Inki Dae
  2012-03-15 10:39   ` Dave Airlie
  2012-03-13 14:46 ` [PATCH 03/10] drm/exynos: added buffer allocation type Inki Dae
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14:46 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 99d5527..303af60 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] 28+ messages in thread

* [PATCH 03/10] drm/exynos: added buffer allocation type.
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
  2012-03-13 14:46 ` [PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
  2012-03-13 14:46 ` [PATCH 02/10] drm/exynos: added mode_fixup feature and code clean Inki Dae
@ 2012-03-13 14:46 ` Inki Dae
  2012-03-13 14:46 ` [PATCH 04/10] drm/exynos: added new funtion to get/put dma address Inki Dae
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14:46 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   |  148 +++++++++++++--
 drivers/gpu/drm/exynos/exynos_drm_buf.h   |    4 +-
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c |    4 +-
 drivers/gpu/drm/exynos/exynos_drm_gem.c   |  284 ++++++++++++++++++++++++++---
 drivers/gpu/drm/exynos/exynos_drm_gem.h   |   11 +-
 include/drm/exynos_drm.h                  |    6 +
 6 files changed, 407 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 3cf785c..554f674 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -25,45 +25,151 @@
 
 #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)
 {
+	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");
-		return -ENOMEM;
+	/*
+	 * allocate only physically continuous memory and
+	 * non-continuous memory would be allocated by exynos
+	 * gem framework.
+	 */
+	if (!(flags & EXYNOS_BO_NONCONTIG)) {
+		dma_addr_t start_addr, end_addr;
+		unsigned int npages, page_size, i = 0;
+		struct scatterlist *sgl;
+
+		if (buf->dma_addr) {
+			DRM_DEBUG_KMS("already allocated.\n");
+			return -EINVAL;
+		}
+
+		/*
+		 * according to desired size, it sets page size
+		 * for performance with using iommu so physically
+		 * continuous memory could be mapped to iommu in
+		 * multiple page size.
+		 */
+		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;
+		}
+
+		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;
+		}
+
+		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;
+		}
+
+		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)buffer->kvaddr,
-			(unsigned long)buffer->dma_addr,
-			buffer->size);
-
-	return 0;
+			(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)) {
+		sg_free_table(buf->sgt);
+
+		kfree(buf->sgt);
+		buf->sgt = NULL;
+
+		kfree(buf->pages);
+		buf->pages = NULL;
+
+		if (buf->dma_addr && buf->size)
+			dma_free_writecombine(dev->dev, buf->size, buf->kvaddr,
+					(dma_addr_t)buf->dma_addr);
+		else
+			DRM_DEBUG_KMS("buffer data are invalid.\n");
+
+		buf->dma_addr = (dma_addr_t)NULL;
+	}
 }
 
 struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
-		unsigned int size)
+		unsigned int flags, unsigned int size)
 {
 	struct exynos_drm_gem_buf *buffer;
 
@@ -82,7 +188,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
 	 * 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) {
+	if (lowlevel_buffer_allocate(dev, flags, buffer) < 0) {
 		kfree(buffer);
 		return NULL;
 	}
@@ -91,7 +197,7 @@ struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
 }
 
 void exynos_drm_buf_destroy(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer)
+		unsigned int flags, struct exynos_drm_gem_buf *buffer)
 {
 	DRM_DEBUG_KMS("%s.\n", __FILE__);
 
@@ -100,7 +206,7 @@ void exynos_drm_buf_destroy(struct drm_device *dev,
 		return;
 	}
 
-	lowlevel_buffer_deallocate(dev, buffer);
+	lowlevel_buffer_deallocate(dev, flags, buffer);
 
 	kfree(buffer);
 	buffer = NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h
index c913f2b..3422267 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h
@@ -28,10 +28,10 @@
 
 /* allocate physical memory. */
 struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
-		unsigned int size);
+		unsigned int flags, unsigned int size);
 
 /* remove allocated physical memory. */
 void exynos_drm_buf_destroy(struct drm_device *dev,
-		struct exynos_drm_gem_buf *buffer);
+		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 3508700..4e86d15 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -151,7 +151,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 025abb3..36d081d 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,181 @@ 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.
+	 */
+	if ((exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) &&
+			buf->pages) {
+		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 +266,10 @@ 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);
+	exynos_drm_gem_put_pages(obj);
+
+	exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->flags,
+				exynos_gem_obj->buffer);
 
 	if (obj->map_list.map)
 		drm_gem_free_mmap_offset(obj);
@@ -114,6 +293,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 +309,49 @@ 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;
+	int ret;
 
 	size = roundup(size, PAGE_SIZE);
 	DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
 
-	buffer = exynos_drm_buf_create(dev, size);
+	buffer = exynos_drm_buf_create(dev, flags, size);
 	if (!buffer)
 		return ERR_PTR(-ENOMEM);
 
 	exynos_gem_obj = exynos_drm_gem_init(dev, size);
 	if (!exynos_gem_obj) {
-		exynos_drm_buf_destroy(dev, buffer);
+		exynos_drm_buf_destroy(dev, flags, buffer);
 		return ERR_PTR(-ENOMEM);
 	}
 
 	exynos_gem_obj->buffer = buffer;
 
+	/*
+	 * 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)
+			goto err;
+	}
+
+	/* set memory type and cache attribute from user side. */
+	exynos_gem_obj->flags = mask_gem_flags(flags);
+
+
 	return exynos_gem_obj;
+
+err:
+	exynos_drm_buf_destroy(dev, flags, buffer);
+	drm_gem_object_release(&exynos_gem_obj->base);
+	kfree(exynos_gem_obj);
+	return ERR_PTR(ret);
 }
 
 int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -161,7 +363,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 +402,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__);
 
@@ -210,7 +413,8 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	vma->vm_file = filp;
 
-	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.
@@ -221,18 +425,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;
@@ -312,9 +535,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);
 
@@ -398,20 +621,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] 28+ messages in thread

* [PATCH 04/10] drm/exynos: added new funtion to get/put dma address.
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (2 preceding siblings ...)
  2012-03-13 14:46 ` [PATCH 03/10] drm/exynos: added buffer allocation type Inki Dae
@ 2012-03-13 14:46 ` Inki Dae
  2012-03-13 14:46 ` [PATCH 05/10] drm/exynos: release pending pageflip events when closed Inki Dae
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14:46 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 36d081d..ddcb7e3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -377,6 +377,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] 28+ messages in thread

* [PATCH 05/10] drm/exynos: release pending pageflip events when closed
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (3 preceding siblings ...)
  2012-03-13 14:46 ` [PATCH 04/10] drm/exynos: added new funtion to get/put dma address Inki Dae
@ 2012-03-13 14:46 ` Inki Dae
  2012-03-13 14:47 ` [PATCH 06/10] drm/exynos: remove module of exynos drm subdrv Inki Dae
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14:46 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 09cc13f..aaa1b40 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] 28+ messages in thread

* [PATCH 06/10] drm/exynos: remove module of exynos drm subdrv
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (4 preceding siblings ...)
  2012-03-13 14:46 ` [PATCH 05/10] drm/exynos: release pending pageflip events when closed Inki Dae
@ 2012-03-13 14:47 ` Inki Dae
  2012-03-13 14:47 ` [PATCH 07/10] drm/exynos: add subdrv open/close functions Inki Dae
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14: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_buf.c       |    4 -
 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 --
 17 files changed, 77 insertions(+), 359 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_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 554f674..0fb5ceb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -211,7 +211,3 @@ void exynos_drm_buf_destroy(struct drm_device *dev,
 	kfree(buffer);
 	buffer = NULL;
 }
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM Buffer Management Module");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 303af60..33893a9 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 aaa1b40..a2f8fae 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 4e86d15..d033c62 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -342,89 +342,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 56458ee..ecb6db2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -1007,7 +1007,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		= {
@@ -1016,21 +1016,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 ddcb7e3..9bd7a7f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -727,7 +727,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] 28+ messages in thread

* [PATCH 07/10] drm/exynos: add subdrv open/close functions
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (5 preceding siblings ...)
  2012-03-13 14:47 ` [PATCH 06/10] drm/exynos: remove module of exynos drm subdrv Inki Dae
@ 2012-03-13 14:47 ` Inki Dae
  2012-03-13 14:47 ` [PATCH 08/10] drm/exynos: add is_local member in exynos_drm_subdrv struct Inki Dae
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14: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 a2f8fae..b4e265f 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] 28+ messages in thread

* [PATCH 08/10] drm/exynos: add is_local member in exynos_drm_subdrv struct
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (6 preceding siblings ...)
  2012-03-13 14:47 ` [PATCH 07/10] drm/exynos: add subdrv open/close functions Inki Dae
@ 2012-03-13 14:47 ` Inki Dae
  2012-03-13 14:47 ` [PATCH 09/10] drm/exynos: add G2D driver Inki Dae
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14: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] 28+ messages in thread

* [PATCH 09/10] drm/exynos: add G2D driver
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (7 preceding siblings ...)
  2012-03-13 14:47 ` [PATCH 08/10] drm/exynos: add is_local member in exynos_drm_subdrv struct Inki Dae
@ 2012-03-13 14:47 ` Inki Dae
  2012-03-15 10:50   ` Dave Airlie
  2012-03-13 14:47 ` [PATCH 10/10] drm/exynos: added virtual display driver Inki Dae
  2012-03-13 15:00 ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
  10 siblings, 1 reply; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

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

G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
G2D driver is exynos drm specific and supports only exynos4x12 series.
user application fills command set in cmdlist and once dma start request
these cmdlists are parsed and performed by dma.

This adds below three exynos specific ioctl and one event for G2D.
 - DRM_EXYNOS_G2D_GET_VER
 - DRM_EXYNOS_G2D_SET_CMDLIST
 - DRM_EXYNOS_G2D_EXEC
 - DRM_EXYNOS_G2D_EVENT

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 |   11 +
 drivers/gpu/drm/exynos/exynos_drm_g2d.c |  864 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_g2d.h |   36 ++
 include/drm/exynos_drm.h                |   56 ++
 7 files changed, 1005 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 b4e265f..2b72c5d 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..d7b50e5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -203,6 +203,16 @@ 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 drm_exynos_file_private {
+	struct exynos_drm_g2d_private	*g2d_priv;
+};
+
 /*
  * Exynos drm private structure.
  */
@@ -284,4 +294,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..69839f2
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -0,0 +1,864 @@
+/*
+ * 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)
+
+#define MAX_BUF_ADDR_NR			5
+
+/* 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_cmdlist_node {
+	struct list_head	list;
+	struct g2d_cmdlist	*cmdlist;
+	unsigned int		gem_nr;
+	unsigned int		gem_handle[MAX_BUF_ADDR_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 g2d_cmdlist_node *node,
+			       struct drm_device *drm_dev,
+			       struct drm_file *file)
+{
+	struct g2d_cmdlist *cmdlist = node->cmdlist;
+	dma_addr_t *addr;
+	int offset;
+	int i;
+
+	for (i = 0; i < node->gem_nr; i++) {
+		offset = cmdlist->last - (i * 2 + 1);
+		node->gem_handle[i] = cmdlist->data[offset];
+
+		addr = exynos_drm_gem_get_dma_addr(drm_dev, node->gem_handle[i],
+						   file);
+		if (IS_ERR(addr)) {
+			node->gem_nr = i;
+			return PTR_ERR(addr);
+		}
+
+		cmdlist->data[offset] = *addr;
+	}
+
+	return 0;
+}
+
+static void g2d_put_cmdlist_gem(struct drm_device *drm_dev,
+				  struct g2d_cmdlist_node *node,
+				  struct drm_file *file)
+{
+	struct g2d_cmdlist *cmdlist = node->cmdlist;
+	int offset;
+	int i;
+
+	for (i = 0; i < node->gem_nr; i++) {
+		offset = cmdlist->last - (i * 2 + 1);
+		exynos_drm_gem_put_dma_addr(drm_dev, node->gem_handle[i], file);
+	}
+}
+
+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(node, drm_dev, file);
+		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, node, file);
+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_priv.\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);
+
+	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);
+
+	/* TODO: do exynos_drm_gem_put_dma_addr() */
+	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		= {
+		/* FIXME */
+		.name	= "s5p-fimg2d",
+		.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..907daaf 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 */
+	enum drm_exynos_g2d_event_type		event_type;
+	__u32					user_data;
+};
+
+struct drm_exynos_g2d_exec {
+	__u32					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,24 @@ 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;
+	__u32			tv_sec;
+	__u32			tv_usec;
+	__u32			cmdlist_no;
+	__u32			user_data;
+};
+
 #ifdef __KERNEL__
 
 /**
-- 
1.7.4.1

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

* [PATCH 10/10] drm/exynos: added virtual display driver.
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (8 preceding siblings ...)
  2012-03-13 14:47 ` [PATCH 09/10] drm/exynos: add G2D driver Inki Dae
@ 2012-03-13 14:47 ` Inki Dae
  2012-03-15 10:44   ` Dave Airlie
  2012-03-13 15:00 ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
  10 siblings, 1 reply; 28+ messages in thread
From: Inki Dae @ 2012-03-13 14: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      |  677 +++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_vidi.h      |   36 ++
 include/drm/exynos_drm.h                      |   20 +
 9 files changed, 768 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..76aed3a 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -22,6 +22,12 @@ config DRM_EXYNOS_HDMI
 	help
 	  Choose this option if you want to use Exynos HDMI for DRM.
 
+config DRM_EXYNOS_VIDI
+	bool "Samsung DRM Virtual Display"
+	depends on DRM_EXYNOS
+	help
+	  Choose this option if you want to use Samsung VIDI for DRM.
+
 config DRM_EXYNOS_G2D
 	bool "Exynos DRM G2D"
 	depends on DRM_EXYNOS
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index d6c1a3c..8ee8fb4 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -12,6 +12,7 @@ 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_VIDI)	+= exynos_drm_vidi.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_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 33893a9..bf791fa 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 2b72c5d..76524f4 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 d7b50e5..943853a 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,
 };
 
 /*
@@ -294,5 +296,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..338dc59
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -0,0 +1,677 @@
+/* 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 = 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);
+
+	/* this sysfs would be used for test. */
+	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 907daaf..1123342 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -76,6 +76,22 @@ 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.
+ * @pad: just padding to be 64-bit aligned.
+ * @edid: the edid data pointer from user side.
+ */
+struct drm_exynos_vidi_connection {
+	unsigned int connection;
+	unsigned int extensions;
+	unsigned int pad;
+	void *edid;
+};
+
 struct drm_exynos_plane_set_zpos {
 	__u32 plane_id;
 	__s32 zpos;
@@ -123,6 +139,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 +158,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] 28+ messages in thread

* [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support
  2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
                   ` (9 preceding siblings ...)
  2012-03-13 14:47 ` [PATCH 10/10] drm/exynos: added virtual display driver Inki Dae
@ 2012-03-13 15:00 ` Inki Dae
  2012-03-13 15:00   ` [RESEND][PATCH 09/10] drm/exynos: add G2D driver Inki Dae
  2012-03-15 10:52   ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Dave Airlie
  10 siblings, 2 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 15:00 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.

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] 28+ messages in thread

* [RESEND][PATCH 09/10] drm/exynos: add G2D driver
  2012-03-13 15:00 ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
@ 2012-03-13 15:00   ` Inki Dae
  2012-03-15 10:52   ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Dave Airlie
  1 sibling, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-13 15:00 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: Inki Dae, kyungmin.park, sw0312.kim

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

G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
G2D driver is exynos drm specific.

This adds below three exynos specific ioctl and one event for G2D.
 - DRM_EXYNOS_G2D_GET_VER
 - DRM_EXYNOS_G2D_SET_CMDLIST
 - DRM_EXYNOS_G2D_EXEC
 - DRM_EXYNOS_G2D_EVENT

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                |   56 ++
 7 files changed, 1028 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 b4e265f..2b72c5d 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..907daaf 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 */
+	enum drm_exynos_g2d_event_type		event_type;
+	__u32					user_data;
+};
+
+struct drm_exynos_g2d_exec {
+	__u32					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,24 @@ 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;
+	__u32			tv_sec;
+	__u32			tv_usec;
+	__u32			cmdlist_no;
+	__u32			user_data;
+};
+
 #ifdef __KERNEL__
 
 /**
-- 
1.7.4.1

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

* Re: [PATCH 02/10] drm/exynos: added mode_fixup feature and code clean.
  2012-03-13 14:46 ` [PATCH 02/10] drm/exynos: added mode_fixup feature and code clean Inki Dae
@ 2012-03-15 10:39   ` Dave Airlie
  2012-03-15 11:21     ` Inki Dae
  0 siblings, 1 reply; 28+ messages in thread
From: Dave Airlie @ 2012-03-15 10:39 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin.park, sw0312.kim, dri-devel

>  };
> 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));

This just seems wrong on lots of levels, if you get an error how are
you going to fallback?

You should be passing the modes into the crtc_update function and
doing things like other drivers here.

Dave.

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

* Re: [PATCH 10/10] drm/exynos: added virtual display driver.
  2012-03-13 14:47 ` [PATCH 10/10] drm/exynos: added virtual display driver Inki Dae
@ 2012-03-15 10:44   ` Dave Airlie
  2012-03-15 11:36     ` Inki Dae
  0 siblings, 1 reply; 28+ messages in thread
From: Dave Airlie @ 2012-03-15 10:44 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin.park, sw0312.kim, dri-devel

> diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
> index 907daaf..1123342 100644
> --- a/include/drm/exynos_drm.h
> +++ b/include/drm/exynos_drm.h
> @@ -76,6 +76,22 @@ 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.
> + * @pad: just padding to be 64-bit aligned.
> + * @edid: the edid data pointer from user side.
> + */
> +struct drm_exynos_vidi_connection {
> +       unsigned int connection;
> +       unsigned int extensions;
> +       unsigned int pad;
> +       void *edid;
> +};
> +

No void * in ioctl structs use u64, also not sure why you have a
32-bit pad since you probably want it padded to 64-bit.

Dave.

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

* Re: [PATCH 09/10] drm/exynos: add G2D driver
  2012-03-13 14:47 ` [PATCH 09/10] drm/exynos: add G2D driver Inki Dae
@ 2012-03-15 10:50   ` Dave Airlie
  2012-03-15 11:05     ` Joonyoung Shim
  2012-03-16  6:28     ` Joonyoung Shim
  0 siblings, 2 replies; 28+ messages in thread
From: Dave Airlie @ 2012-03-15 10:50 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin.park, sw0312.kim, dri-devel

>
> G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
> G2D driver is exynos drm specific and supports only exynos4x12 series.
> user application fills command set in cmdlist and once dma start request
> these cmdlists are parsed and performed by dma.

Where is this block documented or a pointer to the corresponding open
userspace user code?

Again the ioctls look like they need to be depointered and use __u64.

It would be nice if you could document how the command stream and engine work.

How does userspace pass addresses to it? straight or via gem objects?
how does it
stop userspace blt to places it shouldn't etc.

I'm getting the feeling this accel enabled driver needs a lot more of
a commit message
and lot more documentation on what it can be used for.

Dave.

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

* Re: [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support
  2012-03-13 15:00 ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
  2012-03-13 15:00   ` [RESEND][PATCH 09/10] drm/exynos: add G2D driver Inki Dae
@ 2012-03-15 10:52   ` Dave Airlie
  2012-03-15 10:59     ` Joonyoung Shim
  1 sibling, 1 reply; 28+ messages in thread
From: Dave Airlie @ 2012-03-15 10:52 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin.park, sw0312.kim, dri-devel

> 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;
>  };

Is this an ABI change, where do you document to userspace that it can
use this field, have you bumped some userspace accessible version?

Dave.

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

* Re: [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support
  2012-03-15 10:52   ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Dave Airlie
@ 2012-03-15 10:59     ` Joonyoung Shim
  0 siblings, 0 replies; 28+ messages in thread
From: Joonyoung Shim @ 2012-03-15 10:59 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Inki Dae, kyungmin.park, sw0312.kim, dri-devel

On 03/15/2012 07:52 PM, Dave Airlie wrote:
>> 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;
>>   };
> Is this an ABI change, where do you document to userspace that it can
> use this field, have you bumped some userspace accessible version?
>

No, this doesn't related with user space currently.

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

* Re: [PATCH 09/10] drm/exynos: add G2D driver
  2012-03-15 10:50   ` Dave Airlie
@ 2012-03-15 11:05     ` Joonyoung Shim
  2012-03-16  6:28     ` Joonyoung Shim
  1 sibling, 0 replies; 28+ messages in thread
From: Joonyoung Shim @ 2012-03-15 11:05 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Inki Dae, kyungmin.park, sw0312.kim, dri-devel

On 03/15/2012 07:50 PM, Dave Airlie wrote:
>> G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
>> G2D driver is exynos drm specific and supports only exynos4x12 series.
>> user application fills command set in cmdlist and once dma start request
>> these cmdlists are parsed and performed by dma.
> Where is this block documented or a pointer to the corresponding open
> userspace user code?
>
> Again the ioctls look like they need to be depointered and use __u64.
>
> It would be nice if you could document how the command stream and engine work.
>
> How does userspace pass addresses to it? straight or via gem objects?
> how does it
> stop userspace blt to places it shouldn't etc.
>
> I'm getting the feeling this accel enabled driver needs a lot more of
> a commit message
> and lot more documentation on what it can be used for.

OK, i will update the more documentation and simple user space program.

Thanks.

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

* RE: [PATCH 02/10] drm/exynos: added mode_fixup feature and code clean.
  2012-03-15 10:39   ` Dave Airlie
@ 2012-03-15 11:21     ` Inki Dae
  2012-03-16  4:52       ` InKi Dae
  0 siblings, 1 reply; 28+ messages in thread
From: Inki Dae @ 2012-03-15 11:21 UTC (permalink / raw)
  To: 'Dave Airlie'; +Cc: kyungmin.park, sw0312.kim, dri-devel

> -----Original Message-----
> From: Dave Airlie [mailto:airlied@gmail.com]
> Sent: Thursday, March 15, 2012 7:40 PM
> To: Inki Dae
> Cc: airlied@linux.ie; dri-devel@lists.freedesktop.org;
> kyungmin.park@samsung.com; sw0312.kim@samsung.com
> Subject: Re: [PATCH 02/10] drm/exynos: added mode_fixup feature and code
> clean.
> 
> >  };
> > 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));
> 
> This just seems wrong on lots of levels, if you get an error how are
> you going to fallback?
> 
> You should be passing the modes into the crtc_update function and
> doing things like other drivers here.
> 
> Dave.

Got it. I will check return value from crtc_update and if it gets an error
then I will handle it properly.

Thanks,
Inki Dae

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

* RE: [PATCH 10/10] drm/exynos: added virtual display driver.
  2012-03-15 10:44   ` Dave Airlie
@ 2012-03-15 11:36     ` Inki Dae
  2012-03-15 11:43       ` David Airlie
  0 siblings, 1 reply; 28+ messages in thread
From: Inki Dae @ 2012-03-15 11:36 UTC (permalink / raw)
  To: 'Dave Airlie'; +Cc: kyungmin.park, sw0312.kim, dri-devel



> -----Original Message-----
> From: Dave Airlie [mailto:airlied@gmail.com]
> Sent: Thursday, March 15, 2012 7:44 PM
> To: Inki Dae
> Cc: dri-devel@lists.freedesktop.org; kyungmin.park@samsung.com;
> sw0312.kim@samsung.com
> Subject: Re: [PATCH 10/10] drm/exynos: added virtual display driver.
> 
> > diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
> > index 907daaf..1123342 100644
> > --- a/include/drm/exynos_drm.h
> > +++ b/include/drm/exynos_drm.h
> > @@ -76,6 +76,22 @@ 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.
> > + * @pad: just padding to be 64-bit aligned.
> > + * @edid: the edid data pointer from user side.
> > + */
> > +struct drm_exynos_vidi_connection {
> > +       unsigned int connection;
> > +       unsigned int extensions;
> > +       unsigned int pad;
> > +       void *edid;
> > +};
> > +
> 
> No void * in ioctl structs use u64, also not sure why you have a
> 32-bit pad since you probably want it padded to 64-bit.
> 
> Dave.

Yes, right. I wanted it to be padded to 64-bit. and edid would point to
buffer containing edit data and it would be passed from user to kernel side
so for this, is it right to use u64? I will change variable type to "void
__user *" if your missing point. please let me know if there is any problem.

Thanks,
Inki Dae

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

* Re: [PATCH 10/10] drm/exynos: added virtual display driver.
  2012-03-15 11:36     ` Inki Dae
@ 2012-03-15 11:43       ` David Airlie
  2012-03-15 12:01         ` Inki Dae
  0 siblings, 1 reply; 28+ messages in thread
From: David Airlie @ 2012-03-15 11:43 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin park, sw0312 kim, dri-devel



----- Original Message -----
> From: "Inki Dae" <inki.dae@samsung.com>
> To: "Dave Airlie" <airlied@gmail.com>
> Cc: "kyungmin park" <kyungmin.park@samsung.com>, "sw0312 kim" <sw0312.kim@samsung.com>,
> dri-devel@lists.freedesktop.org
> Sent: Thursday, 15 March, 2012 11:36:14 AM
> Subject: RE: [PATCH 10/10] drm/exynos: added virtual display driver.
> 
> 
> 
> > -----Original Message-----
> > From: Dave Airlie [mailto:airlied@gmail.com]
> > Sent: Thursday, March 15, 2012 7:44 PM
> > To: Inki Dae
> > Cc: dri-devel@lists.freedesktop.org; kyungmin.park@samsung.com;
> > sw0312.kim@samsung.com
> > Subject: Re: [PATCH 10/10] drm/exynos: added virtual display
> > driver.
> > 
> > > diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
> > > index 907daaf..1123342 100644
> > > --- a/include/drm/exynos_drm.h
> > > +++ b/include/drm/exynos_drm.h
> > > @@ -76,6 +76,22 @@ 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.
> > > + * @pad: just padding to be 64-bit aligned.
> > > + * @edid: the edid data pointer from user side.
> > > + */
> > > +struct drm_exynos_vidi_connection {
> > > +       unsigned int connection;
> > > +       unsigned int extensions;
> > > +       unsigned int pad;
> > > +       void *edid;
> > > +};
> > > +
> > 
> > No void * in ioctl structs use u64, also not sure why you have a
> > 32-bit pad since you probably want it padded to 64-bit.
> > 
> > Dave.
> 
> Yes, right. I wanted it to be padded to 64-bit. and edid would point
> to
> buffer containing edit data and it would be passed from user to
> kernel side
> so for this, is it right to use u64? I will change variable type to
> "void
> __user *" if your missing point. please let me know if there is any
> problem.
> 

You need to use __u64 instead of a void, since void * isn't a fixed length across 32/64-bit.

You'll notice this done a few places in the drm kms interfaces.

Dave.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* RE: [PATCH 10/10] drm/exynos: added virtual display driver.
  2012-03-15 11:43       ` David Airlie
@ 2012-03-15 12:01         ` Inki Dae
  0 siblings, 0 replies; 28+ messages in thread
From: Inki Dae @ 2012-03-15 12:01 UTC (permalink / raw)
  To: 'David Airlie'
  Cc: 'kyungmin park', 'sw0312 kim', dri-devel



> -----Original Message-----
> From: David Airlie [mailto:airlied@redhat.com]
> Sent: Thursday, March 15, 2012 8:44 PM
> To: Inki Dae
> Cc: kyungmin park; sw0312 kim; dri-devel@lists.freedesktop.org; Dave
> Airlie
> Subject: Re: [PATCH 10/10] drm/exynos: added virtual display driver.
> 
> 
> 
> ----- Original Message -----
> > From: "Inki Dae" <inki.dae@samsung.com>
> > To: "Dave Airlie" <airlied@gmail.com>
> > Cc: "kyungmin park" <kyungmin.park@samsung.com>, "sw0312 kim"
> <sw0312.kim@samsung.com>,
> > dri-devel@lists.freedesktop.org
> > Sent: Thursday, 15 March, 2012 11:36:14 AM
> > Subject: RE: [PATCH 10/10] drm/exynos: added virtual display driver.
> >
> >
> >
> > > -----Original Message-----
> > > From: Dave Airlie [mailto:airlied@gmail.com]
> > > Sent: Thursday, March 15, 2012 7:44 PM
> > > To: Inki Dae
> > > Cc: dri-devel@lists.freedesktop.org; kyungmin.park@samsung.com;
> > > sw0312.kim@samsung.com
> > > Subject: Re: [PATCH 10/10] drm/exynos: added virtual display
> > > driver.
> > >
> > > > diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
> > > > index 907daaf..1123342 100644
> > > > --- a/include/drm/exynos_drm.h
> > > > +++ b/include/drm/exynos_drm.h
> > > > @@ -76,6 +76,22 @@ 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.
> > > > + * @pad: just padding to be 64-bit aligned.
> > > > + * @edid: the edid data pointer from user side.
> > > > + */
> > > > +struct drm_exynos_vidi_connection {
> > > > +       unsigned int connection;
> > > > +       unsigned int extensions;
> > > > +       unsigned int pad;
> > > > +       void *edid;
> > > > +};
> > > > +
> > >
> > > No void * in ioctl structs use u64, also not sure why you have a
> > > 32-bit pad since you probably want it padded to 64-bit.
> > >
> > > Dave.
> >
> > Yes, right. I wanted it to be padded to 64-bit. and edid would point
> > to
> > buffer containing edit data and it would be passed from user to
> > kernel side
> > so for this, is it right to use u64? I will change variable type to
> > "void
> > __user *" if your missing point. please let me know if there is any
> > problem.
> >
> 
> You need to use __u64 instead of a void, since void * isn't a fixed length
> across 32/64-bit.
> 
> You'll notice this done a few places in the drm kms interfaces.
> 
> Dave.

Ok, got it. thanks for your comment.

Inki Dae

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

* Re: [PATCH 02/10] drm/exynos: added mode_fixup feature and code clean.
  2012-03-15 11:21     ` Inki Dae
@ 2012-03-16  4:52       ` InKi Dae
  0 siblings, 0 replies; 28+ messages in thread
From: InKi Dae @ 2012-03-16  4:52 UTC (permalink / raw)
  To: Inki Dae; +Cc: sw0312.kim, kyungmin.park, dri-devel

Hi Dave.

2012년 3월 15일 오후 8:21, Inki Dae <inki.dae@samsung.com>님의 말:
>> -----Original Message-----
>> From: Dave Airlie [mailto:airlied@gmail.com]
>> Sent: Thursday, March 15, 2012 7:40 PM
>> To: Inki Dae
>> Cc: airlied@linux.ie; dri-devel@lists.freedesktop.org;
>> kyungmin.park@samsung.com; sw0312.kim@samsung.com
>> Subject: Re: [PATCH 02/10] drm/exynos: added mode_fixup feature and code
>> clean.
>>
>> >  };
>> > 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));
>>
>> This just seems wrong on lots of levels, if you get an error how are
>> you going to fallback?
>>
>> You should be passing the modes into the crtc_update function and
>> doing things like other drivers here.
>>
>> Dave.
>

I have looked into the part you pointed out but I think it's ok.
exynos_drm_crtc_update just sets mode values to overlay structure and
overlay structure is common data structure that all hardware can use
and exynos crtc has no hardware defendency so we could use it commoly
for all hardware such as FIMD, HDMI and Virtual Display. so with
exynos_drm_crtc_update call, any hardward isn't updated. if
exynos_drm_crtc_update is fail then adjusted_mode would be released
and back to saved_mode. only if crtc_func->mode_set is true then
hardware would be updated. please let me know if there is my missing
point.

Thanks,
Inki Dae



> Got it. I will check return value from crtc_update and if it gets an error
> then I will handle it properly.
>
> Thanks,
> Inki Dae
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 09/10] drm/exynos: add G2D driver
  2012-03-15 10:50   ` Dave Airlie
  2012-03-15 11:05     ` Joonyoung Shim
@ 2012-03-16  6:28     ` Joonyoung Shim
  2013-01-20 17:33       ` Rob Clark
  1 sibling, 1 reply; 28+ messages in thread
From: Joonyoung Shim @ 2012-03-16  6:28 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Inki Dae, kyungmin.park, sw0312.kim, dri-devel

[-- Attachment #1: Type: text/plain, Size: 1263 bytes --]

On 03/15/2012 07:50 PM, Dave Airlie wrote:
>> G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
>> G2D driver is exynos drm specific and supports only exynos4x12 series.
>> user application fills command set in cmdlist and once dma start request
>> these cmdlists are parsed and performed by dma.
> Where is this block documented or a pointer to the corresponding open
> userspace user code?

I attach simple g2dtest program patch. The base of this patch is master
branch of lastest libdrm git.

This user progrem can test just solid color fill example.
I will cleanup and update it for more operations later.

Thanks.

> Again the ioctls look like they need to be depointered and use __u64.
>
> It would be nice if you could document how the command stream and engine work.
>
> How does userspace pass addresses to it? straight or via gem objects?
> how does it
> stop userspace blt to places it shouldn't etc.
>
> I'm getting the feeling this accel enabled driver needs a lot more of
> a commit message
> and lot more documentation on what it can be used for.
>
> Dave.
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>


[-- Attachment #2: 0001-Add-simple-g2dtest.patch --]
[-- Type: text/x-patch, Size: 26524 bytes --]

>From 845c0a1bbf67b342099c5eae6f573063af8fc023 Mon Sep 17 00:00:00 2001
From: Joonyoung Shim <jy0922.shim@samsung.com>
Date: Fri, 16 Mar 2012 15:13:45 +0900
Subject: [PATCH] Add simple g2dtest

This can test only solid color fill.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
---
 configure.ac              |    1 +
 include/drm/exynos_drm.h  |  185 ++++++++++++++
 tests/Makefile.am         |    2 +-
 tests/g2dtest/Makefile.am |   16 ++
 tests/g2dtest/g2d.h       |   64 +++++
 tests/g2dtest/g2d_reg.h   |  108 ++++++++
 tests/g2dtest/g2dtest.c   |  612 +++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 987 insertions(+), 1 deletions(-)
 create mode 100644 include/drm/exynos_drm.h
 create mode 100644 tests/g2dtest/Makefile.am
 create mode 100644 tests/g2dtest/g2d.h
 create mode 100644 tests/g2dtest/g2d_reg.h
 create mode 100644 tests/g2dtest/g2dtest.c

diff --git a/configure.ac b/configure.ac
index 71a596c..1b51b65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -297,6 +297,7 @@ AC_CONFIG_FILES([
 	tests/kmstest/Makefile
 	tests/radeon/Makefile
 	tests/vbltest/Makefile
+	tests/g2dtest/Makefile
 	include/Makefile
 	include/drm/Makefile
 	libdrm.pc])
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
new file mode 100644
index 0000000..701dbd9
--- /dev/null
+++ b/include/drm/exynos_drm.h
@@ -0,0 +1,185 @@
+/* exynos_drm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Authors:
+ *	Inki Dae <inki.dae@samsung.com>
+ *	Joonyoung Shim <jy0922.shim@samsung.com>
+ *	Seung-Woo Kim <sw0312.kim@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_H_
+#define _EXYNOS_DRM_H_
+
+#include "drm.h"
+
+/**
+ * User-desired buffer creation information structure.
+ *
+ * @size: user-desired memory allocation size.
+ *	- this size value would be page-aligned internally.
+ * @flags: user request for setting memory type or cache attributes.
+ * @handle: returned a handle to created gem object.
+ *	- this handle will be set by gem module of kernel side.
+ */
+struct drm_exynos_gem_create {
+	uint64_t size;
+	unsigned int flags;
+	unsigned int handle;
+};
+
+/**
+ * A structure for getting buffer offset.
+ *
+ * @handle: a pointer to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @offset: relatived offset value of the memory region allocated.
+ *	- this value should be set by user.
+ */
+struct drm_exynos_gem_map_off {
+	unsigned int handle;
+	unsigned int pad;
+	uint64_t offset;
+};
+
+/**
+ * A structure for mapping buffer.
+ *
+ * @handle: a handle to gem object created.
+ * @size: memory size to be mapped.
+ * @mapped: having user virtual address mmaped.
+ *	- this variable would be filled by exynos gem module
+ *	of kernel side with user virtual address which is allocated
+ *	by do_mmap().
+ */
+struct drm_exynos_gem_mmap {
+	unsigned int handle;
+	unsigned int size;
+	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.
+ * @pad: just padding to be 64-bit aligned.
+ * @edid: the edid data pointer from user side.
+ */
+struct drm_exynos_vidi_connection {
+	unsigned int connection;
+	unsigned int extensions;
+	unsigned int pad;
+	void *edid;
+};
+
+struct drm_exynos_plane_set_zpos {
+	__u32 crtc_id;
+	__u32 plane_id;
+	__s32 zpos;
+	__u32 pad;
+};
+
+/* memory type definitions. */
+enum e_drm_exynos_gem_mem_type {
+	/* Physically Non-Continuous memory. */
+	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
+#define DRM_EXYNOS_VIDI_CONNECTION	0x07
+
+/* 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)
+
+#define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off)
+
+#define DRM_IOCTL_EXYNOS_GEM_MMAP	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
+
+#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 + \
+		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;
+};
+
+#endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a3a59bd..58a4d36 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -13,7 +13,7 @@ check_PROGRAMS = \
 SUBDIRS = modeprint
 
 if HAVE_LIBKMS
-SUBDIRS += kmstest modetest
+SUBDIRS += kmstest modetest g2dtest
 endif
 
 if HAVE_RADEON
diff --git a/tests/g2dtest/Makefile.am b/tests/g2dtest/Makefile.am
new file mode 100644
index 0000000..17d78cf
--- /dev/null
+++ b/tests/g2dtest/Makefile.am
@@ -0,0 +1,16 @@
+AM_CFLAGS = \
+	-I$(top_srcdir)/include/drm \
+	-I$(top_srcdir)/libkms/ \
+	-I$(top_srcdir) \
+	$(CAIRO_CFLAGS)
+
+noinst_PROGRAMS = \
+	g2dtest
+
+g2dtest_SOURCES = \
+	g2dtest.c
+
+g2dtest_LDADD = \
+	$(top_builddir)/libdrm.la \
+	$(top_builddir)/libkms/libkms.la \
+	$(CAIRO_LIBS)
diff --git a/tests/g2dtest/g2d.h b/tests/g2dtest/g2d.h
new file mode 100644
index 0000000..1a62880
--- /dev/null
+++ b/tests/g2dtest/g2d.h
@@ -0,0 +1,64 @@
+#ifndef _G2D_H_
+#define _G2D_H_
+
+#include "g2d_reg.h"
+
+typedef enum {
+	G2D_SELECT_MODE_NORMAL = (0 << 0),
+	G2D_SELECT_MODE_FGCOLOR = (1 << 0),
+	G2D_SELECT_MODE_BGCOLOR = (2 << 0),
+	G2D_SELECT_MODE_MAX = (3 << 0),
+} G2dSelectMode;
+
+typedef enum {
+	/* COLOR FORMAT */
+	G2D_COLOR_FMT_XRGB8888,
+	G2D_COLOR_FMT_ARGB8888,
+	G2D_COLOR_FMT_RGB565,
+	G2D_COLOR_FMT_XRGB1555,
+	G2D_COLOR_FMT_ARGB1555,
+	G2D_COLOR_FMT_XRGB4444,
+	G2D_COLOR_FMT_ARGB4444,
+	G2D_COLOR_FMT_PRGB888,
+	G2D_COLOR_FMT_YCbCr444,
+	G2D_COLOR_FMT_YCbCr422,
+	G2D_COLOR_FMT_YCbCr420 = 10,
+	G2D_COLOR_FMT_A8,                       /* alpha 8bit */
+	G2D_COLOR_FMT_L8,                       /* Luminance 8bit: gray color */
+	G2D_COLOR_FMT_A1,                       /* alpha 1bit */
+	G2D_COLOR_FMT_A4,                       /* alpha 4bit */
+	G2D_COLOR_FMT_MASK = (15 << 0),		/* VER4.1 */
+
+	/* COLOR ORDER */
+	G2D_ORDER_AXRGB = (0 << 4),			/* VER4.1 */
+	G2D_ORDER_RGBAX = (1 << 4),			/* VER4.1 */
+	G2D_ORDER_AXBGR = (2 << 4),			/* VER4.1 */
+	G2D_ORDER_BGRAX = (3 << 4),			/* VER4.1 */
+	G2D_ORDER_MASK = (3 << 4),			/* VER4.1 */
+
+	/* Number of YCbCr plane */
+	G2D_YCbCr_1PLANE = (0 << 8),			/* VER4.1 */
+	G2D_YCbCr_2PLANE = (1 << 8),			/* VER4.1 */
+	G2D_YCbCr_PLANE_MASK = (3 << 8),		/* VER4.1 */
+
+	/* Order in YCbCr */
+	G2D_YCbCr_ORDER_CrY1CbY0 = (0 << 12),		/* VER4.1 */
+	G2D_YCbCr_ORDER_CbY1CrY0 = (1 << 12),		/* VER4.1 */
+	G2D_YCbCr_ORDER_Y1CrY0Cb = (2 << 12),		/* VER4.1 */
+	G2D_YCbCr_ORDER_Y1CbY0Cr = (3 << 12),		/* VER4.1 */
+	G2D_YCbCr_ORDER_MASK = (3 < 12),		/* VER4.1 */
+
+	/* CSC */
+	G2D_CSC_601 = (0 << 16),			/* VER4.1 */
+	G2D_CSC_709 = (1 << 16),			/* VER4.1 */
+	G2D_CSC_MASK = (1 << 16),			/* VER4.1 */
+
+	/* Valid value range of YCbCr */
+	G2D_YCbCr_RANGE_NARROW = (0 << 17),		/* VER4.1 */
+	G2D_YCbCr_RANGE_WIDE = (1 << 17),		/* VER4.1 */
+	G2D_YCbCr_RANGE_MASK= (1 << 17),		/* VER4.1 */
+
+	G2D_COLOR_MODE_MASK = 0xFFFFFFFF
+} G2dColorMode;
+
+#endif /* _G2D_H_ */
diff --git a/tests/g2dtest/g2d_reg.h b/tests/g2dtest/g2d_reg.h
new file mode 100644
index 0000000..b991681
--- /dev/null
+++ b/tests/g2dtest/g2d_reg.h
@@ -0,0 +1,108 @@
+#ifndef _G2D_REG_H_
+#define _G2D_REG_H_
+
+/* Registers */
+/* GEBERAL REGISTER */
+#define SOFT_RESET_REG			(0x0000)
+#define INTEN_REG			(0x0004)
+#define INTC_PEND_REG			(0x000c)
+#define FIFO_STAT_REG			(0x0010)
+#define AXI_MODE_REG			(0x001C)
+#define DMA_SFR_BASE_ADDR_REG		(0x0080)
+#define DMA_COMMAND_REG			(0x0084)
+#define DMA_EXE_LIST_NUM_REG		(0x0088)
+#define DMA_STATUS_REG			(0x008C)
+#define DMA_HOLD_CMD_REG		(0x0090)
+
+/* COMMAND REGISTER */
+#define BITBLT_START_REG		(0x0100)
+#define BITBLT_COMMAND_REG		(0x0104)
+#define BLEND_FUNCTION_REG		(0x0108)	/* VER4.1 */
+#define ROUND_MODE_REG			(0x010C)	/* VER4.1 */
+
+/* PARAMETER SETTING REGISTER */
+
+/*	ROTATE and DIRECTION	*/
+#define ROTATE_REG			(0x0200)
+#define SRC_MASK_DIRECT_REG		(0x0204)
+#define DST_PAT_DIRECT_REG		(0x0208)
+
+/*	SOURCE	*/
+#define SRC_SELECT_REG			(0x0300)
+#define SRC_BASE_ADDR_REG		(0x0304)
+#define SRC_STRIDE_REG			(0x0308)
+#define SRC_COLOR_MODE_REG		(0x030c)
+#define SRC_LEFT_TOP_REG		(0x0310)
+#define SRC_RIGHT_BOTTOM_REG		(0x0314)
+#define SRC_PLANE2_BASE_ADDR_REG	(0x0318)	/* VER4.1 */
+#define SRC_REPEAT_MODE_REG		(0x031C)
+#define SRC_PAD_VALUE_REG		(0x0320)
+#define SRC_A8_RGB_EXT_REG		(0x0324)
+#define SRC_SCALE_CTRL_REG		(0x0328)
+#define SRC_XSCALE_REG			(0x032C)
+#define SRC_YSCALE_REG			(0x0330)
+
+/*	DESTINATION	*/
+#define DST_SELECT_REG			(0x0400)
+#define DST_BASE_ADDR_REG		(0x0404)
+#define DST_STRIDE_REG			(0x0408)
+#define DST_COLOR_MODE_REG		(0x040C)
+#define DST_LEFT_TOP_REG		(0x0410)
+#define DST_RIGHT_BOTTOM_REG		(0x0414)
+#define DST_PLANE2_BASE_ADDR_REG	(0x0418)	/* VER4.1 */
+#define DST_A8_RGB_EXT_REG		(0x041C)
+
+/*	PATTERN	*/
+#define PAT_BASE_ADDR_REG		(0x0500)
+#define PAT_SIZE_REG			(0x0504)
+#define PAT_COLOR_MODE_REG		(0x0508)
+#define PAT_OFFSET_REG			(0x050C)
+#define PAT_STRIDE_REG			(0x0510)
+
+/*	MASK	*/
+#define MASK_BASE_ADDR_REG		(0x0520)
+#define MASK_STRIDE_REG			(0x0524)
+#define MASK_LEFT_TOP_REG		(0x0528)	/* VER4.1 */
+#define MASK_RIGHT_BOTTOM_REG		(0x052C)	/* VER4.1 */
+#define MASK_MODE_REG			(0x0530)	/* VER4.1 */
+#define MASK_REPEAT_MODE_REG		(0x0534)
+#define MASK_PAD_VALUE_REG		(0x0538)
+#define MASK_SCALE_CTRL_REG		(0x053C)
+#define MASK_XSCALE_REG			(0x0540)
+#define MASK_YSCALE_REG			(0x0544)
+
+/* CLIPPING WINDOW */
+#define CW_LT_REG			(0x0600)
+#define CW_RB_REG			(0x0604)
+
+/* ROP & ALPHA SETTING */
+#define THIRD_OPERAND_REG		(0x0610)
+#define ROP4_REG			(0x0614)
+#define ALPHA_REG			(0x0618)
+
+/* COLOR SETTING */
+#define FG_COLOR_REG			(0x0700)
+#define BG_COLOR_REG			(0x0704)
+#define BS_COLOR_REG			(0x0708)
+#define SF_COLOR_REG			(0x070C)	/* VER4.1 */
+
+/* COLOR KEY */
+#define SRC_COLORKEY_CTRL_REG		(0x0710)
+#define SRC_COLORKEY_DR_MIN_REG		(0x0714)
+#define SRC_COLORKEY_DR_MAX_REG		(0x0718)
+#define DST_COLORKEY_CTRL_REG		(0x071C)
+#define DST_COLORKEY_DR_MIN_REG		(0x0720)
+#define DST_COLORKEY_DR_MAX_REG		(0x0724)
+/*	YCbCr src Color Key	*/
+#define YCbCr_SRC_COLORKEY_CTRL_REG	(0x0728)	/* VER4.1 */
+#define YCbCr_SRC_COLORKEY_DR_MIN_REG	(0x072C)	/* VER4.1 */
+#define YCbCr_SRC_COLORKEY_DR_MAX_REG	(0x0730)	/* VER4.1 */
+/*	YCbCr dst Color Key	*/
+#define YCbCr_DST_COLORKEY_CTRL_REG	(0x0734)	/* VER4.1 */
+#define YCbCr_DST_COLORKEY_DR_MIN_REG	(0x0738)	/* VER4.1 */
+#define YCbCr_DST_COLORKEY_DR_MAX_REG	(0x073C)	/* VER4.1 */
+
+/* bits of BITBLT_COMMAND_REG */
+#define	G2D_FAST_SOLID_COLOR_FILL	(1 << 28)
+
+#endif /* _G2D_REG_H_ */
diff --git a/tests/g2dtest/g2dtest.c b/tests/g2dtest/g2dtest.c
new file mode 100644
index 0000000..4521cd4
--- /dev/null
+++ b/tests/g2dtest/g2dtest.c
@@ -0,0 +1,612 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+#include "exynos_drm.h"
+#include "drm_fourcc.h"
+#include "g2d.h"
+
+#define DRM_MODULE_NAME		"exynos-drm"
+
+struct connector {
+	uint32_t id;
+	char mode_str[64];
+	drmModeModeInfo *mode;
+	drmModeEncoder *encoder;
+	int crtc;
+	int plane_zpos;
+	unsigned int fb_id[2], current_fb_id;
+	struct timeval start;
+
+	int swap_count;
+};
+
+struct drm_buffer {
+	struct drm_exynos_gem_create	gem;
+	struct drm_exynos_gem_mmap	gem_mmap;
+};
+
+struct drm_fb {
+	uint32_t			id;
+	struct drm_buffer		drm_buffer;
+};
+
+struct drm_desc {
+	int				fd;
+	struct connector		connector;
+	int				plane_id[5];
+	int				width;
+	int				height;
+};
+
+enum format {
+	FMT_RGB565,
+	FMT_RGB888,
+	FMT_NV12M,
+};
+
+static void connector_find_mode(int fd, struct connector *c,
+				drmModeRes *resources)
+{
+	drmModeConnector *connector;
+	int i, j;
+
+	/* First, find the connector & mode */
+	c->mode = NULL;
+	for (i = 0; i < resources->count_connectors; i++) {
+		connector = drmModeGetConnector(fd, resources->connectors[i]);
+
+		if (!connector) {
+			fprintf(stderr, "could not get connector %i: %s\n",
+				resources->connectors[i], strerror(errno));
+			drmModeFreeConnector(connector);
+			continue;
+		}
+
+		if (!connector->count_modes) {
+			drmModeFreeConnector(connector);
+			continue;
+		}
+
+		if (connector->connector_id != c->id) {
+			drmModeFreeConnector(connector);
+			continue;
+		}
+
+		for (j = 0; j < connector->count_modes; j++) {
+			c->mode = &connector->modes[j];
+			if (!strcmp(c->mode->name, c->mode_str))
+				break;
+		}
+
+		/* Found it, break out */
+		if (c->mode)
+			break;
+
+		drmModeFreeConnector(connector);
+	}
+
+	if (!c->mode) {
+		fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
+		return;
+	}
+
+	/* Now get the encoder */
+	for (i = 0; i < resources->count_encoders; i++) {
+		c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
+
+		if (!c->encoder) {
+			fprintf(stderr, "could not get encoder %i: %s\n",
+				resources->encoders[i], strerror(errno));
+			drmModeFreeEncoder(c->encoder);
+			continue;
+		}
+
+		if (c->encoder->encoder_id  == connector->encoder_id)
+			break;
+
+		drmModeFreeEncoder(c->encoder);
+	}
+
+	if (c->crtc == -1)
+		c->crtc = c->encoder->crtc_id;
+}
+
+static int connector_find_plane(int fd, unsigned int *plane_id)
+{
+	drmModePlaneRes *plane_resources;
+	drmModePlane *ovr;
+	int i;
+
+	plane_resources = drmModeGetPlaneResources(fd);
+	if (!plane_resources) {
+		fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
+			strerror(errno));
+		return -1;
+	}
+
+	for (i = 0; i < plane_resources->count_planes; i++) {
+		plane_id[i] = 0;
+
+		ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
+		if (!ovr) {
+			fprintf(stderr, "drmModeGetPlane failed: %s\n",
+				strerror(errno));
+			continue;
+		}
+
+		if (ovr->possible_crtcs & (1 << 0))
+			plane_id[i] = ovr->plane_id;
+		drmModeFreePlane(ovr);
+	}
+
+	return 0;
+}
+
+static int exynos_g2d_get_ver(int fd, struct drm_exynos_g2d_get_ver *ver)
+{
+	int ret;
+
+	ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, ver);
+	if (ret < 0) {
+		fprintf(stderr, "failed to get version: %s\n", strerror(-ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_g2d_set_cmdlist(int fd,
+				  struct drm_exynos_g2d_set_cmdlist *cmdlist)
+{
+	int ret;
+
+	ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, cmdlist);
+	if (ret < 0) {
+		fprintf(stderr, "failed to set cmdlist: %s\n", strerror(-ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_g2d_exec(int fd, int async)
+{
+	struct drm_exynos_g2d_exec exec;
+	int ret;
+
+	exec.async = async;
+	ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec);
+	if (ret < 0) {
+		fprintf(stderr, "failed to execute: %s\n", strerror(-ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_plane_set_zpos(int fd, unsigned int plane_id, int zpos)
+{
+	struct drm_exynos_plane_set_zpos zpos_req;
+	int ret;
+
+	zpos_req.plane_id = plane_id;
+	zpos_req.zpos = zpos;
+
+	ret = ioctl(fd, DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS, &zpos_req);
+	if (ret < 0) {
+		fprintf(stderr, "failed to set plane zpos: %s\n",
+				strerror(-ret));
+		return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem)
+{
+	int ret;
+
+	if (!gem)
+		return -EINVAL;
+
+	ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, gem);
+	if (ret < 0)
+		perror("ioctl failed\n");
+
+	return ret;
+}
+
+static int exynos_gem_map_offset(int fd, struct drm_exynos_gem_map_off *map_off)
+{
+	int ret;
+
+	if (!map_off)
+		return -EINVAL;
+
+	ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET, map_off);
+	if (ret < 0)
+		perror("ioctl failed\n");
+
+	return ret;
+}
+
+static int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap)
+{
+	int ret;
+
+	if (!in_mmap)
+		return -EINVAL;
+
+	ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MMAP, in_mmap);
+	if (ret < 0)
+		perror("ioctl failed\n");
+
+	return ret;
+}
+
+static int exynos_gem_close(int fd, struct drm_gem_close *gem_close)
+{
+	int ret;
+
+	if (!gem_close)
+		return -EINVAL;
+
+	ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, gem_close);
+	if (ret < 0)
+		perror("ioctl failed\n");
+
+	return ret;
+}
+
+static struct drm_desc *drm_alloc_desc(void)
+{
+	struct drm_desc *drm_desc;
+
+	drm_desc = malloc(sizeof(struct drm_desc));
+	if (!drm_desc) {
+		perror("memory alloc error\n");
+		return NULL;
+	}
+	memset(drm_desc, 0, sizeof(struct drm_desc));
+
+	return drm_desc;
+}
+
+static int drm_open(struct drm_desc *drm_desc)
+{
+	if (!drm_desc) {
+		fprintf(stderr, "drm_desc is NULL\n");
+		return -EINVAL;
+	}
+
+	drm_desc->fd = drmOpen(DRM_MODULE_NAME, NULL);
+	if (drm_desc->fd < 0) {
+		printf("Failed to open %s module\n", DRM_MODULE_NAME);
+		return drm_desc->fd;
+	}
+
+	return 0;
+}
+
+static int drm_create_buffer(struct drm_desc *drm_desc, struct drm_fb *drm_fb,
+			     int width, int height)
+{
+	struct drm_buffer *drm_buffer;
+	unsigned int num_planes;
+	unsigned long size;
+	int i;
+	int ret;
+
+	if (!drm_desc)
+		return -EINVAL;
+
+	size = width * height * 4;
+
+	drm_buffer = &drm_fb->drm_buffer;
+
+	{
+		struct drm_exynos_gem_create *gem = &drm_buffer->gem;
+		struct drm_exynos_gem_mmap *gem_mmap = &drm_buffer->gem_mmap;
+
+		memset(gem, 0, sizeof(struct drm_exynos_gem_create));
+		gem->size = size;
+
+		ret = exynos_gem_create(drm_desc->fd, gem);
+		if (ret < 0) {
+			printf("failed to create gem\n");
+			goto err_gem;
+		}
+
+		gem_mmap->handle = gem->handle;
+		gem_mmap->size = gem->size;
+		ret = exynos_gem_mmap(drm_desc->fd, gem_mmap);
+		if (ret < 0) {
+			printf("failed to mmap gem directly\n");
+			goto err_gem;
+		}
+
+		/* init gem buffer */
+		memset((void *)(unsigned long)gem_mmap->mapped, 0,
+				gem_mmap->size);
+	}
+
+	return 0;
+
+err_gem:
+	{
+		struct drm_exynos_gem_create *gem = &drm_buffer->gem;
+		struct drm_gem_close gem_close;
+
+		gem_close.handle = gem->handle;
+		exynos_gem_close(drm_desc->fd, &gem_close);
+	}
+
+	return ret;
+}
+
+static int drm_create_fb(struct drm_desc *drm_desc, struct drm_fb *drm_fb,
+			 int width, int height)
+{
+	unsigned int pixel_format;
+	unsigned int num_planes;
+	unsigned int pitch;
+	int i;
+	int j;
+	int ret;
+
+	if (!drm_desc)
+		return -EINVAL;
+
+	drm_desc->width = width;
+	drm_desc->height = height;
+
+	pixel_format = DRM_FORMAT_RGBA8888;
+	num_planes = 1;
+	pitch = width * 4;
+
+	{
+		uint32_t bo[4] = {0,};
+		uint32_t pitches[4] = {0,};
+		uint32_t offset[4] = {0,};
+
+		ret = drm_create_buffer(drm_desc, drm_fb, width, height);
+		if (ret < 0)
+			goto err;
+
+		for (j = 0; j < num_planes; j++) {
+			struct drm_buffer *drm_buffer = &drm_fb->drm_buffer;
+			struct drm_exynos_gem_create *gem = &drm_buffer->gem;
+
+			bo[j] = gem->handle;
+			pitches[j] = pitch;
+		}
+
+		ret = drmModeAddFB2(drm_desc->fd, width, height, pixel_format,
+				bo, pitches, offset, &drm_fb->id,
+				0);
+		if (ret < 0) {
+			perror("failed to add fb\n");
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	/* TODO: free buffer */
+	return ret;
+}
+
+static int drm_set_crtc(struct drm_desc *drm_desc, struct connector *c,
+			struct drm_fb *drm_fb)
+{
+	drmModeRes *resources;
+	int ret;
+
+	memcpy(&drm_desc->connector, c, sizeof(struct connector));
+
+	resources = drmModeGetResources(drm_desc->fd);
+	if (!resources) {
+		fprintf(stderr, "drmModeGetResources failed: %s\n",
+			strerror(errno));
+		ret = -EFAULT;
+		goto err;
+	}
+
+	connector_find_mode(drm_desc->fd, &drm_desc->connector, resources);
+	drmModeFreeResources(resources);
+
+	ret = drmModeSetCrtc(drm_desc->fd, drm_desc->connector.crtc,
+			drm_fb->id, 0, 0,
+			&drm_desc->connector.id, 1,
+			drm_desc->connector.mode);
+	if (ret) {
+		fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
+		goto err;
+	}
+
+	return 0;
+
+err:
+	/* TODO */
+	return ret;
+}
+
+static inline void set_cmd(struct drm_exynos_g2d_cmd *cmd,
+				      __u32 offset, __u32 data)
+{
+	cmd->offset = offset;
+	cmd->data = data;
+}
+
+static int exynos_g2d_test_solid_fill(struct drm_desc *drm_desc, int x, int y,
+				      int color, int gem_handle)
+{
+	struct drm_exynos_g2d_set_cmdlist cmdlist;
+	struct drm_exynos_g2d_cmd cmd[20];
+	struct drm_exynos_g2d_cmd cmd_gem[5];
+	int nr = 0;
+	int gem_nr = 0;
+	int ret;
+
+	memset(&cmdlist, 0, sizeof(struct drm_exynos_g2d_set_cmdlist));
+	memset(cmd, 0, sizeof(struct drm_exynos_g2d_cmd) * 20);
+	memset(cmd_gem, 0, sizeof(struct drm_exynos_g2d_cmd) * 5);
+
+	cmdlist.cmd = cmd;
+	cmdlist.cmd_gem = cmd_gem;
+
+	set_cmd(&cmd[nr++], BITBLT_COMMAND_REG, G2D_FAST_SOLID_COLOR_FILL);
+	/* [14:10] R, [9:5] G, [4:0] B */
+	set_cmd(&cmd[nr++], SF_COLOR_REG, color);
+
+	/* DST */
+	set_cmd(&cmd[nr++], DST_SELECT_REG, G2D_SELECT_MODE_FGCOLOR);
+	set_cmd(&cmd_gem[gem_nr++], DST_BASE_ADDR_REG, gem_handle);
+	set_cmd(&cmd[nr++], DST_STRIDE_REG, 720 * 4);
+	set_cmd(&cmd[nr++], DST_COLOR_MODE_REG, G2D_COLOR_FMT_ARGB8888 |
+						G2D_ORDER_AXRGB);
+	set_cmd(&cmd[nr++], DST_LEFT_TOP_REG, (0 << 16) | 0);
+	set_cmd(&cmd[nr++], DST_RIGHT_BOTTOM_REG, (y << 16) | x);
+	set_cmd(&cmd[nr++], DST_PLANE2_BASE_ADDR_REG, 0);
+	set_cmd(&cmd[nr++], DST_A8_RGB_EXT_REG, 0);
+
+	cmdlist.cmd_nr = nr;
+	cmdlist.cmd_gem_nr = gem_nr;
+
+	cmdlist.event_type = G2D_EVENT_NONSTOP;
+	cmdlist.user_data = 1234;
+
+	ret = exynos_g2d_set_cmdlist(drm_desc->fd, &cmdlist);
+	if (ret < 0)
+		return ret;
+}
+
+static int exynos_g2d_event(int fd)
+{
+	char buffer[1024];
+	int len, i;
+	struct drm_event *e;
+	struct drm_exynos_g2d_event *g2d_event;
+
+	len = read(fd, buffer, sizeof buffer);
+	if (len == 0)
+		return 0;
+	if (len < sizeof *e)
+		return -1;
+
+	i = 0;
+	while (i < len) {
+		e = (struct drm_event *) &buffer[i];
+		switch (e->type) {
+		case DRM_EXYNOS_G2D_EVENT:
+			g2d_event = (struct drm_exynos_g2d_event *) e;
+			printf("cmdlist_no: %d\n", g2d_event->cmdlist_no);
+			printf("user_data: %lld\n", g2d_event->user_data);
+			break;
+		default:
+			break;
+		}
+		i += e->length;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct connector con_args;
+	struct drm_desc *drm_desc;
+	struct drm_fb drm_fb;
+	struct drm_exynos_g2d_get_ver ver;
+	int x, y;
+	int ret;
+
+	/* default set of connector */
+	memset(&con_args, 0, sizeof(struct connector));
+	con_args.id = 12;
+	con_args.crtc = 3;
+	con_args.plane_zpos = -1;
+	strcpy(con_args.mode_str, "720x1280");
+	x = 720;
+	y = 1280;
+
+	drm_desc = drm_alloc_desc();
+	if (!drm_desc) {
+		ret = -1;
+		goto err_free;
+	}
+
+	ret = drm_open(drm_desc);
+	if (ret < 0)
+		goto err_free;
+
+	/* check version */
+	ret = exynos_g2d_get_ver(drm_desc->fd, &ver);
+	if (ret < 0)
+		return ret;
+
+	if (ver.major != 4 || ver.minor != 1) {
+		fprintf(stderr, "version(%d.%d) mismatch\n", ver.major, ver.minor);
+		return -1;
+	}
+	printf("g2d hw version: %d.%d\n", ver.major, ver.minor);
+
+	ret = drm_create_fb(drm_desc, &drm_fb, x, y);
+	if (ret < 0)
+		goto err_drm_close;
+
+	ret = drm_set_crtc(drm_desc, &con_args, &drm_fb);
+	if (ret < 0)
+		goto err;
+
+	getchar();
+
+	ret = exynos_g2d_test_solid_fill(drm_desc, x, y, 0x1f,
+					 drm_fb.drm_buffer.gem.handle);
+	if (ret < 0)
+		goto err;
+
+	ret = exynos_g2d_exec(drm_desc->fd, 1);
+	if (ret < 0)
+		return ret;
+
+	while (1) {
+		struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
+		fd_set fds;
+		int ret;
+
+		FD_ZERO(&fds);
+		FD_SET(0, &fds);
+		FD_SET(drm_desc->fd, &fds);
+		ret = select(drm_desc->fd + 1, &fds, NULL, NULL, &timeout);
+
+		if (ret <= 0) {
+			fprintf(stderr, "select timed out or error (ret %d)\n",
+				ret);
+			continue;
+		} else if (FD_ISSET(0, &fds)) {
+			break;
+		}
+
+		exynos_g2d_event(drm_desc->fd);
+	}
+
+	getchar();
+
+	/* TODO */
+
+err:
+	/* TODO */
+err_drm_close:
+	drmClose(drm_desc->fd);
+err_free:
+	if (drm_desc)
+		free(drm_desc);
+
+	return ret;
+}
-- 
1.7.5.4


[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 09/10] drm/exynos: add G2D driver
  2012-03-16  6:28     ` Joonyoung Shim
@ 2013-01-20 17:33       ` Rob Clark
  2013-01-22  1:33         ` Inki Dae
  0 siblings, 1 reply; 28+ messages in thread
From: Rob Clark @ 2013-01-20 17:33 UTC (permalink / raw)
  To: Joonyoung Shim; +Cc: sw0312.kim, kyungmin.park, dri-devel

I don't suppose you could send a libdrm patch to the list with an up
to date version of the g2dtest code so we can get it in libdrm tree?

BR,
-R

On Fri, Mar 16, 2012 at 1:28 AM, Joonyoung Shim <jy0922.shim@samsung.com> wrote:
> On 03/15/2012 07:50 PM, Dave Airlie wrote:
>>>
>>> G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
>>> G2D driver is exynos drm specific and supports only exynos4x12 series.
>>> user application fills command set in cmdlist and once dma start request
>>> these cmdlists are parsed and performed by dma.
>>
>> Where is this block documented or a pointer to the corresponding open
>> userspace user code?
>
>
> I attach simple g2dtest program patch. The base of this patch is master
> branch of lastest libdrm git.
>
> This user progrem can test just solid color fill example.
> I will cleanup and update it for more operations later.
>
> Thanks.
>
>
>> Again the ioctls look like they need to be depointered and use __u64.
>>
>> It would be nice if you could document how the command stream and engine
>> work.
>>
>> How does userspace pass addresses to it? straight or via gem objects?
>> how does it
>> stop userspace blt to places it shouldn't etc.
>>
>> I'm getting the feeling this accel enabled driver needs a lot more of
>> a commit message
>> and lot more documentation on what it can be used for.
>>
>> Dave.
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

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

* Re: [PATCH 09/10] drm/exynos: add G2D driver
  2013-01-20 17:33       ` Rob Clark
@ 2013-01-22  1:33         ` Inki Dae
  2013-01-22  1:41           ` Rob Clark
  0 siblings, 1 reply; 28+ messages in thread
From: Inki Dae @ 2013-01-22  1:33 UTC (permalink / raw)
  To: Rob Clark; +Cc: kyungmin.park, sw0312.kim, dri-devel

2013/1/21 Rob Clark <robdclark@gmail.com>:
> I don't suppose you could send a libdrm patch to the list with an up
> to date version of the g2dtest code so we can get it in libdrm tree?
>

We are planning on updating exynos drm for libdrm. At that time, the
up to date version of the g2dtest will be posted.
Joonyoung, let it post. And I will post other things except g2dtest.

Thanks,
Inki Dae

> BR,
> -R
>
> On Fri, Mar 16, 2012 at 1:28 AM, Joonyoung Shim <jy0922.shim@samsung.com> wrote:
>> On 03/15/2012 07:50 PM, Dave Airlie wrote:
>>>>
>>>> G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
>>>> G2D driver is exynos drm specific and supports only exynos4x12 series.
>>>> user application fills command set in cmdlist and once dma start request
>>>> these cmdlists are parsed and performed by dma.
>>>
>>> Where is this block documented or a pointer to the corresponding open
>>> userspace user code?
>>
>>
>> I attach simple g2dtest program patch. The base of this patch is master
>> branch of lastest libdrm git.
>>
>> This user progrem can test just solid color fill example.
>> I will cleanup and update it for more operations later.
>>
>> Thanks.
>>
>>
>>> Again the ioctls look like they need to be depointered and use __u64.
>>>
>>> It would be nice if you could document how the command stream and engine
>>> work.
>>>
>>> How does userspace pass addresses to it? straight or via gem objects?
>>> how does it
>>> stop userspace blt to places it shouldn't etc.
>>>
>>> I'm getting the feeling this accel enabled driver needs a lot more of
>>> a commit message
>>> and lot more documentation on what it can be used for.
>>>
>>> Dave.
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>
>>
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH 09/10] drm/exynos: add G2D driver
  2013-01-22  1:33         ` Inki Dae
@ 2013-01-22  1:41           ` Rob Clark
  0 siblings, 0 replies; 28+ messages in thread
From: Rob Clark @ 2013-01-22  1:41 UTC (permalink / raw)
  To: Inki Dae; +Cc: kyungmin.park, sw0312.kim, dri-devel

On Mon, Jan 21, 2013 at 7:33 PM, Inki Dae <inki.dae@samsung.com> wrote:
> 2013/1/21 Rob Clark <robdclark@gmail.com>:
>> I don't suppose you could send a libdrm patch to the list with an up
>> to date version of the g2dtest code so we can get it in libdrm tree?
>>
>
> We are planning on updating exynos drm for libdrm. At that time, the
> up to date version of the g2dtest will be posted.
> Joonyoung, let it post. And I will post other things except g2dtest.

thanks, I just want to make sure this doesn't get lost

BR,
-R

> Thanks,
> Inki Dae
>
>> BR,
>> -R
>>
>> On Fri, Mar 16, 2012 at 1:28 AM, Joonyoung Shim <jy0922.shim@samsung.com> wrote:
>>> On 03/15/2012 07:50 PM, Dave Airlie wrote:
>>>>>
>>>>> G2D is a 2D graphic accelerator that supports Bit Block Transfer. This
>>>>> G2D driver is exynos drm specific and supports only exynos4x12 series.
>>>>> user application fills command set in cmdlist and once dma start request
>>>>> these cmdlists are parsed and performed by dma.
>>>>
>>>> Where is this block documented or a pointer to the corresponding open
>>>> userspace user code?
>>>
>>>
>>> I attach simple g2dtest program patch. The base of this patch is master
>>> branch of lastest libdrm git.
>>>
>>> This user progrem can test just solid color fill example.
>>> I will cleanup and update it for more operations later.
>>>
>>> Thanks.
>>>
>>>
>>>> Again the ioctls look like they need to be depointered and use __u64.
>>>>
>>>> It would be nice if you could document how the command stream and engine
>>>> work.
>>>>
>>>> How does userspace pass addresses to it? straight or via gem objects?
>>>> how does it
>>>> stop userspace blt to places it shouldn't etc.
>>>>
>>>> I'm getting the feeling this accel enabled driver needs a lot more of
>>>> a commit message
>>>> and lot more documentation on what it can be used for.
>>>>
>>>> Dave.
>>>> _______________________________________________
>>>> dri-devel mailing list
>>>> dri-devel@lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>
>>>
>>>
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

end of thread, other threads:[~2013-01-22  1:41 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-13 14:46 [PATCH 00/10] updated exynos-drm-next Inki Dae
2012-03-13 14:46 ` [PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
2012-03-13 14:46 ` [PATCH 02/10] drm/exynos: added mode_fixup feature and code clean Inki Dae
2012-03-15 10:39   ` Dave Airlie
2012-03-15 11:21     ` Inki Dae
2012-03-16  4:52       ` InKi Dae
2012-03-13 14:46 ` [PATCH 03/10] drm/exynos: added buffer allocation type Inki Dae
2012-03-13 14:46 ` [PATCH 04/10] drm/exynos: added new funtion to get/put dma address Inki Dae
2012-03-13 14:46 ` [PATCH 05/10] drm/exynos: release pending pageflip events when closed Inki Dae
2012-03-13 14:47 ` [PATCH 06/10] drm/exynos: remove module of exynos drm subdrv Inki Dae
2012-03-13 14:47 ` [PATCH 07/10] drm/exynos: add subdrv open/close functions Inki Dae
2012-03-13 14:47 ` [PATCH 08/10] drm/exynos: add is_local member in exynos_drm_subdrv struct Inki Dae
2012-03-13 14:47 ` [PATCH 09/10] drm/exynos: add G2D driver Inki Dae
2012-03-15 10:50   ` Dave Airlie
2012-03-15 11:05     ` Joonyoung Shim
2012-03-16  6:28     ` Joonyoung Shim
2013-01-20 17:33       ` Rob Clark
2013-01-22  1:33         ` Inki Dae
2013-01-22  1:41           ` Rob Clark
2012-03-13 14:47 ` [PATCH 10/10] drm/exynos: added virtual display driver Inki Dae
2012-03-15 10:44   ` Dave Airlie
2012-03-15 11:36     ` Inki Dae
2012-03-15 11:43       ` David Airlie
2012-03-15 12:01         ` Inki Dae
2012-03-13 15:00 ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Inki Dae
2012-03-13 15:00   ` [RESEND][PATCH 09/10] drm/exynos: add G2D driver Inki Dae
2012-03-15 10:52   ` [RESEND][PATCH 01/10] drm/exynos: add HDMI version 1.4 support Dave Airlie
2012-03-15 10:59     ` Joonyoung Shim

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.