[PATCH v2 11/11] drm/exynos: remove struct exynos_drm_encoder layer

Inki Dae inki.dae at samsung.com
Fri Aug 7 04:50:34 PDT 2015


Hi Gustavo,

On 2015년 08월 06일 22:31, Gustavo Padovan wrote:
> From: Gustavo Padovan <gustavo.padovan at collabora.co.uk>
> 
> struct exynos_drm_encoder was justing wrapping struct drm_encoder, it had
> only a drm_encoder member and the internal exynos_drm_encoders ops that
> was directly mapped to the drm_encoder helper funcs.
> 
> So now exynos DRM uses struct drm_encoder directly, this removes
> completely the struct exynos_drm_encoder.
> 

Trats2 board, which uses Exynos4412 Soc, doesn't work after this patch
is applied. Below is the booting logs,
[    1.171318] console [ttySAC2] enabled
[    1.175522] 13830000.serial: ttySAC3 at MMIO 0x13830000 (irq = 60,
base_baud = 0) is a S3C6400/10
[    1.185545] [drm] Initialized drm 1.1.0 20060810
[    1.194104] exynos-drm exynos-drm: bound 11c00000.fimd (ops
fimd_component_ops)
[    1.200352] exynos-drm exynos-drm: bound 11c80000.dsi (ops
exynos_dsi_component_ops)
[    1.207688] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    1.214313] [drm] No driver support for vblank timestamp query.
[    1.220218] [drm] Initialized exynos 1.0.0 20110530 on minor 0

Booting is locked up here. This patch looks good to me so I tried to
find why locked up and I found the booting is locked up as soon as
console_lock function is called. Can you and other guys look into this
issue?

Thanks,
Inki Dae

> Signed-off-by: Gustavo Padovan <gustavo.padovan at collabora.co.uk>
> ---
>  drivers/gpu/drm/exynos/Makefile             |   7 +-
>  drivers/gpu/drm/exynos/exynos7_drm_decon.c  |   2 +-
>  drivers/gpu/drm/exynos/exynos_dp_core.c     |  68 ++++++++++++------
>  drivers/gpu/drm/exynos/exynos_dp_core.h     |   2 +-
>  drivers/gpu/drm/exynos/exynos_drm_core.c    |   1 -
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c    |   1 -
>  drivers/gpu/drm/exynos/exynos_drm_dpi.c     |  51 ++++++++------
>  drivers/gpu/drm/exynos/exynos_drm_drv.c     |   1 -
>  drivers/gpu/drm/exynos/exynos_drm_drv.h     |  47 ++-----------
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c     |  80 +++++++++++----------
>  drivers/gpu/drm/exynos/exynos_drm_encoder.c | 105 ----------------------------
>  drivers/gpu/drm/exynos/exynos_drm_encoder.h |  22 ------
>  drivers/gpu/drm/exynos/exynos_drm_fimd.c    |   2 +-
>  drivers/gpu/drm/exynos/exynos_drm_vidi.c    |  71 ++++++++++++++-----
>  drivers/gpu/drm/exynos/exynos_hdmi.c        |  85 +++++++++++++---------
>  15 files changed, 236 insertions(+), 309 deletions(-)
>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_encoder.c
>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_encoder.h
> 
> diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
> index 7de0b10..61c2906 100644
> --- a/drivers/gpu/drm/exynos/Makefile
> +++ b/drivers/gpu/drm/exynos/Makefile
> @@ -3,10 +3,9 @@
>  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
>  
>  ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
> -exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
> -		exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
> -		exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
> -		exynos_drm_plane.o exynos_drm_dmabuf.o
> +exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fbdev.o \
> +		exynos_drm_fb.o exynos_drm_buf.o exynos_drm_gem.o \
> +		exynos_drm_core.o exynos_drm_plane.o exynos_drm_dmabuf.o
>  
>  exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
>  exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
> diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
> index e1a2ce7..0792654 100644
> --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c
> +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
> @@ -61,7 +61,7 @@ struct decon_context {
>  	atomic_t			wait_vsync_event;
>  
>  	struct exynos_drm_panel_info panel;
> -	struct exynos_drm_encoder *encoder;
> +	struct drm_encoder *encoder;
>  };
>  
>  static const struct of_device_id decon_driver_dt_match[] = {
> diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
> index 4d49d25..92864ef 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp_core.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
> @@ -32,18 +32,18 @@
>  #include <drm/drm_panel.h>
>  
>  #include "exynos_dp_core.h"
> -#include "exynos_drm_encoder.h"
> +#include "exynos_drm_crtc.h"
>  
>  #define ctx_from_connector(c)	container_of(c, struct exynos_dp_device, \
>  					connector)
>  
>  static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp)
>  {
> -	return to_exynos_crtc(dp->encoder.base.crtc);
> +	return to_exynos_crtc(dp->encoder.crtc);
>  }
>  
>  static inline struct exynos_dp_device *encoder_to_dp(
> -						struct exynos_drm_encoder *e)
> +						struct drm_encoder *e)
>  {
>  	return container_of(e, struct exynos_dp_device, encoder);
>  }
> @@ -889,7 +889,7 @@ static void exynos_dp_hotplug(struct work_struct *work)
>  		drm_helper_hpd_irq_event(dp->drm_dev);
>  }
>  
> -static void exynos_dp_commit(struct exynos_drm_encoder *encoder)
> +static void exynos_dp_commit(struct drm_encoder *encoder)
>  {
>  	struct exynos_dp_device *dp = encoder_to_dp(encoder);
>  	int ret;
> @@ -995,7 +995,7 @@ static struct drm_encoder *exynos_dp_best_encoder(
>  {
>  	struct exynos_dp_device *dp = ctx_from_connector(connector);
>  
> -	return &dp->encoder.base;
> +	return &dp->encoder;
>  }
>  
>  static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
> @@ -1020,10 +1020,9 @@ static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
>  	return 0;
>  }
>  
> -static int exynos_dp_create_connector(struct exynos_drm_encoder *exynos_encoder)
> +static int exynos_dp_create_connector(struct drm_encoder *encoder)
>  {
> -	struct exynos_dp_device *dp = encoder_to_dp(exynos_encoder);
> -	struct drm_encoder *encoder = &exynos_encoder->base;
> +	struct exynos_dp_device *dp = encoder_to_dp(encoder);
>  	struct drm_connector *connector = &dp->connector;
>  	int ret;
>  
> @@ -1053,7 +1052,20 @@ static int exynos_dp_create_connector(struct exynos_drm_encoder *exynos_encoder)
>  	return ret;
>  }
>  
> -static void exynos_dp_enable(struct exynos_drm_encoder *encoder)
> +static bool exynos_dp_mode_fixup(struct drm_encoder *encoder,
> +				 const struct drm_display_mode *mode,
> +				 struct drm_display_mode *adjusted_mode)
> +{
> +	return true;
> +}
> +
> +static void exynos_dp_mode_set(struct drm_encoder *encoder,
> +			       struct drm_display_mode *mode,
> +			       struct drm_display_mode *adjusted_mode)
> +{
> +}
> +
> +static void exynos_dp_enable(struct drm_encoder *encoder)
>  {
>  	struct exynos_dp_device *dp = encoder_to_dp(encoder);
>  	struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
> @@ -1078,7 +1090,7 @@ static void exynos_dp_enable(struct exynos_drm_encoder *encoder)
>  	exynos_dp_commit(&dp->encoder);
>  }
>  
> -static void exynos_dp_disable(struct exynos_drm_encoder *encoder)
> +static void exynos_dp_disable(struct drm_encoder *encoder)
>  {
>  	struct exynos_dp_device *dp = encoder_to_dp(encoder);
>  	struct exynos_drm_crtc *crtc = dp_to_crtc(dp);
> @@ -1107,11 +1119,17 @@ static void exynos_dp_disable(struct exynos_drm_encoder *encoder)
>  	}
>  }
>  
> -static struct exynos_drm_encoder_ops exynos_dp_encoder_ops = {
> +static struct drm_encoder_helper_funcs exynos_dp_encoder_helper_funcs = {
> +	.mode_fixup = exynos_dp_mode_fixup,
> +	.mode_set = exynos_dp_mode_set,
>  	.enable = exynos_dp_enable,
>  	.disable = exynos_dp_disable,
>  };
>  
> +static struct drm_encoder_funcs exynos_dp_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>  static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
>  {
>  	struct device_node *dp_node = dev->of_node;
> @@ -1188,10 +1206,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>  	struct exynos_dp_device *dp = dev_get_drvdata(dev);
>  	struct platform_device *pdev = to_platform_device(dev);
>  	struct drm_device *drm_dev = data;
> -	struct exynos_drm_encoder *exynos_encoder = &dp->encoder;
> +	struct drm_encoder *encoder = &dp->encoder;
>  	struct resource *res;
>  	unsigned int irq_flags;
> -	int ret = 0;
> +	int pipe, ret = 0;
>  
>  	dp->dev = &pdev->dev;
>  	dp->dpms_mode = DRM_MODE_DPMS_OFF;
> @@ -1281,17 +1299,24 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
>  
>  	dp->drm_dev = drm_dev;
>  
> -	ret = exynos_drm_encoder_create(drm_dev, exynos_encoder,
> -					EXYNOS_DISPLAY_TYPE_LCD);
> -	if (ret) {
> -		DRM_ERROR("failed to create encoder\n");
> -		return ret;
> -	}
> +	pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
> +						  EXYNOS_DISPLAY_TYPE_LCD);
> +	if (pipe < 0)
> +		return pipe;
> +
> +	encoder->possible_crtcs = 1 << pipe;
> +
> +	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
> +
> +	drm_encoder_init(drm_dev, encoder, &exynos_dp_encoder_funcs,
> +			 DRM_MODE_ENCODER_TMDS);
> +
> +	drm_encoder_helper_add(encoder, &exynos_dp_encoder_helper_funcs);
>  
> -	ret = exynos_dp_create_connector(exynos_encoder);
> +	ret = exynos_dp_create_connector(encoder);
>  	if (ret) {
>  		DRM_ERROR("failed to create connector ret = %d\n", ret);
> -		drm_encoder_cleanup(&exynos_encoder->base);
> +		drm_encoder_cleanup(encoder);
>  		return ret;
>  	}
>  
> @@ -1322,7 +1347,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
>  	if (!dp)
>  		return -ENOMEM;
>  
> -	dp->encoder.ops = &exynos_dp_encoder_ops;
>  	platform_set_drvdata(pdev, dp);
>  
>  	panel_node = of_parse_phandle(dev->of_node, "panel", 0);
> diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
> index f8cc202..e413b6f 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp_core.h
> +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
> @@ -147,7 +147,7 @@ struct link_train {
>  };
>  
>  struct exynos_dp_device {
> -	struct exynos_drm_encoder encoder;
> +	struct drm_encoder	encoder;
>  	struct device		*dev;
>  	struct drm_device	*drm_dev;
>  	struct drm_connector	connector;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
> index 1f38a44..c68a6a2 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_core.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
> @@ -15,7 +15,6 @@
>  #include <drm/drmP.h>
>  #include "exynos_drm_drv.h"
>  #include "exynos_drm_crtc.h"
> -#include "exynos_drm_encoder.h"
>  #include "exynos_drm_fbdev.h"
>  
>  static LIST_HEAD(exynos_drm_subdrv_list);
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> index 2715c2a..b9b0e9c 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
> @@ -19,7 +19,6 @@
>  
>  #include "exynos_drm_crtc.h"
>  #include "exynos_drm_drv.h"
> -#include "exynos_drm_encoder.h"
>  #include "exynos_drm_plane.h"
>  
>  static void exynos_drm_crtc_enable(struct drm_crtc *crtc)
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> index 6850ce5..0476260 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> @@ -20,11 +20,10 @@
>  #include <video/of_videomode.h>
>  #include <video/videomode.h>
>  
> -#include "exynos_drm_encoder.h"
>  #include "exynos_drm_crtc.h"
>  
>  struct exynos_dpi {
> -	struct exynos_drm_encoder encoder;
> +	struct drm_encoder encoder;
>  	struct device *dev;
>  	struct device_node *panel_node;
>  
> @@ -36,7 +35,7 @@ struct exynos_dpi {
>  
>  #define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
>  
> -static inline struct exynos_dpi *encoder_to_dpi(struct exynos_drm_encoder *e)
> +static inline struct exynos_dpi *encoder_to_dpi(struct drm_encoder *e)
>  {
>  	return container_of(e, struct exynos_dpi, encoder);
>  }
> @@ -98,7 +97,7 @@ exynos_dpi_best_encoder(struct drm_connector *connector)
>  {
>  	struct exynos_dpi *ctx = connector_to_dpi(connector);
>  
> -	return &ctx->encoder.base;
> +	return &ctx->encoder;
>  }
>  
>  static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
> @@ -106,11 +105,9 @@ static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
>  	.best_encoder = exynos_dpi_best_encoder,
>  };
>  
> -static int exynos_dpi_create_connector(
> -				struct exynos_drm_encoder *exynos_encoder)
> +static int exynos_dpi_create_connector(struct drm_encoder *encoder)
>  {
> -	struct exynos_dpi *ctx = encoder_to_dpi(exynos_encoder);
> -	struct drm_encoder *encoder = &exynos_encoder->base;
> +	struct exynos_dpi *ctx = encoder_to_dpi(encoder);
>  	struct drm_connector *connector = &ctx->connector;
>  	int ret;
>  
> @@ -131,7 +128,7 @@ static int exynos_dpi_create_connector(
>  	return 0;
>  }
>  
> -static void exynos_dpi_enable(struct exynos_drm_encoder *encoder)
> +static void exynos_dpi_enable(struct drm_encoder *encoder)
>  {
>  	struct exynos_dpi *ctx = encoder_to_dpi(encoder);
>  
> @@ -141,7 +138,7 @@ static void exynos_dpi_enable(struct exynos_drm_encoder *encoder)
>  	}
>  }
>  
> -static void exynos_dpi_disable(struct exynos_drm_encoder *encoder)
> +static void exynos_dpi_disable(struct drm_encoder *encoder)
>  {
>  	struct exynos_dpi *ctx = encoder_to_dpi(encoder);
>  
> @@ -151,11 +148,15 @@ static void exynos_dpi_disable(struct exynos_drm_encoder *encoder)
>  	}
>  }
>  
> -static struct exynos_drm_encoder_ops exynos_dpi_encoder_ops = {
> +static struct drm_encoder_helper_funcs exynos_dpi_encoder_helper_funcs = {
>  	.enable = exynos_dpi_enable,
>  	.disable = exynos_dpi_disable,
>  };
>  
> +static struct drm_encoder_funcs exynos_dpi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>  /* of_* functions will be removed after merge of of_graph patches */
>  static struct device_node *
>  of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
> @@ -280,29 +281,34 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
>  	return 0;
>  }
>  
> -int exynos_dpi_bind(struct drm_device *dev,
> -		    struct exynos_drm_encoder *exynos_encoder)
> +int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder)
>  {
>  	int ret;
>  
> -	ret = exynos_drm_encoder_create(dev, exynos_encoder,
> -					EXYNOS_DISPLAY_TYPE_LCD);
> -	if (ret) {
> -		DRM_ERROR("failed to create encoder\n");
> +	ret = exynos_drm_crtc_get_pipe_from_type(dev, EXYNOS_DISPLAY_TYPE_LCD);
> +	if (ret < 0)
>  		return ret;
> -	}
>  
> -	ret = exynos_dpi_create_connector(exynos_encoder);
> +	encoder->possible_crtcs = 1 << ret;
> +
> +	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
> +
> +	drm_encoder_init(dev, encoder, &exynos_dpi_encoder_funcs,
> +			 DRM_MODE_ENCODER_TMDS);
> +
> +	drm_encoder_helper_add(encoder, &exynos_dpi_encoder_helper_funcs);
> +
> +	ret = exynos_dpi_create_connector(encoder);
>  	if (ret) {
>  		DRM_ERROR("failed to create connector ret = %d\n", ret);
> -		drm_encoder_cleanup(&exynos_encoder->base);
> +		drm_encoder_cleanup(encoder);
>  		return ret;
>  	}
>  
>  	return 0;
>  }
>  
> -struct exynos_drm_encoder *exynos_dpi_probe(struct device *dev)
> +struct drm_encoder *exynos_dpi_probe(struct device *dev)
>  {
>  	struct exynos_dpi *ctx;
>  	int ret;
> @@ -311,7 +317,6 @@ struct exynos_drm_encoder *exynos_dpi_probe(struct device *dev)
>  	if (!ctx)
>  		return ERR_PTR(-ENOMEM);
>  
> -	ctx->encoder.ops = &exynos_dpi_encoder_ops;
>  	ctx->dev = dev;
>  
>  	ret = exynos_dpi_parse_dt(ctx);
> @@ -329,7 +334,7 @@ struct exynos_drm_encoder *exynos_dpi_probe(struct device *dev)
>  	return &ctx->encoder;
>  }
>  
> -int exynos_dpi_remove(struct exynos_drm_encoder *encoder)
> +int exynos_dpi_remove(struct drm_encoder *encoder)
>  {
>  	struct exynos_dpi *ctx = encoder_to_dpi(encoder);
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> index 105f10e..6675e76 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> @@ -21,7 +21,6 @@
>  
>  #include "exynos_drm_drv.h"
>  #include "exynos_drm_crtc.h"
> -#include "exynos_drm_encoder.h"
>  #include "exynos_drm_fbdev.h"
>  #include "exynos_drm_fb.h"
>  #include "exynos_drm_gem.h"
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> index a4977be..6b8a30f 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> @@ -22,7 +22,6 @@
>  #define MAX_PLANE	5
>  #define MAX_FB_BUFFER	4
>  
> -#define to_exynos_encoder(x)	container_of(x, struct exynos_drm_encoder, base)
>  #define to_exynos_crtc(x)	container_of(x, struct exynos_drm_crtc, base)
>  #define to_exynos_plane(x)	container_of(x, struct exynos_drm_plane, base)
>  
> @@ -78,40 +77,6 @@ struct exynos_drm_plane {
>  };
>  
>  /*
> - * Exynos DRM Encoder Structure.
> - *	- this structure is common to analog tv, digital tv and lcd panel.
> - *
> - * @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().
> - * @enable: display device on.
> - * @disable: display device off.
> - */
> -struct exynos_drm_encoder;
> -struct exynos_drm_encoder_ops {
> -	void (*mode_fixup)(struct exynos_drm_encoder *encoder,
> -				struct drm_connector *connector,
> -				const struct drm_display_mode *mode,
> -				struct drm_display_mode *adjusted_mode);
> -	void (*mode_set)(struct exynos_drm_encoder *encoder,
> -				struct drm_display_mode *mode);
> -	void (*enable)(struct exynos_drm_encoder *encoder);
> -	void (*disable)(struct exynos_drm_encoder *encoder);
> -};
> -
> -/*
> - * exynos specific encoder structure.
> - *
> - * @drm_encoder: encoder object.
> - * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
> - * @ops: pointer to callbacks for exynos drm specific functionality
> - */
> -struct exynos_drm_encoder {
> -	struct drm_encoder		base;
> -	struct exynos_drm_encoder_ops	*ops;
> -};
> -
> -/*
>   * Exynos drm crtc ops
>   *
>   * @enable: enable the device
> @@ -255,18 +220,18 @@ 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);
>  
>  #ifdef CONFIG_DRM_EXYNOS_DPI
> -struct exynos_drm_encoder *exynos_dpi_probe(struct device *dev);
> -int exynos_dpi_remove(struct exynos_drm_encoder *encoder);
> -int exynos_dpi_bind(struct drm_device *dev, struct exynos_drm_encoder *encoder);
> +struct drm_encoder *exynos_dpi_probe(struct device *dev);
> +int exynos_dpi_remove(struct drm_encoder *encoder);
> +int exynos_dpi_bind(struct drm_device *dev, struct drm_encoder *encoder);
>  #else
> -static inline struct exynos_drm_encoder *
> +static inline struct drm_encoder *
>  exynos_dpi_probe(struct device *dev) { return NULL; }
> -static inline int exynos_dpi_remove(struct exynos_drm_encoder *encoder)
> +static inline int exynos_dpi_remove(struct drm_encoder *encoder)
>  {
>  	return 0;
>  }
>  static inline int exynos_dpi_bind(struct drm_device *dev,
> -				  struct exynos_drm_encoder *encoder)
> +				  struct drm_encoder *encoder)
>  {
>  	return 0;
>  }
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index d791ad4..a87d030 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -30,7 +30,6 @@
>  #include <video/videomode.h>
>  
>  #include "exynos_drm_crtc.h"
> -#include "exynos_drm_encoder.h"
>  #include "exynos_drm_drv.h"
>  
>  /* returns true iff both arguments logically differs */
> @@ -260,7 +259,7 @@ struct exynos_dsi_driver_data {
>  };
>  
>  struct exynos_dsi {
> -	struct exynos_drm_encoder encoder;
> +	struct drm_encoder encoder;
>  	struct mipi_dsi_host dsi_host;
>  	struct drm_connector connector;
>  	struct device_node *panel_node;
> @@ -296,7 +295,7 @@ struct exynos_dsi {
>  #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
>  #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
>  
> -static inline struct exynos_dsi *encoder_to_dsi(struct exynos_drm_encoder *e)
> +static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e)
>  {
>  	return container_of(e, struct exynos_dsi, encoder);
>  }
> @@ -1273,7 +1272,7 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
>  static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
>  {
>  	struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
> -	struct drm_encoder *encoder = &dsi->encoder.base;
> +	struct drm_encoder *encoder = &dsi->encoder;
>  
>  	if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE)
>  		exynos_drm_crtc_te_handler(encoder->crtc);
> @@ -1519,7 +1518,7 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
>  		dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
>  }
>  
> -static void exynos_dsi_enable(struct exynos_drm_encoder *encoder)
> +static void exynos_dsi_enable(struct drm_encoder *encoder)
>  {
>  	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>  	int ret;
> @@ -1555,7 +1554,7 @@ static void exynos_dsi_enable(struct exynos_drm_encoder *encoder)
>  	dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
>  }
>  
> -static void exynos_dsi_disable(struct exynos_drm_encoder *encoder)
> +static void exynos_dsi_disable(struct drm_encoder *encoder)
>  {
>  	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>  
> @@ -1583,7 +1582,7 @@ exynos_dsi_detect(struct drm_connector *connector, bool force)
>  		if (dsi->panel)
>  			drm_panel_attach(dsi->panel, &dsi->connector);
>  	} else if (!dsi->panel_node) {
> -		struct exynos_drm_encoder *encoder;
> +		struct drm_encoder *encoder;
>  
>  		encoder = platform_get_drvdata(to_platform_device(dsi->dev));
>  		exynos_dsi_disable(encoder);
> @@ -1629,7 +1628,7 @@ exynos_dsi_best_encoder(struct drm_connector *connector)
>  {
>  	struct exynos_dsi *dsi = connector_to_dsi(connector);
>  
> -	return &dsi->encoder.base;
> +	return &dsi->encoder;
>  }
>  
>  static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
> @@ -1637,11 +1636,9 @@ static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
>  	.best_encoder = exynos_dsi_best_encoder,
>  };
>  
> -static int exynos_dsi_create_connector(
> -				struct exynos_drm_encoder *exynos_encoder)
> +static int exynos_dsi_create_connector(struct drm_encoder *encoder)
>  {
> -	struct exynos_dsi *dsi = encoder_to_dsi(exynos_encoder);
> -	struct drm_encoder *encoder = &exynos_encoder->base;
> +	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>  	struct drm_connector *connector = &dsi->connector;
>  	int ret;
>  
> @@ -1662,28 +1659,34 @@ static int exynos_dsi_create_connector(
>  	return 0;
>  }
>  
> -static void exynos_dsi_mode_set(struct exynos_drm_encoder *encoder,
> -			 struct drm_display_mode *mode)
> +static void exynos_dsi_mode_set(struct drm_encoder *encoder,
> +				struct drm_display_mode *mode,
> +				struct drm_display_mode *adjusted_mode)
>  {
>  	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>  	struct videomode *vm = &dsi->vm;
> -
> -	vm->hactive = mode->hdisplay;
> -	vm->vactive = mode->vdisplay;
> -	vm->vfront_porch = mode->vsync_start - mode->vdisplay;
> -	vm->vback_porch = mode->vtotal - mode->vsync_end;
> -	vm->vsync_len = mode->vsync_end - mode->vsync_start;
> -	vm->hfront_porch = mode->hsync_start - mode->hdisplay;
> -	vm->hback_porch = mode->htotal - mode->hsync_end;
> -	vm->hsync_len = mode->hsync_end - mode->hsync_start;
> +	struct drm_display_mode *m = adjusted_mode;
> +
> +	vm->hactive = m->hdisplay;
> +	vm->vactive = m->vdisplay;
> +	vm->vfront_porch = m->vsync_start - m->vdisplay;
> +	vm->vback_porch = m->vtotal - m->vsync_end;
> +	vm->vsync_len = m->vsync_end - m->vsync_start;
> +	vm->hfront_porch = m->hsync_start - m->hdisplay;
> +	vm->hback_porch = m->htotal - m->hsync_end;
> +	vm->hsync_len = m->hsync_end - m->hsync_start;
>  }
>  
> -static struct exynos_drm_encoder_ops exynos_dsi_encoder_ops = {
> +static struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
>  	.mode_set = exynos_dsi_mode_set,
>  	.enable = exynos_dsi_enable,
>  	.disable = exynos_dsi_disable,
>  };
>  
> +static struct drm_encoder_funcs exynos_dsi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>  MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
>  
>  /* of_* functions will be removed after merge of of_graph patches */
> @@ -1804,23 +1807,30 @@ end:
>  static int exynos_dsi_bind(struct device *dev, struct device *master,
>  				void *data)
>  {
> -	struct exynos_drm_encoder *exynos_encoder = dev_get_drvdata(dev);
> -	struct exynos_dsi *dsi = encoder_to_dsi(exynos_encoder);
> +	struct drm_encoder *encoder = dev_get_drvdata(dev);
> +	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>  	struct drm_device *drm_dev = data;
>  	struct drm_bridge *bridge;
>  	int ret;
>  
> -	ret = exynos_drm_encoder_create(drm_dev, exynos_encoder,
> -					EXYNOS_DISPLAY_TYPE_LCD);
> -	if (ret) {
> -		DRM_ERROR("failed to create encoder\n");
> +	ret = exynos_drm_crtc_get_pipe_from_type(drm_dev,
> +						  EXYNOS_DISPLAY_TYPE_LCD);
> +	if (ret < 0)
>  		return ret;
> -	}
>  
> -	ret = exynos_dsi_create_connector(exynos_encoder);
> +	encoder->possible_crtcs = 1 << ret;
> +
> +	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
> +
> +	drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
> +			 DRM_MODE_ENCODER_TMDS);
> +
> +	drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs);
> +
> +	ret = exynos_dsi_create_connector(encoder);
>  	if (ret) {
>  		DRM_ERROR("failed to create connector ret = %d\n", ret);
> -		drm_encoder_cleanup(&exynos_encoder->base);
> +		drm_encoder_cleanup(encoder);
>  		return ret;
>  	}
>  
> @@ -1835,7 +1845,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
>  static void exynos_dsi_unbind(struct device *dev, struct device *master,
>  				void *data)
>  {
> -	struct exynos_drm_encoder *encoder = dev_get_drvdata(dev);
> +	struct drm_encoder *encoder = dev_get_drvdata(dev);
>  	struct exynos_dsi *dsi = encoder_to_dsi(encoder);
>  
>  	exynos_dsi_disable(encoder);
> @@ -1859,8 +1869,6 @@ static int exynos_dsi_probe(struct platform_device *pdev)
>  	if (!dsi)
>  		return -ENOMEM;
>  
> -	dsi->encoder.ops = &exynos_dsi_encoder_ops;
> -
>  	/* To be checked as invalid one */
>  	dsi->te_gpio = -ENOENT;
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> deleted file mode 100644
> index d45a5c5..0000000
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> +++ /dev/null
> @@ -1,105 +0,0 @@
> -/* exynos_drm_encoder.c
> - *
> - * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> - * Authors:
> - *	Inki Dae <inki.dae at samsung.com>
> - *	Joonyoung Shim <jy0922.shim at samsung.com>
> - *	Seung-Woo Kim <sw0312.kim at 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 <drm/drmP.h>
> -#include <drm/drm_crtc_helper.h>
> -
> -#include "exynos_drm_drv.h"
> -#include "exynos_drm_encoder.h"
> -#include "exynos_drm_crtc.h"
> -
> -static bool
> -exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
> -			       const struct drm_display_mode *mode,
> -			       struct drm_display_mode *adjusted_mode)
> -{
> -	struct drm_device *dev = encoder->dev;
> -	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> -	struct drm_connector *connector;
> -
> -	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> -		if (connector->encoder != encoder)
> -			continue;
> -
> -		if (exynos_encoder->ops->mode_fixup)
> -			exynos_encoder->ops->mode_fixup(exynos_encoder,
> -							connector, mode,
> -							adjusted_mode);
> -	}
> -
> -	return true;
> -}
> -
> -static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
> -					 struct drm_display_mode *mode,
> -					 struct drm_display_mode *adjusted_mode)
> -{
> -	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> -
> -	if (exynos_encoder->ops->mode_set)
> -		exynos_encoder->ops->mode_set(exynos_encoder, adjusted_mode);
> -}
> -
> -static void exynos_drm_encoder_enable(struct drm_encoder *encoder)
> -{
> -	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> -
> -	if (exynos_encoder->ops->enable)
> -		exynos_encoder->ops->enable(exynos_encoder);
> -}
> -
> -static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
> -{
> -	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
> -
> -	if (exynos_encoder->ops->disable)
> -		exynos_encoder->ops->disable(exynos_encoder);
> -}
> -
> -static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
> -	.mode_fixup	= exynos_drm_encoder_mode_fixup,
> -	.mode_set	= exynos_drm_encoder_mode_set,
> -	.enable		= exynos_drm_encoder_enable,
> -	.disable	= exynos_drm_encoder_disable,
> -};
> -
> -static struct drm_encoder_funcs exynos_encoder_funcs = {
> -	.destroy = drm_encoder_cleanup,
> -};
> -
> -int exynos_drm_encoder_create(struct drm_device *dev,
> -			      struct exynos_drm_encoder *exynos_encoder,
> -			      enum exynos_drm_output_type type)
> -{
> -	struct drm_encoder *encoder;
> -	int pipe;
> -
> -	pipe = exynos_drm_crtc_get_pipe_from_type(dev, type);
> -	if (pipe < 0)
> -		return pipe;
> -
> -	encoder = &exynos_encoder->base;
> -	encoder->possible_crtcs = 1 << pipe;
> -
> -	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
> -
> -	drm_encoder_init(dev, encoder, &exynos_encoder_funcs,
> -			DRM_MODE_ENCODER_TMDS);
> -
> -	drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
> -
> -	DRM_DEBUG_KMS("encoder has been created\n");
> -
> -	return 0;
> -}
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> deleted file mode 100644
> index 6610dee..0000000
> --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
> +++ /dev/null
> @@ -1,22 +0,0 @@
> -/*
> - * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> - * Authors:
> - *	Inki Dae <inki.dae at samsung.com>
> - *	Joonyoung Shim <jy0922.shim at samsung.com>
> - *	Seung-Woo Kim <sw0312.kim at 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.
> - */
> -
> -#ifndef _EXYNOS_DRM_ENCODER_H_
> -#define _EXYNOS_DRM_ENCODER_H_
> -
> -#include "exynos_drm_drv.h"
> -
> -int exynos_drm_encoder_create(struct drm_device *dev, struct exynos_drm_encoder
> -			      *encoder, enum exynos_drm_output_type type);
> -
> -#endif
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 6c0d3de..5def6bc 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -169,7 +169,7 @@ struct fimd_context {
>  
>  	struct exynos_drm_panel_info panel;
>  	struct fimd_driver_data *driver_data;
> -	struct exynos_drm_encoder *encoder;
> +	struct drm_encoder *encoder;
>  };
>  
>  static const struct of_device_id fimd_driver_dt_match[] = {
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> index 9b64c77..581af35 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
> @@ -25,7 +25,6 @@
>  #include "exynos_drm_drv.h"
>  #include "exynos_drm_crtc.h"
>  #include "exynos_drm_plane.h"
> -#include "exynos_drm_encoder.h"
>  #include "exynos_drm_vidi.h"
>  
>  /* vidi has totally three virtual windows. */
> @@ -35,7 +34,7 @@
>  					connector)
>  
>  struct vidi_context {
> -	struct exynos_drm_encoder	encoder;
> +	struct drm_encoder		encoder;
>  	struct platform_device		*pdev;
>  	struct drm_device		*drm_dev;
>  	struct exynos_drm_crtc		*crtc;
> @@ -54,7 +53,7 @@ struct vidi_context {
>  	int				pipe;
>  };
>  
> -static inline struct vidi_context *encoder_to_vidi(struct exynos_drm_encoder *e)
> +static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e)
>  {
>  	return container_of(e, struct vidi_context, encoder);
>  }
> @@ -358,7 +357,7 @@ static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
>  {
>  	struct vidi_context *ctx = ctx_from_connector(connector);
>  
> -	return &ctx->encoder.base;
> +	return &ctx->encoder;
>  }
>  
>  static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
> @@ -366,10 +365,9 @@ static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
>  	.best_encoder = vidi_best_encoder,
>  };
>  
> -static int vidi_create_connector(struct exynos_drm_encoder *exynos_encoder)
> +static int vidi_create_connector(struct drm_encoder *encoder)
>  {
> -	struct vidi_context *ctx = encoder_to_vidi(exynos_encoder);
> -	struct drm_encoder *encoder = &exynos_encoder->base;
> +	struct vidi_context *ctx = encoder_to_vidi(encoder);
>  	struct drm_connector *connector = &ctx->connector;
>  	int ret;
>  
> @@ -389,15 +387,47 @@ static int vidi_create_connector(struct exynos_drm_encoder *exynos_encoder)
>  	return 0;
>  }
>  
> +static bool exynos_vidi_mode_fixup(struct drm_encoder *encoder,
> +				 const struct drm_display_mode *mode,
> +				 struct drm_display_mode *adjusted_mode)
> +{
> +	return true;
> +}
> +
> +static void exynos_vidi_mode_set(struct drm_encoder *encoder,
> +			       struct drm_display_mode *mode,
> +			       struct drm_display_mode *adjusted_mode)
> +{
> +}
> +
> +static void exynos_vidi_enable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void exynos_vidi_disable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static struct drm_encoder_helper_funcs exynos_vidi_encoder_helper_funcs = {
> +	.mode_fixup = exynos_vidi_mode_fixup,
> +	.mode_set = exynos_vidi_mode_set,
> +	.enable = exynos_vidi_enable,
> +	.disable = exynos_vidi_disable,
> +};
> +
> +static struct drm_encoder_funcs exynos_vidi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>  static int vidi_bind(struct device *dev, struct device *master, void *data)
>  {
>  	struct vidi_context *ctx = dev_get_drvdata(dev);
>  	struct drm_device *drm_dev = data;
> -	struct exynos_drm_encoder *exynos_encoder = &ctx->encoder;
> +	struct drm_encoder *encoder = &ctx->encoder;
>  	struct exynos_drm_plane *exynos_plane;
>  	enum drm_plane_type type;
>  	unsigned int zpos;
> -	int ret;
> +	int pipe, ret;
>  
>  	vidi_ctx_initialize(ctx, drm_dev);
>  
> @@ -419,17 +449,24 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
>  		return PTR_ERR(ctx->crtc);
>  	}
>  
> -	ret = exynos_drm_encoder_create(drm_dev, exynos_encoder,
> -					EXYNOS_DISPLAY_TYPE_VIDI);
> -	if (ret) {
> -		DRM_ERROR("failed to create encoder\n");
> -		return ret;
> -	}
> +	pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
> +						  EXYNOS_DISPLAY_TYPE_VIDI);
> +	if (pipe < 0)
> +		return pipe;
> +
> +	encoder->possible_crtcs = 1 << pipe;
> +
> +	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
> +
> +	drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs,
> +			 DRM_MODE_ENCODER_TMDS);
> +
> +	drm_encoder_helper_add(encoder, &exynos_vidi_encoder_helper_funcs);
>  
> -	ret = vidi_create_connector(exynos_encoder);
> +	ret = vidi_create_connector(encoder);
>  	if (ret) {
>  		DRM_ERROR("failed to create connector ret = %d\n", ret);
> -		drm_encoder_cleanup(&exynos_encoder->base);
> +		drm_encoder_cleanup(encoder);
>  		return ret;
>  	}
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index 148e42f..932f7fa 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -44,7 +44,6 @@
>  
>  #include "exynos_drm_drv.h"
>  #include "exynos_drm_crtc.h"
> -#include "exynos_drm_encoder.h"
>  #include "exynos_mixer.h"
>  
>  #include <linux/gpio.h>
> @@ -88,7 +87,7 @@ struct hdmi_resources {
>  };
>  
>  struct hdmi_context {
> -	struct exynos_drm_encoder	encoder;
> +	struct drm_encoder		encoder;
>  	struct device			*dev;
>  	struct drm_device		*drm_dev;
>  	struct drm_connector		connector;
> @@ -116,7 +115,7 @@ struct hdmi_context {
>  	struct regmap			*pmureg;
>  };
>  
> -static inline struct hdmi_context *encoder_to_hdmi(struct exynos_drm_encoder *e)
> +static inline struct hdmi_context *encoder_to_hdmi(struct drm_encoder *e)
>  {
>  	return container_of(e, struct hdmi_context, encoder);
>  }
> @@ -1032,7 +1031,7 @@ static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
>  {
>  	struct hdmi_context *hdata = ctx_from_connector(connector);
>  
> -	return &hdata->encoder.base;
> +	return &hdata->encoder;
>  }
>  
>  static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
> @@ -1041,9 +1040,9 @@ static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
>  	.best_encoder = hdmi_best_encoder,
>  };
>  
> -static int hdmi_create_connector(struct exynos_drm_encoder *exynos_encoder)
> +static int hdmi_create_connector(struct drm_encoder *encoder)
>  {
> -	struct hdmi_context *hdata = encoder_to_hdmi(exynos_encoder);
> +	struct hdmi_context *hdata = encoder_to_hdmi(encoder);
>  	struct drm_connector *connector = &hdata->connector;
>  	int ret;
>  
> @@ -1059,28 +1058,35 @@ static int hdmi_create_connector(struct exynos_drm_encoder *exynos_encoder)
>  
>  	drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
>  	drm_connector_register(connector);
> -	drm_mode_connector_attach_encoder(connector, &exynos_encoder->base);
> +	drm_mode_connector_attach_encoder(connector, encoder);
>  
>  	return 0;
>  }
>  
> -static void hdmi_mode_fixup(struct exynos_drm_encoder *encoder,
> -				struct drm_connector *connector,
> -				const struct drm_display_mode *mode,
> -				struct drm_display_mode *adjusted_mode)
> +static bool hdmi_mode_fixup(struct drm_encoder *encoder,
> +			    const struct drm_display_mode *mode,
> +			    struct drm_display_mode *adjusted_mode)
>  {
> +	struct drm_device *dev = encoder->dev;
> +	struct drm_connector *connector;
>  	struct drm_display_mode *m;
>  	int mode_ok;
>  
> -	DRM_DEBUG_KMS("%s\n", __FILE__);
> -
>  	drm_mode_set_crtcinfo(adjusted_mode, 0);
>  
> +	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> +		if (connector->encoder == encoder)
> +			break;
> +	}
> +
> +	if (connector->encoder != encoder)
> +		return true;
> +
>  	mode_ok = hdmi_mode_valid(connector, adjusted_mode);
>  
>  	/* just return if user desired mode exists. */
>  	if (mode_ok == MODE_OK)
> -		return;
> +		return true;
>  
>  	/*
>  	 * otherwise, find the most suitable mode among modes and change it
> @@ -1100,6 +1106,8 @@ static void hdmi_mode_fixup(struct exynos_drm_encoder *encoder,
>  			break;
>  		}
>  	}
> +
> +	return true;
>  }
>  
>  static void hdmi_set_acr(u32 freq, u8 *acr)
> @@ -1697,22 +1705,23 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
>  	hdmi_regs_dump(hdata, "start");
>  }
>  
> -static void hdmi_mode_set(struct exynos_drm_encoder *encoder,
> -			struct drm_display_mode *mode)
> +static void hdmi_mode_set(struct drm_encoder *encoder,
> +			  struct drm_display_mode *mode,
> +			  struct drm_display_mode *adjusted_mode)
>  {
>  	struct hdmi_context *hdata = encoder_to_hdmi(encoder);
> -	struct drm_display_mode *m = mode;
> +	struct drm_display_mode *m = adjusted_mode;
>  
>  	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
>  		m->hdisplay, m->vdisplay,
>  		m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
>  		"INTERLACED" : "PROGRESSIVE");
>  
> -	drm_mode_copy(&hdata->current_mode, mode);
> +	drm_mode_copy(&hdata->current_mode, m);
>  	hdata->cea_video_id = drm_match_cea_mode(mode);
>  }
>  
> -static void hdmi_enable(struct exynos_drm_encoder *encoder)
> +static void hdmi_enable(struct drm_encoder *encoder)
>  {
>  	struct hdmi_context *hdata = encoder_to_hdmi(encoder);
>  	struct hdmi_resources *res = &hdata->res;
> @@ -1738,11 +1747,11 @@ static void hdmi_enable(struct exynos_drm_encoder *encoder)
>  	hdmi_conf_apply(hdata);
>  }
>  
> -static void hdmi_disable(struct exynos_drm_encoder *encoder)
> +static void hdmi_disable(struct drm_encoder *encoder)
>  {
>  	struct hdmi_context *hdata = encoder_to_hdmi(encoder);
>  	struct hdmi_resources *res = &hdata->res;
> -	struct drm_crtc *crtc = hdata->encoder.base.crtc;
> +	struct drm_crtc *crtc = encoder->crtc;
>  	const struct drm_crtc_helper_funcs *funcs = NULL;
>  
>  	if (!hdata->powered)
> @@ -1783,13 +1792,17 @@ static void hdmi_disable(struct exynos_drm_encoder *encoder)
>  	hdata->powered = false;
>  }
>  
> -static struct exynos_drm_encoder_ops hdmi_encoder_ops = {
> +static struct drm_encoder_helper_funcs exynos_hdmi_encoder_helper_funcs = {
>  	.mode_fixup	= hdmi_mode_fixup,
>  	.mode_set	= hdmi_mode_set,
>  	.enable		= hdmi_enable,
>  	.disable	= hdmi_disable,
>  };
>  
> +static struct drm_encoder_funcs exynos_hdmi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>  static void hdmi_hotplug_work_func(struct work_struct *work)
>  {
>  	struct hdmi_context *hdata;
> @@ -1917,22 +1930,29 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
>  {
>  	struct drm_device *drm_dev = data;
>  	struct hdmi_context *hdata = dev_get_drvdata(dev);
> -	struct exynos_drm_encoder *exynos_encoder = &hdata->encoder;
> -	int ret;
> +	struct drm_encoder *encoder = &hdata->encoder;
> +	int ret, pipe;
>  
>  	hdata->drm_dev = drm_dev;
>  
> -	ret = exynos_drm_encoder_create(drm_dev, exynos_encoder,
> -					EXYNOS_DISPLAY_TYPE_HDMI);
> -	if (ret) {
> -		DRM_ERROR("failed to create encoder\n");
> -		return ret;
> -	}
> +	pipe = exynos_drm_crtc_get_pipe_from_type(drm_dev,
> +						  EXYNOS_DISPLAY_TYPE_HDMI);
> +	if (pipe < 0)
> +		return pipe;
> +
> +	encoder->possible_crtcs = 1 << pipe;
> +
> +	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
> +
> +	drm_encoder_init(drm_dev, encoder, &exynos_hdmi_encoder_funcs,
> +			 DRM_MODE_ENCODER_TMDS);
> +
> +	drm_encoder_helper_add(encoder, &exynos_hdmi_encoder_helper_funcs);
>  
> -	ret = hdmi_create_connector(exynos_encoder);
> +	ret = hdmi_create_connector(encoder);
>  	if (ret) {
>  		DRM_ERROR("failed to create connector ret = %d\n", ret);
> -		drm_encoder_cleanup(&exynos_encoder->base);
> +		drm_encoder_cleanup(encoder);
>  		return ret;
>  	}
>  
> @@ -1985,7 +2005,6 @@ static int hdmi_probe(struct platform_device *pdev)
>  		return -ENODEV;
>  
>  	hdata->drv_data = match->data;
> -	hdata->encoder.ops = &hdmi_encoder_ops;
>  
>  	platform_set_drvdata(pdev, hdata);
>  
> 



More information about the dri-devel mailing list