Merge tag 'drm-vc4-fixes-2016-09-14' of https://github.com/anholt/linux into drm...
[linux-2.6-block.git] / drivers / gpu / drm / imx / ipuv3-plane.c
index a4bb44118d331179385b3a7824347cebde7db3dc..29423e757d365edce655e89aa1ca2f16fe49fba2 100644 (file)
  */
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.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 "video/imx-ipu-v3.h"
 #include "ipuv3-plane.h"
 
-#define to_ipu_plane(x)        container_of(x, struct ipu_plane, base)
+static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
+{
+       return container_of(p, struct ipu_plane, base);
+}
 
 static const uint32_t ipu_plane_formats[] = {
        DRM_FORMAT_ARGB1555,
@@ -53,62 +59,67 @@ int ipu_plane_irq(struct ipu_plane *ipu_plane)
                                     IPU_IRQ_EOF);
 }
 
-static int calc_vref(struct drm_display_mode *mode)
+static inline unsigned long
+drm_plane_state_to_eba(struct drm_plane_state *state)
 {
-       unsigned long htotal, vtotal;
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_gem_cma_object *cma_obj;
 
-       htotal = mode->htotal;
-       vtotal = mode->vtotal;
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       BUG_ON(!cma_obj);
 
-       if (!htotal || !vtotal)
-               return 60;
-
-       return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
+       return cma_obj->paddr + fb->offsets[0] +
+              fb->pitches[0] * (state->src_y >> 16) +
+              (fb->bits_per_pixel >> 3) * (state->src_x >> 16);
 }
 
-static inline int calc_bandwidth(int width, int height, unsigned int vref)
+static inline unsigned long
+drm_plane_state_to_ubo(struct drm_plane_state *state)
 {
-       return width * height * vref;
-}
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_gem_cma_object *cma_obj;
+       unsigned long eba = drm_plane_state_to_eba(state);
 
-int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
-                      int x, int y)
-{
-       struct drm_gem_cma_object *cma_obj[3];
-       unsigned long eba, ubo, vbo;
-       int active, i;
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
+       BUG_ON(!cma_obj);
 
-       for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
-               cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i);
-               if (!cma_obj[i]) {
-                       DRM_DEBUG_KMS("plane %d entry is null.\n", i);
-                       return -EFAULT;
-               }
-       }
+       return cma_obj->paddr + fb->offsets[1] +
+              fb->pitches[1] * (state->src_y >> 16) / 2 +
+              (state->src_x >> 16) / 2 - eba;
+}
 
-       eba = cma_obj[0]->paddr + fb->offsets[0] +
-             fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
+static inline unsigned long
+drm_plane_state_to_vbo(struct drm_plane_state *state)
+{
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_gem_cma_object *cma_obj;
+       unsigned long eba = drm_plane_state_to_eba(state);
 
-       if (eba & 0x7) {
-               DRM_DEBUG_KMS("base address must be a multiple of 8.\n");
-               return -EINVAL;
-       }
+       cma_obj = drm_fb_cma_get_gem_obj(fb, 2);
+       BUG_ON(!cma_obj);
 
-       if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) {
-               DRM_DEBUG_KMS("pitches out of range.\n");
-               return -EINVAL;
-       }
+       return cma_obj->paddr + fb->offsets[2] +
+              fb->pitches[2] * (state->src_y >> 16) / 2 +
+              (state->src_x >> 16) / 2 - eba;
+}
 
