On Fri, Feb 10, 2017 at 07:07:45PM +0100, Boris Brezillon wrote:
> An HLCDC layers in Atmel's nomenclature is either a DRM plane or a 'Post
> Processing Layer' which can be used to output the results of the HLCDC
> composition in a memory buffer.
> 
> atmel_hlcdc_layer.c was designed to be generic enough to be re-usable in
> both cases, but we're not exposing the post-processing layer yet, and
> even if we were, I'm not sure the code would provide the necessary tools
> to manipulate this kind of layer.
> 
> Moreover, the code in atmel_hlcdc_{plane,layer}.c was designed before the
> atomic modesetting API, and was trying solve the
> check-setting/commit-if-ok/rollback-otherwise problem, which is now
> entirely solved by the existing core infrastructure.
> 
> And finally, the code in atmel_hlcdc_layer.c in over-complicated compared
> to what we really need. This rework is a good excuse to simplify it. Note
> that this rework solves an existing resource leak (leading to a -EBUSY
> error) which I failed to clearly identify.
> 
> Signed-off-by: Boris Brezillon <boris.brezil...@free-electrons.com>
> ---
> Hi Daniel,
> 
> I intentionally dropped your ack, since inheriting from atmel_hlcdc_layer
> is implying a lot of changes.

Well I acked the idea, that still kinda holds. But if you want to
kickstart the drm-misc driver ack economy, Eric has 1-2 vc4 patches that
still need an ack, you could trade r-bs :-)

Cheers, Daniel

