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_frontend.h"
19 #include "sun4i_layer.h"
20 #include "sunxi_engine.h"
22 static void sun4i_backend_layer_reset(struct drm_plane
*plane
)
24 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
25 struct sun4i_layer_state
*state
;
28 state
= state_to_sun4i_layer_state(plane
->state
);
30 __drm_atomic_helper_plane_destroy_state(&state
->state
);
36 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
38 plane
->state
= &state
->state
;
39 plane
->state
->plane
= plane
;
40 plane
->state
->alpha
= DRM_BLEND_ALPHA_OPAQUE
;
41 plane
->state
->zpos
= layer
->id
;
45 static struct drm_plane_state
*
46 sun4i_backend_layer_duplicate_state(struct drm_plane
*plane
)
48 struct sun4i_layer_state
*orig
= state_to_sun4i_layer_state(plane
->state
);
49 struct sun4i_layer_state
*copy
;
51 copy
= kzalloc(sizeof(*copy
), GFP_KERNEL
);
55 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->state
);
56 copy
->uses_frontend
= orig
->uses_frontend
;
61 static void sun4i_backend_layer_destroy_state(struct drm_plane
*plane
,
62 struct drm_plane_state
*state
)
64 struct sun4i_layer_state
*s_state
= state_to_sun4i_layer_state(state
);
66 __drm_atomic_helper_plane_destroy_state(state
);
71 static void sun4i_backend_layer_atomic_disable(struct drm_plane
*plane
,
72 struct drm_plane_state
*old_state
)
74 struct sun4i_layer_state
*layer_state
= state_to_sun4i_layer_state(old_state
);
75 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
76 struct sun4i_backend
*backend
= layer
->backend
;
78 sun4i_backend_layer_enable(backend
, layer
->id
, false);
80 if (layer_state
->uses_frontend
) {
83 spin_lock_irqsave(&backend
->frontend_lock
, flags
);
84 backend
->frontend_teardown
= true;
85 spin_unlock_irqrestore(&backend
->frontend_lock
, flags
);
89 static void sun4i_backend_layer_atomic_update(struct drm_plane
*plane
,
90 struct drm_plane_state
*old_state
)
92 struct sun4i_layer_state
*layer_state
= state_to_sun4i_layer_state(plane
->state
);
93 struct sun4i_layer
*layer
= plane_to_sun4i_layer(plane
);
94 struct sun4i_backend
*backend
= layer
->backend
;
95 struct sun4i_frontend
*frontend
= backend
->frontend
;
97 if (layer_state
->uses_frontend
) {
98 sun4i_frontend_init(frontend
);
99 sun4i_frontend_update_coord(frontend
, plane
);
100 sun4i_frontend_update_buffer(frontend
, plane
);
101 sun4i_frontend_update_formats(frontend
, plane
,
102 DRM_FORMAT_ARGB8888
);
103 sun4i_backend_update_layer_frontend(backend
, layer
->id
,
104 DRM_FORMAT_ARGB8888
);
105 sun4i_frontend_enable(frontend
);
107 sun4i_backend_update_layer_formats(backend
, layer
->id
, plane
);
108 sun4i_backend_update_layer_buffer(backend
, layer
->id
, plane
);
111 sun4i_backend_update_layer_coord(backend
, layer
->id
, plane
);
112 sun4i_backend_update_layer_zpos(backend
, layer
->id
, plane
);
113 sun4i_backend_layer_enable(backend
, layer
->id
, true);
116 static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs
= {
117 .atomic_disable
= sun4i_backend_layer_atomic_disable
,
118 .atomic_update
= sun4i_backend_layer_atomic_update
,
121 static const struct drm_plane_funcs sun4i_backend_layer_funcs
= {
122 .atomic_destroy_state
= sun4i_backend_layer_destroy_state
,
123 .atomic_duplicate_state
= sun4i_backend_layer_duplicate_state
,
124 .destroy
= drm_plane_cleanup
,
125 .disable_plane
= drm_atomic_helper_disable_plane
,
126 .reset
= sun4i_backend_layer_reset
,
127 .update_plane
= drm_atomic_helper_update_plane
,
130 static const uint32_t sun4i_backend_layer_formats
[] = {
145 static struct sun4i_layer
*sun4i_layer_init_one(struct drm_device
*drm
,
146 struct sun4i_backend
*backend
,
147 enum drm_plane_type type
)
149 struct sun4i_layer
*layer
;
152 layer
= devm_kzalloc(drm
->dev
, sizeof(*layer
), GFP_KERNEL
);
154 return ERR_PTR(-ENOMEM
);
156 /* possible crtcs are set later */
157 ret
= drm_universal_plane_init(drm
, &layer
->plane
, 0,
158 &sun4i_backend_layer_funcs
,
159 sun4i_backend_layer_formats
,
160 ARRAY_SIZE(sun4i_backend_layer_formats
),
163 dev_err(drm
->dev
, "Couldn't initialize layer\n");
167 drm_plane_helper_add(&layer
->plane
,
168 &sun4i_backend_layer_helper_funcs
);
169 layer
->backend
= backend
;
171 drm_plane_create_alpha_property(&layer
->plane
);
172 drm_plane_create_zpos_property(&layer
->plane
, 0, 0,
173 SUN4I_BACKEND_NUM_LAYERS
- 1);
178 struct drm_plane
**sun4i_layers_init(struct drm_device
*drm
,
179 struct sunxi_engine
*engine
)
181 struct drm_plane
**planes
;
182 struct sun4i_backend
*backend
= engine_to_sun4i_backend(engine
);
185 /* We need to have a sentinel at the need, hence the overallocation */
186 planes
= devm_kcalloc(drm
->dev
, SUN4I_BACKEND_NUM_LAYERS
+ 1,
187 sizeof(*planes
), GFP_KERNEL
);
189 return ERR_PTR(-ENOMEM
);
191 for (i
= 0; i
< SUN4I_BACKEND_NUM_LAYERS
; i
++) {
192 enum drm_plane_type type
= i
? DRM_PLANE_TYPE_OVERLAY
: DRM_PLANE_TYPE_PRIMARY
;
193 struct sun4i_layer
*layer
;
195 layer
= sun4i_layer_init_one(drm
, backend
, type
);
197 dev_err(drm
->dev
, "Couldn't initialize %s plane\n",
198 i
? "overlay" : "primary");
199 return ERR_CAST(layer
);
203 planes
[i
] = &layer
->plane
;