diff mbox

[4/4] drm/sti: atomic crtc/plane update

Message ID 1438337607-13122-5-git-send-email-vincent.abriou@st.com (mailing list archive)
State New, archived
Headers show

Commit Message

Vincent Abriou July 31, 2015, 10:13 a.m. UTC
Better fit STI hardware structure.
Planes are no more responsible of updating mixer information such
as z-order and status. It is now up to the CRTC atomic flush to
do it. Plane actions (enable or disable) are performed atomically.
Disabling of a plane is synchronize with the vsync event.

Signed-off-by: Vincent Abriou <vincent.abriou@st.com>
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 drivers/gpu/drm/sti/sti_compositor.c |  32 +--
 drivers/gpu/drm/sti/sti_crtc.c       | 120 +++++++--
 drivers/gpu/drm/sti/sti_cursor.c     | 211 +++++++++------
 drivers/gpu/drm/sti/sti_cursor.h     |   6 +-
 drivers/gpu/drm/sti/sti_gdp.c        | 493 +++++++++++++++++++----------------
 drivers/gpu/drm/sti/sti_gdp.h        |   8 +-
 drivers/gpu/drm/sti/sti_hqvdp.c      | 429 ++++++++++++++++--------------
 drivers/gpu/drm/sti/sti_mixer.h      |  10 +-
 drivers/gpu/drm/sti/sti_plane.c      | 251 +-----------------
 drivers/gpu/drm/sti/sti_plane.h      |  66 ++---
 drivers/gpu/drm/sti/sti_vid.c        |  29 ++-
 drivers/gpu/drm/sti/sti_vid.h        |   5 +-
 12 files changed, 808 insertions(+), 852 deletions(-)

Comments

Emil Velikov July 31, 2015, 12:22 p.m. UTC | #1
Hello Vincent,

On 31 July 2015 at 11:13, Vincent Abriou <vincent.abriou@st.com> wrote:
> Better fit STI hardware structure.
> Planes are no more responsible of updating mixer information such
> as z-order and status. It is now up to the CRTC atomic flush to
> do it. Plane actions (enable or disable) are performed atomically.
> Disabling of a plane is synchronize with the vsync event.
>
> Signed-off-by: Vincent Abriou <vincent.abriou@st.com>
> Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> ---
>  drivers/gpu/drm/sti/sti_compositor.c |  32 +--
>  drivers/gpu/drm/sti/sti_crtc.c       | 120 +++++++--
>  drivers/gpu/drm/sti/sti_cursor.c     | 211 +++++++++------
>  drivers/gpu/drm/sti/sti_cursor.h     |   6 +-
>  drivers/gpu/drm/sti/sti_gdp.c        | 493 +++++++++++++++++++----------------
>  drivers/gpu/drm/sti/sti_gdp.h        |   8 +-
>  drivers/gpu/drm/sti/sti_hqvdp.c      | 429 ++++++++++++++++--------------
>  drivers/gpu/drm/sti/sti_mixer.h      |  10 +-
>  drivers/gpu/drm/sti/sti_plane.c      | 251 +-----------------
>  drivers/gpu/drm/sti/sti_plane.h      |  66 ++---
>  drivers/gpu/drm/sti/sti_vid.c        |  29 ++-
>  drivers/gpu/drm/sti/sti_vid.h        |   5 +-
>  12 files changed, 808 insertions(+), 852 deletions(-)
>
Just a friendly note - other drivers transitioning to atomics have
done so in a more gradual manner. I believe the idea/intent was to
ensure commits are simple and straightforward enough to minimise the
cases of regressions/bugs.

Either way the decision is between you and the driver maintainer.
Speaking of which there isn't one listed in MAINTAINERS. Is that
intentional ?

Cheers,
Emil
Benjamin Gaignard July 31, 2015, 12:54 p.m. UTC | #2
Hello Emil,

This series of patches is the second step to convert sit driver to atomic,
I have the first step few weeks ago.
This time we really take benefit of the atomic helpers to make match
correctly code and hardware split. To give you an example, before
those patches, we were calling code driving hardware planes while
setting crtc hardware...

I agree that is a big change but we can to less then that to keep
everything working.
We have done quite many tests with modetest and weston to be sure we
do not have regressions.

Both Vincent and I should be put in MAINTAINERS file, I will do a
patch for that.

Regards,
Benjamin


2015-07-31 14:22 GMT+02:00 Emil Velikov <emil.l.velikov@gmail.com>:
> Hello Vincent,
>
> On 31 July 2015 at 11:13, Vincent Abriou <vincent.abriou@st.com> wrote:
>> Better fit STI hardware structure.
>> Planes are no more responsible of updating mixer information such
>> as z-order and status. It is now up to the CRTC atomic flush to
>> do it. Plane actions (enable or disable) are performed atomically.
>> Disabling of a plane is synchronize with the vsync event.
>>
>> Signed-off-by: Vincent Abriou <vincent.abriou@st.com>
>> Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>> ---
>>  drivers/gpu/drm/sti/sti_compositor.c |  32 +--
>>  drivers/gpu/drm/sti/sti_crtc.c       | 120 +++++++--
>>  drivers/gpu/drm/sti/sti_cursor.c     | 211 +++++++++------
>>  drivers/gpu/drm/sti/sti_cursor.h     |   6 +-
>>  drivers/gpu/drm/sti/sti_gdp.c        | 493 +++++++++++++++++++----------------
>>  drivers/gpu/drm/sti/sti_gdp.h        |   8 +-
>>  drivers/gpu/drm/sti/sti_hqvdp.c      | 429 ++++++++++++++++--------------
>>  drivers/gpu/drm/sti/sti_mixer.h      |  10 +-
>>  drivers/gpu/drm/sti/sti_plane.c      | 251 +-----------------
>>  drivers/gpu/drm/sti/sti_plane.h      |  66 ++---
>>  drivers/gpu/drm/sti/sti_vid.c        |  29 ++-
>>  drivers/gpu/drm/sti/sti_vid.h        |   5 +-
>>  12 files changed, 808 insertions(+), 852 deletions(-)
>>
> Just a friendly note - other drivers transitioning to atomics have
> done so in a more gradual manner. I believe the idea/intent was to
> ensure commits are simple and straightforward enough to minimise the
> cases of regressions/bugs.
>
> Either way the decision is between you and the driver maintainer.
> Speaking of which there isn't one listed in MAINTAINERS. Is that
> intentional ?
>
> Cheers,
> Emil
Emil Velikov July 31, 2015, 1:24 p.m. UTC | #3
On 31 July 2015 at 13:54, Benjamin Gaignard
<benjamin.gaignard@linaro.org> wrote:
> Hello Emil,
>
> This series of patches is the second step to convert sit driver to atomic,
> I have the first step few weeks ago.
> This time we really take benefit of the atomic helpers to make match
> correctly code and hardware split. To give you an example, before
> those patches, we were calling code driving hardware planes while
> setting crtc hardware...
>
> I agree that is a big change but we can to less then that to keep
> everything working.
> We have done quite many tests with modetest and weston to be sure we
> do not have regressions.
>
Fair enough. Just wanted to put it out on the table, as other teams
(with more developers and testers) do occasionally stumble upon corner
cases with atomics. I did not mean to tell you how you should do your
job, but mitigate the awkward cases like the one floating around a
couple of days ago.

> Both Vincent and I should be put in MAINTAINERS file, I will do a
> patch for that.
>
Great. Now if we can convince a few others to do the same ;-)

Thanks
Emil
Daniel Vetter July 31, 2015, 1:45 p.m. UTC | #4
On Fri, Jul 31, 2015 at 12:13:27PM +0200, Vincent Abriou wrote:
>  static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
>  	.dpms = sti_crtc_dpms,

dpms isn't needed any more with atomic, you should use
drm_atomic_helper_connector_dpms instead of drm_helper_connector_dpms.

> -	.prepare = sti_crtc_prepare,
> -	.commit = sti_crtc_commit,
> +	.prepare = sti_crtc_helper_prepare,

prepare is now called .enable for clarity.

> +	.commit = sti_crtc_helper_commit,

commit and disable are redundant with atomic.

Cheers, Daniel
diff mbox

Patch

diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index d62ed7f..c652627 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -61,15 +61,13 @@  static int sti_compositor_bind(struct device *dev,
 {
 	struct sti_compositor *compo = dev_get_drvdata(dev);
 	struct drm_device *drm_dev = data;
-	unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0;
+	unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0;
 	struct sti_private *dev_priv = drm_dev->dev_private;
 	struct drm_plane *cursor = NULL;
 	struct drm_plane *primary = NULL;
 	struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc;
 	unsigned int array_size = compo->data.nb_subdev;
 
-	struct sti_plane *plane;
-
 	dev_priv->compo = compo;
 
 	/* Register mixer subdev and video subdev first */
@@ -110,27 +108,25 @@  static int sti_compositor_bind(struct device *dev,
 			/* Nothing to do, already done at the first round */
 			break;
 		case STI_CURSOR_SUBDEV:
-			plane = sti_cursor_create(compo->dev, desc[i].id,
-						  compo->regs + desc[i].offset);
-			if (!plane) {
+			cursor = sti_cursor_create(drm_dev, compo->dev,
+						   desc[i].id,
+						   compo->regs + desc[i].offset,
+						   1);
+			if (!cursor) {
 				DRM_ERROR("Can't create CURSOR plane\n");
 				break;
 			}
-			cursor = sti_plane_init(drm_dev, plane, 1,
-						DRM_PLANE_TYPE_CURSOR);
-			plane_id++;
 			break;
 		case STI_GPD_SUBDEV:
-			plane = sti_gdp_create(compo->dev, desc[i].id,
-					       compo->regs + desc[i].offset);
-			if (!plane) {
+			primary = sti_gdp_create(drm_dev, compo->dev,
+						 desc[i].id,
+						 compo->regs + desc[i].offset,
+						 (1 << mixer_id) - 1,
+						 plane_type);
+			if (!primary) {
 				DRM_ERROR("Can't create GDP plane\n");
 				break;
 			}
-			primary = sti_plane_init(drm_dev, plane,
-						 (1 << mixer_id) - 1,
-						 plane_type);
-			plane_id++;
 			break;
 		default:
 			DRM_ERROR("Unknown subdev compoment type\n");
@@ -151,10 +147,6 @@  static int sti_compositor_bind(struct device *dev,
 	/* Allow usage of vblank without having to call drm_irq_install */
 	drm_dev->irq_enabled = 1;
 
-	DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
-			 crtc_id, plane_id);
-	DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index 27b3ef2..2a12738 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -17,6 +17,7 @@ 
 #include "sti_compositor.h"
 #include "sti_crtc.h"
 #include "sti_drv.h"
+#include "sti_vid.h"
 #include "sti_vtg.h"
 
 static void sti_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -24,13 +25,13 @@  static void sti_crtc_dpms(struct drm_crtc *crtc, int mode)
 	DRM_DEBUG_KMS("\n");
 }
 
-static void sti_crtc_prepare(struct drm_crtc *crtc)
+static void sti_crtc_helper_prepare(struct drm_crtc *crtc)
 {
 	struct sti_mixer *mixer = to_sti_mixer(crtc);
 	struct device *dev = mixer->dev;
 	struct sti_compositor *compo = dev_get_drvdata(dev);
 
-	mixer->enabled = true;
+	mixer->status = STI_MIXER_READY;
 
 	/* Prepare and enable the compo IP clock */
 	if (mixer->id == STI_MIXER_MAIN) {
@@ -44,28 +45,25 @@  static void sti_crtc_prepare(struct drm_crtc *crtc)
 	sti_mixer_clear_all_planes(mixer);
 }
 
-static void sti_crtc_commit(struct drm_crtc *crtc)
+static void sti_crtc_helper_commit(struct drm_crtc *crtc)
 {
 	struct sti_mixer *mixer = to_sti_mixer(crtc);
 	struct device *dev = mixer->dev;
 	struct sti_compositor *compo = dev_get_drvdata(dev);
-	struct sti_plane *plane;
 
 	if ((!mixer || !compo)) {
 		DRM_ERROR("Can't find mixer or compositor)\n");
 		return;
 	}
 
-	/* get GDP which is reserved to the CRTC FB */
-	plane = to_sti_plane(crtc->primary);
-	if (!plane)
-		DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n");
+	drm_crtc_vblank_on(crtc);
+}
 
-	/* Enable plane on mixer */
-	if (sti_mixer_set_plane_status(mixer, plane, true))
-		DRM_ERROR("Cannot enable plane at mixer\n");
+static void sti_crtc_helper_disable(struct drm_crtc *crtc)
+{
+	struct sti_mixer *mixer = to_sti_mixer(crtc);
 
-	drm_crtc_vblank_on(crtc);
+	mixer->status = STI_MIXER_DISABLING;
 }
 
 static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -133,9 +131,6 @@  static void sti_crtc_disable(struct drm_crtc *crtc)
 	struct device *dev = mixer->dev;
 	struct sti_compositor *compo = dev_get_drvdata(dev);
 
-	if (!mixer->enabled)
-		return;
-
 	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
 
 	/* Disable Background */
@@ -152,13 +147,13 @@  static void sti_crtc_disable(struct drm_crtc *crtc)
 		clk_disable_unprepare(compo->clk_compo_aux);
 	}
 
-	mixer->enabled = false;
+	mixer->status = STI_MIXER_DISABLED;
 }
 
 static void
 sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
-	sti_crtc_prepare(crtc);
+	sti_crtc_helper_prepare(crtc);
 	sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
 }
 
@@ -178,17 +173,81 @@  static void sti_crtc_atomic_begin(struct drm_crtc *crtc)
 
 static void sti_crtc_atomic_flush(struct drm_crtc *crtc)
 {
+	struct drm_device *drm_dev = crtc->dev;
+	struct sti_mixer *mixer = to_sti_mixer(crtc);
+	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
+	struct drm_plane *p;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	/* perform plane actions */
+	list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
+		struct sti_plane *plane = to_sti_plane(p);
+
+		switch (plane->status) {
+		case STI_PLANE_UPDATED:
+			/* update planes tag as updated */
+			DRM_DEBUG_DRIVER("update plane %s\n",
+					 sti_plane_to_str(plane));
+
+			if (sti_mixer_set_plane_depth(mixer, plane)) {
+				DRM_ERROR("Cannot set plane %s depth\n",
+					  sti_plane_to_str(plane));
+				break;
+			}
+
+			if (sti_mixer_set_plane_status(mixer, plane, true)) {
+				DRM_ERROR("Cannot enable plane %s at mixer\n",
+					  sti_plane_to_str(plane));
+				break;
+			}
+
+			/* if plane is HQVDP_0 then commit the vid[0] */
+			if (plane->desc == STI_HQVDP_0)
+				sti_vid_commit(compo->vid[0], p->state);
+
+			plane->status = STI_PLANE_READY;
+
+			break;
+		case STI_PLANE_DISABLING:
+			/* disabling sequence for planes tag as disabling */
+			DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
+					 sti_plane_to_str(plane));
+
+			if (sti_mixer_set_plane_status(mixer, plane, false)) {
+				DRM_ERROR("Cannot disable plane %s at mixer\n",
+					  sti_plane_to_str(plane));
+				continue;
+			}
+
+			if (plane->desc == STI_CURSOR)
+				/* tag plane status for disabled */
+				plane->status = STI_PLANE_DISABLED;
+			else
+				/* tag plane status for flushing */
+				plane->status = STI_PLANE_FLUSHING;
+
+			/* if plane is HQVDP_0 then disable the vid[0] */
+			if (plane->desc == STI_HQVDP_0)
+				sti_vid_disable(compo->vid[0]);
+
+			break;
+		default:
+			/* Other status case are not handled */
+			break;
+		}
+	}
 }
 
 static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
 	.dpms = sti_crtc_dpms,
-	.prepare = sti_crtc_prepare,
-	.commit = sti_crtc_commit,
+	.prepare = sti_crtc_helper_prepare,
+	.commit = sti_crtc_helper_commit,
+	.disable = sti_crtc_helper_disable,
 	.mode_fixup = sti_crtc_mode_fixup,
 	.mode_set = drm_helper_crtc_mode_set,
 	.mode_set_nofb = sti_crtc_mode_set_nofb,
 	.mode_set_base = drm_helper_crtc_mode_set_base,
-	.disable = sti_crtc_disable,
 	.atomic_begin = sti_crtc_atomic_begin,
 	.atomic_flush = sti_crtc_atomic_flush,
 };
@@ -237,6 +296,21 @@  int sti_crtc_vblank_cb(struct notifier_block *nb,
 	}
 	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
 
+	if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
+		struct drm_plane *p;
+
+		/* Disable mixer only if all overlay planes (GDP and VDP)
+		 * are disabled */
+		list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
+			struct sti_plane *plane = to_sti_plane(p);
+
+			if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
+				if (plane->status != STI_PLANE_DISABLED)
+					return 0;
+		}
+		sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
+	}
+
 	return 0;
 }
 
@@ -259,9 +333,9 @@  int sti_crtc_enable_vblank(struct drm_device *dev, int crtc)
 }
 EXPORT_SYMBOL(sti_crtc_enable_vblank);
 
-void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)
+void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc)
 {
-	struct sti_private *priv = dev->dev_private;
+	struct sti_private *priv = drm_dev->dev_private;
 	struct sti_compositor *compo = priv->compo;
 	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
 
@@ -273,7 +347,7 @@  void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)
 
 	/* free the resources of the pending requests */
 	if (compo->mixer[crtc]->pending_event) {
-		drm_vblank_put(dev, crtc);
+		drm_vblank_put(drm_dev, crtc);
 		compo->mixer[crtc]->pending_event = NULL;
 	}
 }
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index 2868909..dd10321 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -7,6 +7,12 @@ 
  */
 #include <drm/drmP.h>
 
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "sti_compositor.h"
 #include "sti_cursor.h"
 #include "sti_plane.h"
 #include "sti_vtg.h"
@@ -42,14 +48,14 @@  struct dma_pixmap {
 /**
  * STI Cursor structure
  *
- * @sti_plane:  sti_plane structure
- * @dev:        driver device
- * @regs:       cursor registers
- * @width:      cursor width
- * @height:     cursor height
- * @clut:       color look up table
- * @clut_paddr: color look up table physical address
- * @pixmap:     pixmap dma buffer (clut8-format cursor)
+ * @sti_plane:    sti_plane structure
+ * @dev:          driver device
+ * @regs:         cursor registers
+ * @width:        cursor width
+ * @height:       cursor height
+ * @clut:         color look up table
+ * @clut_paddr:   color look up table physical address
+ * @pixmap:       pixmap dma buffer (clut8-format cursor)
  */
 struct sti_cursor {
 	struct sti_plane plane;
@@ -68,20 +74,8 @@  static const uint32_t cursor_supported_formats[] = {
 
 #define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
 
-static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane)
-{
-	return cursor_supported_formats;
-}
-
-static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane)
-{
-	return ARRAY_SIZE(cursor_supported_formats);
-}
-
-static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
+static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
 {
-	struct sti_cursor *cursor = to_sti_cursor(plane);
-	u32 *src = plane->vaddr;
 	u8  *dst = cursor->pixmap.base;
 	unsigned int i, j;
 	u32 a, r, g, b;
@@ -100,32 +94,67 @@  static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
 	}
 }
 
-static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
+static void sti_cursor_init(struct sti_cursor *cursor)
+{
+	unsigned short *base = cursor->clut;
+	unsigned int a, r, g, b;
+
+	/* Assign CLUT values, ARGB444 format */
+	for (a = 0; a < 4; a++)
+		for (r = 0; r < 4; r++)
+			for (g = 0; g < 4; g++)
+				for (b = 0; b < 4; b++)
+					*base++ = (a * 5) << 12 |
+						  (r * 5) << 8 |
+						  (g * 5) << 4 |
+						  (b * 5);
+}
+
+static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
+				     struct drm_plane_state *oldstate)
 {
+	struct drm_plane_state *state = drm_plane->state;
+	struct sti_plane *plane = to_sti_plane(drm_plane);
 	struct sti_cursor *cursor = to_sti_cursor(plane);
-	struct drm_display_mode *mode = plane->mode;
+	struct drm_crtc *crtc = state->crtc;
+	struct sti_mixer *mixer = to_sti_mixer(crtc);
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_display_mode *mode = &crtc->mode;
+	int dst_x = state->crtc_x;
+	int dst_y = state->crtc_y;
+	int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+	int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+	/* src_x are in 16.16 format */
+	int src_w = state->src_w >> 16;
+	int src_h = state->src_h >> 16;
+	bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
+	struct drm_gem_cma_object *cma_obj;
 	u32 y, x;
 	u32 val;
 
-	DRM_DEBUG_DRIVER("\n");
+	DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
+		      crtc->base.id, sti_mixer_to_str(mixer),
+		      drm_plane->base.id, sti_plane_to_str(plane));
+	DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);
 
