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_plane_helper.h>
17 #include "sun4i_backend.h"
18 #include "sun4i_layer.h"
19 #include "sunxi_engine.h"
21 struct sun4i_plane_desc
{
22 enum drm_plane_type type
;
24 const uint32_t *formats
;
28 static int sun4i_backend_layer_atomic_check(struct drm_plane
*plane
,
29 struct drm_plane_state
*state
)
34 static void sun4i_backend_layer_atomic_disable(struct drm_plane
*plane
,
35 struct drm_plane_state
*old_state
)
37 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
38 struct sun4i_backend
*backend
= layer
->backend
;
40 sun4i_backend_layer_enable(backend
, layer
->id
, false);
43 static void sun4i_backend_layer_atomic_update(struct drm_plane
*plane
,
44 struct drm_plane_state
*old_state
)
46 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
47 struct sun4i_backend
*backend
= layer
->backend
;
49 sun4i_backend_update_layer_coord(backend
, layer
->id
, plane
);
50 sun4i_backend_update_layer_formats(backend
, layer
->id
, plane
);
51 sun4i_backend_update_layer_buffer(backend
, layer
->id
, plane
);
52 sun4i_backend_layer_enable(backend
, layer
->id
, true);
55 static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs
= {
56 .atomic_check
= sun4i_backend_layer_atomic_check
,
57 .atomic_disable
= sun4i_backend_layer_atomic_disable
,
58 .atomic_update
= sun4i_backend_layer_atomic_update
,
61 static const struct drm_plane_funcs sun4i_backend_layer_funcs
= {
62 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
63 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
64 .destroy
= drm_plane_cleanup
,
65 .disable_plane
= drm_atomic_helper_disable_plane
,
66 .reset
= drm_atomic_helper_plane_reset
,
67 .update_plane
= drm_atomic_helper_update_plane
,
70 static const uint32_t sun4i_backend_layer_formats_primary
[] = {
77 static const uint32_t sun4i_backend_layer_formats_overlay
[] = {
88 static const struct sun4i_plane_desc sun4i_backend_planes
[] = {
90 .type
= DRM_PLANE_TYPE_PRIMARY
,
92 .formats
= sun4i_backend_layer_formats_primary
,
93 .nformats
= ARRAY_SIZE(sun4i_backend_layer_formats_primary
),
96 .type
= DRM_PLANE_TYPE_OVERLAY
,
98 .formats
= sun4i_backend_layer_formats_overlay
,
99 .nformats
= ARRAY_SIZE(sun4i_backend_layer_formats_overlay
),
103 static struct sun4i_layer
*sun4i_layer_init_one(struct drm_device
*drm
,
104 struct sun4i_backend
*backend
,
105 const struct sun4i_plane_desc
*plane
)
107 struct sun4i_layer
*layer
;
110 layer
= devm_kzalloc(drm
->dev
, sizeof(*layer
), GFP_KERNEL
);
112 return ERR_PTR(-ENOMEM
);
114 /* possible crtcs are set later */
115 ret
= drm_universal_plane_init(drm
, &layer
->plane
, 0,
116 &sun4i_backend_layer_funcs
,
117 plane
->formats
, plane
->nformats
,
120 dev_err(drm
->dev
, "Couldn't initialize layer\n");
124 drm_plane_helper_add(&layer
->plane
,
125 &sun4i_backend_layer_helper_funcs
);
126 layer
->backend
= backend
;
131 struct drm_plane
**sun4i_layers_init(struct drm_device
*drm
,
132 struct sunxi_engine
*engine
)
134 struct drm_plane
**planes
;
135 struct sun4i_backend
*backend
= engine_to_sun4i_backend(engine
);
138 planes
= devm_kcalloc(drm
->dev
, ARRAY_SIZE(sun4i_backend_planes
) + 1,
139 sizeof(*planes
), GFP_KERNEL
);
141 return ERR_PTR(-ENOMEM
);
144 * The hardware is a bit unusual here.
146 * Even though it supports 4 layers, it does the composition
147 * in two separate steps.
149 * The first one is assigning a layer to one of its two
150 * pipes. If more that 1 layer is assigned to the same pipe,
151 * and if pixels overlaps, the pipe will take the pixel from
152 * the layer with the highest priority.
154 * The second step is the actual alpha blending, that takes
155 * the two pipes as input, and uses the eventual alpha
156 * component to do the transparency between the two.
158 * This two steps scenario makes us unable to guarantee a
159 * robust alpha blending between the 4 layers in all
160 * situations. So we just expose two layers, one per pipe. On
161 * SoCs that support it, sprites could fill the need for more
164 for (i
= 0; i
< ARRAY_SIZE(sun4i_backend_planes
); i
++) {
165 const struct sun4i_plane_desc
*plane
= &sun4i_backend_planes
[i
];
166 struct sun4i_layer
*layer
;
168 layer
= sun4i_layer_init_one(drm
, backend
, plane
);
170 dev_err(drm
->dev
, "Couldn't initialize %s plane\n",
171 i
? "overlay" : "primary");
172 return ERR_CAST(layer
);
175 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
176 i
? "overlay" : "primary", plane
->pipe
);
177 regmap_update_bits(engine
->regs
, SUN4I_BACKEND_ATTCTL_REG0(i
),
178 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK
,
179 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane
->pipe
));
182 planes
[i
] = &layer
->plane
;