1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2015 Free Electrons
4 * Copyright (C) 2015 NextThing Co
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
9 #include <drm/drm_atomic_helper.h>
10 #include <drm/drm_gem_framebuffer_helper.h>
11 #include <drm/drm_plane_helper.h>
13 #include "sun4i_backend.h"
14 #include "sun4i_frontend.h"
15 #include "sun4i_layer.h"
16 #include "sunxi_engine.h"
18 static void sun4i_backend_layer_reset(struct drm_plane
*plane
)
20 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
21 struct sun4i_layer_state
*state
;
24 state
= state_to_sun4i_layer_state(plane
->state
);
26 __drm_atomic_helper_plane_destroy_state(&state
->state
);
32 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
34 __drm_atomic_helper_plane_reset(plane
, &state
->state
);
35 plane
->state
->zpos
= layer
->id
;
39 static struct drm_plane_state
*
40 sun4i_backend_layer_duplicate_state(struct drm_plane
*plane
)
42 struct sun4i_layer_state
*orig
= state_to_sun4i_layer_state(plane
->state
);
43 struct sun4i_layer_state
*copy
;
45 copy
= kzalloc(sizeof(*copy
), GFP_KERNEL
);
49 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->state
);
50 copy
->uses_frontend
= orig
->uses_frontend
;
55 static void sun4i_backend_layer_destroy_state(struct drm_plane
*plane
,
56 struct drm_plane_state
*state
)
58 struct sun4i_layer_state
*s_state
= state_to_sun4i_layer_state(state
);
60 __drm_atomic_helper_plane_destroy_state(state
);
65 static void sun4i_backend_layer_atomic_disable(struct drm_plane
*plane
,
66 struct drm_plane_state
*old_state
)
68 struct sun4i_layer_state
*layer_state
= state_to_sun4i_layer_state(old_state
);
69 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
70 struct sun4i_backend
*backend
= layer
->backend
;
72 sun4i_backend_layer_enable(backend
, layer
->id
, false);
74 if (layer_state
->uses_frontend
) {
77 spin_lock_irqsave(&backend
->frontend_lock
, flags
);
78 backend
->frontend_teardown
= true;
79 spin_unlock_irqrestore(&backend
->frontend_lock
, flags
);
83 static void sun4i_backend_layer_atomic_update(struct drm_plane
*plane
,
84 struct drm_plane_state
*old_state
)
86 struct sun4i_layer_state
*layer_state
= state_to_sun4i_layer_state(plane
->state
);
87 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
88 struct sun4i_backend
*backend
= layer
->backend
;
89 struct sun4i_frontend
*frontend
= backend
->frontend
;
91 sun4i_backend_cleanup_layer(backend
, layer
->id
);
93 if (layer_state
->uses_frontend
) {
94 sun4i_frontend_init(frontend
);
95 sun4i_frontend_update_coord(frontend
, plane
);
96 sun4i_frontend_update_buffer(frontend
, plane
);
97 sun4i_frontend_update_formats(frontend
, plane
,
99 sun4i_backend_update_layer_frontend(backend
, layer
->id
,
100 DRM_FORMAT_XRGB8888
);
101 sun4i_frontend_enable(frontend
);
103 sun4i_backend_update_layer_formats(backend
, layer
->id
, plane
);
104 sun4i_backend_update_layer_buffer(backend
, layer
->id
, plane
);
107 sun4i_backend_update_layer_coord(backend
, layer
->id
, plane
);
108 sun4i_backend_update_layer_zpos(backend
, layer
->id
, plane
);
109 sun4i_backend_layer_enable(backend
, layer
->id
, true);
112 static bool sun4i_layer_format_mod_supported(struct drm_plane
*plane
,
113 uint32_t format
, uint64_t modifier
)
115 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
117 if (IS_ERR_OR_NULL(layer
->backend
->frontend
))
118 sun4i_backend_format_is_supported(format
, modifier
);
120 return sun4i_backend_format_is_supported(format
, modifier
) ||
121 sun4i_frontend_format_is_supported(format
, modifier
);
124 static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs
= {
125 .prepare_fb
= drm_gem_fb_prepare_fb
,
126 .atomic_disable
= sun4i_backend_layer_atomic_disable
,
127 .atomic_update
= sun4i_backend_layer_atomic_update
,
130 static const struct drm_plane_funcs sun4i_backend_layer_funcs
= {
131 .atomic_destroy_state
= sun4i_backend_layer_destroy_state
,
132 .atomic_duplicate_state
= sun4i_backend_layer_duplicate_state
,
133 .destroy
= drm_plane_cleanup
,
134 .disable_plane
= drm_atomic_helper_disable_plane
,
135 .reset
= sun4i_backend_layer_reset
,
136 .update_plane
= drm_atomic_helper_update_plane
,
137 .format_mod_supported
= sun4i_layer_format_mod_supported
,
140 static const uint32_t sun4i_layer_formats
[] = {
168 static const uint32_t sun4i_backend_layer_formats
[] = {
183 static const uint64_t sun4i_layer_modifiers
[] = {
184 DRM_FORMAT_MOD_LINEAR
,
185 DRM_FORMAT_MOD_ALLWINNER_TILED
,
186 DRM_FORMAT_MOD_INVALID
189 static struct sun4i_layer
*sun4i_layer_init_one(struct drm_device
*drm
,
190 struct sun4i_backend
*backend
,
191 enum drm_plane_type type
)
193 const uint64_t *modifiers
= sun4i_layer_modifiers
;
194 const uint32_t *formats
= sun4i_layer_formats
;
195 unsigned int formats_len
= ARRAY_SIZE(sun4i_layer_formats
);
196 struct sun4i_layer
*layer
;
199 layer
= devm_kzalloc(drm
->dev
, sizeof(*layer
), GFP_KERNEL
);
201 return ERR_PTR(-ENOMEM
);
203 layer
->backend
= backend
;
205 if (IS_ERR_OR_NULL(backend
->frontend
)) {
206 formats
= sun4i_backend_layer_formats
;
207 formats_len
= ARRAY_SIZE(sun4i_backend_layer_formats
);
211 /* possible crtcs are set later */
212 ret
= drm_universal_plane_init(drm
, &layer
->plane
, 0,
213 &sun4i_backend_layer_funcs
,
214 formats
, formats_len
,
215 modifiers
, type
, NULL
);
217 dev_err(drm
->dev
, "Couldn't initialize layer\n");
221 drm_plane_helper_add(&layer
->plane
,
222 &sun4i_backend_layer_helper_funcs
);
224 drm_plane_create_alpha_property(&layer
->plane
);
225 drm_plane_create_zpos_property(&layer
->plane
, 0, 0,
226 SUN4I_BACKEND_NUM_LAYERS
- 1);
231 struct drm_plane
**sun4i_layers_init(struct drm_device
*drm
,
232 struct sunxi_engine
*engine
)
234 struct drm_plane
**planes
;
235 struct sun4i_backend
*backend
= engine_to_sun4i_backend(engine
);
238 /* We need to have a sentinel at the need, hence the overallocation */
239 planes
= devm_kcalloc(drm
->dev
, SUN4I_BACKEND_NUM_LAYERS
+ 1,
240 sizeof(*planes
), GFP_KERNEL
);
242 return ERR_PTR(-ENOMEM
);
244 for (i
= 0; i
< SUN4I_BACKEND_NUM_LAYERS
; i
++) {
245 enum drm_plane_type type
= i
? DRM_PLANE_TYPE_OVERLAY
: DRM_PLANE_TYPE_PRIMARY
;
246 struct sun4i_layer
*layer
;
248 layer
= sun4i_layer_init_one(drm
, backend
, type
);
250 dev_err(drm
->dev
, "Couldn't initialize %s plane\n",
251 i
? "overlay" : "primary");
252 return ERR_CAST(layer
);
256 planes
[i
] = &layer
->plane
;