-	dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
+	dev_dbg(cursor->dev, "%s %s\n", __func__,
+		sti_plane_to_str(plane));
 
-	if (plane->src_w < STI_CURS_MIN_SIZE ||
-	    plane->src_h < STI_CURS_MIN_SIZE ||
-	    plane->src_w > STI_CURS_MAX_SIZE ||
-	    plane->src_h > STI_CURS_MAX_SIZE) {
+	if (src_w < STI_CURS_MIN_SIZE ||
+	    src_h < STI_CURS_MIN_SIZE ||
+	    src_w > STI_CURS_MAX_SIZE ||
+	    src_h > STI_CURS_MAX_SIZE) {
 		DRM_ERROR("Invalid cursor size (%dx%d)\n",
-				plane->src_w, plane->src_h);
-		return -EINVAL;
+				src_w, src_h);
+		return;
 	}
 
 	/* If the cursor size has changed, re-allocated the pixmap */
 	if (!cursor->pixmap.base ||
-	    (cursor->width != plane->src_w) ||
-	    (cursor->height != plane->src_h)) {
-		cursor->width = plane->src_w;
-		cursor->height = plane->src_h;
+	    (cursor->width != src_w) ||
+	    (cursor->height != src_h)) {
+		cursor->width = src_w;
+		cursor->height = src_h;
 
 		if (cursor->pixmap.base)
 			dma_free_writecombine(cursor->dev,
@@ -141,12 +170,18 @@  static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
 							GFP_KERNEL | GFP_DMA);
 		if (!cursor->pixmap.base) {
 			DRM_ERROR("Failed to allocate memory for pixmap\n");
-			return -ENOMEM;
+			return;
 		}
 	}
 
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	if (!cma_obj) {
+		DRM_ERROR("Can't get CMA GEM object for fb\n");
+		return;
+	}
+
 	/* Convert ARGB8888 to CLUT8 */
-	sti_cursor_argb8888_to_clut8(plane);
+	sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);
 
 	/* AWS and AWE depend on the mode */
 	y = sti_vtg_get_line_number(*mode, 0);
@@ -164,62 +199,50 @@  static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
 		writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
 	}
 
-	return 0;
-}
-
-static int sti_cursor_commit_plane(struct sti_plane *plane)
-{
-	struct sti_cursor *cursor = to_sti_cursor(plane);
-	struct drm_display_mode *mode = plane->mode;
-	u32 ydo, xdo;
-
-	dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
-
 	/* Set memory location, size, and position */
 	writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
 	writel(cursor->width, cursor->regs + CUR_PMP);
 	writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);
 
-	ydo = sti_vtg_get_line_number(*mode, plane->dst_y);
-	xdo = sti_vtg_get_pixel_number(*mode, plane->dst_y);
-	writel((ydo << 16) | xdo, cursor->regs + CUR_VPO);
+	y = sti_vtg_get_line_number(*mode, dst_y);
+	x = sti_vtg_get_pixel_number(*mode, dst_y);
+	writel((y << 16) | x, cursor->regs + CUR_VPO);
 
-	return 0;
+	plane->status = STI_PLANE_UPDATED;
 }
 
-static int sti_cursor_disable_plane(struct sti_plane *plane)
+static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
+				      struct drm_plane_state *oldstate)
 {
-	return 0;
-}
+	struct sti_plane *plane = to_sti_plane(drm_plane);
+	struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
 
-static void sti_cursor_init(struct sti_cursor *cursor)
-{
-	unsigned short *base = cursor->clut;
-	unsigned int a, r, g, b;
+	if (!drm_plane->crtc) {
+		DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
+				 drm_plane->base.id);
+		return;
+	}
 
-	/* Assign CLUT values, ARGB444 format */
-	for (a = 0; a < 4; a++)
-		for (r = 0; r < 4; r++)
-			for (g = 0; g < 4; g++)
-				for (b = 0; b < 4; b++)
-					*base++ = (a * 5) << 12 |
-						  (r * 5) << 8 |
-						  (g * 5) << 4 |
-						  (b * 5);
+	DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
+			 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
+			 drm_plane->base.id, sti_plane_to_str(plane));
+
+	plane->status = STI_PLANE_DISABLING;
 }
 
-static const struct sti_plane_funcs cursor_plane_ops = {
-	.get_formats = sti_cursor_get_formats,
-	.get_nb_formats = sti_cursor_get_nb_formats,
-	.prepare = sti_cursor_prepare_plane,
-	.commit = sti_cursor_commit_plane,
-	.disable = sti_cursor_disable_plane,
+static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
+	.atomic_update = sti_cursor_atomic_update,
+	.atomic_disable = sti_cursor_atomic_disable,
 };
 
-struct sti_plane *sti_cursor_create(struct device *dev, int desc,
-				    void __iomem *baseaddr)
+struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
+				    struct device *dev, int desc,
+				    void __iomem *baseaddr,
+				    unsigned int possible_crtcs)
 {
 	struct sti_cursor *cursor;
+	size_t size;
+	int res;
 
 	cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
 	if (!cursor) {
@@ -228,23 +251,43 @@  struct sti_plane *sti_cursor_create(struct device *dev, int desc,
 	}
 
 	/* Allocate clut buffer */
-	cursor->clut = dma_alloc_writecombine(dev,
-			0x100 * sizeof(unsigned short),
-			&cursor->clut_paddr,
-			GFP_KERNEL | GFP_DMA);
+	size = 0x100 * sizeof(unsigned short);
+	cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr,
+					      GFP_KERNEL | GFP_DMA);
 
 	if (!cursor->clut) {
 		DRM_ERROR("Failed to allocate memory for cursor clut\n");
-		devm_kfree(dev, cursor);
-		return NULL;
+		goto err_clut;
 	}
 
 	cursor->dev = dev;
 	cursor->regs = baseaddr;
 	cursor->plane.desc = desc;
-	cursor->plane.ops = &cursor_plane_ops;
+	cursor->plane.status = STI_PLANE_DISABLED;
 
 	sti_cursor_init(cursor);
 
-	return &cursor->plane;
+	res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane,
+				       possible_crtcs,
+				       &sti_plane_helpers_funcs,
+				       cursor_supported_formats,
+				       ARRAY_SIZE(cursor_supported_formats),
+				       DRM_PLANE_TYPE_CURSOR);
+	if (res) {
+		DRM_ERROR("Failed to initialize universal plane\n");
+		goto err_plane;
+	}
+
+	drm_plane_helper_add(&cursor->plane.drm_plane,
+			     &sti_cursor_helpers_funcs);
+
+	sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
+
+	return &cursor->plane.drm_plane;
+
+err_plane:
+	dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr);
+err_clut:
+	devm_kfree(dev, cursor);
+	return NULL;
 }
diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h
index db973b7..2ee5c10 100644
--- a/drivers/gpu/drm/sti/sti_cursor.h
+++ b/drivers/gpu/drm/sti/sti_cursor.h
@@ -7,7 +7,9 @@ 
 #ifndef _STI_CURSOR_H_
 #define _STI_CURSOR_H_
 
-struct sti_plane *sti_cursor_create(struct device *dev, int desc,
-				    void __iomem *baseaddr);
+struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
+				    struct device *dev, int desc,
+				    void __iomem *baseaddr,
+				    unsigned int possible_crtcs);
 
 #endif
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index e323310..9365670 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -9,6 +9,9 @@ 
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
 #include "sti_compositor.h"
 #include "sti_gdp.h"
 #include "sti_plane.h"
@@ -26,7 +29,7 @@ 
 #define GDP_XBGR8888    (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
 #define GDP_ARGB8565    0x04
 #define GDP_ARGB8888    0x05
-#define GDP_ABGR8888	(GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
+#define GDP_ABGR8888    (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
 #define GDP_ARGB1555    0x06
 #define GDP_ARGB4444    0x07
 #define GDP_CLUT8       0x0B
@@ -53,8 +56,8 @@ 
 #define GAM_GDP_PPT_IGNORE      (BIT(1) | BIT(0))
 #define GAM_GDP_SIZE_MAX        0x7FF
 
-#define GDP_NODE_NB_BANK	2
-#define GDP_NODE_PER_FIELD	2
+#define GDP_NODE_NB_BANK        2
+#define GDP_NODE_PER_FIELD      2
 
 struct sti_gdp_node {
 	u32 gam_gdp_ctl;
@@ -124,16 +127,6 @@  static const uint32_t gdp_supported_formats[] = {
 	DRM_FORMAT_C8,
 };
 
-static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane)
-{
-	return gdp_supported_formats;
-}
-
-static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane)
-{
-	return ARRAY_SIZE(gdp_supported_formats);
-}
-
 static int sti_gdp_fourcc2format(int fourcc)
 {
 	switch (fourcc) {
@@ -179,17 +172,16 @@  static int sti_gdp_get_alpharange(int format)
 
 /**
  * sti_gdp_get_free_nodes
- * @plane: gdp plane
+ * @gdp: gdp pointer
  *
  * Look for a GDP node list that is not currently read by the HW.
  *
  * RETURNS:
  * Pointer to the free GDP node list
  */
-static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane)
+static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_gdp *gdp)
 {
 	int hw_nvn;
-	struct sti_gdp *gdp = to_sti_gdp(plane);
 	unsigned int i;
 
 	hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
@@ -203,7 +195,7 @@  static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane)
 
 	/* in hazardious cases restart with the first node */
 	DRM_ERROR("inconsistent NVN for %s: 0x%08X\n",
-			sti_plane_to_str(plane), hw_nvn);
+			sti_plane_to_str(&gdp->plane), hw_nvn);
 
 end:
 	return &gdp->node_list[0];
@@ -211,7 +203,7 @@  end:
 
 /**
  * sti_gdp_get_current_nodes
- * @plane: GDP plane
+ * @gdp: gdp pointer
  *
  * Look for GDP nodes that are currently read by the HW.
  *
@@ -219,10 +211,9 @@  end:
  * Pointer to the current GDP node list
  */
 static
-struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane)
+struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_gdp *gdp)
 {
 	int hw_nvn;
-	struct sti_gdp *gdp = to_sti_gdp(plane);
 	unsigned int i;
 
 	hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET);
@@ -236,205 +227,25 @@  struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane)
 
 end:
 	DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n",
-				hw_nvn, sti_plane_to_str(plane));
+				hw_nvn, sti_plane_to_str(&gdp->plane));
 
 	return NULL;
 }
 
 /**
- * sti_gdp_prepare
- * @plane: gdp plane
- * @first_prepare: true if it is the first time this function is called
- *
- * Update the free GDP node list according to the plane properties.
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_gdp_prepare(struct sti_plane *plane, bool first_prepare)
-{
-	struct sti_gdp_node_list *list;
-	struct sti_gdp_node *top_field, *btm_field;
-	struct drm_display_mode *mode = plane->mode;
-	struct sti_gdp *gdp = to_sti_gdp(plane);
-	struct device *dev = gdp->dev;
-	struct sti_compositor *compo = dev_get_drvdata(dev);
-	int format;
-	unsigned int depth, bpp;
-	int rate = mode->clock * 1000;
-	int res;
-	u32 ydo, xdo, yds, xds;
-
-	list = sti_gdp_get_free_nodes(plane);
-	top_field = list->top_field;
-	btm_field = list->btm_field;
-
-	dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
-			sti_plane_to_str(plane), top_field, btm_field);
-
-	/* Build the top field from plane params */
-	top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
-	top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
-	format = sti_gdp_fourcc2format(plane->format);
-	if (format == -1) {
-		DRM_ERROR("Format not supported by GDP %.4s\n",
-			  (char *)&plane->format);
-		return 1;
-	}
-	top_field->gam_gdp_ctl |= format;
-	top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
-	top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
-
-	/* pixel memory location */
-	drm_fb_get_bpp_depth(plane->format, &depth, &bpp);
-	top_field->gam_gdp_pml = (u32)plane->paddr + plane->offsets[0];
-	top_field->gam_gdp_pml += plane->src_x * (bpp >> 3);
-	top_field->gam_gdp_pml += plane->src_y * plane->pitches[0];
-
-	/* input parameters */
-	top_field->gam_gdp_pmp = plane->pitches[0];
-	top_field->gam_gdp_size =
-	    clamp_val(plane->src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
-	    clamp_val(plane->src_w, 0, GAM_GDP_SIZE_MAX);
-
-	/* output parameters */
-	ydo = sti_vtg_get_line_number(*mode, plane->dst_y);
-	yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1);
-	xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x);
-	xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1);
-	top_field->gam_gdp_vpo = (ydo << 16) | xdo;
-	top_field->gam_gdp_vps = (yds << 16) | xds;
-
-	/* Same content and chained together */
-	memcpy(btm_field, top_field, sizeof(*btm_field));
-	top_field->gam_gdp_nvn = list->btm_field_paddr;
-	btm_field->gam_gdp_nvn = list->top_field_paddr;
-
-	/* Interlaced mode */
-	if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE)
-		btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
-		    plane->pitches[0];
-
-	if (first_prepare) {
-		/* Register gdp callback */
-		if (sti_vtg_register_client(plane->mixer_id == STI_MIXER_MAIN ?
-				compo->vtg_main : compo->vtg_aux,
-				&gdp->vtg_field_nb, plane->mixer_id)) {
-			DRM_ERROR("Cannot register VTG notifier\n");
-			return 1;
-		}
-
-		/* Set and enable gdp clock */
-		if (gdp->clk_pix) {
-			struct clk *clkp;
-			/* According to the mixer used, the gdp pixel clock
-			 * should have a different parent clock. */
-			if (plane->mixer_id == STI_MIXER_MAIN)
-				clkp = gdp->clk_main_parent;
-			else
-				clkp = gdp->clk_aux_parent;
-
-			if (clkp)
-				clk_set_parent(gdp->clk_pix, clkp);
-
-			res = clk_set_rate(gdp->clk_pix, rate);
-			if (res < 0) {
-				DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
-						rate);
-				return 1;
-			}
-
-			if (clk_prepare_enable(gdp->clk_pix)) {
-				DRM_ERROR("Failed to prepare/enable gdp\n");
-				return 1;
-			}
-		}
-	}
-
-	return 0;
-}
-
-/**
- * sti_gdp_commit
- * @plane: gdp plane
- *
- * Update the NVN field of the 'right' field of the current GDP node (being
- * used by the HW) with the address of the updated ('free') top field GDP node.
- * - In interlaced mode the 'right' field is the bottom field as we update
- *   frames starting from their top field
- * - In progressive mode, we update both bottom and top fields which are
- *   equal nodes.
- * At the next VSYNC, the updated node list will be used by the HW.
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_gdp_commit(struct sti_plane *plane)
-{
-	struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(plane);
-	struct sti_gdp_node *updated_top_node = updated_list->top_field;
-	struct sti_gdp_node *updated_btm_node = updated_list->btm_field;
-	struct sti_gdp *gdp = to_sti_gdp(plane);
-	u32 dma_updated_top = updated_list->top_field_paddr;
-	u32 dma_updated_btm = updated_list->btm_field_paddr;
-	struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(plane);
-
-	dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__,
-		sti_plane_to_str(plane),
-		updated_top_node, updated_btm_node);
-	dev_dbg(gdp->dev, "Current NVN:0x%X\n",
-		readl(gdp->regs + GAM_GDP_NVN_OFFSET));
-	dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
-		(unsigned long)plane->paddr,
-		readl(gdp->regs + GAM_GDP_PML_OFFSET));
-
-	if (curr_list == NULL) {
-		/* First update or invalid node should directly write in the
-		 * hw register */
-		DRM_DEBUG_DRIVER("%s first update (or invalid node)",
-				sti_plane_to_str(plane));
-
-		writel(gdp->is_curr_top == true ?
-				dma_updated_btm : dma_updated_top,
-				gdp->regs + GAM_GDP_NVN_OFFSET);
-		return 0;
-	}
-
-	if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) {
-		if (gdp->is_curr_top == true) {
-			/* Do not update in the middle of the frame, but
-			 * postpone the update after the bottom field has
-			 * been displayed */
-			curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
-		} else {
-			/* Direct update to avoid one frame delay */
-			writel(dma_updated_top,
-				gdp->regs + GAM_GDP_NVN_OFFSET);
-		}
-	} else {
-		/* Direct update for progressive to avoid one frame delay */
-		writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET);
-	}
-
-	return 0;
-}
-
-/**
  * sti_gdp_disable
- * @plane: gdp plane
+ * @gdp: gdp pointer
  *
  * Disable a GDP.
- *
- * RETURNS:
- * 0 on success.
  */
-static int sti_gdp_disable(struct sti_plane *plane)
+static void sti_gdp_disable(struct sti_gdp *gdp)
 {
-	unsigned int i;
-	struct sti_gdp *gdp = to_sti_gdp(plane);
+	struct drm_plane *drm_plane = &gdp->plane.drm_plane;
+	struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
 	struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
+	unsigned int i;
 
-	DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane));
+	DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane));
 
 	/* Set the nodes as 'to be ignored on mixer' */
 	for (i = 0; i < GDP_NODE_NB_BANK; i++) {
@@ -442,14 +253,14 @@  static int sti_gdp_disable(struct sti_plane *plane)
 		gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
 	}
 
-	if (sti_vtg_unregister_client(plane->mixer_id == STI_MIXER_MAIN ?
+	if (sti_vtg_unregister_client(mixer->id == STI_MIXER_MAIN ?
 			compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb))
 		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
 
 	if (gdp->clk_pix)
 		clk_disable_unprepare(gdp->clk_pix);
 
-	return 0;
+	gdp->plane.status = STI_PLANE_DISABLED;
 }
 
 /**
@@ -468,6 +279,14 @@  int sti_gdp_field_cb(struct notifier_block *nb,
 {
 	struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb);
 
+	if (gdp->plane.status == STI_PLANE_FLUSHING) {
+		/* disable need to be synchronize on vsync event */
+		DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
+				 sti_plane_to_str(&gdp->plane));
+
+		sti_gdp_disable(gdp);
+	}
+
 	switch (event) {
 	case VTG_TOP_FIELD_EVENT:
 		gdp->is_curr_top = true;
@@ -561,18 +380,235 @@  static void sti_gdp_init(struct sti_gdp *gdp)
 	}
 }
 
