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@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_output.o \ atmel_hlcdc_plane.oatmel_hlcdc_layer.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,
.layout = { .xstride = { 2 }, .default_color = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .xstride = { 2 }, .default_color = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x4c,
@@ -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,
.max_width = 128, .max_height = 128,.nconfigs = 10,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .xstride = { 2 }, .default_color = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x4c,
@@ -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,
.max_width = 128, .max_height = 128,.nconfigs = 10,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .xstride = { 2 }, .default_color = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x2c,
@@ -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,
.layout = { .pos = 2, .size = 3,.cfgs_offset = 0x4c,
@@ -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@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.brezillon@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:
- update layer format from RGB888 (1 plane/buffer) to YUV422
- (2 planes/buffers)
- the format update is applied but the DMA channel for the second
- plane/buffer is not enabled
- 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),
} else {desc->layout.phicoeffs.y);
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))
else cfg |= ATMEL_HLCDC_LAYER_GAEN | ATMEL_HLCDC_LAYER_GA(state->alpha); }if (atmel_hlcdc_format_embeds_alpha(format)) cfg |= ATMEL_HLCDC_LAYER_LAEN;
- 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 ||
return -EINVAL;(!desc->layout.memsize || atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
@@ -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) {
drm_object_attach_property(&plane->base.base, props->alpha, 255);desc->type == ATMEL_HLCDC_CURSOR_LAYER)
/* 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