> 
> Regards,
> 
> Boris
> 
> Changes in v2:
> - make atmel_hlcdc_plane inherit from atmel_hlcdc_layer
> - provide read/write_reg/cfg() helpers to access layer regs
> - move all layer related definitions into atmel_hlcdc_dc.h and remove
>   atmel_hlcdc_layer.h
> - fix a bug in atmel_hlcdc_plane_atomic_duplicate_state()
> ---
>  drivers/gpu/drm/atmel-hlcdc/Makefile            |   1 -
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c  |  39 +-
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c    |  82 +--
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h    | 364 +++++++++++--
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 666 
> ------------------------
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 399 --------------
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 637 +++++++++++-----------
>  7 files changed, 695 insertions(+), 1493 deletions(-)
>  delete mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
>  delete mode 100644 drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> 
> diff --git a/drivers/gpu/drm/atmel-hlcdc/Makefile 
> b/drivers/gpu/drm/atmel-hlcdc/Makefile
> index 10ae426e60bd..bb5f8507a8ce 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/Makefile
> +++ b/drivers/gpu/drm/atmel-hlcdc/Makefile
> @@ -1,6 +1,5 @@
>  atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
>               atmel_hlcdc_dc.o \
> -             atmel_hlcdc_layer.o \
>               atmel_hlcdc_output.o \
>               atmel_hlcdc_plane.o
>  
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c 
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> index 9b17a66cf0e1..2fcec0a72567 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
> @@ -445,8 +445,8 @@ static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs 
> = {
>  
>  int atmel_hlcdc_crtc_create(struct drm_device *dev)
>  {
> +     struct atmel_hlcdc_plane *primary = NULL, *cursor = NULL;
>       struct atmel_hlcdc_dc *dc = dev->dev_private;
> -     struct atmel_hlcdc_planes *planes = dc->planes;
>       struct atmel_hlcdc_crtc *crtc;
>       int ret;
>       int i;
> @@ -457,20 +457,41 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
>  
>       crtc->dc = dc;
>  
> -     ret = drm_crtc_init_with_planes(dev, &crtc->base,
> -                             &planes->primary->base,
> -                             planes->cursor ? &planes->cursor->base : NULL,
> -                             &atmel_hlcdc_crtc_funcs, NULL);
> +     for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
> +             if (!dc->layers[i])
> +                     continue;
> +
> +             switch (dc->layers[i]->desc->type) {
> +             case ATMEL_HLCDC_BASE_LAYER:
> +                     primary = atmel_hlcdc_layer_to_plane(dc->layers[i]);
> +                     break;
> +
> +             case ATMEL_HLCDC_CURSOR_LAYER:
> +                     cursor = atmel_hlcdc_layer_to_plane(dc->layers[i]);
> +                     break;
> +
> +             default:
> +                     break;
> +             }
> +     }
> +
> +     ret = drm_crtc_init_with_planes(dev, &crtc->base, &primary->base,
> +                                     &cursor->base, &atmel_hlcdc_crtc_funcs,
> +                                     NULL);
>       if (ret < 0)
>               goto fail;
>  
>       crtc->id = drm_crtc_index(&crtc->base);
>  
> -     if (planes->cursor)
> -             planes->cursor->base.possible_crtcs = 1 << crtc->id;
> +     for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
> +             struct atmel_hlcdc_plane *overlay;
>  
> -     for (i = 0; i < planes->noverlays; i++)
> -             planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
> +             if (dc->layers[i] &&
> +                 dc->layers[i]->desc->type == ATMEL_HLCDC_OVERLAY_LAYER) {
> +                     overlay = atmel_hlcdc_layer_to_plane(dc->layers[i]);
> +                     overlay->base.possible_crtcs = 1 << crtc->id;
> +             }
> +     }
>  
>       drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
>       drm_crtc_vblank_reset(&crtc->base);
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c 
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> index 0bf32d6ac39b..8eb1d7471c63 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
> @@ -36,7 +36,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_at91sam9n12_layers[] = {
>               .regs_offset = 0x40,
>               .id = 0,
>               .type = ATMEL_HLCDC_BASE_LAYER,
> -             .nconfigs = 5,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .xstride = { 2 },
>                       .default_color = 3,
> @@ -65,7 +65,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_at91sam9x5_layers[] = {
>               .regs_offset = 0x40,
>               .id = 0,
>               .type = ATMEL_HLCDC_BASE_LAYER,
> -             .nconfigs = 5,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .xstride = { 2 },
>                       .default_color = 3,
> @@ -80,7 +80,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_at91sam9x5_layers[] = {
>               .regs_offset = 0x100,
>               .id = 1,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 10,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -98,7 +98,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_at91sam9x5_layers[] = {
>               .regs_offset = 0x280,
>               .id = 2,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 17,
> +             .cfgs_offset = 0x4c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -109,6 +109,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_at91sam9x5_layers[] = {
>                       .chroma_key = 10,
>                       .chroma_key_mask = 11,
>                       .general_config = 12,
> +                     .scaler_config = 13,
>                       .csc = 14,
>               },
>       },
> @@ -118,9 +119,9 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_at91sam9x5_layers[] = {
>               .regs_offset = 0x340,
>               .id = 3,
>               .type = ATMEL_HLCDC_CURSOR_LAYER,
> -             .nconfigs = 10,
>               .max_width = 128,
>               .max_height = 128,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -153,7 +154,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d3_layers[] = {
>               .regs_offset = 0x40,
>               .id = 0,
>               .type = ATMEL_HLCDC_BASE_LAYER,
> -             .nconfigs = 7,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .xstride = { 2 },
>                       .default_color = 3,
> @@ -168,7 +169,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d3_layers[] = {
>               .regs_offset = 0x140,
>               .id = 1,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 10,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -186,7 +187,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d3_layers[] = {
>               .regs_offset = 0x240,
>               .id = 2,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 10,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -204,7 +205,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d3_layers[] = {
>               .regs_offset = 0x340,
>               .id = 3,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 42,
> +             .cfgs_offset = 0x4c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -215,6 +216,11 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d3_layers[] = {
>                       .chroma_key = 10,
>                       .chroma_key_mask = 11,
>                       .general_config = 12,
> +                     .scaler_config = 13,
> +                     .phicoeffs = {
> +                             .x = 17,
> +                             .y = 33,
> +                     },
>                       .csc = 14,
>               },
>       },
> @@ -224,9 +230,9 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d3_layers[] = {
>               .regs_offset = 0x440,
>               .id = 4,
>               .type = ATMEL_HLCDC_CURSOR_LAYER,
> -             .nconfigs = 10,
>               .max_width = 128,
>               .max_height = 128,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -236,6 +242,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d3_layers[] = {
>                       .chroma_key = 7,
>                       .chroma_key_mask = 8,
>                       .general_config = 9,
> +                     .scaler_config = 13,
>               },
>       },
>  };
> @@ -260,7 +267,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d4_layers[] = {
>               .regs_offset = 0x40,
>               .id = 0,
>               .type = ATMEL_HLCDC_BASE_LAYER,
> -             .nconfigs = 7,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .xstride = { 2 },
>                       .default_color = 3,
> @@ -275,7 +282,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d4_layers[] = {
>               .regs_offset = 0x140,
>               .id = 1,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 10,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -293,7 +300,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d4_layers[] = {
>               .regs_offset = 0x240,
>               .id = 2,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 10,
> +             .cfgs_offset = 0x2c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -311,7 +318,7 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d4_layers[] = {
>               .regs_offset = 0x340,
>               .id = 3,
>               .type = ATMEL_HLCDC_OVERLAY_LAYER,
> -             .nconfigs = 42,
> +             .cfgs_offset = 0x4c,
>               .layout = {
>                       .pos = 2,
>                       .size = 3,
> @@ -322,6 +329,11 @@ static const struct atmel_hlcdc_layer_desc 
> atmel_hlcdc_sama5d4_layers[] = {
>                       .chroma_key = 10,
>                       .chroma_key_mask = 11,
>                       .general_config = 12,
> +                     .scaler_config = 13,
> +                     .phicoeffs = {
> +                             .x = 17,
> +                             .y = 33,
> +                     },
>                       .csc = 14,
>               },
>       },
> @@ -392,6 +404,17 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
>       return MODE_OK;
>  }
>  
> +static void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
> +{
> +     if (!layer)
> +             return;
> +
> +     if (layer->desc->type == ATMEL_HLCDC_BASE_LAYER ||
> +         layer->desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
> +         layer->desc->type == ATMEL_HLCDC_CURSOR_LAYER)
> +             atmel_hlcdc_plane_irq(atmel_hlcdc_layer_to_plane(layer));
> +}
> +
>  static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
>  {
>       struct drm_device *dev = data;
> @@ -410,12 +433,8 @@ static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, 
> void *data)
>               atmel_hlcdc_crtc_irq(dc->crtc);
>  
>       for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
> -             struct atmel_hlcdc_layer *layer = dc->layers[i];
> -
> -             if (!(ATMEL_HLCDC_LAYER_STATUS(i) & status) || !layer)
> -                     continue;
> -
> -             atmel_hlcdc_layer_irq(layer);
> +             if (ATMEL_HLCDC_LAYER_STATUS(i) & status)
> +                     atmel_hlcdc_layer_irq(dc->layers[i]);
>       }
>  
>       return IRQ_HANDLED;
> @@ -537,9 +556,7 @@ static const struct drm_mode_config_funcs 
> mode_config_funcs = {
>  static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
>  {
>       struct atmel_hlcdc_dc *dc = dev->dev_private;
> -     struct atmel_hlcdc_planes *planes;
>       int ret;
> -     int i;
>  
>       drm_mode_config_init(dev);
>  
> @@ -549,25 +566,12 @@ static int atmel_hlcdc_dc_modeset_init(struct 
> drm_device *dev)
>               return ret;
>       }
>  
> -     planes = atmel_hlcdc_create_planes(dev);
> -     if (IS_ERR(planes)) {
> -             dev_err(dev->dev, "failed to create planes\n");
> -             return PTR_ERR(planes);
> +     ret = atmel_hlcdc_create_planes(dev);
> +     if (ret) {
> +             dev_err(dev->dev, "failed to create planes: %d\n", ret);
> +             return ret;
>       }
>  
> -     dc->planes = planes;
> -
> -     dc->layers[planes->primary->layer.desc->id] =
> -                                             &planes->primary->layer;
> -
> -     if (planes->cursor)
> -             dc->layers[planes->cursor->layer.desc->id] =
> -                                                     &planes->cursor->layer;
> -
> -     for (i = 0; i < planes->noverlays; i++)
> -             dc->layers[planes->overlays[i]->layer.desc->id] =
> -                                             &planes->overlays[i]->layer;
> -
>       ret = atmel_hlcdc_crtc_create(dev);
>       if (ret) {
>               dev_err(dev->dev, "failed to create crtc\n");
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h 
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> index 7a47f8c094d0..d84c9a56bbb5 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
> @@ -23,7 +23,9 @@
>  #define DRM_ATMEL_HLCDC_H
>  
>  #include <linux/clk.h>
> +#include <linux/dmapool.h>
>  #include <linux/irqdomain.h>
> +#include <linux/mfd/atmel-hlcdc.h>
>  #include <linux/pwm.h>
>  
>  #include <drm/drm_atomic.h>
> @@ -36,51 +38,245 @@
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drmP.h>
>  
> -#include "atmel_hlcdc_layer.h"
> +#define ATMEL_HLCDC_LAYER_CHER                       0x0
> +#define ATMEL_HLCDC_LAYER_CHDR                       0x4
> +#define ATMEL_HLCDC_LAYER_CHSR                       0x8
> +#define ATMEL_HLCDC_LAYER_EN                 BIT(0)
> +#define ATMEL_HLCDC_LAYER_UPDATE             BIT(1)
> +#define ATMEL_HLCDC_LAYER_A2Q                        BIT(2)
> +#define ATMEL_HLCDC_LAYER_RST                        BIT(8)
>  
> -#define ATMEL_HLCDC_MAX_LAYERS               5
> +#define ATMEL_HLCDC_LAYER_IER                        0xc
> +#define ATMEL_HLCDC_LAYER_IDR                        0x10
> +#define ATMEL_HLCDC_LAYER_IMR                        0x14
> +#define ATMEL_HLCDC_LAYER_ISR                        0x18
> +#define ATMEL_HLCDC_LAYER_DFETCH             BIT(0)
> +#define ATMEL_HLCDC_LAYER_LFETCH             BIT(1)
> +#define ATMEL_HLCDC_LAYER_DMA_IRQ(p)         BIT(2 + (8 * (p)))
> +#define ATMEL_HLCDC_LAYER_DSCR_IRQ(p)                BIT(3 + (8 * (p)))
> +#define ATMEL_HLCDC_LAYER_ADD_IRQ(p)         BIT(4 + (8 * (p)))
> +#define ATMEL_HLCDC_LAYER_DONE_IRQ(p)                BIT(5 + (8 * (p)))
> +#define ATMEL_HLCDC_LAYER_OVR_IRQ(p)         BIT(6 + (8 * (p)))
> +
> +#define ATMEL_HLCDC_LAYER_PLANE_HEAD(p)              (((p) * 0x10) + 0x1c)
> +#define ATMEL_HLCDC_LAYER_PLANE_ADDR(p)              (((p) * 0x10) + 0x20)
> +#define ATMEL_HLCDC_LAYER_PLANE_CTRL(p)              (((p) * 0x10) + 0x24)
> +#define ATMEL_HLCDC_LAYER_PLANE_NEXT(p)              (((p) * 0x10) + 0x28)
> +
> +#define ATMEL_HLCDC_LAYER_DMA_CFG            0
> +#define ATMEL_HLCDC_LAYER_DMA_SIF            BIT(0)
> +#define ATMEL_HLCDC_LAYER_DMA_BLEN_MASK              GENMASK(5, 4)
> +#define ATMEL_HLCDC_LAYER_DMA_BLEN_SINGLE    (0 << 4)
> +#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR4     (1 << 4)
> +#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR8     (2 << 4)
> +#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16    (3 << 4)
> +#define ATMEL_HLCDC_LAYER_DMA_DLBO           BIT(8)
> +#define ATMEL_HLCDC_LAYER_DMA_ROTDIS         BIT(12)
> +#define ATMEL_HLCDC_LAYER_DMA_LOCKDIS                BIT(13)
> +
> +#define ATMEL_HLCDC_LAYER_FORMAT_CFG         1
> +#define ATMEL_HLCDC_LAYER_RGB                        (0 << 0)
> +#define ATMEL_HLCDC_LAYER_CLUT                       (1 << 0)
> +#define ATMEL_HLCDC_LAYER_YUV                        (2 << 0)
> +#define ATMEL_HLCDC_RGB_MODE(m)                      \
> +     (ATMEL_HLCDC_LAYER_RGB | (((m) & 0xf) << 4))
> +#define ATMEL_HLCDC_CLUT_MODE(m)             \
> +     (ATMEL_HLCDC_LAYER_CLUT | (((m) & 0x3) << 8))
> +#define ATMEL_HLCDC_YUV_MODE(m)                      \
> +     (ATMEL_HLCDC_LAYER_YUV | (((m) & 0xf) << 12))
> +#define ATMEL_HLCDC_YUV422ROT                        BIT(16)
> +#define ATMEL_HLCDC_YUV422SWP                        BIT(17)
> +#define ATMEL_HLCDC_DSCALEOPT                        BIT(20)
> +
> +#define ATMEL_HLCDC_XRGB4444_MODE            ATMEL_HLCDC_RGB_MODE(0)
> +#define ATMEL_HLCDC_ARGB4444_MODE            ATMEL_HLCDC_RGB_MODE(1)
> +#define ATMEL_HLCDC_RGBA4444_MODE            ATMEL_HLCDC_RGB_MODE(2)
> +#define ATMEL_HLCDC_RGB565_MODE                      ATMEL_HLCDC_RGB_MODE(3)
> +#define ATMEL_HLCDC_ARGB1555_MODE            ATMEL_HLCDC_RGB_MODE(4)
> +#define ATMEL_HLCDC_XRGB8888_MODE            ATMEL_HLCDC_RGB_MODE(9)
> +#define ATMEL_HLCDC_RGB888_MODE                      ATMEL_HLCDC_RGB_MODE(10)
> +#define ATMEL_HLCDC_ARGB8888_MODE            ATMEL_HLCDC_RGB_MODE(12)
> +#define ATMEL_HLCDC_RGBA8888_MODE            ATMEL_HLCDC_RGB_MODE(13)
> +
> +#define ATMEL_HLCDC_AYUV_MODE                        ATMEL_HLCDC_YUV_MODE(0)
> +#define ATMEL_HLCDC_YUYV_MODE                        ATMEL_HLCDC_YUV_MODE(1)
> +#define ATMEL_HLCDC_UYVY_MODE                        ATMEL_HLCDC_YUV_MODE(2)
> +#define ATMEL_HLCDC_YVYU_MODE                        ATMEL_HLCDC_YUV_MODE(3)
> +#define ATMEL_HLCDC_VYUY_MODE                        ATMEL_HLCDC_YUV_MODE(4)
> +#define ATMEL_HLCDC_NV61_MODE                        ATMEL_HLCDC_YUV_MODE(5)
> +#define ATMEL_HLCDC_YUV422_MODE                      ATMEL_HLCDC_YUV_MODE(6)
> +#define ATMEL_HLCDC_NV21_MODE                        ATMEL_HLCDC_YUV_MODE(7)
> +#define ATMEL_HLCDC_YUV420_MODE                      ATMEL_HLCDC_YUV_MODE(8)
> +
> +#define ATMEL_HLCDC_LAYER_POS(x, y)          ((x) | ((y) << 16))
> +#define ATMEL_HLCDC_LAYER_SIZE(w, h)         (((w) - 1) | (((h) - 1) << 16))
> +
> +#define ATMEL_HLCDC_LAYER_CRKEY                      BIT(0)
> +#define ATMEL_HLCDC_LAYER_INV                        BIT(1)
> +#define ATMEL_HLCDC_LAYER_ITER2BL            BIT(2)
> +#define ATMEL_HLCDC_LAYER_ITER                       BIT(3)
> +#define ATMEL_HLCDC_LAYER_REVALPHA           BIT(4)
> +#define ATMEL_HLCDC_LAYER_GAEN                       BIT(5)
> +#define ATMEL_HLCDC_LAYER_LAEN                       BIT(6)
> +#define ATMEL_HLCDC_LAYER_OVR                        BIT(7)
> +#define ATMEL_HLCDC_LAYER_DMA                        BIT(8)
> +#define ATMEL_HLCDC_LAYER_REP                        BIT(9)
> +#define ATMEL_HLCDC_LAYER_DSTKEY             BIT(10)
> +#define ATMEL_HLCDC_LAYER_DISCEN             BIT(11)
> +#define ATMEL_HLCDC_LAYER_GA_SHIFT           16
> +#define ATMEL_HLCDC_LAYER_GA_MASK            \
> +     GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT)
> +#define ATMEL_HLCDC_LAYER_GA(x)                      \
> +     ((x) << ATMEL_HLCDC_LAYER_GA_SHIFT)
> +
> +#define ATMEL_HLCDC_LAYER_DISC_POS(x, y)     ((x) | ((y) << 16))
> +#define ATMEL_HLCDC_LAYER_DISC_SIZE(w, h)    (((w) - 1) | (((h) - 1) << 16))
> +
> +#define ATMEL_HLCDC_LAYER_SCALER_FACTORS(x, y)       ((x) | ((y) << 16))
> +#define ATMEL_HLCDC_LAYER_SCALER_ENABLE              BIT(31)
> +
> +#define ATMEL_HLCDC_LAYER_MAX_PLANES         3
> +
> +#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED        BIT(0)
> +#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED  BIT(1)
> +#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE    BIT(2)
> +#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN BIT(3)
> +
> +#define ATMEL_HLCDC_MAX_LAYERS                       6
>  
>  /**
> - * Atmel HLCDC Display Controller description structure.
> + * Atmel HLCDC Layer registers layout structure
>   *
> - * This structure describe the HLCDC IP capabilities and depends on the
> - * HLCDC IP version (or Atmel SoC family).
> + * Each HLCDC layer has its own register organization and a given register
> + * can be placed differently on 2 different layers depending on its
> + * capabilities.
> + * This structure stores common registers layout for a given layer and is
> + * used by HLCDC layer code to choose the appropriate register to write to
> + * or to read from.
>   *
> - * @min_width: minimum width supported by the Display Controller
> - * @min_height: minimum height supported by the Display Controller
> - * @max_width: maximum width supported by the Display Controller
> - * @max_height: maximum height supported by the Display Controller
> - * @max_spw: maximum vertical/horizontal pulse width
> - * @max_vpw: maximum vertical back/front porch width
> - * @max_hpw: maximum horizontal back/front porch width
> - * @conflicting_output_formats: true if RGBXXX output formats conflict with
> - *                           each other.
> - * @layers: a layer description table describing available layers
> - * @nlayers: layer description table size
> + * For all fields, a value of zero means "unsupported".
> + *
> + * See Atmel's datasheet for a detailled description of these registers.
> + *
> + * @xstride: xstride registers
> + * @pstride: pstride registers
> + * @pos: position register
> + * @size: displayed size register
> + * @memsize: memory size register
> + * @default_color: default color register
> + * @chroma_key: chroma key register
> + * @chroma_key_mask: chroma key mask register
> + * @general_config: general layer config register
> + * @sacler_config: scaler factors register
> + * @phicoeffs: X/Y PHI coefficient registers
> + * @disc_pos: discard area position register
> + * @disc_size: discard area size register
> + * @csc: color space conversion register
>   */
> -struct atmel_hlcdc_dc_desc {
> -     int min_width;
> -     int min_height;
> +struct atmel_hlcdc_layer_cfg_layout {
> +     int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
> +     int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
> +     int pos;
> +     int size;
> +     int memsize;
> +     int default_color;
> +     int chroma_key;
> +     int chroma_key_mask;
> +     int general_config;
> +     int scaler_config;
> +     struct {
> +             int x;
> +             int y;
> +     } phicoeffs;
> +     int disc_pos;
> +     int disc_size;
> +     int csc;
> +};
> +
> +/**
> + * Atmel HLCDC DMA descriptor structure
> + *
> + * This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
> + *
> + * The structure fields must remain in this specific order, because they're
> + * used by the HLCDC DMA engine, which expect them in this order.
> + * HLCDC DMA descriptors must be aligned on 64 bits.
> + *
> + * @addr: buffer DMA address
> + * @ctrl: DMA transfer options
> + * @next: next DMA descriptor to fetch
> + * @self: descriptor DMA address
> + */
> +struct atmel_hlcdc_dma_channel_dscr {
> +     dma_addr_t addr;
> +     u32 ctrl;
> +     dma_addr_t next;
> +     dma_addr_t self;
> +} __aligned(sizeof(u64));
> +
> +/**
> + * Atmel HLCDC layer types
> + */
> +enum atmel_hlcdc_layer_type {
> +     ATMEL_HLCDC_NO_LAYER,
> +     ATMEL_HLCDC_BASE_LAYER,
> +     ATMEL_HLCDC_OVERLAY_LAYER,
> +     ATMEL_HLCDC_CURSOR_LAYER,
> +     ATMEL_HLCDC_PP_LAYER,
> +};
> +
> +/**
> + * Atmel HLCDC Supported formats structure
> + *
> + * This structure list all the formats supported by a given layer.
> + *
> + * @nformats: number of supported formats
> + * @formats: supported formats
> + */
> +struct atmel_hlcdc_formats {
> +     int nformats;
> +     u32 *formats;
> +};
> +
> +/**
> + * Atmel HLCDC Layer description structure
> + *
> + * This structure describe the capabilities provided by a given layer.
> + *
> + * @name: layer name
> + * @type: layer type
> + * @id: layer id
> + * @regs_offset: offset of the layer registers from the HLCDC registers base
> + * @cfgs_offset: CFGX registers offset from the layer registers base
> + * @formats: supported formats
> + * @layout: config registers layout
> + * @max_width: maximum width supported by this layer (0 means unlimited)
> + * @max_height: maximum height supported by this layer (0 means unlimited)
> + */
> +struct atmel_hlcdc_layer_desc {
> +     const char *name;
> +     enum atmel_hlcdc_layer_type type;
> +     int id;
> +     int regs_offset;
> +     int cfgs_offset;
> +     struct atmel_hlcdc_formats *formats;
> +     struct atmel_hlcdc_layer_cfg_layout layout;
>       int max_width;
>       int max_height;
> -     int max_spw;
> -     int max_vpw;
> -     int max_hpw;
> -     bool conflicting_output_formats;
> -     const struct atmel_hlcdc_layer_desc *layers;
> -     int nlayers;
>  };
>  
>  /**
> - * Atmel HLCDC Plane properties.
> + * Atmel HLCDC Layer.
>   *
> - * This structure stores plane property definitions.
> + * A layer can be a DRM plane of a post processing layer used to render
> + * HLCDC composition into memory.
>   *
> - * @alpha: alpha blending (or transparency) property
> - * @rotation: rotation property
> + * @type: layer type
> + * @plane: pointer to the DRM plane exposed by this layer
>   */
> -struct atmel_hlcdc_plane_properties {
> -     struct drm_property *alpha;
> +struct atmel_hlcdc_layer {
> +     const struct atmel_hlcdc_layer_desc *desc;
> +     struct regmap *regmap;
>  };
>  
>  /**
> @@ -89,12 +285,13 @@ struct atmel_hlcdc_plane_properties {
>   * @base: base DRM plane structure
>   * @layer: HLCDC layer structure
>   * @properties: pointer to the property definitions structure
> - * @rotation: current rotation status
> + * @regmap: HLCDC regmap
>   */
>  struct atmel_hlcdc_plane {
>       struct drm_plane base;
>       struct atmel_hlcdc_layer layer;
>       struct atmel_hlcdc_plane_properties *properties;
> +     struct regmap *regmap;
>  };
>  
>  static inline struct atmel_hlcdc_plane *
> @@ -104,27 +301,52 @@ drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
>  }
>  
>  static inline struct atmel_hlcdc_plane *
> -atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
> +atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *layer)
>  {
> -     return container_of(l, struct atmel_hlcdc_plane, layer);
> +     return container_of(layer, struct atmel_hlcdc_plane, layer);
>  }
>  
>  /**
> - * Atmel HLCDC Planes.
> + * Atmel HLCDC Display Controller description structure.
>   *
> - * This structure stores the instantiated HLCDC Planes and can be accessed by
> - * the HLCDC Display Controller or the HLCDC CRTC.
> + * This structure describe the HLCDC IP capabilities and depends on the
> + * HLCDC IP version (or Atmel SoC family).
>   *
> - * @primary: primary plane
> - * @cursor: hardware cursor plane
> - * @overlays: overlay plane table
> - * @noverlays: number of overlay planes
> + * @min_width: minimum width supported by the Display Controller
> + * @min_height: minimum height supported by the Display Controller
> + * @max_width: maximum width supported by the Display Controller
> + * @max_height: maximum height supported by the Display Controller
> + * @max_spw: maximum vertical/horizontal pulse width
> + * @max_vpw: maximum vertical back/front porch width
> + * @max_hpw: maximum horizontal back/front porch width
> + * @conflicting_output_formats: true if RGBXXX output formats conflict with
> + *                           each other.
> + * @layers: a layer description table describing available layers
> + * @nlayers: layer description table size
>   */
> -struct atmel_hlcdc_planes {
> -     struct atmel_hlcdc_plane *primary;
> -     struct atmel_hlcdc_plane *cursor;
> -     struct atmel_hlcdc_plane **overlays;
> -     int noverlays;
> +struct atmel_hlcdc_dc_desc {
> +     int min_width;
> +     int min_height;
> +     int max_width;
> +     int max_height;
> +     int max_spw;
> +     int max_vpw;
> +     int max_hpw;
> +     bool conflicting_output_formats;
> +     const struct atmel_hlcdc_layer_desc *layers;
> +     int nlayers;
> +};
> +
> +/**
> + * Atmel HLCDC Plane properties.
> + *
> + * This structure stores plane property definitions.
> + *
> + * @alpha: alpha blending (or transparency) property
> + * @rotation: rotation property
> + */
> +struct atmel_hlcdc_plane_properties {
> +     struct drm_property *alpha;
>  };
>  
>  /**
> @@ -135,18 +357,18 @@ struct atmel_hlcdc_planes {
>   * @fbdev: framebuffer device attached to the Display Controller
>   * @crtc: CRTC provided by the display controller
>   * @planes: instantiated planes
> - * @layers: active HLCDC layer
> + * @layers: active HLCDC layers
>   * @wq: display controller workqueue
>   * @commit: used for async commit handling
>   */
>  struct atmel_hlcdc_dc {
>       const struct atmel_hlcdc_dc_desc *desc;
> +     struct dma_pool *dscrpool;
>       struct atmel_hlcdc *hlcdc;
>       struct drm_fbdev_cma *fbdev;
>       struct drm_crtc *crtc;
> -     struct atmel_hlcdc_planes *planes;
> -     struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
>       struct workqueue_struct *wq;
> +     struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
>       struct {
>               wait_queue_head_t wait;
>               bool pending;
> @@ -156,11 +378,51 @@ struct atmel_hlcdc_dc {
>  extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
>  extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats;
>  
> +static inline void atmel_hlcdc_layer_write_reg(struct atmel_hlcdc_layer 
> *layer,
> +                                            unsigned int reg, u32 val)
> +{
> +     regmap_write(layer->regmap, layer->desc->regs_offset + reg, val);
> +}
> +
> +static inline u32 atmel_hlcdc_layer_read_reg(struct atmel_hlcdc_layer *layer,
> +                                          unsigned int reg)
> +{
> +     u32 val;
> +
> +     regmap_read(layer->regmap, layer->desc->regs_offset + reg, &val);
> +
> +     return val;
> +}
> +
> +static inline void atmel_hlcdc_layer_write_cfg(struct atmel_hlcdc_layer 
> *layer,
> +                                            unsigned int cfgid, u32 val)
> +{
> +     atmel_hlcdc_layer_write_reg(layer,
> +                                 layer->desc->cfgs_offset +
> +                                 (cfgid * sizeof(u32)), val);
> +}
> +
> +static inline u32 atmel_hlcdc_layer_read_cfg(struct atmel_hlcdc_layer *layer,
> +                                          unsigned int cfgid)
> +{
> +     return atmel_hlcdc_layer_read_reg(layer,
> +                                       layer->desc->cfgs_offset +
> +                                       (cfgid * sizeof(u32)));
> +}
> +
> +static inline void atmel_hlcdc_layer_init(struct atmel_hlcdc_layer *layer,
> +                             const struct atmel_hlcdc_layer_desc *desc,
> +                             struct regmap *regmap)
> +{
> +     layer->desc = desc;
> +     layer->regmap = regmap;
> +}
> +
>  int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
>                             struct drm_display_mode *mode);
>  
> -struct atmel_hlcdc_planes *
> -atmel_hlcdc_create_planes(struct drm_device *dev);
> +int atmel_hlcdc_create_planes(struct drm_device *dev);
> +void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane);
>  
>  int atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state);
>  int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state);
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c 
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> deleted file mode 100644
> index 377e43cea9dd..000000000000
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
> +++ /dev/null
> @@ -1,666 +0,0 @@
> -/*
> - * Copyright (C) 2014 Free Electrons
> - * Copyright (C) 2014 Atmel
> - *
> - * Author: Boris BREZILLON <boris.brezil...@free-electrons.com>
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms of the GNU General Public License version 2 as published 
> by
> - * the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful, but 
> WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along 
> with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include <linux/dma-mapping.h>
> -#include <linux/interrupt.h>
> -
> -#include "atmel_hlcdc_dc.h"
> -
> -static void
> -atmel_hlcdc_layer_fb_flip_release(struct drm_flip_work *work, void *val)
> -{
> -     struct atmel_hlcdc_layer_fb_flip *flip = val;
> -
> -     if (flip->fb)
> -             drm_framebuffer_unreference(flip->fb);
> -     kfree(flip);
> -}
> -
> -static void
> -atmel_hlcdc_layer_fb_flip_destroy(struct atmel_hlcdc_layer_fb_flip *flip)
> -{
> -     if (flip->fb)
> -             drm_framebuffer_unreference(flip->fb);
> -     kfree(flip->task);
> -     kfree(flip);
> -}
> -
> -static void
> -atmel_hlcdc_layer_fb_flip_release_queue(struct atmel_hlcdc_layer *layer,
> -                                     struct atmel_hlcdc_layer_fb_flip *flip)
> -{
> -     int i;
> -
> -     if (!flip)
> -             return;
> -
> -     for (i = 0; i < layer->max_planes; i++) {
> -             if (!flip->dscrs[i])
> -                     break;
> -
> -             flip->dscrs[i]->status = 0;
> -             flip->dscrs[i] = NULL;
> -     }
> -
> -     drm_flip_work_queue_task(&layer->gc, flip->task);
> -     drm_flip_work_commit(&layer->gc, layer->wq);
> -}
> -
> -static void atmel_hlcdc_layer_update_reset(struct atmel_hlcdc_layer *layer,
> -                                        int id)
> -{
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     struct atmel_hlcdc_layer_update_slot *slot;
> -
> -     if (id < 0 || id > 1)
> -             return;
> -
> -     slot = &upd->slots[id];
> -     bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
> -     memset(slot->configs, 0,
> -            sizeof(*slot->configs) * layer->desc->nconfigs);
> -
> -     if (slot->fb_flip) {
> -             atmel_hlcdc_layer_fb_flip_release_queue(layer, slot->fb_flip);
> -             slot->fb_flip = NULL;
> -     }
> -}
> -
> -static void atmel_hlcdc_layer_update_apply(struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> -     const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     struct regmap *regmap = layer->hlcdc->regmap;
> -     struct atmel_hlcdc_layer_update_slot *slot;
> -     struct atmel_hlcdc_layer_fb_flip *fb_flip;
> -     struct atmel_hlcdc_dma_channel_dscr *dscr;
> -     unsigned int cfg;
> -     u32 action = 0;
> -     int i = 0;
> -
> -     if (upd->pending < 0 || upd->pending > 1)
> -             return;
> -
> -     slot = &upd->slots[upd->pending];
> -
> -     for_each_set_bit(cfg, slot->updated_configs, layer->desc->nconfigs) {
> -             regmap_write(regmap,
> -                          desc->regs_offset +
> -                          ATMEL_HLCDC_LAYER_CFG(layer, cfg),
> -                          slot->configs[cfg]);
> -             action |= ATMEL_HLCDC_LAYER_UPDATE;
> -     }
> -
> -     fb_flip = slot->fb_flip;
> -
> -     if (!fb_flip->fb)
> -             goto apply;
> -
> -     if (dma->status == ATMEL_HLCDC_LAYER_DISABLED) {
> -             for (i = 0; i < fb_flip->ngems; i++) {
> -                     dscr = fb_flip->dscrs[i];
> -                     dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
> -                                  ATMEL_HLCDC_LAYER_DMA_IRQ |
> -                                  ATMEL_HLCDC_LAYER_ADD_IRQ |
> -                                  ATMEL_HLCDC_LAYER_DONE_IRQ;
> -
> -                     regmap_write(regmap,
> -                                  desc->regs_offset +
> -                                  ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
> -                                  dscr->addr);
> -                     regmap_write(regmap,
> -                                  desc->regs_offset +
> -                                  ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
> -                                  dscr->ctrl);
> -                     regmap_write(regmap,
> -                                  desc->regs_offset +
> -                                  ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
> -                                  dscr->next);
> -             }
> -
> -             action |= ATMEL_HLCDC_LAYER_DMA_CHAN;
> -             dma->status = ATMEL_HLCDC_LAYER_ENABLED;
> -     } else {
> -             for (i = 0; i < fb_flip->ngems; i++) {
> -                     dscr =  fb_flip->dscrs[i];
> -                     dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
> -                                  ATMEL_HLCDC_LAYER_DMA_IRQ |
> -                                  ATMEL_HLCDC_LAYER_DSCR_IRQ |
> -                                  ATMEL_HLCDC_LAYER_DONE_IRQ;
> -
> -                     regmap_write(regmap,
> -                                  desc->regs_offset +
> -                                  ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
> -                                  dscr->next);
> -             }
> -
> -             action |= ATMEL_HLCDC_LAYER_A2Q;
> -     }
> -
> -     /* Release unneeded descriptors */
> -     for (i = fb_flip->ngems; i < layer->max_planes; i++) {
> -             fb_flip->dscrs[i]->status = 0;
> -             fb_flip->dscrs[i] = NULL;
> -     }
> -
> -     dma->queue = fb_flip;
> -     slot->fb_flip = NULL;
> -
> -apply:
> -     if (action)
> -             regmap_write(regmap,
> -                          desc->regs_offset + ATMEL_HLCDC_LAYER_CHER,
> -                          action);
> -
> -     atmel_hlcdc_layer_update_reset(layer, upd->pending);
> -
> -     upd->pending = -1;
> -}
> -
> -void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> -     const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> -     struct regmap *regmap = layer->hlcdc->regmap;
> -     struct atmel_hlcdc_layer_fb_flip *flip;
> -     unsigned long flags;
> -     unsigned int isr, imr;
> -     unsigned int status;
> -     unsigned int plane_status;
> -     u32 flip_status;
> -
> -     int i;
> -
> -     regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IMR, &imr);
> -     regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
> -     status = imr & isr;
> -     if (!status)
> -             return;
> -
> -     spin_lock_irqsave(&layer->lock, flags);
> -
> -     flip = dma->queue ? dma->queue : dma->cur;
> -
> -     if (!flip) {
> -             spin_unlock_irqrestore(&layer->lock, flags);
> -             return;
> -     }
> -
> -     /*
> -      * Set LOADED and DONE flags: they'll be cleared if at least one
> -      * memory plane is not LOADED or DONE.
> -      */
> -     flip_status = ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED |
> -                   ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
> -     for (i = 0; i < flip->ngems; i++) {
> -             plane_status = (status >> (8 * i));
> -
> -             if (plane_status &
> -                 (ATMEL_HLCDC_LAYER_ADD_IRQ |
> -                  ATMEL_HLCDC_LAYER_DSCR_IRQ) &
> -                 ~flip->dscrs[i]->ctrl) {
> -                     flip->dscrs[i]->status |=
> -                                     ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
> -                     flip->dscrs[i]->ctrl |=
> -                                     ATMEL_HLCDC_LAYER_ADD_IRQ |
> -                                     ATMEL_HLCDC_LAYER_DSCR_IRQ;
> -             }
> -
> -             if (plane_status &
> -                 ATMEL_HLCDC_LAYER_DONE_IRQ &
> -                 ~flip->dscrs[i]->ctrl) {
> -                     flip->dscrs[i]->status |=
> -                                     ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
> -                     flip->dscrs[i]->ctrl |=
> -                                     ATMEL_HLCDC_LAYER_DONE_IRQ;
> -             }
> -
> -             if (plane_status & ATMEL_HLCDC_LAYER_OVR_IRQ)
> -                     flip->dscrs[i]->status |=
> -                                     ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
> -
> -             /*
> -              * Clear LOADED and DONE flags if the memory plane is either
> -              * not LOADED or not DONE.
> -              */
> -             if (!(flip->dscrs[i]->status &
> -                   ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED))
> -                     flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
> -
> -             if (!(flip->dscrs[i]->status &
> -                   ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE))
> -                     flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
> -
> -             /*
> -              * An overrun on one memory plane impact the whole framebuffer
> -              * transfer, hence we set the OVERRUN flag as soon as there's
> -              * one memory plane reporting such an overrun.
> -              */
> -             flip_status |= flip->dscrs[i]->status &
> -                            ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
> -     }
> -
> -     /* Get changed bits */
> -     flip_status ^= flip->status;
> -     flip->status |= flip_status;
> -
> -     if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED) {
> -             atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
> -             dma->cur = dma->queue;
> -             dma->queue = NULL;
> -     }
> -
> -     if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE) {
> -             atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
> -             dma->cur = NULL;
> -     }
> -
> -     if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN) {
> -             regmap_write(regmap,
> -                          desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
> -                          ATMEL_HLCDC_LAYER_RST);
> -             if (dma->queue)
> -                     atmel_hlcdc_layer_fb_flip_release_queue(layer,
> -                                                             dma->queue);
> -
> -             if (dma->cur)
> -                     atmel_hlcdc_layer_fb_flip_release_queue(layer,
> -                                                             dma->cur);
> -
> -             dma->cur = NULL;
> -             dma->queue = NULL;
> -     }
> -
> -     if (!dma->queue) {
> -             atmel_hlcdc_layer_update_apply(layer);
> -
> -             if (!dma->cur)
> -                     dma->status = ATMEL_HLCDC_LAYER_DISABLED;
> -     }
> -
> -     spin_unlock_irqrestore(&layer->lock, flags);
> -}
> -
> -void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     struct regmap *regmap = layer->hlcdc->regmap;
> -     const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> -     unsigned long flags;
> -     unsigned int isr;
> -
> -     spin_lock_irqsave(&layer->lock, flags);
> -
> -     /* Disable the layer */
> -     regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
> -                  ATMEL_HLCDC_LAYER_RST | ATMEL_HLCDC_LAYER_A2Q |
> -                  ATMEL_HLCDC_LAYER_UPDATE);
> -
> -     /* Clear all pending interrupts */
> -     regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
> -
> -     /* Discard current and queued framebuffer transfers. */
> -     if (dma->cur) {
> -             atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
> -             dma->cur = NULL;
> -     }
> -
> -     if (dma->queue) {
> -             atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->queue);
> -             dma->queue = NULL;
> -     }
> -
> -     /*
> -      * Then discard the pending update request (if any) to prevent
> -      * DMA irq handler from restarting the DMA channel after it has
> -      * been disabled.
> -      */
> -     if (upd->pending >= 0) {
> -             atmel_hlcdc_layer_update_reset(layer, upd->pending);
> -             upd->pending = -1;
> -     }
> -
> -     dma->status = ATMEL_HLCDC_LAYER_DISABLED;
> -
> -     spin_unlock_irqrestore(&layer->lock, flags);
> -}
> -
> -int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     struct regmap *regmap = layer->hlcdc->regmap;
> -     struct atmel_hlcdc_layer_fb_flip *fb_flip;
> -     struct atmel_hlcdc_layer_update_slot *slot;
> -     unsigned long flags;
> -     int i, j = 0;
> -
> -     fb_flip = kzalloc(sizeof(*fb_flip), GFP_KERNEL);
> -     if (!fb_flip)
> -             return -ENOMEM;
> -
> -     fb_flip->task = drm_flip_work_allocate_task(fb_flip, GFP_KERNEL);
> -     if (!fb_flip->task) {
> -             kfree(fb_flip);
> -             return -ENOMEM;
> -     }
> -
> -     spin_lock_irqsave(&layer->lock, flags);
> -
> -     upd->next = upd->pending ? 0 : 1;
> -
> -     slot = &upd->slots[upd->next];
> -
> -     for (i = 0; i < layer->max_planes * 4; i++) {
> -             if (!dma->dscrs[i].status) {
> -                     fb_flip->dscrs[j++] = &dma->dscrs[i];
> -                     dma->dscrs[i].status =
> -                             ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED;
> -                     if (j == layer->max_planes)
> -                             break;
> -             }
> -     }
> -
> -     if (j < layer->max_planes) {
> -             for (i = 0; i < j; i++)
> -                     fb_flip->dscrs[i]->status = 0;
> -     }
> -
> -     if (j < layer->max_planes) {
> -             spin_unlock_irqrestore(&layer->lock, flags);
> -             atmel_hlcdc_layer_fb_flip_destroy(fb_flip);
> -             return -EBUSY;
> -     }
> -
> -     slot->fb_flip = fb_flip;
> -
> -     if (upd->pending >= 0) {
> -             memcpy(slot->configs,
> -                    upd->slots[upd->pending].configs,
> -                    layer->desc->nconfigs * sizeof(u32));
> -             memcpy(slot->updated_configs,
> -                    upd->slots[upd->pending].updated_configs,
> -                    DIV_ROUND_UP(layer->desc->nconfigs,
> -                                 BITS_PER_BYTE * sizeof(unsigned long)) *
> -                    sizeof(unsigned long));
> -             slot->fb_flip->fb = upd->slots[upd->pending].fb_flip->fb;
> -             if (upd->slots[upd->pending].fb_flip->fb) {
> -                     slot->fb_flip->fb =
> -                             upd->slots[upd->pending].fb_flip->fb;
> -                     slot->fb_flip->ngems =
> -                             upd->slots[upd->pending].fb_flip->ngems;
> -                     drm_framebuffer_reference(slot->fb_flip->fb);
> -             }
> -     } else {
> -             regmap_bulk_read(regmap,
> -                              layer->desc->regs_offset +
> -                              ATMEL_HLCDC_LAYER_CFG(layer, 0),
> -                              upd->slots[upd->next].configs,
> -                              layer->desc->nconfigs);
> -     }
> -
> -     spin_unlock_irqrestore(&layer->lock, flags);
> -
> -     return 0;
> -}
> -
> -void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -
> -     atmel_hlcdc_layer_update_reset(layer, upd->next);
> -     upd->next = -1;
> -}
> -
> -void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
> -                                  struct drm_framebuffer *fb,
> -                                  unsigned int *offsets)
> -{
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     struct atmel_hlcdc_layer_fb_flip *fb_flip;
> -     struct atmel_hlcdc_layer_update_slot *slot;
> -     struct atmel_hlcdc_dma_channel_dscr *dscr;
> -     struct drm_framebuffer *old_fb;
> -     int nplanes = 0;
> -     int i;
> -
> -     if (upd->next < 0 || upd->next > 1)
> -             return;
> -
> -     if (fb)
> -             nplanes = drm_format_num_planes(fb->pixel_format);
> -
> -     if (nplanes > layer->max_planes)
> -             return;
> -
> -     slot = &upd->slots[upd->next];
> -
> -     fb_flip = slot->fb_flip;
> -     old_fb = slot->fb_flip->fb;
> -
> -     for (i = 0; i < nplanes; i++) {
> -             struct drm_gem_cma_object *gem;
> -
> -             dscr = slot->fb_flip->dscrs[i];
> -             gem = drm_fb_cma_get_gem_obj(fb, i);
> -             dscr->addr = gem->paddr + offsets[i];
> -     }
> -
> -     fb_flip->ngems = nplanes;
> -     fb_flip->fb = fb;
> -
> -     if (fb)
> -             drm_framebuffer_reference(fb);
> -
> -     if (old_fb)
> -             drm_framebuffer_unreference(old_fb);
> -}
> -
> -void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
> -                               u32 mask, u32 val)
> -{
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     struct atmel_hlcdc_layer_update_slot *slot;
> -
> -     if (upd->next < 0 || upd->next > 1)
> -             return;
> -
> -     if (cfg >= layer->desc->nconfigs)
> -             return;
> -
> -     slot = &upd->slots[upd->next];
> -     slot->configs[cfg] &= ~mask;
> -     slot->configs[cfg] |= (val & mask);
> -     set_bit(cfg, slot->updated_configs);
> -}
> -
> -void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     struct atmel_hlcdc_layer_update_slot *slot;
> -     unsigned long flags;
> -
> -     if (upd->next < 0  || upd->next > 1)
> -             return;
> -
> -     slot = &upd->slots[upd->next];
> -
> -     spin_lock_irqsave(&layer->lock, flags);
> -
> -     /*
> -      * Release pending update request and replace it by the new one.
> -      */
> -     if (upd->pending >= 0)
> -             atmel_hlcdc_layer_update_reset(layer, upd->pending);
> -
> -     upd->pending = upd->next;
> -     upd->next = -1;
> -
> -     if (!dma->queue)
> -             atmel_hlcdc_layer_update_apply(layer);
> -
> -     spin_unlock_irqrestore(&layer->lock, flags);
> -
> -
> -     upd->next = -1;
> -}
> -
> -static int atmel_hlcdc_layer_dma_init(struct drm_device *dev,
> -                                   struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> -     dma_addr_t dma_addr;
> -     int i;
> -
> -     dma->dscrs = dma_alloc_coherent(dev->dev,
> -                                     layer->max_planes * 4 *
> -                                     sizeof(*dma->dscrs),
> -                                     &dma_addr, GFP_KERNEL);
> -     if (!dma->dscrs)
> -             return -ENOMEM;
> -
> -     for (i = 0; i < layer->max_planes * 4; i++) {
> -             struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
> -
> -             dscr->next = dma_addr + (i * sizeof(*dscr));
> -     }
> -
> -     return 0;
> -}
> -
> -static void atmel_hlcdc_layer_dma_cleanup(struct drm_device *dev,
> -                                       struct atmel_hlcdc_layer *layer)
> -{
> -     struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
> -     int i;
> -
> -     for (i = 0; i < layer->max_planes * 4; i++) {
> -             struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
> -
> -             dscr->status = 0;
> -     }
> -
> -     dma_free_coherent(dev->dev, layer->max_planes * 4 *
> -                       sizeof(*dma->dscrs), dma->dscrs,
> -                       dma->dscrs[0].next);
> -}
> -
> -static int atmel_hlcdc_layer_update_init(struct drm_device *dev,
> -                             struct atmel_hlcdc_layer *layer,
> -                             const struct atmel_hlcdc_layer_desc *desc)
> -{
> -     struct atmel_hlcdc_layer_update *upd = &layer->update;
> -     int updated_size;
> -     void *buffer;
> -     int i;
> -
> -     updated_size = DIV_ROUND_UP(desc->nconfigs,
> -                                 BITS_PER_BYTE *
> -                                 sizeof(unsigned long));
> -
> -     buffer = devm_kzalloc(dev->dev,
> -                           ((desc->nconfigs * sizeof(u32)) +
> -                             (updated_size * sizeof(unsigned long))) * 2,
> -                           GFP_KERNEL);
> -     if (!buffer)
> -             return -ENOMEM;
> -
> -     for (i = 0; i < 2; i++) {
> -             upd->slots[i].updated_configs = buffer;
> -             buffer += updated_size * sizeof(unsigned long);
> -             upd->slots[i].configs = buffer;
> -             buffer += desc->nconfigs * sizeof(u32);
> -     }
> -
> -     upd->pending = -1;
> -     upd->next = -1;
> -
> -     return 0;
> -}
> -
> -int atmel_hlcdc_layer_init(struct drm_device *dev,
> -                        struct atmel_hlcdc_layer *layer,
> -                        const struct atmel_hlcdc_layer_desc *desc)
> -{
> -     struct atmel_hlcdc_dc *dc = dev->dev_private;
> -     struct regmap *regmap = dc->hlcdc->regmap;
> -     unsigned int tmp;
> -     int ret;
> -     int i;
> -
> -     layer->hlcdc = dc->hlcdc;
> -     layer->wq = dc->wq;
> -     layer->desc = desc;
> -
> -     regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
> -                  ATMEL_HLCDC_LAYER_RST);
> -     for (i = 0; i < desc->formats->nformats; i++) {
> -             int nplanes = drm_format_num_planes(desc->formats->formats[i]);
> -
> -             if (nplanes > layer->max_planes)
> -                     layer->max_planes = nplanes;
> -     }
> -
> -     spin_lock_init(&layer->lock);
> -     drm_flip_work_init(&layer->gc, desc->name,
> -                        atmel_hlcdc_layer_fb_flip_release);
> -     ret = atmel_hlcdc_layer_dma_init(dev, layer);
> -     if (ret)
> -             return ret;
> -
> -     ret = atmel_hlcdc_layer_update_init(dev, layer, desc);
> -     if (ret)
> -             return ret;
> -
> -     /* Flush Status Register */
> -     regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
> -                  0xffffffff);
> -     regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR,
> -                 &tmp);
> -
> -     tmp = 0;
> -     for (i = 0; i < layer->max_planes; i++)
> -             tmp |= (ATMEL_HLCDC_LAYER_DMA_IRQ |
> -                     ATMEL_HLCDC_LAYER_DSCR_IRQ |
> -                     ATMEL_HLCDC_LAYER_ADD_IRQ |
> -                     ATMEL_HLCDC_LAYER_DONE_IRQ |
> -                     ATMEL_HLCDC_LAYER_OVR_IRQ) << (8 * i);
> -
> -     regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IER, tmp);
> -
> -     return 0;
> -}
> -
> -void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
> -                            struct atmel_hlcdc_layer *layer)
> -{
> -     const struct atmel_hlcdc_layer_desc *desc = layer->desc;
> -     struct regmap *regmap = layer->hlcdc->regmap;
> -
> -     regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
> -                  0xffffffff);
> -     regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
> -                  ATMEL_HLCDC_LAYER_RST);
> -
> -     atmel_hlcdc_layer_dma_cleanup(dev, layer);
> -     drm_flip_work_cleanup(&layer->gc);
> -}
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h 
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> deleted file mode 100644
> index 9beabc940bce..000000000000
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
> +++ /dev/null
> @@ -1,399 +0,0 @@
> -/*
> - * Copyright (C) 2014 Free Electrons
> - * Copyright (C) 2014 Atmel
> - *
> - * Author: Boris BREZILLON <boris.brezil...@free-electrons.com>
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms of the GNU General Public License version 2 as published 
> by
> - * the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful, but 
> WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along 
> with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef DRM_ATMEL_HLCDC_LAYER_H
> -#define DRM_ATMEL_HLCDC_LAYER_H
> -
> -#include <linux/mfd/atmel-hlcdc.h>
> -
> -#include <drm/drm_crtc.h>
> -#include <drm/drm_flip_work.h>
> -#include <drm/drmP.h>
> -
> -#define ATMEL_HLCDC_LAYER_CHER                       0x0
> -#define ATMEL_HLCDC_LAYER_CHDR                       0x4
> -#define ATMEL_HLCDC_LAYER_CHSR                       0x8
> -#define ATMEL_HLCDC_LAYER_DMA_CHAN           BIT(0)
> -#define ATMEL_HLCDC_LAYER_UPDATE             BIT(1)
> -#define ATMEL_HLCDC_LAYER_A2Q                        BIT(2)
> -#define ATMEL_HLCDC_LAYER_RST                        BIT(8)
> -
> -#define ATMEL_HLCDC_LAYER_IER                        0xc
> -#define ATMEL_HLCDC_LAYER_IDR                        0x10
> -#define ATMEL_HLCDC_LAYER_IMR                        0x14
> -#define ATMEL_HLCDC_LAYER_ISR                        0x18
> -#define ATMEL_HLCDC_LAYER_DFETCH             BIT(0)
> -#define ATMEL_HLCDC_LAYER_LFETCH             BIT(1)
> -#define ATMEL_HLCDC_LAYER_DMA_IRQ            BIT(2)
> -#define ATMEL_HLCDC_LAYER_DSCR_IRQ           BIT(3)
> -#define ATMEL_HLCDC_LAYER_ADD_IRQ            BIT(4)
> -#define ATMEL_HLCDC_LAYER_DONE_IRQ           BIT(5)
> -#define ATMEL_HLCDC_LAYER_OVR_IRQ            BIT(6)
> -
> -#define ATMEL_HLCDC_LAYER_PLANE_HEAD(n)              (((n) * 0x10) + 0x1c)
> -#define ATMEL_HLCDC_LAYER_PLANE_ADDR(n)              (((n) * 0x10) + 0x20)
> -#define ATMEL_HLCDC_LAYER_PLANE_CTRL(n)              (((n) * 0x10) + 0x24)
> -#define ATMEL_HLCDC_LAYER_PLANE_NEXT(n)              (((n) * 0x10) + 0x28)
> -#define ATMEL_HLCDC_LAYER_CFG(p, c)          (((c) * 4) + ((p)->max_planes * 
> 0x10) + 0x1c)
> -
> -#define ATMEL_HLCDC_LAYER_DMA_CFG_ID         0
> -#define ATMEL_HLCDC_LAYER_DMA_CFG(p)         ATMEL_HLCDC_LAYER_CFG(p, 
> ATMEL_HLCDC_LAYER_DMA_CFG_ID)
> -#define ATMEL_HLCDC_LAYER_DMA_SIF            BIT(0)
> -#define ATMEL_HLCDC_LAYER_DMA_BLEN_MASK              GENMASK(5, 4)
> -#define ATMEL_HLCDC_LAYER_DMA_BLEN_SINGLE    (0 << 4)
> -#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR4     (1 << 4)
> -#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR8     (2 << 4)
> -#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16    (3 << 4)
> -#define ATMEL_HLCDC_LAYER_DMA_DLBO           BIT(8)
> -#define ATMEL_HLCDC_LAYER_DMA_ROTDIS         BIT(12)
> -#define ATMEL_HLCDC_LAYER_DMA_LOCKDIS                BIT(13)
> -
> -#define ATMEL_HLCDC_LAYER_FORMAT_CFG_ID              1
> -#define ATMEL_HLCDC_LAYER_FORMAT_CFG(p)              
> ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_FORMAT_CFG_ID)
> -#define ATMEL_HLCDC_LAYER_RGB                        (0 << 0)
> -#define ATMEL_HLCDC_LAYER_CLUT                       (1 << 0)
> -#define ATMEL_HLCDC_LAYER_YUV                        (2 << 0)
> -#define ATMEL_HLCDC_RGB_MODE(m)                      (((m) & 0xf) << 4)
> -#define ATMEL_HLCDC_CLUT_MODE(m)             (((m) & 0x3) << 8)
> -#define ATMEL_HLCDC_YUV_MODE(m)                      (((m) & 0xf) << 12)
> -#define ATMEL_HLCDC_YUV422ROT                        BIT(16)
> -#define ATMEL_HLCDC_YUV422SWP                        BIT(17)
> -#define ATMEL_HLCDC_DSCALEOPT                        BIT(20)
> -
> -#define ATMEL_HLCDC_XRGB4444_MODE            (ATMEL_HLCDC_LAYER_RGB | 
> ATMEL_HLCDC_RGB_MODE(0))
> -#define ATMEL_HLCDC_ARGB4444_MODE            (ATMEL_HLCDC_LAYER_RGB | 
> ATMEL_HLCDC_RGB_MODE(1))
> -#define ATMEL_HLCDC_RGBA4444_MODE            (ATMEL_HLCDC_LAYER_RGB | 
> ATMEL_HLCDC_RGB_MODE(2))
> -#define ATMEL_HLCDC_RGB565_MODE                      (ATMEL_HLCDC_LAYER_RGB 
> | ATMEL_HLCDC_RGB_MODE(3))
> -#define ATMEL_HLCDC_ARGB1555_MODE            (ATMEL_HLCDC_LAYER_RGB | 
> ATMEL_HLCDC_RGB_MODE(4))
> -#define ATMEL_HLCDC_XRGB8888_MODE            (ATMEL_HLCDC_LAYER_RGB | 
> ATMEL_HLCDC_RGB_MODE(9))
> -#define ATMEL_HLCDC_RGB888_MODE                      (ATMEL_HLCDC_LAYER_RGB 
> | ATMEL_HLCDC_RGB_MODE(10))
> -#define ATMEL_HLCDC_ARGB8888_MODE            (ATMEL_HLCDC_LAYER_RGB | 
> ATMEL_HLCDC_RGB_MODE(12))
> -#define ATMEL_HLCDC_RGBA8888_MODE            (ATMEL_HLCDC_LAYER_RGB | 
> ATMEL_HLCDC_RGB_MODE(13))
> -
> -#define ATMEL_HLCDC_AYUV_MODE                        (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(0))
> -#define ATMEL_HLCDC_YUYV_MODE                        (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(1))
> -#define ATMEL_HLCDC_UYVY_MODE                        (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(2))
> -#define ATMEL_HLCDC_YVYU_MODE                        (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(3))
> -#define ATMEL_HLCDC_VYUY_MODE                        (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(4))
> -#define ATMEL_HLCDC_NV61_MODE                        (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(5))
> -#define ATMEL_HLCDC_YUV422_MODE                      (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(6))
> -#define ATMEL_HLCDC_NV21_MODE                        (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(7))
> -#define ATMEL_HLCDC_YUV420_MODE                      (ATMEL_HLCDC_LAYER_YUV 
> | ATMEL_HLCDC_YUV_MODE(8))
> -
> -#define ATMEL_HLCDC_LAYER_POS_CFG(p)         ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.pos)
> -#define ATMEL_HLCDC_LAYER_SIZE_CFG(p)                
> ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.size)
> -#define ATMEL_HLCDC_LAYER_MEMSIZE_CFG(p)     ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.memsize)
> -#define ATMEL_HLCDC_LAYER_XSTRIDE_CFG(p)     ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.xstride)
> -#define ATMEL_HLCDC_LAYER_PSTRIDE_CFG(p)     ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.pstride)
> -#define ATMEL_HLCDC_LAYER_DFLTCOLOR_CFG(p)   ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.default_color)
> -#define ATMEL_HLCDC_LAYER_CRKEY_CFG(p)               
> ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key)
> -#define ATMEL_HLCDC_LAYER_CRKEY_MASK_CFG(p)  ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.chroma_key_mask)
> -
> -#define ATMEL_HLCDC_LAYER_GENERAL_CFG(p)     ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.general_config)
> -#define ATMEL_HLCDC_LAYER_CRKEY                      BIT(0)
> -#define ATMEL_HLCDC_LAYER_INV                        BIT(1)
> -#define ATMEL_HLCDC_LAYER_ITER2BL            BIT(2)
> -#define ATMEL_HLCDC_LAYER_ITER                       BIT(3)
> -#define ATMEL_HLCDC_LAYER_REVALPHA           BIT(4)
> -#define ATMEL_HLCDC_LAYER_GAEN                       BIT(5)
> -#define ATMEL_HLCDC_LAYER_LAEN                       BIT(6)
> -#define ATMEL_HLCDC_LAYER_OVR                        BIT(7)
> -#define ATMEL_HLCDC_LAYER_DMA                        BIT(8)
> -#define ATMEL_HLCDC_LAYER_REP                        BIT(9)
> -#define ATMEL_HLCDC_LAYER_DSTKEY             BIT(10)
> -#define ATMEL_HLCDC_LAYER_DISCEN             BIT(11)
> -#define ATMEL_HLCDC_LAYER_GA_SHIFT           16
> -#define ATMEL_HLCDC_LAYER_GA_MASK            GENMASK(23, 
> ATMEL_HLCDC_LAYER_GA_SHIFT)
> -#define ATMEL_HLCDC_LAYER_GA(x)                      ((x) << 
> ATMEL_HLCDC_LAYER_GA_SHIFT)
> -
> -#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o)              
> ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
> -
> -#define ATMEL_HLCDC_LAYER_DISC_POS_CFG(p)    ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.disc_pos)
> -
> -#define ATMEL_HLCDC_LAYER_DISC_SIZE_CFG(p)   ATMEL_HLCDC_LAYER_CFG(p, 
> (p)->desc->layout.disc_size)
> -
> -#define ATMEL_HLCDC_MAX_PLANES                       3
> -
> -#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED        BIT(0)
> -#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED  BIT(1)
> -#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE    BIT(2)
> -#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN BIT(3)
> -
> -/**
> - * Atmel HLCDC Layer registers layout structure
> - *
> - * Each HLCDC layer has its own register organization and a given register
> - * can be placed differently on 2 different layers depending on its
> - * capabilities.
> - * This structure stores common registers layout for a given layer and is
> - * used by HLCDC layer code to choose the appropriate register to write to
> - * or to read from.
> - *
> - * For all fields, a value of zero means "unsupported".
> - *
> - * See Atmel's datasheet for a detailled description of these registers.
> - *
> - * @xstride: xstride registers
> - * @pstride: pstride registers
> - * @pos: position register
> - * @size: displayed size register
> - * @memsize: memory size register
> - * @default_color: default color register
> - * @chroma_key: chroma key register
> - * @chroma_key_mask: chroma key mask register
> - * @general_config: general layer config register
> - * @disc_pos: discard area position register
> - * @disc_size: discard area size register
> - * @csc: color space conversion register
> - */
> -struct atmel_hlcdc_layer_cfg_layout {
> -     int xstride[ATMEL_HLCDC_MAX_PLANES];
> -     int pstride[ATMEL_HLCDC_MAX_PLANES];
> -     int pos;
> -     int size;
> -     int memsize;
> -     int default_color;
> -     int chroma_key;
> -     int chroma_key_mask;
> -     int general_config;
> -     int disc_pos;
> -     int disc_size;
> -     int csc;
> -};
> -
> -/**
> - * Atmel HLCDC framebuffer flip structure
> - *
> - * This structure is allocated when someone asked for a layer update (most
> - * likely a DRM plane update, either primary, overlay or cursor plane) and
> - * released when the layer do not need to reference the framebuffer object
> - * anymore (i.e. the layer was disabled or updated).
> - *
> - * @dscrs: DMA descriptors
> - * @fb: the referenced framebuffer object
> - * @ngems: number of GEM objects referenced by the fb element
> - * @status: fb flip operation status
> - */
> -struct atmel_hlcdc_layer_fb_flip {
> -     struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
> -     struct drm_flip_task *task;
> -     struct drm_framebuffer *fb;
> -     int ngems;
> -     u32 status;
> -};
> -
> -/**
> - * Atmel HLCDC DMA descriptor structure
> - *
> - * This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
> - *
> - * The structure fields must remain in this specific order, because they're
> - * used by the HLCDC DMA engine, which expect them in this order.
> - * HLCDC DMA descriptors must be aligned on 64 bits.
> - *
> - * @addr: buffer DMA address
> - * @ctrl: DMA transfer options
> - * @next: next DMA descriptor to fetch
> - * @gem_flip: the attached gem_flip operation
> - */
> -struct atmel_hlcdc_dma_channel_dscr {
> -     dma_addr_t addr;
> -     u32 ctrl;
> -     dma_addr_t next;
> -     u32 status;
> -} __aligned(sizeof(u64));
> -
> -/**
> - * Atmel HLCDC layer types
> - */
> -enum atmel_hlcdc_layer_type {
> -     ATMEL_HLCDC_BASE_LAYER,
> -     ATMEL_HLCDC_OVERLAY_LAYER,
> -     ATMEL_HLCDC_CURSOR_LAYER,
> -     ATMEL_HLCDC_PP_LAYER,
> -};
> -
> -/**
> - * Atmel HLCDC Supported formats structure
> - *
> - * This structure list all the formats supported by a given layer.
> - *
> - * @nformats: number of supported formats
> - * @formats: supported formats
> - */
> -struct atmel_hlcdc_formats {
> -     int nformats;
> -     uint32_t *formats;
> -};
> -
> -/**
> - * Atmel HLCDC Layer description structure
> - *
> - * This structure describe the capabilities provided by a given layer.
> - *
> - * @name: layer name
> - * @type: layer type
> - * @id: layer id
> - * @regs_offset: offset of the layer registers from the HLCDC registers base
> - * @nconfigs: number of config registers provided by this layer
> - * @formats: supported formats
> - * @layout: config registers layout
> - * @max_width: maximum width supported by this layer (0 means unlimited)
> - * @max_height: maximum height supported by this layer (0 means unlimited)
> - */
> -struct atmel_hlcdc_layer_desc {
> -     const char *name;
> -     enum atmel_hlcdc_layer_type type;
> -     int id;
> -     int regs_offset;
> -     int nconfigs;
> -     struct atmel_hlcdc_formats *formats;
> -     struct atmel_hlcdc_layer_cfg_layout layout;
> -     int max_width;
> -     int max_height;
> -};
> -
> -/**
> - * Atmel HLCDC Layer Update Slot structure
> - *
> - * This structure stores layer update requests to be applied on next frame.
> - * This is the base structure behind the atomic layer update infrastructure.
> - *
> - * Atomic layer update provides a way to update all layer's parameters
> - * simultaneously. This is needed to avoid incompatible sequential updates
> - * like this one:
> - * 1) update layer format from RGB888 (1 plane/buffer) to YUV422
> - *    (2 planes/buffers)
> - * 2) the format update is applied but the DMA channel for the second
> - *    plane/buffer is not enabled
> - * 3) enable the DMA channel for the second plane
> - *
> - * @fb_flip: fb_flip object
> - * @updated_configs: bitmask used to record modified configs
> - * @configs: new config values
> - */
> -struct atmel_hlcdc_layer_update_slot {
> -     struct atmel_hlcdc_layer_fb_flip *fb_flip;
> -     unsigned long *updated_configs;
> -     u32 *configs;
> -};
> -
> -/**
> - * Atmel HLCDC Layer Update structure
> - *
> - * This structure provides a way to queue layer update requests.
> - *
> - * At a given time there is at most:
> - *  - one pending update request, which means the update request has been
> - *    committed (or validated) and is waiting for the DMA channel(s) to be
> - *    available
> - *  - one request being prepared, which means someone started a layer update
> - *    but has not committed it yet. There cannot be more than one started
> - *    request, because the update lock is taken when starting a layer update
> - *    and release when committing or rolling back the request.
> - *
> - * @slots: update slots. One is used for pending request and the other one
> - *      for started update request
> - * @pending: the pending slot index or -1 if no request is pending
> - * @next: the started update slot index or -1 no update has been started
> - */
> -struct atmel_hlcdc_layer_update {
> -     struct atmel_hlcdc_layer_update_slot slots[2];
> -     int pending;
> -     int next;
> -};
> -
> -enum atmel_hlcdc_layer_dma_channel_status {
> -     ATMEL_HLCDC_LAYER_DISABLED,
> -     ATMEL_HLCDC_LAYER_ENABLED,
> -     ATMEL_HLCDC_LAYER_DISABLING,
> -};
> -
> -/**
> - * Atmel HLCDC Layer DMA channel structure
> - *
> - * This structure stores information on the DMA channel associated to a
> - * given layer.
> - *
> - * @status: DMA channel status
> - * @cur: current framebuffer
> - * @queue: next framebuffer
> - * @dscrs: allocated DMA descriptors
> - */
> -struct atmel_hlcdc_layer_dma_channel {
> -     enum atmel_hlcdc_layer_dma_channel_status status;
> -     struct atmel_hlcdc_layer_fb_flip *cur;
> -     struct atmel_hlcdc_layer_fb_flip *queue;
> -     struct atmel_hlcdc_dma_channel_dscr *dscrs;
> -};
> -
> -/**
> - * Atmel HLCDC Layer structure
> - *
> - * This structure stores information on the layer instance.
> - *
> - * @desc: layer description
> - * @max_planes: maximum planes/buffers that can be associated with this 
> layer.
> - *          This depends on the supported formats.
> - * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
> - * @dma: dma channel
> - * @gc: fb flip garbage collector
> - * @update: update handler
> - * @lock: layer lock
> - */
> -struct atmel_hlcdc_layer {
> -     const struct atmel_hlcdc_layer_desc *desc;
> -     int max_planes;
> -     struct atmel_hlcdc *hlcdc;
> -     struct workqueue_struct *wq;
> -     struct drm_flip_work gc;
> -     struct atmel_hlcdc_layer_dma_channel dma;
> -     struct atmel_hlcdc_layer_update update;
> -     spinlock_t lock;
> -};
> -
> -void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer);
> -
> -int atmel_hlcdc_layer_init(struct drm_device *dev,
> -                        struct atmel_hlcdc_layer *layer,
> -                        const struct atmel_hlcdc_layer_desc *desc);
> -
> -void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
> -                            struct atmel_hlcdc_layer *layer);
> -
> -void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
> -
> -int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
> -
> -void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
> -                               u32 mask, u32 val);
> -
> -void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
> -                                  struct drm_framebuffer *fb,
> -                                  unsigned int *offsets);
> -
> -void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
> -                                        void (*finished)(void *data),
> -                                        void *finished_data);
> -
> -void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer);
> -
> -void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer);
> -
> -#endif /* DRM_ATMEL_HLCDC_LAYER_H */
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c 
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> index 246ed1e33d8a..cb6b2d5ae50b 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> @@ -37,7 +37,6 @@
>   * @xstride: value to add to the pixel pointer between each line
>   * @pstride: value to add to the pixel pointer between each pixel
>   * @nplanes: number of planes (deduced from pixel_format)
> - * @prepared: plane update has been prepared
>   */
>  struct atmel_hlcdc_plane_state {
>       struct drm_plane_state base;
> @@ -52,8 +51,6 @@ struct atmel_hlcdc_plane_state {
>  
>       u8 alpha;
>  
> -     bool disc_updated;
> -
>       int disc_x;
>       int disc_y;
>       int disc_w;
> @@ -62,12 +59,14 @@ struct atmel_hlcdc_plane_state {
>       int ahb_id;
>  
>       /* These fields are private and should not be touched */
> -     int bpp[ATMEL_HLCDC_MAX_PLANES];
> -     unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
> -     int xstride[ATMEL_HLCDC_MAX_PLANES];
> -     int pstride[ATMEL_HLCDC_MAX_PLANES];
> +     int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
> +     unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
> +     int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
> +     int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
>       int nplanes;
> -     bool prepared;
> +
> +     /* DMA descriptors. */
> +     struct atmel_hlcdc_dma_channel_dscr 
> *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
>  };
>  
>  static inline struct atmel_hlcdc_plane_state *
> @@ -259,125 +258,146 @@ static u32 heo_upscaling_ycoef[] = {
>       0x00205907,
>  };
>  
> +#define ATMEL_HLCDC_XPHIDEF  4
> +#define ATMEL_HLCDC_YPHIDEF  4
> +
> +static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
> +                                               u32 dstsize,
> +                                               u32 phidef)
> +{
> +     u32 factor, max_memsize;
> +
> +     factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
> +     max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
> +
> +     if (max_memsize > srcsize - 1)
> +             factor--;
> +
> +     return factor;
> +}
> +
>  static void
> -atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
> -                                   struct atmel_hlcdc_plane_state *state)
> +atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
> +                                   const u32 *coeff_tab, int size,
> +                                   unsigned int cfg_offs)
>  {
> -     const struct atmel_hlcdc_layer_cfg_layout *layout =
> -                                             &plane->layer.desc->layout;
> -
> -     if (layout->size)
> -             atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                          layout->size,
> -                                          0xffffffff,
> -                                          (state->crtc_w - 1) |
> -                                          ((state->crtc_h - 1) << 16));
> -
> -     if (layout->memsize)
> -             atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                          layout->memsize,
> -                                          0xffffffff,
> -                                          (state->src_w - 1) |
> -                                          ((state->src_h - 1) << 16));
> -
> -     if (layout->pos)
> -             atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                          layout->pos,
> -                                          0xffffffff,
> -                                          state->crtc_x |
> -                                          (state->crtc_y  << 16));
> -
> -     /* TODO: rework the rescaling part */
> -     if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
> -             u32 factor_reg = 0;
> -
> -             if (state->crtc_w != state->src_w) {
> -                     int i;
> -                     u32 factor;
> -                     u32 *coeff_tab = heo_upscaling_xcoef;
> -                     u32 max_memsize;
> -
> -                     if (state->crtc_w < state->src_w)
> -                             coeff_tab = heo_downscaling_xcoef;
> -                     for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
> -                             atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                                          17 + i,
> -                                                          0xffffffff,
> -                                                          coeff_tab[i]);
> -                     factor = ((8 * 256 * state->src_w) - (256 * 4)) /
> -                              state->crtc_w;
> -                     factor++;
> -                     max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
> -                                   2048;
> -                     if (max_memsize > state->src_w)
> -                             factor--;
> -                     factor_reg |= factor | 0x80000000;
> -             }
> +     int i;
>  
> -             if (state->crtc_h != state->src_h) {
> -                     int i;
> -                     u32 factor;
> -                     u32 *coeff_tab = heo_upscaling_ycoef;
> -                     u32 max_memsize;
> -
> -                     if (state->crtc_h < state->src_h)
> -                             coeff_tab = heo_downscaling_ycoef;
> -                     for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
> -                             atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                                          33 + i,
> -                                                          0xffffffff,
> -                                                          coeff_tab[i]);
> -                     factor = ((8 * 256 * state->src_h) - (256 * 4)) /
> -                              state->crtc_h;
> -                     factor++;
> -                     max_memsize = ((factor * state->crtc_h) + (256 * 4)) /
> -                                   2048;
> -                     if (max_memsize > state->src_h)
> -                             factor--;
> -                     factor_reg |= (factor << 16) | 0x80000000;
> -             }
> +     for (i = 0; i < size; i++)
> +             atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
> +                                         coeff_tab[i]);
> +}
> +
> +void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
> +                                 struct atmel_hlcdc_plane_state *state)
> +{
> +     const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
> +     u32 xfactor, yfactor;
> +
> +     if (!desc->layout.scaler_config)
> +             return;
>  
> -             atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
> -                                          factor_reg);
> +     if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
> +             atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                         desc->layout.scaler_config, 0);
> +             return;
> +     }
> +
> +     if (desc->layout.phicoeffs.x) {
> +             xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
> +                                                     state->crtc_w,
> +                                                     ATMEL_HLCDC_XPHIDEF);
> +
> +             yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
> +                                                     state->crtc_h,
> +                                                     ATMEL_HLCDC_YPHIDEF);
> +
> +             atmel_hlcdc_plane_scaler_set_phicoeff(plane,
> +                             state->crtc_w < state->src_w ?
> +                             heo_downscaling_xcoef :
> +                             heo_upscaling_xcoef,
> +                             ARRAY_SIZE(heo_upscaling_xcoef),
> +                             desc->layout.phicoeffs.x);
> +
> +             atmel_hlcdc_plane_scaler_set_phicoeff(plane,
> +                             state->crtc_h < state->src_h ?
> +                             heo_downscaling_ycoef :
> +                             heo_upscaling_ycoef,
> +                             ARRAY_SIZE(heo_upscaling_ycoef),
> +                             desc->layout.phicoeffs.y);
>       } else {
> -             atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 0);
> +             xfactor = (1024 * state->src_w) / state->crtc_w;
> +             yfactor = (1024 * state->src_h) / state->crtc_h;
>       }
> +
> +     atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
> +                                 ATMEL_HLCDC_LAYER_SCALER_ENABLE |
> +                                 ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
> +                                                                  yfactor));
> +}
> +
> +static void
> +atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
> +                                   struct atmel_hlcdc_plane_state *state)
> +{
> +     const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
> +
> +     if (desc->layout.size)
> +             atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
> +                                     ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
> +                                                            state->crtc_h));
> +
> +     if (desc->layout.memsize)
> +             atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                     desc->layout.memsize,
> +                                     ATMEL_HLCDC_LAYER_SIZE(state->src_w,
> +                                                            state->src_h));
> +
> +     if (desc->layout.pos)
> +             atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
> +                                     ATMEL_HLCDC_LAYER_POS(state->crtc_x,
> +                                                           state->crtc_y));
> +
> +     atmel_hlcdc_plane_setup_scaler(plane, state);
>  }
>  
>  static void
>  atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
>                                       struct atmel_hlcdc_plane_state *state)
>  {
> -     const struct atmel_hlcdc_layer_cfg_layout *layout =
> -                                             &plane->layer.desc->layout;
> -     unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
> +     unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
> +     const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
> +
> +     /*
> +      * Rotation optimization is not working on RGB888 (rotation is still
> +      * working but without any optimization).
> +      */
> +     if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
> +             cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
> +
> +     atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
> +                                 cfg);
> +
> +     cfg = ATMEL_HLCDC_LAYER_DMA;
>  
>       if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
> +             u32 format = state->base.fb->pixel_format;
> +
>               cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
>                      ATMEL_HLCDC_LAYER_ITER;
>  
> -             if 
> (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
> +             if (atmel_hlcdc_format_embeds_alpha(format))
>                       cfg |= ATMEL_HLCDC_LAYER_LAEN;
>               else
>                       cfg |= ATMEL_HLCDC_LAYER_GAEN |
>                              ATMEL_HLCDC_LAYER_GA(state->alpha);
>       }
>  
> -     atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                  ATMEL_HLCDC_LAYER_DMA_CFG_ID,
> -                                  ATMEL_HLCDC_LAYER_DMA_BLEN_MASK |
> -                                  ATMEL_HLCDC_LAYER_DMA_SIF,
> -                                  ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 |
> -                                  state->ahb_id);
> -
> -     atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
> -                                  ATMEL_HLCDC_LAYER_ITER2BL |
> -                                  ATMEL_HLCDC_LAYER_ITER |
> -                                  ATMEL_HLCDC_LAYER_GAEN |
> -                                  ATMEL_HLCDC_LAYER_GA_MASK |
> -                                  ATMEL_HLCDC_LAYER_LAEN |
> -                                  ATMEL_HLCDC_LAYER_OVR |
> -                                  ATMEL_HLCDC_LAYER_DMA, cfg);
> +     if (state->disc_h * state->disc_w)
> +             cfg |= ATMEL_HLCDC_LAYER_DISCEN;
> +
> +     atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
> +                                 cfg);
>  }
>  
>  static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
> @@ -396,50 +416,51 @@ static void atmel_hlcdc_plane_update_format(struct 
> atmel_hlcdc_plane *plane,
>           drm_rotation_90_or_270(state->base.rotation))
>               cfg |= ATMEL_HLCDC_YUV422ROT;
>  
> -     atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                  ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
> -                                  0xffffffff,
> -                                  cfg);
> +     atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                 ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
>  
> -     /*
> -      * Rotation optimization is not working on RGB888 (rotation is still
> -      * working but without any optimization).
> -      */
> -     if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
> -             cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
> -     else
> -             cfg = 0;
> -
> -     atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                  ATMEL_HLCDC_LAYER_DMA_CFG_ID,
> -                                  ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
>  }
>  
>  static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
>                                       struct atmel_hlcdc_plane_state *state)
>  {
> -     struct atmel_hlcdc_layer *layer = &plane->layer;
> -     const struct atmel_hlcdc_layer_cfg_layout *layout =
> -                                                     &layer->desc->layout;
> +     const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
> +     struct drm_framebuffer *fb = state->base.fb;
> +     u32 sr;
>       int i;
>  
> -     atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
> -                                     state->offsets);
> +     sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
>  
>       for (i = 0; i < state->nplanes; i++) {
> -             if (layout->xstride[i]) {
> -                     atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                             layout->xstride[i],
> -                                             0xffffffff,
> -                                             state->xstride[i]);
> +             struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
> +
> +             state->dscrs[i]->addr = gem->paddr + state->offsets[i];
> +
> +             atmel_hlcdc_layer_write_reg(&plane->layer,
> +                                         ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
> +                                         state->dscrs[i]->self);
> +
> +             if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
> +                     atmel_hlcdc_layer_write_reg(&plane->layer,
> +                                     ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
> +                                     state->dscrs[i]->addr);
> +                     atmel_hlcdc_layer_write_reg(&plane->layer,
> +                                     ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
> +                                     state->dscrs[i]->ctrl);
> +                     atmel_hlcdc_layer_write_reg(&plane->layer,
> +                                     ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
> +                                     state->dscrs[i]->self);
>               }
>  
> -             if (layout->pstride[i]) {
> -                     atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                             layout->pstride[i],
> -                                             0xffffffff,
> -                                             state->pstride[i]);
> -             }
> +             if (desc->layout.xstride[i])
> +                     atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                                 desc->layout.xstride[i],
> +                                                 state->xstride[i]);
> +
> +             if (desc->layout.pstride[i])
> +                     atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                                 desc->layout.pstride[i],
> +                                                 state->pstride[i]);
>       }
>  }
>  
> @@ -528,18 +549,10 @@ atmel_hlcdc_plane_prepare_disc_area(struct 
> drm_crtc_state *c_state)
>               disc_w = ovl_state->crtc_w;
>       }
>  
> -     if (disc_x == primary_state->disc_x &&
> -         disc_y == primary_state->disc_y &&
> -         disc_w == primary_state->disc_w &&
> -         disc_h == primary_state->disc_h)
> -             return 0;
> -
> -
>       primary_state->disc_x = disc_x;
>       primary_state->disc_y = disc_y;
>       primary_state->disc_w = disc_w;
>       primary_state->disc_h = disc_h;
> -     primary_state->disc_updated = true;
>  
>       return 0;
>  }
> @@ -548,32 +561,19 @@ static void
>  atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
>                                  struct atmel_hlcdc_plane_state *state)
>  {
> -     const struct atmel_hlcdc_layer_cfg_layout *layout =
> -                                             &plane->layer.desc->layout;
> -     int disc_surface = 0;
> -
> -     if (!state->disc_updated)
> -             return;
> -
> -     disc_surface = state->disc_h * state->disc_w;
> -
> -     atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
> -                             ATMEL_HLCDC_LAYER_DISCEN,
> -                             disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
> +     const struct atmel_hlcdc_layer_cfg_layout *layout;
>  
> -     if (!disc_surface)
> +     layout = &plane->layer.desc->layout;
> +     if (!layout->disc_pos || !layout->disc_size)
>               return;
>  
> -     atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                  layout->disc_pos,
> -                                  0xffffffff,
> -                                  state->disc_x | (state->disc_y << 16));
> +     atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
> +                             ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
> +                                                        state->disc_y));
>  
> -     atmel_hlcdc_layer_update_cfg(&plane->layer,
> -                                  layout->disc_size,
> -                                  0xffffffff,
> -                                  (state->disc_w - 1) |
> -                                  ((state->disc_h - 1) << 16));
> +     atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
> +                             ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
> +                                                         state->disc_h));
>  }
>  
>  static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
> @@ -582,8 +582,7 @@ static int atmel_hlcdc_plane_atomic_check(struct 
> drm_plane *p,
>       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
>       struct atmel_hlcdc_plane_state *state =
>                               drm_plane_state_to_atmel_hlcdc_plane_state(s);
> -     const struct atmel_hlcdc_layer_cfg_layout *layout =
> -                                             &plane->layer.desc->layout;
> +     const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
>       struct drm_framebuffer *fb = state->base.fb;
>       const struct drm_display_mode *mode;
>       struct drm_crtc_state *crtc_state;
> @@ -622,7 +621,7 @@ static int atmel_hlcdc_plane_atomic_check(struct 
> drm_plane *p,
>       state->src_h >>= 16;
>  
>       state->nplanes = drm_format_num_planes(fb->pixel_format);
> -     if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
> +     if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
>               return -EINVAL;
>  
>       /*
> @@ -726,21 +725,19 @@ static int atmel_hlcdc_plane_atomic_check(struct 
> drm_plane *p,
>       state->crtc_w = patched_crtc_w;
>       state->crtc_h = patched_crtc_h;
>  
> -     if (!layout->size &&
> +     if (!desc->layout.size &&
>           (mode->hdisplay != state->crtc_w ||
>            mode->vdisplay != state->crtc_h))
>               return -EINVAL;
>  
> -     if (plane->layer.desc->max_height &&
> -         state->crtc_h > plane->layer.desc->max_height)
> +     if (desc->max_height && state->crtc_h > desc->max_height)
>               return -EINVAL;
>  
> -     if (plane->layer.desc->max_width &&
> -         state->crtc_w > plane->layer.desc->max_width)
> +     if (desc->max_width && state->crtc_w > desc->max_width)
>               return -EINVAL;
>  
>       if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
> -         (!layout->memsize ||
> +         (!desc->layout.memsize ||
>            atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
>               return -EINVAL;
>  
> @@ -754,65 +751,13 @@ static int atmel_hlcdc_plane_atomic_check(struct 
> drm_plane *p,
>       return 0;
>  }
>  
> -static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
> -                                     struct drm_plane_state *new_state)
> -{
> -     /*
> -      * FIXME: we should avoid this const -> non-const cast but it's
> -      * currently the only solution we have to modify the ->prepared
> -      * state and rollback the update request.
> -      * Ideally, we should rework the code to attach all the resources
> -      * to atmel_hlcdc_plane_state (including the DMA desc allocation),
> -      * but this require a complete rework of the atmel_hlcdc_layer
> -      * code.
> -      */
> -     struct drm_plane_state *s = (struct drm_plane_state *)new_state;
> -     struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> -     struct atmel_hlcdc_plane_state *state =
> -                     drm_plane_state_to_atmel_hlcdc_plane_state(s);
> -     int ret;
> -
> -     ret = atmel_hlcdc_layer_update_start(&plane->layer);
> -     if (!ret)
> -             state->prepared = true;
> -
> -     return ret;
> -}
> -
> -static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p,
> -                                      struct drm_plane_state *old_state)
> -{
> -     /*
> -      * FIXME: we should avoid this const -> non-const cast but it's
> -      * currently the only solution we have to modify the ->prepared
> -      * state and rollback the update request.
> -      * Ideally, we should rework the code to attach all the resources
> -      * to atmel_hlcdc_plane_state (including the DMA desc allocation),
> -      * but this require a complete rework of the atmel_hlcdc_layer
> -      * code.
> -      */
> -     struct drm_plane_state *s = (struct drm_plane_state *)old_state;
> -     struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
> -     struct atmel_hlcdc_plane_state *state =
> -                     drm_plane_state_to_atmel_hlcdc_plane_state(s);
> -
> -     /*
> -      * The Request has already been applied or cancelled, nothing to do
> -      * here.
> -      */
> -     if (!state->prepared)
> -             return;
> -
> -     atmel_hlcdc_layer_update_rollback(&plane->layer);
> -     state->prepared = false;
> -}
> -
>  static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
>                                           struct drm_plane_state *old_s)
>  {
>       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
>       struct atmel_hlcdc_plane_state *state =
>                       drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
> +     u32 sr;
>  
>       if (!p->state->crtc || !p->state->fb)
>               return;
> @@ -823,7 +768,18 @@ static void atmel_hlcdc_plane_atomic_update(struct 
> drm_plane *p,
>       atmel_hlcdc_plane_update_buffers(plane, state);
>       atmel_hlcdc_plane_update_disc_area(plane, state);
>  
> -     atmel_hlcdc_layer_update_commit(&plane->layer);
> +     /* Enable the overrun interrupts. */
> +     atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
> +                                 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
> +                                 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
> +                                 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
> +
> +     /* Apply the new config at the next SOF event. */
> +     sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
> +     atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
> +                     ATMEL_HLCDC_LAYER_UPDATE |
> +                     (sr & ATMEL_HLCDC_LAYER_EN ?
> +                      ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
>  }
>  
>  static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
> @@ -831,7 +787,18 @@ static void atmel_hlcdc_plane_atomic_disable(struct 
> drm_plane *p,
>  {
>       struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
>  
> -     atmel_hlcdc_layer_disable(&plane->layer);
> +     /* Disable interrupts */
> +     atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
> +                                 0xffffffff);
> +
> +     /* Disable the layer */
> +     atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
> +                                 ATMEL_HLCDC_LAYER_RST |
> +                                 ATMEL_HLCDC_LAYER_A2Q |
> +                                 ATMEL_HLCDC_LAYER_UPDATE);
> +
> +     /* Clear all pending interrupts */
> +     atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
>  }
>  
>  static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
> @@ -841,10 +808,7 @@ static void atmel_hlcdc_plane_destroy(struct drm_plane 
> *p)
>       if (plane->base.fb)
>               drm_framebuffer_unreference(plane->base.fb);
>  
> -     atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
> -
>       drm_plane_cleanup(p);
> -     devm_kfree(p->dev->dev, plane);
>  }
>  
>  static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
> @@ -884,24 +848,15 @@ static int atmel_hlcdc_plane_atomic_get_property(struct 
> drm_plane *p,
>  }
>  
>  static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
> -                                          const struct 
> atmel_hlcdc_layer_desc *desc,
> -                                          struct 
> atmel_hlcdc_plane_properties *props)
> +                             struct atmel_hlcdc_plane_properties *props)
>  {
> -     struct regmap *regmap = plane->layer.hlcdc->regmap;
> +     const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
>  
>       if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
> -         desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
> +         desc->type == ATMEL_HLCDC_CURSOR_LAYER)
>               drm_object_attach_property(&plane->base.base,
>                                          props->alpha, 255);
>  
> -             /* Set default alpha value */
> -             regmap_update_bits(regmap,
> -                             desc->regs_offset +
> -                             ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
> -                             ATMEL_HLCDC_LAYER_GA_MASK,
> -                             ATMEL_HLCDC_LAYER_GA_MASK);
> -     }
> -
>       if (desc->layout.xstride && desc->layout.pstride) {
>               int ret;
>  
> @@ -920,31 +875,78 @@ static int atmel_hlcdc_plane_init_properties(struct 
> atmel_hlcdc_plane *plane,
>                * TODO: decare a "yuv-to-rgb-conv-factors" property to let
>                * userspace modify these factors (using a BLOB property ?).
>                */
> -             regmap_write(regmap,
> -                          desc->regs_offset +
> -                          ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
> -                          0x4c900091);
> -             regmap_write(regmap,
> -                          desc->regs_offset +
> -                          ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
> -                          0x7a5f5090);
> -             regmap_write(regmap,
> -                          desc->regs_offset +
> -                          ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
> -                          0x40040890);
> +             atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                         desc->layout.csc,
> +                                         0x4c900091);
> +             atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                         desc->layout.csc + 1,
> +                                         0x7a5f5090);
> +             atmel_hlcdc_layer_write_cfg(&plane->layer,
> +                                         desc->layout.csc + 2,
> +                                         0x40040890);
>       }
>  
>       return 0;
>  }
>  
> +void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
> +{
> +     const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
> +     u32 isr;
> +
> +     isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
> +
> +     /*
> +      * There's not much we can do in case of overrun except informing
> +      * the user. However, we are in interrupt context here, hence the
> +      * use of dev_dbg().
> +      */
> +     if (isr &
> +         (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
> +          ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
> +             dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
> +                     desc->name);
> +}
> +
>  static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
> -     .prepare_fb = atmel_hlcdc_plane_prepare_fb,
> -     .cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
>       .atomic_check = atmel_hlcdc_plane_atomic_check,
>       .atomic_update = atmel_hlcdc_plane_atomic_update,
>       .atomic_disable = atmel_hlcdc_plane_atomic_disable,
>  };
>  
> +static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
> +                                      struct atmel_hlcdc_plane_state *state)
> +{
> +     struct atmel_hlcdc_dc *dc = p->dev->dev_private;
> +     int i;
> +
> +     for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
> +             struct atmel_hlcdc_dma_channel_dscr *dscr;
> +             dma_addr_t dscr_dma;
> +
> +             dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
> +             if (!dscr)
> +                     goto err;
> +
> +             dscr->addr = 0;
> +             dscr->next = dscr_dma;
> +             dscr->self = dscr_dma;
> +             dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
> +
> +             state->dscrs[i] = dscr;
> +     }
> +
> +     return 0;
> +
> +err:
> +     for (i--; i >= 0; i--) {
> +             dma_pool_free(dc->dscrpool, state->dscrs[i],
> +                           state->dscrs[i]->self);
> +     }
> +
> +     return -ENOMEM;
> +}
> +
>  static void atmel_hlcdc_plane_reset(struct drm_plane *p)
>  {
>       struct atmel_hlcdc_plane_state *state;
> @@ -961,6 +963,13 @@ static void atmel_hlcdc_plane_reset(struct drm_plane *p)
>  
>       state = kzalloc(sizeof(*state), GFP_KERNEL);
>       if (state) {
> +             if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
> +                     kfree(state);
> +                     dev_err(p->dev->dev,
> +                             "Failed to allocate initial plane state\n");
> +                     return;
> +             }
> +
>               state->alpha = 255;
>               p->state = &state->base;
>               p->state->plane = p;
> @@ -978,8 +987,10 @@ atmel_hlcdc_plane_atomic_duplicate_state(struct 
> drm_plane *p)
>       if (!copy)
>               return NULL;
>  
> -     copy->disc_updated = false;
> -     copy->prepared = false;
> +     if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
> +             kfree(copy);
> +             return NULL;
> +     }
>  
>       if (copy->base.fb)
>               drm_framebuffer_reference(copy->base.fb);
> @@ -987,11 +998,18 @@ atmel_hlcdc_plane_atomic_duplicate_state(struct 
> drm_plane *p)
>       return &copy->base;
>  }
>  
> -static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
> +static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
>                                                  struct drm_plane_state *s)
>  {
>       struct atmel_hlcdc_plane_state *state =
>                       drm_plane_state_to_atmel_hlcdc_plane_state(s);
> +     struct atmel_hlcdc_dc *dc = p->dev->dev_private;
> +     int i;
> +
> +     for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
> +             dma_pool_free(dc->dscrpool, state->dscrs[i],
> +                           state->dscrs[i]->self);
> +     }
>  
>       if (s->fb)
>               drm_framebuffer_unreference(s->fb);
> @@ -1011,22 +1029,21 @@ static struct drm_plane_funcs layer_plane_funcs = {
>       .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
>  };
>  
> -static struct atmel_hlcdc_plane *
> -atmel_hlcdc_plane_create(struct drm_device *dev,
> -                      const struct atmel_hlcdc_layer_desc *desc,
> -                      struct atmel_hlcdc_plane_properties *props)
> +static int atmel_hlcdc_plane_create(struct drm_device *dev,
> +                                 const struct atmel_hlcdc_layer_desc *desc,
> +                                 struct atmel_hlcdc_plane_properties *props)
>  {
> +     struct atmel_hlcdc_dc *dc = dev->dev_private;
>       struct atmel_hlcdc_plane *plane;
>       enum drm_plane_type type;
>       int ret;
>  
>       plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
>       if (!plane)
> -             return ERR_PTR(-ENOMEM);
> +             return -ENOMEM;
>  
> -     ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
> -     if (ret)
> -             return ERR_PTR(ret);
> +     atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
> +     plane->properties = props;
>  
>       if (desc->type == ATMEL_HLCDC_BASE_LAYER)
>               type = DRM_PLANE_TYPE_PRIMARY;
> @@ -1040,17 +1057,19 @@ atmel_hlcdc_plane_create(struct drm_device *dev,
>                                      desc->formats->formats,
>                                      desc->formats->nformats, type, NULL);
>       if (ret)
> -             return ERR_PTR(ret);
> +             return ret;
>  
>       drm_plane_helper_add(&plane->base,
>                            &atmel_hlcdc_layer_plane_helper_funcs);
>  
>       /* Set default property values*/
> -     ret = atmel_hlcdc_plane_init_properties(plane, desc, props);
> +     ret = atmel_hlcdc_plane_init_properties(plane, props);
>       if (ret)
> -             return ERR_PTR(ret);
> +             return ret;
> +
> +     dc->layers[desc->id] = &plane->layer;
>  
> -     return plane;
> +     return 0;
>  }
>  
>  static struct atmel_hlcdc_plane_properties *
> @@ -1069,72 +1088,34 @@ atmel_hlcdc_plane_create_properties(struct drm_device 
> *dev)
>       return props;
>  }
>  
> -struct atmel_hlcdc_planes *
> -atmel_hlcdc_create_planes(struct drm_device *dev)
> +int atmel_hlcdc_create_planes(struct drm_device *dev)
>  {
>       struct atmel_hlcdc_dc *dc = dev->dev_private;
>       struct atmel_hlcdc_plane_properties *props;
> -     struct atmel_hlcdc_planes *planes;
>       const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
>       int nlayers = dc->desc->nlayers;
> -     int i;
> -
> -     planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
> -     if (!planes)
> -             return ERR_PTR(-ENOMEM);
> -
> -     for (i = 0; i < nlayers; i++) {
> -             if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
> -                     planes->noverlays++;
> -     }
> -
> -     if (planes->noverlays) {
> -             planes->overlays = devm_kzalloc(dev->dev,
> -                                             planes->noverlays *
> -                                             sizeof(*planes->overlays),
> -                                             GFP_KERNEL);
> -             if (!planes->overlays)
> -                     return ERR_PTR(-ENOMEM);
> -     }
> +     int i, ret;
>  
>       props = atmel_hlcdc_plane_create_properties(dev);
>       if (IS_ERR(props))
> -             return ERR_CAST(props);
> +             return PTR_ERR(props);
>  
> -     planes->noverlays = 0;
> -     for (i = 0; i < nlayers; i++) {
> -             struct atmel_hlcdc_plane *plane;
> +     dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
> +                             sizeof(struct atmel_hlcdc_dma_channel_dscr),
> +                             sizeof(u64), 0);
> +     if (!dc->dscrpool)
> +             return -ENOMEM;
>  
> -             if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
> +     for (i = 0; i < nlayers; i++) {
> +             if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
> +                 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
> +                 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
>                       continue;
>  
> -             plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
> -             if (IS_ERR(plane))
> -                     return ERR_CAST(plane);
> -
> -             plane->properties = props;
> -
> -             switch (descs[i].type) {
> -             case ATMEL_HLCDC_BASE_LAYER:
> -                     if (planes->primary)
> -                             return ERR_PTR(-EINVAL);
> -                     planes->primary = plane;
> -                     break;
> -
> -             case ATMEL_HLCDC_OVERLAY_LAYER:
> -                     planes->overlays[planes->noverlays++] = plane;
> -                     break;
> -
> -             case ATMEL_HLCDC_CURSOR_LAYER:
> -                     if (planes->cursor)
> -                             return ERR_PTR(-EINVAL);
> -                     planes->cursor = plane;
> -                     break;
> -
> -             default:
> -                     break;
> -             }
> +             ret = atmel_hlcdc_plane_create(dev, &descs[i], props);
> +             if (ret)
> +                     return ret;
>       }
>  
> -     return planes;
> +     return 0;
>  }
> -- 
> 2.7.4
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to