-static const struct sti_plane_funcs gdp_plane_ops = {
-	.get_formats = sti_gdp_get_formats,
-	.get_nb_formats = sti_gdp_get_nb_formats,
-	.prepare = sti_gdp_prepare,
-	.commit = sti_gdp_commit,
-	.disable = sti_gdp_disable,
+static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
+				  struct drm_plane_state *oldstate)
+{
+	struct drm_plane_state *state = drm_plane->state;
+	struct sti_plane *plane = to_sti_plane(drm_plane);
+	struct sti_gdp *gdp = to_sti_gdp(plane);
+	struct drm_crtc *crtc = state->crtc;
+	struct sti_compositor *compo = dev_get_drvdata(gdp->dev);
+	struct drm_framebuffer *fb =  state->fb;
+	bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
+	struct sti_mixer *mixer;
+	struct drm_display_mode *mode;
+	int dst_x, dst_y, dst_w, dst_h;
+	int src_x, src_y, src_w, src_h;
+	struct drm_gem_cma_object *cma_obj;
+	struct sti_gdp_node_list *list;
+	struct sti_gdp_node_list *curr_list;
+	struct sti_gdp_node *top_field, *btm_field;
+	u32 dma_updated_top;
+	u32 dma_updated_btm;
+	int format;
+	unsigned int depth, bpp;
+	u32 ydo, xdo, yds, xds;
+	int res;
+
+	/* Manage the case where crtc is null (disabled) */
+	if (!crtc)
+		return;
+
+	mixer = to_sti_mixer(crtc);
+	mode = &crtc->mode;
+	dst_x = state->crtc_x;
+	dst_y = state->crtc_y;
+	dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+	dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+	/* src_x are in 16.16 format */
+	src_x = state->src_x >> 16;
+	src_y = state->src_y >> 16;
+	src_w = state->src_w >> 16;
+	src_h = state->src_h >> 16;
+
+	DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
+		      crtc->base.id, sti_mixer_to_str(mixer),
+		      drm_plane->base.id, sti_plane_to_str(plane));
+	DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
+		      sti_plane_to_str(plane),
+		      dst_w, dst_h, dst_x, dst_y,
+		      src_w, src_h, src_x, src_y);
+
+	list = sti_gdp_get_free_nodes(gdp);
+	top_field = list->top_field;
+	btm_field = list->btm_field;
+
+	dev_dbg(gdp->dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
+		sti_plane_to_str(plane), top_field, btm_field);
+
+	/* build the top field */
+	top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
+	top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
+	format = sti_gdp_fourcc2format(fb->pixel_format);
+	if (format == -1) {
+		DRM_ERROR("Format not supported by GDP %.4s\n",
+			  (char *)&fb->pixel_format);
+		return;
+	}
+	top_field->gam_gdp_ctl |= format;
+	top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
+	top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	if (!cma_obj) {
+		DRM_ERROR("Can't get CMA GEM object for fb\n");
+		return;
+	}
+
+	DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
+			 (char *)&fb->pixel_format,
+			 (unsigned long)cma_obj->paddr);
+
+	/* pixel memory location */
+	drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
+	top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0];
+	top_field->gam_gdp_pml += src_x * (bpp >> 3);
+	top_field->gam_gdp_pml += src_y * fb->pitches[0];
+
+	/* input parameters */
+	top_field->gam_gdp_pmp = fb->pitches[0];
+	top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
+				  clamp_val(src_w, 0, GAM_GDP_SIZE_MAX);
+
+	/* output parameters */
+	ydo = sti_vtg_get_line_number(*mode, dst_y);
+	yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
+	xdo = sti_vtg_get_pixel_number(*mode, dst_x);
+	xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
+	top_field->gam_gdp_vpo = (ydo << 16) | xdo;
+	top_field->gam_gdp_vps = (yds << 16) | xds;
+
+	/* Same content and chained together */
+	memcpy(btm_field, top_field, sizeof(*btm_field));
+	top_field->gam_gdp_nvn = list->btm_field_paddr;
+	btm_field->gam_gdp_nvn = list->top_field_paddr;
+
+	/* Interlaced mode */
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
+					 fb->pitches[0];
+
+	if (first_prepare) {
+		/* Register gdp callback */
+		if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
+				compo->vtg_main : compo->vtg_aux,
+				&gdp->vtg_field_nb, mixer->id)) {
+			DRM_ERROR("Cannot register VTG notifier\n");
+			return;
+		}
+
+		/* Set and enable gdp clock */
+		if (gdp->clk_pix) {
+			struct clk *clkp;
+			int rate = mode->clock * 1000;
+
+			/* According to the mixer used, the gdp pixel clock
+			 * should have a different parent clock. */
+			if (mixer->id == STI_MIXER_MAIN)
+				clkp = gdp->clk_main_parent;
+			else
+				clkp = gdp->clk_aux_parent;
+
+			if (clkp)
+				clk_set_parent(gdp->clk_pix, clkp);
+
+			res = clk_set_rate(gdp->clk_pix, rate);
+			if (res < 0) {
+				DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
+					  rate);
+				return;
+			}
+
+			if (clk_prepare_enable(gdp->clk_pix)) {
+				DRM_ERROR("Failed to prepare/enable gdp\n");
+				return;
+			}
+		}
+	}
+
+	/* Update the NVN field of the 'right' field of the current GDP node
+	 * (being used by the HW) with the address of the updated ('free') top
+	 * field GDP node.
+	 * - In interlaced mode the 'right' field is the bottom field as we
+	 *   update frames starting from their top field
+	 * - In progressive mode, we update both bottom and top fields which
+	 *   are equal nodes.
+	 * At the next VSYNC, the updated node list will be used by the HW.
+	 */
+	curr_list = sti_gdp_get_current_nodes(gdp);
+	dma_updated_top = list->top_field_paddr;
+	dma_updated_btm = list->btm_field_paddr;
+
+	dev_dbg(gdp->dev, "Current NVN:0x%X\n",
+		readl(gdp->regs + GAM_GDP_NVN_OFFSET));
+	dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n",
+		(unsigned long)cma_obj->paddr,
+		readl(gdp->regs + GAM_GDP_PML_OFFSET));
+
+	if (!curr_list) {
+		/* First update or invalid node should directly write in the
+		 * hw register */
+		DRM_DEBUG_DRIVER("%s first update (or invalid node)",
+				 sti_plane_to_str(plane));
+
+		writel(gdp->is_curr_top ?
+				dma_updated_btm : dma_updated_top,
+				gdp->regs + GAM_GDP_NVN_OFFSET);
+		goto end;
+	}
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		if (gdp->is_curr_top) {
+			/* Do not update in the middle of the frame, but
+			 * postpone the update after the bottom field has
+			 * been displayed */
+			curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
+		} else {
+			/* Direct update to avoid one frame delay */
+			writel(dma_updated_top,
+			       gdp->regs + GAM_GDP_NVN_OFFSET);
+		}
+	} else {
+		/* Direct update for progressive to avoid one frame delay */
+		writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET);
+	}
+
+end:
+	plane->status = STI_PLANE_UPDATED;
+}
+
+static void sti_gdp_atomic_disable(struct drm_plane *drm_plane,
+				   struct drm_plane_state *oldstate)
+{
+	struct sti_plane *plane = to_sti_plane(drm_plane);
+	struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
+
+	if (!drm_plane->crtc) {
+		DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
+				 drm_plane->base.id);
+		return;
+	}
+
+	DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
+			 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
+			 drm_plane->base.id, sti_plane_to_str(plane));
+
+	plane->status = STI_PLANE_DISABLING;
+}
+
+static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
+	.atomic_update = sti_gdp_atomic_update,
+	.atomic_disable = sti_gdp_atomic_disable,
 };
 
-struct sti_plane *sti_gdp_create(struct device *dev, int desc,
-				 void __iomem *baseaddr)
+struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
+				 struct device *dev, int desc,
+				 void __iomem *baseaddr,
+				 unsigned int possible_crtcs,
+				 enum drm_plane_type type)
 {
 	struct sti_gdp *gdp;
+	int res;
 
 	gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL);
 	if (!gdp) {
@@ -583,11 +619,30 @@  struct sti_plane *sti_gdp_create(struct device *dev, int desc,
 	gdp->dev = dev;
 	gdp->regs = baseaddr;
 	gdp->plane.desc = desc;
-	gdp->plane.ops = &gdp_plane_ops;
+	gdp->plane.status = STI_PLANE_DISABLED;
 
 	gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb;
 
 	sti_gdp_init(gdp);
 
-	return &gdp->plane;
+	res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane,
+				       possible_crtcs,
+				       &sti_plane_helpers_funcs,
+				       gdp_supported_formats,
+				       ARRAY_SIZE(gdp_supported_formats),
+				       type);
+	if (res) {
+		DRM_ERROR("Failed to initialize universal plane\n");
+		goto err;
+	}
+
+	drm_plane_helper_add(&gdp->plane.drm_plane, &sti_gdp_helpers_funcs);
+
+	sti_plane_init_property(&gdp->plane, type);
+
+	return &gdp->plane.drm_plane;
+
+err:
+	devm_kfree(dev, gdp);
+	return NULL;
 }
diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h
index 01818ea..73947a4 100644
--- a/drivers/gpu/drm/sti/sti_gdp.h
+++ b/drivers/gpu/drm/sti/sti_gdp.h
@@ -11,7 +11,9 @@ 
 
 #include <linux/types.h>
 
-struct sti_plane *sti_gdp_create(struct device *dev, int desc,
-				 void __iomem *baseaddr);
-
+struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
+				 struct device *dev, int desc,
+				 void __iomem *baseaddr,
+				 unsigned int possible_crtcs,
+				 enum drm_plane_type type);
 #endif
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index b91a009..7c8f9b8 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -12,7 +12,10 @@ 
 #include <linux/reset.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 
+#include "sti_compositor.h"
 #include "sti_hqvdp_lut.h"
 #include "sti_plane.h"
 #include "sti_vtg.h"
@@ -357,16 +360,6 @@  static const uint32_t hqvdp_supported_formats[] = {
 	DRM_FORMAT_NV12,
 };
 
-static const uint32_t *sti_hqvdp_get_formats(struct sti_plane *plane)
-{
-	return hqvdp_supported_formats;
-}
-
-static unsigned int sti_hqvdp_get_nb_formats(struct sti_plane *plane)
-{
-	return ARRAY_SIZE(hqvdp_supported_formats);
-}
-
 /**
  * sti_hqvdp_get_free_cmd
  * @hqvdp: hqvdp structure
@@ -482,7 +475,12 @@  static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale,
 
 /**
  * sti_hqvdp_check_hw_scaling
- * @plane: hqvdp plane
+ * @hqvdp: hqvdp pointer
+ * @mode: display mode with timing constraints
+ * @src_w: source width
+ * @src_h: source height
+ * @dst_w: destination width
+ * @dst_h: destination height
  *
  * Check if the HW is able to perform the scaling request
  * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where:
@@ -496,194 +494,36 @@  static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale,
  * RETURNS:
  * True if the HW can scale.
  */
-static bool sti_hqvdp_check_hw_scaling(struct sti_plane *plane)
+static bool sti_hqvdp_check_hw_scaling(struct sti_hqvdp *hqvdp,
+				       struct drm_display_mode *mode,
+				       int src_w, int src_h,
+				       int dst_w, int dst_h)
 {
-	struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
 	unsigned long lfw;
 	unsigned int inv_zy;
 
-	lfw = plane->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000);
-	lfw /= max(plane->src_w, plane->dst_w) * plane->mode->clock / 1000;
+	lfw = mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000);
+	lfw /= max(src_w, dst_w) * mode->clock / 1000;
 
