Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/*
2 * Copyright (C) 2015 Free Electrons
3 * Copyright (C) 2015 NextThing Co
4 *
5 * Maxime Ripard <maxime.ripard@free-electrons.com>
6 *
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.
11 */
12
13#include <drm/drm_atomic_helper.h>
14#include <drm/drm_plane_helper.h>
15#include <drm/drm_gem_framebuffer_helper.h>
16#include <drm/drmP.h>
17
18#include "sun4i_backend.h"
19#include "sun4i_frontend.h"
20#include "sun4i_layer.h"
21#include "sunxi_engine.h"
22
23static void sun4i_backend_layer_reset(struct drm_plane *plane)
24{
25 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
26 struct sun4i_layer_state *state;
27
28 if (plane->state) {
29 state = state_to_sun4i_layer_state(plane->state);
30
31 __drm_atomic_helper_plane_destroy_state(&state->state);
32
33 kfree(state);
34 plane->state = NULL;
35 }
36
37 state = kzalloc(sizeof(*state), GFP_KERNEL);
38 if (state) {
39 __drm_atomic_helper_plane_reset(plane, &state->state);
40 plane->state->zpos = layer->id;
41 }
42}
43
44static struct drm_plane_state *
45sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
46{
47 struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
48 struct sun4i_layer_state *copy;
49
50 copy = kzalloc(sizeof(*copy), GFP_KERNEL);
51 if (!copy)
52 return NULL;
53
54 __drm_atomic_helper_plane_duplicate_state(plane, ©->state);
55 copy->uses_frontend = orig->uses_frontend;
56
57 return ©->state;
58}
59
60static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
61 struct drm_plane_state *state)
62{
63 struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
64
65 __drm_atomic_helper_plane_destroy_state(state);
66
67 kfree(s_state);
68}
69
70static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
71 struct drm_plane_state *old_state)
72{
73 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
74 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
75 struct sun4i_backend *backend = layer->backend;
76
77 sun4i_backend_layer_enable(backend, layer->id, false);
78
79 if (layer_state->uses_frontend) {
80 unsigned long flags;
81
82 spin_lock_irqsave(&backend->frontend_lock, flags);
83 backend->frontend_teardown = true;
84 spin_unlock_irqrestore(&backend->frontend_lock, flags);
85 }
86}
87
88static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
89 struct drm_plane_state *old_state)
90{
91 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
92 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
93 struct sun4i_backend *backend = layer->backend;
94 struct sun4i_frontend *frontend = backend->frontend;
95
96 sun4i_backend_cleanup_layer(backend, layer->id);
97
98 if (layer_state->uses_frontend) {
99 sun4i_frontend_init(frontend);
100 sun4i_frontend_update_coord(frontend, plane);
101 sun4i_frontend_update_buffer(frontend, plane);
102 sun4i_frontend_update_formats(frontend, plane,
103 DRM_FORMAT_XRGB8888);
104 sun4i_backend_update_layer_frontend(backend, layer->id,
105 DRM_FORMAT_XRGB8888);
106 sun4i_frontend_enable(frontend);
107 } else {
108 sun4i_backend_update_layer_formats(backend, layer->id, plane);
109 sun4i_backend_update_layer_buffer(backend, layer->id, plane);
110 }
111
112 sun4i_backend_update_layer_coord(backend, layer->id, plane);
113 sun4i_backend_update_layer_zpos(backend, layer->id, plane);
114 sun4i_backend_layer_enable(backend, layer->id, true);
115}
116
117static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
118 .prepare_fb = drm_gem_fb_prepare_fb,
119 .atomic_disable = sun4i_backend_layer_atomic_disable,
120 .atomic_update = sun4i_backend_layer_atomic_update,
121};
122
123static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
124 .atomic_destroy_state = sun4i_backend_layer_destroy_state,
125 .atomic_duplicate_state = sun4i_backend_layer_duplicate_state,
126 .destroy = drm_plane_cleanup,
127 .disable_plane = drm_atomic_helper_disable_plane,
128 .reset = sun4i_backend_layer_reset,
129 .update_plane = drm_atomic_helper_update_plane,
130};
131
132static const uint32_t sun4i_layer_formats[] = {
133 DRM_FORMAT_ARGB8888,
134 DRM_FORMAT_ARGB4444,
135 DRM_FORMAT_ARGB1555,
136 DRM_FORMAT_BGRX8888,
137 DRM_FORMAT_RGBA5551,
138 DRM_FORMAT_RGBA4444,
139 DRM_FORMAT_RGB888,
140 DRM_FORMAT_RGB565,
141 DRM_FORMAT_UYVY,
142 DRM_FORMAT_VYUY,
143 DRM_FORMAT_XRGB8888,
144 DRM_FORMAT_YUYV,
145 DRM_FORMAT_YVYU,
146};
147
148static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
149 struct sun4i_backend *backend,
150 enum drm_plane_type type)
151{
152 struct sun4i_layer *layer;
153 int ret;
154
155 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
156 if (!layer)
157 return ERR_PTR(-ENOMEM);
158
159 /* possible crtcs are set later */
160 ret = drm_universal_plane_init(drm, &layer->plane, 0,
161 &sun4i_backend_layer_funcs,
162 sun4i_layer_formats,
163 ARRAY_SIZE(sun4i_layer_formats),
164 NULL, type, NULL);
165 if (ret) {
166 dev_err(drm->dev, "Couldn't initialize layer\n");
167 return ERR_PTR(ret);
168 }
169
170 drm_plane_helper_add(&layer->plane,
171 &sun4i_backend_layer_helper_funcs);
172 layer->backend = backend;
173
174 drm_plane_create_alpha_property(&layer->plane);
175 drm_plane_create_zpos_property(&layer->plane, 0, 0,
176 SUN4I_BACKEND_NUM_LAYERS - 1);
177
178 return layer;
179}
180
181struct drm_plane **sun4i_layers_init(struct drm_device *drm,
182 struct sunxi_engine *engine)
183{
184 struct drm_plane **planes;
185 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
186 int i;
187
188 /* We need to have a sentinel at the need, hence the overallocation */
189 planes = devm_kcalloc(drm->dev, SUN4I_BACKEND_NUM_LAYERS + 1,
190 sizeof(*planes), GFP_KERNEL);
191 if (!planes)
192 return ERR_PTR(-ENOMEM);
193
194 for (i = 0; i < SUN4I_BACKEND_NUM_LAYERS; i++) {
195 enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
196 struct sun4i_layer *layer;
197
198 layer = sun4i_layer_init_one(drm, backend, type);
199 if (IS_ERR(layer)) {
200 dev_err(drm->dev, "Couldn't initialize %s plane\n",
201 i ? "overlay" : "primary");
202 return ERR_CAST(layer);
203 };
204
205 layer->id = i;
206 planes[i] = &layer->plane;
207 };
208
209 return planes;
210}