2 * Copyright (C) 2015 Free Electrons
3 * Copyright (C) 2015 NextThing Co
5 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
13 #include <drm/drm_atomic_helper.h>
14 #include <drm/drm_crtc.h>
15 #include <drm/drm_plane_helper.h>
18 #include "sun4i_backend.h"
19 #include "sun4i_drv.h"
20 #include "sun4i_layer.h"
22 #define SUN4I_NUM_LAYERS 2
24 static int sun4i_backend_layer_atomic_check(struct drm_plane
*plane
,
25 struct drm_plane_state
*state
)
30 static void sun4i_backend_layer_atomic_disable(struct drm_plane
*plane
,
31 struct drm_plane_state
*old_state
)
33 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
34 struct sun4i_drv
*drv
= layer
->drv
;
35 struct sun4i_backend
*backend
= drv
->backend
;
37 sun4i_backend_layer_enable(backend
, layer
->id
, false);
40 static void sun4i_backend_layer_atomic_update(struct drm_plane
*plane
,
41 struct drm_plane_state
*old_state
)
43 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
44 struct sun4i_drv
*drv
= layer
->drv
;
45 struct sun4i_backend
*backend
= drv
->backend
;
47 sun4i_backend_update_layer_coord(backend
, layer
->id
, plane
);
48 sun4i_backend_update_layer_formats(backend
, layer
->id
, plane
);
49 sun4i_backend_update_layer_buffer(backend
, layer
->id
, plane
);
50 sun4i_backend_layer_enable(backend
, layer
->id
, true);
53 static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs
= {
54 .atomic_check
= sun4i_backend_layer_atomic_check
,
55 .atomic_disable
= sun4i_backend_layer_atomic_disable
,
56 .atomic_update
= sun4i_backend_layer_atomic_update
,
59 static const struct drm_plane_funcs sun4i_backend_layer_funcs
= {
60 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
61 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
62 .destroy
= drm_plane_cleanup
,
63 .disable_plane
= drm_atomic_helper_disable_plane
,
64 .reset
= drm_atomic_helper_plane_reset
,
65 .update_plane
= drm_atomic_helper_update_plane
,
68 static const uint32_t sun4i_backend_layer_formats
[] = {
74 static struct sun4i_layer
*sun4i_layer_init_one(struct drm_device
*drm
,
75 enum drm_plane_type type
)
77 struct sun4i_drv
*drv
= drm
->dev_private
;
78 struct sun4i_layer
*layer
;
81 layer
= devm_kzalloc(drm
->dev
, sizeof(*layer
), GFP_KERNEL
);
83 return ERR_PTR(-ENOMEM
);
85 ret
= drm_universal_plane_init(drm
, &layer
->plane
, BIT(0),
86 &sun4i_backend_layer_funcs
,
87 sun4i_backend_layer_formats
,
88 ARRAY_SIZE(sun4i_backend_layer_formats
),
92 dev_err(drm
->dev
, "Couldn't initialize layer\n");
96 drm_plane_helper_add(&layer
->plane
,
97 &sun4i_backend_layer_helper_funcs
);
100 if (type
== DRM_PLANE_TYPE_PRIMARY
)
101 drv
->primary
= &layer
->plane
;
106 struct sun4i_layer
**sun4i_layers_init(struct drm_device
*drm
)
108 struct sun4i_drv
*drv
= drm
->dev_private
;
109 struct sun4i_layer
**layers
;
112 layers
= devm_kcalloc(drm
->dev
, SUN4I_NUM_LAYERS
, sizeof(**layers
),
115 return ERR_PTR(-ENOMEM
);
118 * The hardware is a bit unusual here.
120 * Even though it supports 4 layers, it does the composition
121 * in two separate steps.
123 * The first one is assigning a layer to one of its two
124 * pipes. If more that 1 layer is assigned to the same pipe,
125 * and if pixels overlaps, the pipe will take the pixel from
126 * the layer with the highest priority.
128 * The second step is the actual alpha blending, that takes
129 * the two pipes as input, and uses the eventual alpha
130 * component to do the transparency between the two.
132 * This two steps scenario makes us unable to guarantee a
133 * robust alpha blending between the 4 layers in all
134 * situations. So we just expose two layers, one per pipe. On
135 * SoCs that support it, sprites could fill the need for more
138 for (i
= 0; i
< SUN4I_NUM_LAYERS
; i
++) {
139 enum drm_plane_type type
= (i
== 0)
140 ? DRM_PLANE_TYPE_PRIMARY
141 : DRM_PLANE_TYPE_OVERLAY
;
142 struct sun4i_layer
*layer
= layers
[i
];
144 layer
= sun4i_layer_init_one(drm
, type
);
146 dev_err(drm
->dev
, "Couldn't initialize %s plane\n",
147 i
? "overlay" : "primary");
148 return ERR_CAST(layer
);
151 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
152 i
? "overlay" : "primary", i
);
153 regmap_update_bits(drv
->backend
->regs
, SUN4I_BACKEND_ATTCTL_REG0(i
),
154 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK
,
155 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(i
));