-	inv_zy = DIV_ROUND_UP(plane->src_h, plane->dst_h);
+	inv_zy = DIV_ROUND_UP(src_h, dst_h);
 
 	return (inv_zy <= lfw) ? true : false;
 }
 
 /**
- * sti_hqvdp_prepare
- * @plane: hqvdp plane
- * @first_prepare: true if it is the first time this function is called
- *
- * Prepares a command for the firmware
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_hqvdp_prepare(struct sti_plane *plane, bool first_prepare)
-{
-	struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
-	struct sti_hqvdp_cmd *cmd;
-	int scale_h, scale_v;
-	int cmd_offset;
-
-	dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
-
-	cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
-	if (cmd_offset == -1) {
-		DRM_ERROR("No available hqvdp_cmd now\n");
-		return -EBUSY;
-	}
-	cmd = hqvdp->hqvdp_cmd + cmd_offset;
-
-	if (!sti_hqvdp_check_hw_scaling(plane)) {
-		DRM_ERROR("Scaling beyond HW capabilities\n");
-		return -EINVAL;
-	}
-
-	/* Static parameters, defaulting to progressive mode */
-	cmd->top.config = TOP_CONFIG_PROGRESSIVE;
-	cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
-	cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT;
-	cmd->csdi.config = CSDI_CONFIG_PROG;
-
-	/* VC1RE, FMD bypassed : keep everything set to 0
-	 * IQI/P2I bypassed */
-	cmd->iqi.config = IQI_CONFIG_DFLT;
-	cmd->iqi.con_bri = IQI_CON_BRI_DFLT;
-	cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT;
-	cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
-
-	/* Buffer planes address */
-	cmd->top.current_luma = (u32)plane->paddr + plane->offsets[0];
-	cmd->top.current_chroma = (u32)plane->paddr + plane->offsets[1];
-
-	/* Pitches */
-	cmd->top.luma_processed_pitch = cmd->top.luma_src_pitch =
-			plane->pitches[0];
-	cmd->top.chroma_processed_pitch = cmd->top.chroma_src_pitch =
-			plane->pitches[1];
-
-	/* Input / output size
-	 * Align to upper even value */
-	plane->dst_w = ALIGN(plane->dst_w, 2);
-	plane->dst_h = ALIGN(plane->dst_h, 2);
-
-	if ((plane->src_w > MAX_WIDTH) || (plane->src_w < MIN_WIDTH) ||
-	    (plane->src_h > MAX_HEIGHT) || (plane->src_h < MIN_HEIGHT) ||
-	    (plane->dst_w > MAX_WIDTH) || (plane->dst_w < MIN_WIDTH) ||
-	    (plane->dst_h > MAX_HEIGHT) || (plane->dst_h < MIN_HEIGHT)) {
-		DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
-				plane->src_w, plane->src_h,
-				plane->dst_w, plane->dst_h);
-		return -EINVAL;
-	}
-	cmd->top.input_viewport_size = cmd->top.input_frame_size =
-			plane->src_h << 16 | plane->src_w;
-	cmd->hvsrc.output_picture_size = plane->dst_h << 16 | plane->dst_w;
-	cmd->top.input_viewport_ori = plane->src_y << 16 | plane->src_x;
-
-	/* Handle interlaced */
-	if (plane->fb->flags & DRM_MODE_FB_INTERLACED) {
-		/* Top field to display */
-		cmd->top.config = TOP_CONFIG_INTER_TOP;
-
-		/* Update pitches and vert size */
-		cmd->top.input_frame_size = (plane->src_h / 2) << 16 |
-					     plane->src_w;
-		cmd->top.luma_processed_pitch *= 2;
-		cmd->top.luma_src_pitch *= 2;
-		cmd->top.chroma_processed_pitch *= 2;
-		cmd->top.chroma_src_pitch *= 2;
-
-		/* Enable directional deinterlacing processing */
-		cmd->csdi.config = CSDI_CONFIG_INTER_DIR;
-		cmd->csdi.config2 = CSDI_CONFIG2_DFLT;
-		cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT;
-	}
-
-	/* Update hvsrc lut coef */
-	scale_h = SCALE_FACTOR * plane->dst_w / plane->src_w;
-	sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc);
-
-	scale_v = SCALE_FACTOR * plane->dst_h / plane->src_h;
-	sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
-
-	if (first_prepare) {
-		/* Prevent VTG shutdown */
-		if (clk_prepare_enable(hqvdp->clk_pix_main)) {
-			DRM_ERROR("Failed to prepare/enable pix main clk\n");
-			return -ENXIO;
-		}
-
-		/* Register VTG Vsync callback to handle bottom fields */
-		if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) &&
-		    sti_vtg_register_client(hqvdp->vtg, &hqvdp->vtg_nb,
-					    plane->mixer_id)) {
-			DRM_ERROR("Cannot register VTG notifier\n");
-			return -ENXIO;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * sti_hqvdp_commit
- * @plane: hqvdp plane
- *
- * Enables the HQVDP plane
- *
- * RETURNS:
- * 0 on success.
- */
-static int sti_hqvdp_commit(struct sti_plane *plane)
-{
-	struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
-	int cmd_offset;
-
-	dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
-
-	cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
-	if (cmd_offset == -1) {
-		DRM_ERROR("No available hqvdp_cmd now\n");
-		return -EBUSY;
-	}
-
-	writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
-			hqvdp->regs + HQVDP_MBX_NEXT_CMD);
-
-	hqvdp->curr_field_count++;
-
-	/* Interlaced : get ready to display the bottom field at next Vsync */
-	if (plane->fb->flags & DRM_MODE_FB_INTERLACED)
-		hqvdp->btm_field_pending = true;
-
-	dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
-			__func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
-
-	return 0;
-}
-
-/**
  * sti_hqvdp_disable
- * @plane: hqvdp plane
+ * @hqvdp: hqvdp pointer
  *
  * Disables the HQVDP plane
- *
- * RETURNS:
- * 0 on success.
  */
-static int sti_hqvdp_disable(struct sti_plane *plane)
+static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp)
 {
-	struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
 	int i;
 
-	DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane));
+	DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&hqvdp->plane));
 
 	/* Unregister VTG Vsync callback */
-	if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) &&
-	    sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb))
+	if (sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb))
 		DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
 
 	/* Set next cmd to NULL */
@@ -699,12 +539,10 @@  static int sti_hqvdp_disable(struct sti_plane *plane)
 	/* VTG can stop now */
 	clk_disable_unprepare(hqvdp->clk_pix_main);
 
-	if (i == POLL_MAX_ATTEMPT) {
+	if (i == POLL_MAX_ATTEMPT)
 		DRM_ERROR("XP70 could not revert to idle\n");
-		return -ENXIO;
-	}
 
-	return 0;
+	hqvdp->plane.status = STI_PLANE_DISABLED;
 }
 
 /**
@@ -729,6 +567,14 @@  int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
 		return 0;
 	}
 
+	if (hqvdp->plane.status == STI_PLANE_FLUSHING) {
+		/* disable need to be synchronize on vsync event */
+		DRM_DEBUG_DRIVER("Vsync event received => disable %s\n",
+				 sti_plane_to_str(&hqvdp->plane));
+
+		sti_hqvdp_disable(hqvdp);
+	}
+
 	if (hqvdp->btm_field_pending) {
 		/* Create the btm field command from the current one */
 		btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
@@ -782,24 +628,212 @@  static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
 	memset(hqvdp->hqvdp_cmd, 0, size);
 }
 
