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.brezillon@xxxxxxxxxxxxxxxxxx> > --- > 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.brezillon@xxxxxxxxxxxxxxxxxx> > - * > - * 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.brezillon@xxxxxxxxxxxxxxxxxx> > - * > - * 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 ©->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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel