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 struct sun4i_plane_desc
{
23 enum drm_plane_type type
;
25 const uint32_t *formats
;
29 static int sun4i_backend_layer_atomic_check(struct drm_plane
*plane
,
30 struct drm_plane_state
*state
)
35 static void sun4i_backend_layer_atomic_disable(struct drm_plane
*plane
,
36 struct drm_plane_state
*old_state
)
38 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
39 struct sun4i_drv
*drv
= layer
->drv
;
40 struct sun4i_backend
*backend
= drv
->backend
;
42 sun4i_backend_layer_enable(backend
, layer
->id
, false);
45 static void sun4i_backend_layer_atomic_update(struct drm_plane
*plane
,
46 struct drm_plane_state
*old_state
)
48 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
49 struct sun4i_drv
*drv
= layer
->drv
;
50 struct sun4i_backend
*backend
= drv
->backend
;
52 sun4i_backend_update_layer_coord(backend
, layer
->id
, plane
);
53 sun4i_backend_update_layer_formats(backend
, layer
->id
, plane
);
54 sun4i_backend_update_layer_buffer(backend
, layer
->id
, plane
);
55 sun4i_backend_layer_enable(backend
, layer
->id
, true);
58 static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs
= {
59 .atomic_check
= sun4i_backend_layer_atomic_check
,
60 .atomic_disable
= sun4i_backend_layer_atomic_disable
,
61 .atomic_update
= sun4i_backend_layer_atomic_update
,
64 static const struct drm_plane_funcs sun4i_backend_layer_funcs
= {
65 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
66 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
67 .destroy
= drm_plane_cleanup
,
68 .disable_plane
= drm_atomic_helper_disable_plane
,
69 .reset
= drm_atomic_helper_plane_reset
,
70 .update_plane
= drm_atomic_helper_update_plane
,
73 static const uint32_t sun4i_backend_layer_formats_primary
[] = {
80 static const uint32_t sun4i_backend_layer_formats_overlay
[] = {
91 static const struct sun4i_plane_desc sun4i_backend_planes
[] = {
93 .type
= DRM_PLANE_TYPE_PRIMARY
,
95 .formats
= sun4i_backend_layer_formats_primary
,
96 .nformats
= ARRAY_SIZE(sun4i_backend_layer_formats_primary
),
99 .type
= DRM_PLANE_TYPE_OVERLAY
,
101 .formats
= sun4i_backend_layer_formats_overlay
,
102 .nformats
= ARRAY_SIZE(sun4i_backend_layer_formats_overlay
),
106 static struct sun4i_layer
*sun4i_layer_init_one(struct drm_device
*drm
,
107 const struct sun4i_plane_desc
*plane
)
109 struct sun4i_drv
*drv
= drm
->dev_private
;
110 struct sun4i_layer
*layer
;
113 layer
= devm_kzalloc(drm
->dev
, sizeof(*layer
), GFP_KERNEL
);
115 return ERR_PTR(-ENOMEM
);
117 ret
= drm_universal_plane_init(drm
, &layer
->plane
, BIT(0),
118 &sun4i_backend_layer_funcs
,
119 plane
->formats
, plane
->nformats
,
122 dev_err(drm
->dev
, "Couldn't initialize layer\n");
126 drm_plane_helper_add(&layer
->plane
,
127 &sun4i_backend_layer_helper_funcs
);
130 if (plane
->type
== DRM_PLANE_TYPE_PRIMARY
)
131 drv
->primary
= &layer
->plane
;
136 struct sun4i_layer
**sun4i_layers_init(struct drm_device
*drm
)
138 struct sun4i_drv
*drv
= drm
->dev_private
;
139 struct sun4i_layer
**layers
;
142 layers
= devm_kcalloc(drm
->dev
, ARRAY_SIZE(sun4i_backend_planes
),
143 sizeof(**layers
), GFP_KERNEL
);
145 return ERR_PTR(-ENOMEM
);
148 * The hardware is a bit unusual here.
150 * Even though it supports 4 layers, it does the composition
151 * in two separate steps.
153 * The first one is assigning a layer to one of its two
154 * pipes. If more that 1 layer is assigned to the same pipe,
155 * and if pixels overlaps, the pipe will take the pixel from
156 * the layer with the highest priority.
158 * The second step is the actual alpha blending, that takes
159 * the two pipes as input, and uses the eventual alpha
160 * component to do the transparency between the two.
162 * This two steps scenario makes us unable to guarantee a
163 * robust alpha blending between the 4 layers in all
164 * situations. So we just expose two layers, one per pipe. On
165 * SoCs that support it, sprites could fill the need for more
168 for (i
= 0; i
< ARRAY_SIZE(sun4i_backend_planes
); i
++) {
169 const struct sun4i_plane_desc
*plane
= &sun4i_backend_planes
[i
];
170 struct sun4i_layer
*layer
= layers
[i
];
172 layer
= sun4i_layer_init_one(drm
, plane
);
174 dev_err(drm
->dev
, "Couldn't initialize %s plane\n",
175 i
? "overlay" : "primary");
176 return ERR_CAST(layer
);
179 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
180 i
? "overlay" : "primary", plane
->pipe
);
181 regmap_update_bits(drv
->backend
->regs
, SUN4I_BACKEND_ATTCTL_REG0(i
),
182 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK
,
183 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane
->pipe
));