-static const struct sti_plane_funcs hqvdp_plane_ops = {
-	.get_formats = sti_hqvdp_get_formats,
-	.get_nb_formats = sti_hqvdp_get_nb_formats,
-	.prepare = sti_hqvdp_prepare,
-	.commit = sti_hqvdp_commit,
-	.disable = sti_hqvdp_disable,
+static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
+				    struct drm_plane_state *oldstate)
+{
+	struct drm_plane_state *state = drm_plane->state;
+	struct sti_plane *plane = to_sti_plane(drm_plane);
+	struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane);
+	struct drm_crtc *crtc = state->crtc;
+	struct sti_mixer *mixer = to_sti_mixer(crtc);
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_display_mode *mode = &crtc->mode;
+	int dst_x = state->crtc_x;
+	int dst_y = state->crtc_y;
+	int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+	int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
+	/* src_x are in 16.16 format */
+	int src_x = state->src_x >> 16;
+	int src_y = state->src_y >> 16;
+	int src_w = state->src_w >> 16;
+	int src_h = state->src_h >> 16;
+	bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
+	struct drm_gem_cma_object *cma_obj;
+	struct sti_hqvdp_cmd *cmd;
+	int scale_h, scale_v;
+	int cmd_offset;
+
+	DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
+		      crtc->base.id, sti_mixer_to_str(mixer),
+		      drm_plane->base.id, sti_plane_to_str(plane));
+	DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
+		      sti_plane_to_str(plane),
+		      dst_w, dst_h, dst_x, dst_y,
+		      src_w, src_h, src_x, src_y);
+
+	cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
+	if (cmd_offset == -1) {
+		DRM_ERROR("No available hqvdp_cmd now\n");
+		return;
+	}
+	cmd = hqvdp->hqvdp_cmd + cmd_offset;
+
+	if (!sti_hqvdp_check_hw_scaling(hqvdp, mode,
+					src_w, src_h,
+					dst_w, dst_h)) {
+		DRM_ERROR("Scaling beyond HW capabilities\n");
+		return;
+	}
+
+	/* Static parameters, defaulting to progressive mode */
+	cmd->top.config = TOP_CONFIG_PROGRESSIVE;
+	cmd->top.mem_format = TOP_MEM_FORMAT_DFLT;
+	cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT;
+	cmd->csdi.config = CSDI_CONFIG_PROG;
+
+	/* VC1RE, FMD bypassed : keep everything set to 0
+	 * IQI/P2I bypassed */
+	cmd->iqi.config = IQI_CONFIG_DFLT;
+	cmd->iqi.con_bri = IQI_CON_BRI_DFLT;
+	cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT;
+	cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	if (!cma_obj) {
+		DRM_ERROR("Can't get CMA GEM object for fb\n");
+		return;
+	}
+
+	DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
+			 (char *)&fb->pixel_format,
+			 (unsigned long)cma_obj->paddr);
+
+	/* Buffer planes address */
+	cmd->top.current_luma = (u32)cma_obj->paddr + fb->offsets[0];
+	cmd->top.current_chroma = (u32)cma_obj->paddr + fb->offsets[1];
+
+	/* Pitches */
+	cmd->top.luma_processed_pitch = fb->pitches[0];
+	cmd->top.luma_src_pitch = fb->pitches[0];
+	cmd->top.chroma_processed_pitch = fb->pitches[1];
+	cmd->top.chroma_src_pitch = fb->pitches[1];
+
+	/* Input / output size
+	 * Align to upper even value */
+	dst_w = ALIGN(dst_w, 2);
+	dst_h = ALIGN(dst_h, 2);
+
+	if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) ||
+	    (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) ||
+	    (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) ||
+	    (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) {
+		DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n",
+			  src_w, src_h,
+			  dst_w, dst_h);
+		return;
+	}
+
+	cmd->top.input_viewport_size = src_h << 16 | src_w;
+	cmd->top.input_frame_size = src_h << 16 | src_w;
+	cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w;
+	cmd->top.input_viewport_ori = src_y << 16 | src_x;
+
+	/* Handle interlaced */
+	if (fb->flags & DRM_MODE_FB_INTERLACED) {
+		/* Top field to display */
+		cmd->top.config = TOP_CONFIG_INTER_TOP;
+
+		/* Update pitches and vert size */
+		cmd->top.input_frame_size = (src_h / 2) << 16 | src_w;
+		cmd->top.luma_processed_pitch *= 2;
+		cmd->top.luma_src_pitch *= 2;
+		cmd->top.chroma_processed_pitch *= 2;
+		cmd->top.chroma_src_pitch *= 2;
+
+		/* Enable directional deinterlacing processing */
+		cmd->csdi.config = CSDI_CONFIG_INTER_DIR;
+		cmd->csdi.config2 = CSDI_CONFIG2_DFLT;
+		cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT;
+	}
+
+	/* Update hvsrc lut coef */
+	scale_h = SCALE_FACTOR * dst_w / src_w;
+	sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc);
+
+	scale_v = SCALE_FACTOR * dst_h / src_h;
+	sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
+
+	if (first_prepare) {
+		/* Prevent VTG shutdown */
+		if (clk_prepare_enable(hqvdp->clk_pix_main)) {
+			DRM_ERROR("Failed to prepare/enable pix main clk\n");
+			return;
+		}
+
+		/* Register VTG Vsync callback to handle bottom fields */
+		if (sti_vtg_register_client(hqvdp->vtg,
+					    &hqvdp->vtg_nb,
+					    mixer->id)) {
+			DRM_ERROR("Cannot register VTG notifier\n");
+			return;
+		}
+	}
+
+	writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
+	       hqvdp->regs + HQVDP_MBX_NEXT_CMD);
+
+	hqvdp->curr_field_count++;
+
+	/* Interlaced : get ready to display the bottom field at next Vsync */
+	if (fb->flags & DRM_MODE_FB_INTERLACED)
+		hqvdp->btm_field_pending = true;
+
+	dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
+		__func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
+
+	plane->status = STI_PLANE_UPDATED;
+}
+
+static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane,
+				     struct drm_plane_state *oldstate)
+{
+	struct sti_plane *plane = to_sti_plane(drm_plane);
+	struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
+
+	if (!drm_plane->crtc) {
+		DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
+				 drm_plane->base.id);
+		return;
+	}
+
+	DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
+			 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
+			 drm_plane->base.id, sti_plane_to_str(plane));
+
+	plane->status = STI_PLANE_DISABLING;
+}
+
+static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = {
+	.atomic_update = sti_hqvdp_atomic_update,
+	.atomic_disable = sti_hqvdp_atomic_disable,
 };
 
-struct sti_plane *sti_hqvdp_create(struct device *dev, int desc)
+static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
+					  struct device *dev, int desc)
 {
 	struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
+	int res;
 
 	hqvdp->plane.desc = desc;
-	hqvdp->plane.ops = &hqvdp_plane_ops;
+	hqvdp->plane.status = STI_PLANE_DISABLED;
 
 	sti_hqvdp_init(hqvdp);
 
-	return &hqvdp->plane;
+	res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1,
+				       &sti_plane_helpers_funcs,
+				       hqvdp_supported_formats,
+				       ARRAY_SIZE(hqvdp_supported_formats),
+				       DRM_PLANE_TYPE_OVERLAY);
+	if (res) {
+		DRM_ERROR("Failed to initialize universal plane\n");
+		return NULL;
+	}
+
+	drm_plane_helper_add(&hqvdp->plane.drm_plane, &sti_hqvdp_helpers_funcs);
+
+	sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY);
+
+	return &hqvdp->plane.drm_plane;
 }
 
 static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp)
@@ -948,7 +982,7 @@  int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
 {
 	struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
 	struct drm_device *drm_dev = data;
-	struct sti_plane *plane;
+	struct drm_plane *plane;
 	int err;
 
 	DRM_DEBUG_DRIVER("\n");
@@ -965,11 +999,8 @@  int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
 	}
 
 	/* Create HQVDP plane once xp70 is initialized */
-	plane = sti_hqvdp_create(hqvdp->dev, STI_HQVDP_0);
-	if (plane)
-		sti_plane_init(hqvdp->drm_dev, plane, 1,
-			       DRM_PLANE_TYPE_OVERLAY);
-	else
+	plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0);
+	if (!plane)
 		DRM_ERROR("Can't create HQVDP plane\n");
 
 	return 0;
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h
index 2f69b00..4acf4f8 100644
--- a/drivers/gpu/drm/sti/sti_mixer.h
+++ b/drivers/gpu/drm/sti/sti_mixer.h
@@ -15,6 +15,12 @@ 
 
 #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc)
 
+enum sti_mixer_status {
+	STI_MIXER_READY,
+	STI_MIXER_DISABLING,
+	STI_MIXER_DISABLED,
+};
+
 /**
  * STI Mixer subdevice structure
  *
@@ -23,7 +29,7 @@ 
  * @id: id of the mixer
  * @drm_crtc: crtc object link to the mixer
  * @pending_event: set if a flip event is pending on crtc
- * @enabled: to know if the mixer is active or not
+ * @status: to know the status of the mixer
  */
 struct sti_mixer {
 	struct device *dev;
@@ -31,7 +37,7 @@  struct sti_mixer {
 	int id;
 	struct drm_crtc drm_crtc;
 	struct drm_pending_vblank_event *pending_event;
-	bool enabled;
+	enum sti_mixer_status status;
 };
 
 const char *sti_mixer_to_str(struct sti_mixer *mixer);
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index 6a38521..14685cf 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -7,15 +7,12 @@ 
  */
 
 #include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 
 #include "sti_compositor.h"
 #include "sti_drv.h"
 #include "sti_plane.h"
-#include "sti_vtg.h"
 
 /* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */
 enum sti_plane_desc sti_plane_default_zorder[] = {
@@ -47,115 +44,6 @@  const char *sti_plane_to_str(struct sti_plane *plane)
 }
 EXPORT_SYMBOL(sti_plane_to_str);
 
-static int sti_plane_prepare(struct sti_plane *plane,
-			     struct drm_crtc *crtc,
-			     struct drm_framebuffer *fb,
-			     struct drm_display_mode *mode, int mixer_id,
-			     int dest_x, int dest_y, int dest_w, int dest_h,
-			     int src_x, int src_y, int src_w, int src_h)
-{
-	struct drm_gem_cma_object *cma_obj;
-	unsigned int i;
-	int res;
-
-	if (!plane || !fb || !mode) {
-		DRM_ERROR("Null fb, plane or mode\n");
-		return 1;
-	}
-
-	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
-	if (!cma_obj) {
-		DRM_ERROR("Can't get CMA GEM object for fb\n");
-		return 1;
-	}
-
-	plane->fb = fb;
-	plane->mode = mode;
-	plane->mixer_id = mixer_id;
-	plane->dst_x = dest_x;
-	plane->dst_y = dest_y;
-	plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x);
-	plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y);
-	plane->src_x = src_x;
-	plane->src_y = src_y;
-	plane->src_w = src_w;
-	plane->src_h = src_h;
-	plane->format = fb->pixel_format;
-	plane->vaddr = cma_obj->vaddr;
-	plane->paddr = cma_obj->paddr;
-	for (i = 0; i < 4; i++) {
-		plane->pitches[i] = fb->pitches[i];
-		plane->offsets[i] = fb->offsets[i];
-	}
-
-	DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n",
-			 sti_plane_to_str(plane),
-			 plane->mixer_id);
-	DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
-			 sti_plane_to_str(plane),
-			 plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y,
-			 plane->src_w, plane->src_h, plane->src_x,
-			 plane->src_y);
-
-	DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
-			 (char *)&plane->format, (unsigned long)plane->paddr);
-
-	if (!plane->ops->prepare) {
-		DRM_ERROR("Cannot prepare\n");
-		return 1;
-	}
-
-	res = plane->ops->prepare(plane, !plane->enabled);
-	if (res) {
-		DRM_ERROR("Plane prepare failed\n");
-		return res;
-	}
-
-	plane->enabled = true;
-
-	return 0;
-}
-
-static int sti_plane_commit(struct sti_plane *plane)
-{
-	if (!plane)
-		return 1;
-
-	if (!plane->ops->commit) {
-		DRM_ERROR("Cannot commit\n");
-		return 1;
-	}
-
-	return plane->ops->commit(plane);
-}
-
-static int sti_plane_disable(struct sti_plane *plane)
-{
-	int res;
-
-	DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane));
-	if (!plane)
-		return 1;
-
-	if (!plane->enabled)
-		return 0;
-
-	if (!plane->ops->disable) {
-		DRM_ERROR("Cannot disable\n");
-		return 1;
-	}
-
-	res = plane->ops->disable(plane);
-	if (res) {
-		DRM_ERROR("Plane disable failed\n");
-		return res;
-	}
-
-	plane->enabled = false;
-
-	return 0;
-}
-
 static void sti_plane_destroy(struct drm_plane *drm_plane)
 {
 	DRM_DEBUG_DRIVER("\n");
@@ -182,109 +70,6 @@  static int sti_plane_set_property(struct drm_plane *drm_plane,
 	return -EINVAL;
 }
 
-static struct drm_plane_funcs sti_plane_funcs = {
-	.update_plane = drm_atomic_helper_update_plane,
-	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = sti_plane_destroy,
-	.set_property = sti_plane_set_property,
-	.reset = drm_atomic_helper_plane_reset,
-	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-};
-
-static int sti_plane_atomic_check(struct drm_plane *drm_plane,
-				  struct drm_plane_state *state)
-{
-	return 0;
-}
-
-static void sti_plane_atomic_update(struct drm_plane *drm_plane,
-				    struct drm_plane_state *oldstate)
-{
-	struct drm_plane_state *state = drm_plane->state;
-	struct sti_plane *plane = to_sti_plane(drm_plane);
-	struct sti_mixer *mixer = to_sti_mixer(state->crtc);
-	int res;
-
-	DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
-		      state->crtc->base.id, sti_mixer_to_str(mixer),
-		      drm_plane->base.id, sti_plane_to_str(plane));
-	DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n",
-		      state->crtc_w, state->crtc_h,
-		      state->crtc_x, state->crtc_y);
-
-	res = sti_mixer_set_plane_depth(mixer, plane);
-	if (res) {
-		DRM_ERROR("Cannot set plane depth\n");
-		return;
-	}
-
-	/* src_x are in 16.16 format */
-	res = sti_plane_prepare(plane, state->crtc, state->fb,
-				&state->crtc->mode, mixer->id,
-				state->crtc_x, state->crtc_y,
-				state->crtc_w, state->crtc_h,
-				state->src_x >> 16, state->src_y >> 16,
-				state->src_w >> 16, state->src_h >> 16);
-	if (res) {
-		DRM_ERROR("Plane prepare failed\n");
-		return;
-	}
-
-	res = sti_plane_commit(plane);
-	if (res) {
-		DRM_ERROR("Plane commit failed\n");
-		return;
-	}
-
-	res = sti_mixer_set_plane_status(mixer, plane, true);
-	if (res) {
-		DRM_ERROR("Cannot enable plane at mixer\n");
-		return;
-	}
-}
-
-static void sti_plane_atomic_disable(struct drm_plane *drm_plane,
-				     struct drm_plane_state *oldstate)
-{
-	struct sti_plane *plane = to_sti_plane(drm_plane);
-	struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);
-	int res;
-
-	if (!drm_plane->crtc) {
-		DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
-				 drm_plane->base.id);
-		return;
-	}
-
-	DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
-			 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
-			 drm_plane->base.id, sti_plane_to_str(plane));
-
-	/* Disable plane at mixer level */
-	res = sti_mixer_set_plane_status(mixer, plane, false);
-	if (res) {
-		DRM_ERROR("Cannot disable plane at mixer\n");
-		return;
-	}
-
-	/* Wait a while to be sure that a Vsync event is received */
-	msleep(WAIT_NEXT_VSYNC_MS);
-
-	/* Then disable plane itself */
-	res = sti_plane_disable(plane);
-	if (res) {
-		DRM_ERROR("Plane disable failed\n");
-		return;
-	}
-}
-
-static const struct drm_plane_helper_funcs sti_plane_helpers_funcs = {
-	.atomic_check = sti_plane_atomic_check,
-	.atomic_update = sti_plane_atomic_update,
-	.atomic_disable = sti_plane_atomic_disable,
-};
-
 static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane)
 {
 	struct drm_device *dev = drm_plane->dev;
@@ -305,25 +90,10 @@  static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane)
 	drm_object_attach_property(&drm_plane->base, prop, plane->zorder);
 }
 