-       if (ipu_plane->enabled && fb->pitches[0] != ipu_plane->stride[0]) {
-               DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n");
-               return -EINVAL;
-       }
+static void ipu_plane_atomic_set_base(struct ipu_plane *ipu_plane,
+                                     struct drm_plane_state *old_state)
+{
+       struct drm_plane *plane = &ipu_plane->base;
+       struct drm_plane_state *state = plane->state;
+       struct drm_framebuffer *fb = state->fb;
+       unsigned long eba, ubo, vbo;
+       int active;
 
-       ipu_plane->stride[0] = fb->pitches[0];
+       eba = drm_plane_state_to_eba(state);
 
        switch (fb->pixel_format) {
        case DRM_FORMAT_YUV420:
        case DRM_FORMAT_YVU420:
+               if (old_state->fb)
+                       break;
+
                /*
                 * Multiplanar formats have to meet the following restrictions:
                 * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
@@ -117,59 +128,28 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
                 * - Only EBA may be changed while scanout is active
                 * - The strides of U and V planes must be identical.
                 */
-               ubo = cma_obj[1]->paddr + fb->offsets[1] +
-                     fb->pitches[1] * y / 2 + x / 2 - eba;
-               vbo = cma_obj[2]->paddr + fb->offsets[2] +
-                     fb->pitches[2] * y / 2 + x / 2 - eba;
-
-               if ((ubo & 0x7) || (vbo & 0x7)) {
-                       DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n");
-                       return -EINVAL;
-               }
-
-               if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) {
-                       DRM_DEBUG_KMS("U/V buffer offsets must be positive and not larger than 0xfffff8.\n");
-                       return -EINVAL;
-               }
-
-               if (ipu_plane->enabled && ((ipu_plane->u_offset != ubo) ||
-                                          (ipu_plane->v_offset != vbo))) {
-                       DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n");
-                       return -EINVAL;
-               }
-
-               if (fb->pitches[1] != fb->pitches[2]) {
-                       DRM_DEBUG_KMS("U/V pitches must be identical.\n");
-                       return -EINVAL;
-               }
+               ubo = drm_plane_state_to_ubo(state);
+               vbo = drm_plane_state_to_vbo(state);
 
-               if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) {
-                       DRM_DEBUG_KMS("U/V pitches out of range.\n");
-                       return -EINVAL;
-               }
-
-               if (ipu_plane->enabled &&
-                   (ipu_plane->stride[1] != fb->pitches[1])) {
-                       DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n");
-                       return -EINVAL;
-               }
-
-               ipu_plane->u_offset = ubo;
-               ipu_plane->v_offset = vbo;
-               ipu_plane->stride[1] = fb->pitches[1];
+               if (fb->pixel_format == DRM_FORMAT_YUV420)
+                       ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
+                                                     fb->pitches[1], ubo, vbo);
+               else
+                       ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
+                                                     fb->pitches[1], vbo, ubo);
 
                dev_dbg(ipu_plane->base.dev->dev,
-                       "phys = %pad %pad %pad, x = %d, y = %d",
-                       &cma_obj[0]->paddr, &cma_obj[1]->paddr,
-                       &cma_obj[2]->paddr, x, y);
+                       "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
+                       state->src_x >> 16, state->src_y >> 16);
                break;
        default:
-               dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
-                       &cma_obj[0]->paddr, x, y);
+               dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
+                       eba, state->src_x >> 16, state->src_y >> 16);
+
                break;
        }
 
