blob: f03da16eb92abfa5550a5b9f018906da7c24e88a [file] [log] [blame]
Maxime Ripard9026e0d2015-10-29 09:36:23 +01001/*
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>
Maxime Ripard9026e0d2015-10-29 09:36:23 +010014#include <drm/drm_plane_helper.h>
15#include <drm/drmP.h>
16
17#include "sun4i_backend.h"
Maxime Ripardca07b212018-01-22 10:25:23 +010018#include "sun4i_frontend.h"
Maxime Ripard9026e0d2015-10-29 09:36:23 +010019#include "sun4i_layer.h"
Icenowy Zheng87969332017-05-17 22:47:17 +080020#include "sunxi_engine.h"
Maxime Ripard9026e0d2015-10-29 09:36:23 +010021
Maxime Ripardc222f392016-09-19 22:17:50 +020022struct sun4i_plane_desc {
Maxime Ripard185f1142017-04-30 15:45:14 +020023 enum drm_plane_type type;
24 u8 pipe;
25 const uint32_t *formats;
26 uint32_t nformats;
Maxime Ripardc222f392016-09-19 22:17:50 +020027};
Maxime Ripard9026e0d2015-10-29 09:36:23 +010028
Maxime Ripardd540f822018-01-22 10:25:18 +010029static void sun4i_backend_layer_reset(struct drm_plane *plane)
30{
31 struct sun4i_layer_state *state;
32
33 if (plane->state) {
34 state = state_to_sun4i_layer_state(plane->state);
35
36 __drm_atomic_helper_plane_destroy_state(&state->state);
37
38 kfree(state);
39 plane->state = NULL;
40 }
41
42 state = kzalloc(sizeof(*state), GFP_KERNEL);
43 if (state) {
44 plane->state = &state->state;
45 plane->state->plane = plane;
46 }
47}
48
49static struct drm_plane_state *
50sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
51{
Maxime Ripardca07b212018-01-22 10:25:23 +010052 struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
Maxime Ripardd540f822018-01-22 10:25:18 +010053 struct sun4i_layer_state *copy;
54
55 copy = kzalloc(sizeof(*copy), GFP_KERNEL);
56 if (!copy)
57 return NULL;
58
59 __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
Maxime Ripardca07b212018-01-22 10:25:23 +010060 copy->uses_frontend = orig->uses_frontend;
Maxime Ripardd540f822018-01-22 10:25:18 +010061
62 return &copy->state;
63}
64
65static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
66 struct drm_plane_state *state)
67{
68 struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
69
70 __drm_atomic_helper_plane_destroy_state(state);
71
72 kfree(s_state);
73}
74
Maxime Ripard9026e0d2015-10-29 09:36:23 +010075static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
76 struct drm_plane_state *old_state)
77{
Maxime Ripardca07b212018-01-22 10:25:23 +010078 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
Maxime Ripard9026e0d2015-10-29 09:36:23 +010079 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
Chen-Yu Tsaiace6c092017-02-23 16:05:42 +080080 struct sun4i_backend *backend = layer->backend;
Maxime Ripard9026e0d2015-10-29 09:36:23 +010081
82 sun4i_backend_layer_enable(backend, layer->id, false);
Maxime Ripardca07b212018-01-22 10:25:23 +010083
84 if (layer_state->uses_frontend) {
85 unsigned long flags;
86
87 spin_lock_irqsave(&backend->frontend_lock, flags);
88 backend->frontend_teardown = true;
89 spin_unlock_irqrestore(&backend->frontend_lock, flags);
90 }
Maxime Ripard9026e0d2015-10-29 09:36:23 +010091}
92
93static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
94 struct drm_plane_state *old_state)
95{
Maxime Ripardca07b212018-01-22 10:25:23 +010096 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
Maxime Ripard9026e0d2015-10-29 09:36:23 +010097 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
Chen-Yu Tsaiace6c092017-02-23 16:05:42 +080098 struct sun4i_backend *backend = layer->backend;
Maxime Ripardca07b212018-01-22 10:25:23 +010099 struct sun4i_frontend *frontend = backend->frontend;
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100100
Maxime Ripardca07b212018-01-22 10:25:23 +0100101 if (layer_state->uses_frontend) {
102 sun4i_frontend_init(frontend);
103 sun4i_frontend_update_coord(frontend, plane);
104 sun4i_frontend_update_buffer(frontend, plane);
105 sun4i_frontend_update_formats(frontend, plane,
106 DRM_FORMAT_ARGB8888);
107 sun4i_backend_update_layer_frontend(backend, layer->id,
108 DRM_FORMAT_ARGB8888);
109 sun4i_backend_update_layer_coord(backend, layer->id, plane);
110 sun4i_frontend_enable(frontend);
111 } else {
112 sun4i_backend_update_layer_coord(backend, layer->id, plane);
113 sun4i_backend_update_layer_formats(backend, layer->id, plane);
114 sun4i_backend_update_layer_buffer(backend, layer->id, plane);
115 }
116
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100117 sun4i_backend_layer_enable(backend, layer->id, true);
118}
119
Arvind Yadav934d1432017-07-03 21:35:20 +0530120static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100121 .atomic_disable = sun4i_backend_layer_atomic_disable,
122 .atomic_update = sun4i_backend_layer_atomic_update,
123};
124
125static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
Maxime Ripardd540f822018-01-22 10:25:18 +0100126 .atomic_destroy_state = sun4i_backend_layer_destroy_state,
127 .atomic_duplicate_state = sun4i_backend_layer_duplicate_state,
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100128 .destroy = drm_plane_cleanup,
129 .disable_plane = drm_atomic_helper_disable_plane,
Maxime Ripardd540f822018-01-22 10:25:18 +0100130 .reset = sun4i_backend_layer_reset,
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100131 .update_plane = drm_atomic_helper_update_plane,
132};
133
Maxime Ripardc222f392016-09-19 22:17:50 +0200134static const uint32_t sun4i_backend_layer_formats_primary[] = {
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100135 DRM_FORMAT_ARGB8888,
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100136 DRM_FORMAT_RGB888,
Maxime Ripard47d7fbb2016-10-18 10:46:14 +0200137 DRM_FORMAT_RGB565,
Maxime Ripardc222f392016-09-19 22:17:50 +0200138 DRM_FORMAT_XRGB8888,
139};
140
141static const uint32_t sun4i_backend_layer_formats_overlay[] = {
142 DRM_FORMAT_ARGB8888,
Maxime Ripard47d7fbb2016-10-18 10:46:14 +0200143 DRM_FORMAT_ARGB4444,
144 DRM_FORMAT_ARGB1555,
145 DRM_FORMAT_RGBA5551,
146 DRM_FORMAT_RGBA4444,
Maxime Ripardc222f392016-09-19 22:17:50 +0200147 DRM_FORMAT_RGB888,
Maxime Ripard47d7fbb2016-10-18 10:46:14 +0200148 DRM_FORMAT_RGB565,
Maxime Ripardc222f392016-09-19 22:17:50 +0200149 DRM_FORMAT_XRGB8888,
150};
151
152static const struct sun4i_plane_desc sun4i_backend_planes[] = {
153 {
154 .type = DRM_PLANE_TYPE_PRIMARY,
155 .pipe = 0,
156 .formats = sun4i_backend_layer_formats_primary,
157 .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_primary),
158 },
159 {
160 .type = DRM_PLANE_TYPE_OVERLAY,
161 .pipe = 1,
162 .formats = sun4i_backend_layer_formats_overlay,
163 .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_overlay),
164 },
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100165};
166
167static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
Chen-Yu Tsaia0a68fb2017-03-09 18:05:29 +0800168 struct sun4i_backend *backend,
Maxime Ripardc222f392016-09-19 22:17:50 +0200169 const struct sun4i_plane_desc *plane)
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100170{
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100171 struct sun4i_layer *layer;
172 int ret;
173
174 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
175 if (!layer)
176 return ERR_PTR(-ENOMEM);
177
Chen-Yu Tsaia5154a42017-02-23 16:05:39 +0800178 /* possible crtcs are set later */
179 ret = drm_universal_plane_init(drm, &layer->plane, 0,
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100180 &sun4i_backend_layer_funcs,
Maxime Ripardc222f392016-09-19 22:17:50 +0200181 plane->formats, plane->nformats,
Ben Widawskye6fc3b62017-07-23 20:46:38 -0700182 NULL, plane->type, NULL);
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100183 if (ret) {
184 dev_err(drm->dev, "Couldn't initialize layer\n");
185 return ERR_PTR(ret);
186 }
187
188 drm_plane_helper_add(&layer->plane,
189 &sun4i_backend_layer_helper_funcs);
Chen-Yu Tsaia0a68fb2017-03-09 18:05:29 +0800190 layer->backend = backend;
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100191
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100192 return layer;
193}
194
Icenowy Zheng7921e142017-05-15 00:30:36 +0800195struct drm_plane **sun4i_layers_init(struct drm_device *drm,
Icenowy Zheng87969332017-05-17 22:47:17 +0800196 struct sunxi_engine *engine)
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100197{
Icenowy Zheng7921e142017-05-15 00:30:36 +0800198 struct drm_plane **planes;
Icenowy Zheng87969332017-05-17 22:47:17 +0800199 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100200 int i;
201
Icenowy Zheng7921e142017-05-15 00:30:36 +0800202 planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
203 sizeof(*planes), GFP_KERNEL);
204 if (!planes)
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100205 return ERR_PTR(-ENOMEM);
206
207 /*
208 * The hardware is a bit unusual here.
209 *
210 * Even though it supports 4 layers, it does the composition
211 * in two separate steps.
212 *
213 * The first one is assigning a layer to one of its two
214 * pipes. If more that 1 layer is assigned to the same pipe,
215 * and if pixels overlaps, the pipe will take the pixel from
216 * the layer with the highest priority.
217 *
218 * The second step is the actual alpha blending, that takes
219 * the two pipes as input, and uses the eventual alpha
220 * component to do the transparency between the two.
221 *
222 * This two steps scenario makes us unable to guarantee a
223 * robust alpha blending between the 4 layers in all
224 * situations. So we just expose two layers, one per pipe. On
225 * SoCs that support it, sprites could fill the need for more
226 * layers.
227 */
Maxime Ripardc222f392016-09-19 22:17:50 +0200228 for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
229 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
Chen-Yu Tsai8a164692017-02-17 11:13:28 +0800230 struct sun4i_layer *layer;
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100231
Chen-Yu Tsaia0a68fb2017-03-09 18:05:29 +0800232 layer = sun4i_layer_init_one(drm, backend, plane);
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100233 if (IS_ERR(layer)) {
234 dev_err(drm->dev, "Couldn't initialize %s plane\n",
235 i ? "overlay" : "primary");
236 return ERR_CAST(layer);
237 };
238
239 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
Maxime Ripardc222f392016-09-19 22:17:50 +0200240 i ? "overlay" : "primary", plane->pipe);
Icenowy Zheng87969332017-05-17 22:47:17 +0800241 regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100242 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
Maxime Ripardc222f392016-09-19 22:17:50 +0200243 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100244
245 layer->id = i;
Icenowy Zheng7921e142017-05-15 00:30:36 +0800246 planes[i] = &layer->plane;
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100247 };
248
Icenowy Zheng7921e142017-05-15 00:30:36 +0800249 return planes;
Maxime Ripard9026e0d2015-10-29 09:36:23 +0100250}