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 void sun4i_backend_layer_atomic_disable(struct drm_plane
*plane
,
29 struct drm_plane_state
*old_state
)
31 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
32 struct sun4i_backend
*backend
= layer
->backend
;
34 sun4i_backend_layer_enable(backend
, layer
->id
, false);
37 static void sun4i_backend_layer_atomic_update(struct drm_plane
*plane
,
38 struct drm_plane_state
*old_state
)
40 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
41 struct sun4i_backend
*backend
= layer
->backend
;
43 sun4i_backend_update_layer_coord(backend
, layer
->id
, plane
);
44 sun4i_backend_update_layer_formats(backend
, layer
->id
, plane
);
45 sun4i_backend_update_layer_buffer(backend
, layer
->id
, plane
);
46 sun4i_backend_layer_enable(backend
, layer
->id
, true);
49 static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs
= {
50 .atomic_disable
= sun4i_backend_layer_atomic_disable
,
51 .atomic_update
= sun4i_backend_layer_atomic_update
,
54 static const struct drm_plane_funcs sun4i_backend_layer_funcs
= {
55 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
56 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
57 .destroy
= drm_plane_cleanup
,
58 .disable_plane
= drm_atomic_helper_disable_plane
,
59 .reset
= drm_atomic_helper_plane_reset
,
60 .update_plane
= drm_atomic_helper_update_plane
,
63 static const uint32_t sun4i_backend_layer_formats_primary
[] = {
70 static const uint32_t sun4i_backend_layer_formats_overlay
[] = {
81 static const struct sun4i_plane_desc sun4i_backend_planes
[] = {
83 .type
= DRM_PLANE_TYPE_PRIMARY
,
85 .formats
= sun4i_backend_layer_formats_primary
,
86 .nformats
= ARRAY_SIZE(sun4i_backend_layer_formats_primary
),
89 .type
= DRM_PLANE_TYPE_OVERLAY
,
91 .formats
= sun4i_backend_layer_formats_overlay
,
92 .nformats
= ARRAY_SIZE(sun4i_backend_layer_formats_overlay
),
96 static struct sun4i_layer
*sun4i_layer_init_one(struct drm_device
*drm
,
97 struct sun4i_backend
*backend
,
98 const struct sun4i_plane_desc
*plane
)
100 struct sun4i_layer
*layer
;
103 layer
= devm_kzalloc(drm
->dev
, sizeof(*layer
), GFP_KERNEL
);
105 return ERR_PTR(-ENOMEM
);
107 /* possible crtcs are set later */
108 ret
= drm_universal_plane_init(drm
, &layer
->plane
, 0,
109 &sun4i_backend_layer_funcs
,
110 plane
->formats
, plane
->nformats
,
111 NULL
, plane
->type
, NULL
);
113 dev_err(drm
->dev
, "Couldn't initialize layer\n");
117 drm_plane_helper_add(&layer
->plane
,
118 &sun4i_backend_layer_helper_funcs
);
119 layer
->backend
= backend
;
124 struct drm_plane
**sun4i_layers_init(struct drm_device
*drm
,
125 struct sunxi_engine
*engine
)
127 struct drm_plane
**planes
;
128 struct sun4i_backend
*backend
= engine_to_sun4i_backend(engine
);
131 planes
= devm_kcalloc(drm
->dev
, ARRAY_SIZE(sun4i_backend_planes
) + 1,
132 sizeof(*planes
), GFP_KERNEL
);
134 return ERR_PTR(-ENOMEM
);
137 * The hardware is a bit unusual here.
139 * Even though it supports 4 layers, it does the composition
140 * in two separate steps.
142 * The first one is assigning a layer to one of its two
143 * pipes. If more that 1 layer is assigned to the same pipe,
144 * and if pixels overlaps, the pipe will take the pixel from
145 * the layer with the highest priority.
147 * The second step is the actual alpha blending, that takes
148 * the two pipes as input, and uses the eventual alpha
149 * component to do the transparency between the two.
151 * This two steps scenario makes us unable to guarantee a
152 * robust alpha blending between the 4 layers in all
153 * situations. So we just expose two layers, one per pipe. On
154 * SoCs that support it, sprites could fill the need for more
157 for (i
= 0; i
< ARRAY_SIZE(sun4i_backend_planes
); i
++) {
158 const struct sun4i_plane_desc
*plane
= &sun4i_backend_planes
[i
];
159 struct sun4i_layer
*layer
;
161 layer
= sun4i_layer_init_one(drm
, backend
, plane
);
163 dev_err(drm
->dev
, "Couldn't initialize %s plane\n",
164 i
? "overlay" : "primary");
165 return ERR_CAST(layer
);
168 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
169 i
? "overlay" : "primary", plane
->pipe
);
170 regmap_update_bits(engine
->regs
, SUN4I_BACKEND_ATTCTL_REG0(i
),
171 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK
,
172 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane
->pipe
));
175 planes
[i
] = &layer
->plane
;