-       if (ipu_plane->enabled) {
+       if (old_state->fb) {
                active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
                ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
                ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
@@ -177,155 +157,6 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
                ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
                ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
        }
-
-       /* cache offsets for subsequent pageflips */
-       ipu_plane->x = x;
-       ipu_plane->y = y;
-
-       return 0;
-}
-
-int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
-                      struct drm_display_mode *mode,
-                      struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                      unsigned int crtc_w, unsigned int crtc_h,
-                      uint32_t src_x, uint32_t src_y,
-                      uint32_t src_w, uint32_t src_h, bool interlaced)
-{
-       struct device *dev = ipu_plane->base.dev->dev;
-       int ret;
-
-       /* no scaling */
-       if (src_w != crtc_w || src_h != crtc_h)
-               return -EINVAL;
-
-       /* clip to crtc bounds */
-       if (crtc_x < 0) {
-               if (-crtc_x > crtc_w)
-                       return -EINVAL;
-               src_x += -crtc_x;
-               src_w -= -crtc_x;
-               crtc_w -= -crtc_x;
-               crtc_x = 0;
-       }
-       if (crtc_y < 0) {
-               if (-crtc_y > crtc_h)
-                       return -EINVAL;
-               src_y += -crtc_y;
-               src_h -= -crtc_y;
-               crtc_h -= -crtc_y;
-               crtc_y = 0;
-       }
-       if (crtc_x + crtc_w > mode->hdisplay) {
-               if (crtc_x > mode->hdisplay)
-                       return -EINVAL;
-               crtc_w = mode->hdisplay - crtc_x;
-               src_w = crtc_w;
-       }
-       if (crtc_y + crtc_h > mode->vdisplay) {
-               if (crtc_y > mode->vdisplay)
-                       return -EINVAL;
-               crtc_h = mode->vdisplay - crtc_y;
-               src_h = crtc_h;
-       }
-       /* full plane minimum width is 13 pixels */
-       if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
-               return -EINVAL;
-       if (crtc_h < 2)
-               return -EINVAL;
-
-       /*
-        * since we cannot touch active IDMAC channels, we do not support
-        * resizing the enabled plane or changing its format
-        */
-       if (ipu_plane->enabled) {
-               if (src_w != ipu_plane->w || src_h != ipu_plane->h ||
-                   fb->pixel_format != ipu_plane->base.fb->pixel_format)
-                       return -EINVAL;
-
-               return ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
-       }
-
-       switch (ipu_plane->dp_flow) {
-       case IPU_DP_FLOW_SYNC_BG:
-               ret = ipu_dp_setup_channel(ipu_plane->dp,
-                               IPUV3_COLORSPACE_RGB,
-                               IPUV3_COLORSPACE_RGB);
-               if (ret) {
-                       dev_err(dev,
-                               "initializing display processor failed with %d\n",
-                               ret);
-                       return ret;
-               }
-               ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
-               break;
-       case IPU_DP_FLOW_SYNC_FG:
-               ipu_dp_setup_channel(ipu_plane->dp,
-                               ipu_drm_fourcc_to_colorspace(fb->pixel_format),
-                               IPUV3_COLORSPACE_UNKNOWN);
-               ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
-               /* Enable local alpha on partial plane */
-               switch (fb->pixel_format) {
-               case DRM_FORMAT_ARGB1555:
-               case DRM_FORMAT_ABGR1555:
-               case DRM_FORMAT_RGBA5551:
-               case DRM_FORMAT_BGRA5551:
-               case DRM_FORMAT_ARGB4444:
-               case DRM_FORMAT_ARGB8888:
-               case DRM_FORMAT_ABGR8888:
-               case DRM_FORMAT_RGBA8888:
-               case DRM_FORMAT_BGRA8888:
-                       ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
-                       calc_bandwidth(crtc_w, crtc_h,
-                                      calc_vref(mode)), 64);
-       if (ret) {
-               dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
-               return ret;
-       }
-
-       ipu_dmfc_config_wait4eot(ipu_plane->dmfc, crtc_w);
-
-       ipu_cpmem_zero(ipu_plane->ipu_ch);
-       ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
-       ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
-       if (ret < 0) {
-               dev_err(dev, "unsupported pixel format 0x%08x\n",
-                       fb->pixel_format);
-               return ret;
-       }
-       ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
-       ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
-       ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
-
-       ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
-       if (ret < 0)
-               return ret;
-       if (interlaced)
-               ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);
-
-       if (fb->pixel_format == DRM_FORMAT_YUV420) {
-               ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
-                                             ipu_plane->stride[1],
-                                             ipu_plane->u_offset,
-                                             ipu_plane->v_offset);
-       } else if (fb->pixel_format == DRM_FORMAT_YVU420) {
-               ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
-                                             ipu_plane->stride[1],
-                                             ipu_plane->v_offset,
-                                             ipu_plane->u_offset);
-       }
-
-       ipu_plane->w = src_w;
-       ipu_plane->h = src_h;
-
-       return 0;
 }
 
 void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
@@ -372,7 +203,7 @@ err_out:
        return ret;
 }
 
-void ipu_plane_enable(struct ipu_plane *ipu_plane)
+static void ipu_plane_enable(struct ipu_plane *ipu_plane)
 {
        if (ipu_plane->dp)
                ipu_dp_enable(ipu_plane->ipu);
@@ -380,14 +211,10 @@ void ipu_plane_enable(struct ipu_plane *ipu_plane)
        ipu_idmac_enable_channel(ipu_plane->ipu_ch);
        if (ipu_plane->dp)
                ipu_dp_enable_channel(ipu_plane->dp);
-
-       ipu_plane->enabled = true;
 }
 
-void ipu_plane_disable(struct ipu_plane *ipu_plane)
+static void ipu_plane_disable(struct ipu_plane *ipu_plane)
 {
-       ipu_plane->enabled = false;
-
        ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
 
        if (ipu_plane->dp)
@@ -398,74 +225,232 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane)
                ipu_dp_disable(ipu_plane->ipu);
 }
 
