Skip to content

Commit ca07b21

Browse files
committed
drm/sun4i: backend: Wire in the frontend
Now that we have a driver, we can make use of it. This is done by adding a flag to our custom plane state that will trigger whether we should use the frontend on that particular plane or not. The rest is just plumbing to set up the backend to not perform the DMA but receive its data from the frontend. Note that we're still not making any use of the frontend itself, as no one is setting the flag yet. Reviewed-by: Chen-Yu Tsai <[email protected]> Signed-off-by: Maxime Ripard <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/cdffc25eab2d817820cc78cbd24f1f4b99902014.1516613040.git-series.maxime.ripard@free-electrons.com
1 parent dd0421f commit ca07b21

File tree

5 files changed

+130
-3
lines changed

5 files changed

+130
-3
lines changed

drivers/gpu/drm/sun4i/sun4i_backend.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "sun4i_backend.h"
2828
#include "sun4i_drv.h"
29+
#include "sun4i_frontend.h"
2930
#include "sun4i_layer.h"
3031
#include "sunxi_engine.h"
3132

@@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
203204
return 0;
204205
}
205206

207+
int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
208+
int layer, uint32_t fmt)
209+
{
210+
u32 val;
211+
int ret;
212+
213+
ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
214+
if (ret) {
215+
DRM_DEBUG_DRIVER("Invalid format\n");
216+
return ret;
217+
}
218+
219+
regmap_update_bits(backend->engine.regs,
220+
SUN4I_BACKEND_ATTCTL_REG0(layer),
221+
SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
222+
SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
223+
224+
regmap_update_bits(backend->engine.regs,
225+
SUN4I_BACKEND_ATTCTL_REG1(layer),
226+
SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
227+
228+
return 0;
229+
}
230+
206231
int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
207232
int layer, struct drm_plane *plane)
208233
{
@@ -245,6 +270,36 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
245270
return 0;
246271
}
247272

273+
static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
274+
{
275+
struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
276+
struct sun4i_frontend *frontend = backend->frontend;
277+
278+
if (!frontend)
279+
return;
280+
281+
/*
282+
* In a teardown scenario with the frontend involved, we have
283+
* to keep the frontend enabled until the next vblank, and
284+
* only then disable it.
285+
*
286+
* This is due to the fact that the backend will not take into
287+
* account the new configuration (with the plane that used to
288+
* be fed by the frontend now disabled) until we write to the
289+
* commit bit and the hardware fetches the new configuration
290+
* during the next vblank.
291+
*
292+
* So we keep the frontend around in order to prevent any
293+
* visual artifacts.
294+
*/
295+
spin_lock(&backend->frontend_lock);
296+
if (backend->frontend_teardown) {
297+
sun4i_frontend_exit(frontend);
298+
backend->frontend_teardown = false;
299+
}
300+
spin_unlock(&backend->frontend_lock);
301+
};
302+
248303
static int sun4i_backend_init_sat(struct device *dev) {
249304
struct sun4i_backend *backend = dev_get_drvdata(dev);
250305
int ret;
@@ -329,11 +384,41 @@ static int sun4i_backend_of_get_id(struct device_node *node)
329384
return ret;
330385
}
331386

387+
/* TODO: This needs to take multiple pipelines into account */
388+
static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
389+
struct device_node *node)
390+
{
391+
struct device_node *port, *ep, *remote;
392+
struct sun4i_frontend *frontend;
393+
394+
port = of_graph_get_port_by_id(node, 0);
395+
if (!port)
396+
return ERR_PTR(-EINVAL);
397+
398+
for_each_available_child_of_node(port, ep) {
399+
remote = of_graph_get_remote_port_parent(ep);
400+
if (!remote)
401+
continue;
402+
403+
/* does this node match any registered engines? */
404+
list_for_each_entry(frontend, &drv->frontend_list, list) {
405+
if (remote == frontend->node) {
406+
of_node_put(remote);
407+
of_node_put(port);
408+
return frontend;
409+
}
410+
}
411+
}
412+
413+
return ERR_PTR(-EINVAL);
414+
}
415+
332416
static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
333417
.commit = sun4i_backend_commit,
334418
.layers_init = sun4i_layers_init,
335419
.apply_color_correction = sun4i_backend_apply_color_correction,
336420
.disable_color_correction = sun4i_backend_disable_color_correction,
421+
.vblank_quirk = sun4i_backend_vblank_quirk,
337422
};
338423