-struct drm_plane *sti_plane_init(struct drm_device *dev,
-				 struct sti_plane *plane,
-				 unsigned int possible_crtcs,
-				 enum drm_plane_type type)
+void sti_plane_init_property(struct sti_plane *plane,
+			     enum drm_plane_type type)
 {
-	int err, i;
-
-	err = drm_universal_plane_init(dev, &plane->drm_plane,
-				       possible_crtcs,
-				       &sti_plane_funcs,
-				       plane->ops->get_formats(plane),
-				       plane->ops->get_nb_formats(plane),
-				       type);
-	if (err) {
-		DRM_ERROR("Failed to initialize universal plane\n");
-		return NULL;
-	}
-
-	drm_plane_helper_add(&plane->drm_plane, &sti_plane_helpers_funcs);
+	unsigned int i;
 
 	for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++)
 		if (sti_plane_default_zorder[i] == plane->desc)
@@ -337,7 +107,14 @@  struct drm_plane *sti_plane_init(struct drm_device *dev,
 	DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n",
 			 plane->drm_plane.base.id,
 			 sti_plane_to_str(plane), plane->zorder);
-
-	return &plane->drm_plane;
 }
-EXPORT_SYMBOL(sti_plane_init);
+
+struct drm_plane_funcs sti_plane_helpers_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.destroy = sti_plane_destroy,
+	.set_property = sti_plane_set_property,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h
index bd52754..86f1e6f 100644
--- a/drivers/gpu/drm/sti/sti_plane.h
+++ b/drivers/gpu/drm/sti/sti_plane.h
@@ -8,6 +8,10 @@ 
 #define _STI_PLANE_H_
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+
+extern struct drm_plane_funcs sti_plane_helpers_funcs;
 
 #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane)
 
@@ -38,68 +42,30 @@  enum sti_plane_desc {
 	STI_BACK        = STI_BCK
 };
 
+enum sti_plane_status {
+	STI_PLANE_READY,
+	STI_PLANE_UPDATED,
+	STI_PLANE_DISABLING,
+	STI_PLANE_FLUSHING,
+	STI_PLANE_DISABLED,
+};
+
 /**
  * STI plane structure
  *
  * @plane:              drm plane it is bound to (if any)
- * @fb:                 drm fb it is bound to
- * @mode:               display mode
  * @desc:               plane type & id
- * @ops:                plane functions
+ * @status:             to know the status of the plane
  * @zorder:             plane z-order
- * @mixer_id:           id of the mixer used to display the plane
- * @enabled:            to know if the plane is active or not
- * @src_x src_y:        coordinates of the input (fb) area
- * @src_w src_h:        size of the input (fb) area
- * @dst_x dst_y:        coordinates of the output (crtc) area
- * @dst_w dst_h:        size of the output (crtc) area
- * @format:             format
- * @pitches:            pitch of 'planes' (eg: Y, U, V)
- * @offsets:            offset of 'planes'
- * @vaddr:              virtual address of the input buffer
- * @paddr:              physical address of the input buffer
  */
 struct sti_plane {
 	struct drm_plane drm_plane;
-	struct drm_framebuffer *fb;
-	struct drm_display_mode *mode;
 	enum sti_plane_desc desc;
-	const struct sti_plane_funcs *ops;
+	enum sti_plane_status status;
 	int zorder;
-	int mixer_id;
-	bool enabled;
-	int src_x, src_y;
-	int src_w, src_h;
-	int dst_x, dst_y;
-	int dst_w, dst_h;
-	uint32_t format;
-	unsigned int pitches[4];
-	unsigned int offsets[4];
-	void *vaddr;
-	dma_addr_t paddr;
 };
 
-/**
- * STI plane functions structure
- *
- * @get_formats:     get plane supported formats
- * @get_nb_formats:  get number of format supported
- * @prepare:         prepare plane before rendering
- * @commit:          set plane for rendering
- * @disable:         disable plane
- */
-struct sti_plane_funcs {
-	const uint32_t* (*get_formats)(struct sti_plane *plane);
-	unsigned int (*get_nb_formats)(struct sti_plane *plane);
-	int (*prepare)(struct sti_plane *plane, bool first_prepare);
-	int (*commit)(struct sti_plane *plane);
-	int (*disable)(struct sti_plane *plane);
-};
-
-struct drm_plane *sti_plane_init(struct drm_device *dev,
-				 struct sti_plane *sti_plane,
-				 unsigned int possible_crtcs,
-				 enum drm_plane_type type);
 const char *sti_plane_to_str(struct sti_plane *plane);
-
+void sti_plane_init_property(struct sti_plane *plane,
+			     enum drm_plane_type type);
 #endif
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c
index 1e7e1d7..a8254cc 100644
--- a/drivers/gpu/drm/sti/sti_vid.c
+++ b/drivers/gpu/drm/sti/sti_vid.c
@@ -43,28 +43,37 @@ 
 #define VID_MPR2_BT709          0x07150545
 #define VID_MPR3_BT709          0x00000AE8
 
-int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane)
+void sti_vid_commit(struct sti_vid *vid,
+		    struct drm_plane_state *state)
 {
-	struct drm_display_mode *mode = plane->mode;
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_display_mode *mode = &crtc->mode;
+	int dst_x = state->crtc_x;
+	int dst_y = state->crtc_y;
+	int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
+	int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
 	u32 val, ydo, xdo, yds, xds;
 
+	/* Input / output size
+	 * Align to upper even value */
+	dst_w = ALIGN(dst_w, 2);
+	dst_h = ALIGN(dst_h, 2);
+
 	/* Unmask */
 	val = readl(vid->regs + VID_CTL);
 	val &= ~VID_CTL_IGNORE;
 	writel(val, vid->regs + VID_CTL);
 
-	ydo = sti_vtg_get_line_number(*mode, plane->dst_y);
-	yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1);
-	xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x);
-	xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1);
+	ydo = sti_vtg_get_line_number(*mode, dst_y);
+	yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
+	xdo = sti_vtg_get_pixel_number(*mode, dst_x);
+	xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
 
 	writel((ydo << 16) | xdo, vid->regs + VID_VPO);
 	writel((yds << 16) | xds, vid->regs + VID_VPS);
-
-	return 0;
 }
 
-int sti_vid_disable(struct sti_vid *vid)
+void sti_vid_disable(struct sti_vid *vid)
 {
 	u32 val;
 
@@ -72,8 +81,6 @@  int sti_vid_disable(struct sti_vid *vid)
 	val = readl(vid->regs + VID_CTL);
 	val |= VID_CTL_IGNORE;
 	writel(val, vid->regs + VID_CTL);
-
-	return 0;
 }
 
 static void sti_vid_init(struct sti_vid *vid)
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h
index cc680a2..5dea479 100644
--- a/drivers/gpu/drm/sti/sti_vid.h
+++ b/drivers/gpu/drm/sti/sti_vid.h
@@ -20,8 +20,9 @@  struct sti_vid {
 	int id;
 };
 
-int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane);
-int sti_vid_disable(struct sti_vid *vid);
+void sti_vid_commit(struct sti_vid *vid,
+		    struct drm_plane_state *state);
+void sti_vid_disable(struct sti_vid *vid);
 struct sti_vid *sti_vid_create(struct device *dev, int id,
 			       void __iomem *baseaddr);