-/*
- * drm_plane API
- */
-
-static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
-                           struct drm_framebuffer *fb, int crtc_x, int crtc_y,
-                           unsigned int crtc_w, unsigned int crtc_h,
-                           uint32_t src_x, uint32_t src_y,
-                           uint32_t src_w, uint32_t src_h)
+static int ipu_disable_plane(struct drm_plane *plane)
 {
        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
-       int ret = 0;
-
-       DRM_DEBUG_KMS("plane - %p\n", plane);
-
-       if (!ipu_plane->enabled)
-               ret = ipu_plane_get_resources(ipu_plane);
-       if (ret < 0)
-               return ret;
-
-       ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
-                       crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
-                       false);
-       if (ret < 0) {
-               ipu_plane_put_resources(ipu_plane);
-               return ret;
-       }
 
-       if (crtc != plane->crtc)
-               dev_dbg(plane->dev->dev, "crtc change: %p -> %p\n",
-                               plane->crtc, crtc);
+       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       if (!ipu_plane->enabled)
-               ipu_plane_enable(ipu_plane);
+       ipu_plane_disable(ipu_plane);
 
        return 0;
 }
 
-static int ipu_disable_plane(struct drm_plane *plane)
+static void ipu_plane_destroy(struct drm_plane *plane)
 {
        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       if (ipu_plane->enabled)
-               ipu_plane_disable(ipu_plane);
+       ipu_disable_plane(plane);
+       drm_plane_cleanup(plane);
+       kfree(ipu_plane);
+}
 