339424
static struct regmap_config sun4i_backend_regmap_config = {
@@ -359,13 +444,18 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
359444
if (!backend)
360445
return -ENOMEM;
361446
dev_set_drvdata(dev, backend);
447+
spin_lock_init(&backend->frontend_lock);
362448

363449
backend->engine.node = dev->of_node;
364450
backend->engine.ops = &sun4i_backend_engine_ops;
365451
backend->engine.id = sun4i_backend_of_get_id(dev->of_node);
366452
if (backend->engine.id < 0)
367453
return backend->engine.id;
368454

455+
backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
456+
if (IS_ERR(backend->frontend))
457+
dev_warn(dev, "Couldn't find matching frontend, frontend features disabled\n");
458+
369459
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
370460
regs = devm_ioremap_resource(dev, res);
371461
if (IS_ERR(regs))

drivers/gpu/drm/sun4i/sun4i_backend.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15)
7373
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10)
7474
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10)
75+
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1)
7576

7677
#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l)))
7778
#define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT GENMASK(15, 14)
@@ -145,6 +146,7 @@
145146

146147
struct sun4i_backend {
147148
struct sunxi_engine engine;
149+
struct sun4i_frontend *frontend;
148150

149151
struct reset_control *reset;
150152

@@ -154,6 +156,10 @@ struct sun4i_backend {
154156

155157
struct clk *sat_clk;
156158
struct reset_control *sat_reset;
159+
160+
/* Protects against races in the frontend teardown */
161+
spinlock_t frontend_lock;
162+
bool frontend_teardown;
157163
};
158164

159165
static inline struct sun4i_backend *
@@ -170,5 +176,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
170176
int layer, struct drm_plane *plane);
171177
int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
172178
int layer, struct drm_plane *plane);
179+
int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
180+
int layer, uint32_t in_fmt);
173181

174182
#endif /* _SUN4I_BACKEND_H_ */

drivers/gpu/drm/sun4i/sun4i_crtc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <video/videomode.h>
2727

28+
#include "sun4i_backend.h"
2829
#include "sun4i_crtc.h"
2930
#include "sun4i_drv.h"
3031
#include "sunxi_engine.h"

drivers/gpu/drm/sun4i/sun4i_layer.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <drm/drmP.h>
1616

1717
#include "sun4i_backend.h"
18+
#include "sun4i_frontend.h"
1819
#include "sun4i_layer.h"
1920
#include "sunxi_engine.h"
2021

@@ -48,13 +49,15 @@ static void sun4i_backend_layer_reset(struct drm_plane *plane)
4849
static struct drm_plane_state *
4950
sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
5051
{
52+
struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
5153
struct sun4i_layer_state *copy;
5254

5355
copy = kzalloc(sizeof(*copy), GFP_KERNEL);
5456
if (!copy)
5557
return NULL;
5658

5759
__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
60+
copy->uses_frontend = orig->uses_frontend;
5861

5962
return &copy->state;
6063
}
@@ -72,21 +75,45 @@ static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
7275
static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
7376
struct drm_plane_state *old_state)
7477
{
78+
struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
7579
struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
7680
struct sun4i_backend *backend = layer->backend;
7781

7882
sun4i_backend_layer_enable(backend, layer->id, false);
83+
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+
}
7991
}
8092

8193
static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
8294
struct drm_plane_state *old_state)
8395
{
96+
struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
8497
struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
8598
struct sun4i_backend *backend = layer->backend;
99+
struct sun4i_frontend *frontend = backend->frontend;
100+
101+
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+
}
86116

87-
sun4i_backend_update_layer_coord(backend, layer->id, plane);
88-
sun4i_backend_update_layer_formats(backend, layer->id, plane);
89-
sun4i_backend_update_layer_buffer(backend, layer->id, plane);
90117
sun4i_backend_layer_enable(backend, layer->id, true);
91118
}
92119

drivers/gpu/drm/sun4i/sun4i_layer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct sun4i_layer {
2424

2525
struct sun4i_layer_state {
2626
struct drm_plane_state state;
27+
bool uses_frontend;
2728
};
2829

2930
static inline struct sun4i_layer *

0 commit comments

Comments
 (0)