-       ipu_plane_put_resources(ipu_plane);
+static const struct drm_plane_funcs ipu_plane_funcs = {
+       .update_plane   = drm_atomic_helper_update_plane,
+       .disable_plane  = drm_atomic_helper_disable_plane,
+       .destroy        = ipu_plane_destroy,
+       .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 ipu_plane_atomic_check(struct drm_plane *plane,
+                                 struct drm_plane_state *state)
+{
+       struct drm_plane_state *old_state = plane->state;
+       struct drm_crtc_state *crtc_state;
+       struct device *dev = plane->dev->dev;
+       struct drm_framebuffer *fb = state->fb;
+       struct drm_framebuffer *old_fb = old_state->fb;
+       unsigned long eba, ubo, vbo, old_ubo, old_vbo;
+
+       /* Ok to disable */
+       if (!fb)
+               return 0;
+
+       if (!state->crtc)
+               return -EINVAL;
+
+       crtc_state =
+               drm_atomic_get_existing_crtc_state(state->state, state->crtc);
+       if (WARN_ON(!crtc_state))
+               return -EINVAL;
+
+       /* CRTC should be enabled */
+       if (!crtc_state->enable)
+               return -EINVAL;
+
+       /* no scaling */
+       if (state->src_w >> 16 != state->crtc_w ||
+           state->src_h >> 16 != state->crtc_h)
+               return -EINVAL;
+
+       switch (plane->type) {
+       case DRM_PLANE_TYPE_PRIMARY:
+               /* full plane doesn't support partial off screen */
+               if (state->crtc_x || state->crtc_y ||
+                   state->crtc_w != crtc_state->adjusted_mode.hdisplay ||
+                   state->crtc_h != crtc_state->adjusted_mode.vdisplay)
+                       return -EINVAL;
+
+               /* full plane minimum width is 13 pixels */
+               if (state->crtc_w < 13)
+                       return -EINVAL;
+               break;
+       case DRM_PLANE_TYPE_OVERLAY:
+               if (state->crtc_x < 0 || state->crtc_y < 0)
+                       return -EINVAL;
+
+               if (state->crtc_x + state->crtc_w >
+                   crtc_state->adjusted_mode.hdisplay)
+                       return -EINVAL;
+               if (state->crtc_y + state->crtc_h >
+                   crtc_state->adjusted_mode.vdisplay)
+                       return -EINVAL;
+               break;
+       default:
+               dev_warn(dev, "Unsupported plane type\n");
+               return -EINVAL;
+       }
+
+       if (state->crtc_h < 2)
+               return -EINVAL;
+
+       /*
+        * We support resizing active plane or changing its format by
+        * forcing CRTC mode change and disabling-enabling plane in plane's
+        * ->atomic_update callback.
+        */
+       if (old_fb && (state->src_w != old_state->src_w ||
+                             state->src_h != old_state->src_h ||
+                             fb->pixel_format != old_fb->pixel_format))
+               crtc_state->mode_changed = true;
+
+       eba = drm_plane_state_to_eba(state);
+
+       if (eba & 0x7)
+               return -EINVAL;
+
+       if (fb->pitches[0] < 1 || fb->pitches[0] > 16384)
+               return -EINVAL;
+
+       if (old_fb && fb->pitches[0] != old_fb->pitches[0])
+               crtc_state->mode_changed = true;
+
+       switch (fb->pixel_format) {
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+               /*
+                * Multiplanar formats have to meet the following restrictions:
+                * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
+                * - EBA, UBO and VBO are a multiple of 8
+                * - UBO and VBO are unsigned and not larger than 0xfffff8
+                * - Only EBA may be changed while scanout is active
+                * - The strides of U and V planes must be identical.
+                */
+               ubo = drm_plane_state_to_ubo(state);
+               vbo = drm_plane_state_to_vbo(state);
+
+               if ((ubo & 0x7) || (vbo & 0x7))
+                       return -EINVAL;
+
+               if ((ubo > 0xfffff8) || (vbo > 0xfffff8))
+                       return -EINVAL;
+
+               if (old_fb) {
+                       old_ubo = drm_plane_state_to_ubo(old_state);
+                       old_vbo = drm_plane_state_to_vbo(old_state);
+                       if (ubo != old_ubo || vbo != old_vbo)
+                               return -EINVAL;
+               }
+
+               if (fb->pitches[1] != fb->pitches[2])
+                       return -EINVAL;
+
+               if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
+                       return -EINVAL;
+
+               if (old_fb && old_fb->pitches[1] != fb->pitches[1])
+                       crtc_state->mode_changed = true;
+       }
 
        return 0;
 }
 
-static void ipu_plane_destroy(struct drm_plane *plane)
+static void ipu_plane_atomic_disable(struct drm_plane *plane,
+                                    struct drm_plane_state *old_state)
+{
+       ipu_disable_plane(plane);
+}
+
+static void ipu_plane_atomic_update(struct drm_plane *plane,
+                                   struct drm_plane_state *old_state)
 {
        struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+       struct drm_plane_state *state = plane->state;
+       enum ipu_color_space ics;
 
-       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+       if (old_state->fb) {
+               struct drm_crtc_state *crtc_state = state->crtc->state;
 
-       ipu_disable_plane(plane);
-       drm_plane_cleanup(plane);
-       kfree(ipu_plane);
+               if (!crtc_state->mode_changed) {
+                       ipu_plane_atomic_set_base(ipu_plane, old_state);
+                       return;
+               }
+
+               ipu_disable_plane(plane);
+       }
+
+       switch (ipu_plane->dp_flow) {
+       case IPU_DP_FLOW_SYNC_BG:
+               ipu_dp_setup_channel(ipu_plane->dp,
+                                       IPUV3_COLORSPACE_RGB,
+                                       IPUV3_COLORSPACE_RGB);
+               ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
+               break;
+       case IPU_DP_FLOW_SYNC_FG:
+               ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format);
+               ipu_dp_setup_channel(ipu_plane->dp, ics,
+                                       IPUV3_COLORSPACE_UNKNOWN);
+               ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x,
+                                       state->crtc_y);
+               /* Enable local alpha on partial plane */
+               switch (state->fb->pixel_format) {
+               case DRM_FORMAT_ARGB1555:
+               case DRM_FORMAT_ABGR1555:
+               case DRM_FORMAT_RGBA5551:
+               case DRM_FORMAT_BGRA5551:
+               case DRM_FORMAT_ARGB4444:
+               case DRM_FORMAT_ARGB8888:
+               case DRM_FORMAT_ABGR8888:
+               case DRM_FORMAT_RGBA8888:
+               case DRM_FORMAT_BGRA8888:
+                       ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w);
+
+       ipu_cpmem_zero(ipu_plane->ipu_ch);
+       ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16,
+                                       state->src_h >> 16);
+       ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format);
+       ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
+       ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
+       ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
+       ipu_plane_atomic_set_base(ipu_plane, old_state);
+       ipu_plane_enable(ipu_plane);
 }
 
-static const struct drm_plane_funcs ipu_plane_funcs = {
-       .update_plane   = ipu_update_plane,
-       .disable_plane  = ipu_disable_plane,
-       .destroy        = ipu_plane_destroy,
+static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
+       .atomic_check = ipu_plane_atomic_check,
+       .atomic_disable = ipu_plane_atomic_disable,
+       .atomic_update = ipu_plane_atomic_update,
 };
 
 struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
@@ -498,5 +483,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
                return ERR_PTR(ret);
        }
 
+       drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
+
        return ipu_plane;
 }