aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/sun4i/sun4i_backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_backend.c')
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.c248
1 files changed, 240 insertions, 8 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 847eecbe4d14..245b189fc4d8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -11,6 +11,7 @@
11 */ 11 */
12 12
13#include <drm/drmP.h> 13#include <drm/drmP.h>
14#include <drm/drm_atomic.h>
14#include <drm/drm_atomic_helper.h> 15#include <drm/drm_atomic_helper.h>
15#include <drm/drm_crtc.h> 16#include <drm/drm_crtc.h>
16#include <drm/drm_crtc_helper.h> 17#include <drm/drm_crtc_helper.h>
@@ -26,6 +27,7 @@
26 27
27#include "sun4i_backend.h" 28#include "sun4i_backend.h"
28#include "sun4i_drv.h" 29#include "sun4i_drv.h"
30#include "sun4i_frontend.h"
29#include "sun4i_layer.h" 31#include "sun4i_layer.h"
30#include "sunxi_engine.h" 32#include "sunxi_engine.h"
31 33
@@ -93,7 +95,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
93static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane, 95static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
94 u32 format, u32 *mode) 96 u32 format, u32 *mode)
95{ 97{
96 if ((plane->type == DRM_PLANE_TYPE_PRIMARY) && 98 if (plane && (plane->type == DRM_PLANE_TYPE_PRIMARY) &&
97 (format == DRM_FORMAT_ARGB8888)) 99 (format == DRM_FORMAT_ARGB8888))
98 format = DRM_FORMAT_XRGB8888; 100 format = DRM_FORMAT_XRGB8888;
99 101
@@ -141,7 +143,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
141 int layer, struct drm_plane *plane) 143 int layer, struct drm_plane *plane)
142{ 144{
143 struct drm_plane_state *state = plane->state; 145 struct drm_plane_state *state = plane->state;
144 struct drm_framebuffer *fb = state->fb;
145 146
146 DRM_DEBUG_DRIVER("Updating layer %d\n", layer); 147 DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
147 148
@@ -153,12 +154,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
153 state->crtc_h)); 154 state->crtc_h));
154 } 155 }
155 156
156 /* Set the line width */
157 DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
158 regmap_write(backend->engine.regs,
159 SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
160 fb->pitches[0] * 8);
161
162 /* Set height and width */ 157 /* Set height and width */
163 DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n", 158 DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
164 state->crtc_w, state->crtc_h); 159 state->crtc_w, state->crtc_h);
@@ -210,6 +205,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
210 return 0; 205 return 0;
211} 206}
212 207
208int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
209 int layer, uint32_t fmt)
210{
211 u32 val;
212 int ret;
213
214 ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
215 if (ret) {
216 DRM_DEBUG_DRIVER("Invalid format\n");
217 return ret;
218 }
219
220 regmap_update_bits(backend->engine.regs,
221 SUN4I_BACKEND_ATTCTL_REG0(layer),
222 SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
223 SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
224
225 regmap_update_bits(backend->engine.regs,
226 SUN4I_BACKEND_ATTCTL_REG1(layer),
227 SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
228
229 return 0;
230}
231
213int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, 232int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
214 int layer, struct drm_plane *plane) 233 int layer, struct drm_plane *plane)
215{ 234{
@@ -218,6 +237,12 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
218 u32 lo_paddr, hi_paddr; 237 u32 lo_paddr, hi_paddr;
219 dma_addr_t paddr; 238 dma_addr_t paddr;
220 239
240 /* Set the line width */
241 DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
242 regmap_write(backend->engine.regs,
243 SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
244 fb->pitches[0] * 8);
245
221 /* Get the start of the displayed memory */ 246 /* Get the start of the displayed memory */
222 paddr = drm_fb_cma_get_gem_addr(fb, state, 0); 247 paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
223 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); 248 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
@@ -246,6 +271,176 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
246 return 0; 271 return 0;
247} 272}
248 273
274int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer,
275 struct drm_plane *plane)
276{
277 struct drm_plane_state *state = plane->state;
278 unsigned int priority = state->normalized_zpos;
279
280 DRM_DEBUG_DRIVER("Setting layer %d's priority to %d\n", layer, priority);
281
282 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
283 SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK,
284 SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(priority));
285
286 return 0;
287}
288
289static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
290{
291 u16 src_h = state->src_h >> 16;
292 u16 src_w = state->src_w >> 16;
293
294 DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
295 src_w, src_h, state->crtc_w, state->crtc_h);
296
297 if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
298 return true;
299
300 return false;
301}
302
303static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
304{
305 struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
306 struct sun4i_backend *backend = layer->backend;
307
308 if (IS_ERR(backend->frontend))
309 return false;
310
311 return sun4i_backend_plane_uses_scaler(state);
312}
313
314static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
315 struct drm_crtc_state *old_state)
316{
317 u32 val;
318
319 WARN_ON(regmap_read_poll_timeout(engine->regs,
320 SUN4I_BACKEND_REGBUFFCTL_REG,
321 val, !(val & SUN4I_BACKEND_REGBUFFCTL_LOADCTL),
322 100, 50000));
323}
324
325static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
326 struct drm_crtc_state *crtc_state)
327{
328 struct drm_atomic_state *state = crtc_state->state;
329 struct drm_device *drm = state->dev;
330 struct drm_plane *plane;
331 unsigned int num_planes = 0;
332 unsigned int num_alpha_planes = 0;
333 unsigned int num_frontend_planes = 0;
334
335 DRM_DEBUG_DRIVER("Starting checking our planes\n");
336
337 if (!crtc_state->planes_changed)
338 return 0;
339
340 drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
341 struct drm_plane_state *plane_state =
342 drm_atomic_get_plane_state(state, plane);
343 struct sun4i_layer_state *layer_state =
344 state_to_sun4i_layer_state(plane_state);
345 struct drm_framebuffer *fb = plane_state->fb;
346 struct drm_format_name_buf format_name;
347
348 if (sun4i_backend_plane_uses_frontend(plane_state)) {
349 DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
350 plane->index);
351
352 layer_state->uses_frontend = true;
353 num_frontend_planes++;
354 } else {
355 layer_state->uses_frontend = false;
356 }
357
358 DRM_DEBUG_DRIVER("Plane FB format is %s\n",
359 drm_get_format_name(fb->format->format,
360 &format_name));
361 if (fb->format->has_alpha)
362 num_alpha_planes++;
363
364 num_planes++;
365 }
366
367 /*
368 * The hardware is a bit unusual here.
369 *
370 * Even though it supports 4 layers, it does the composition
371 * in two separate steps.
372 *
373 * The first one is assigning a layer to one of its two
374 * pipes. If more that 1 layer is assigned to the same pipe,
375 * and if pixels overlaps, the pipe will take the pixel from
376 * the layer with the highest priority.
377 *
378 * The second step is the actual alpha blending, that takes
379 * the two pipes as input, and uses the eventual alpha
380 * component to do the transparency between the two.
381 *
382 * This two steps scenario makes us unable to guarantee a
383 * robust alpha blending between the 4 layers in all
384 * situations, since this means that we need to have one layer
385 * with alpha at the lowest position of our two pipes.
386 *
387 * However, we cannot even do that, since the hardware has a
388 * bug where the lowest plane of the lowest pipe (pipe 0,
389 * priority 0), if it has any alpha, will discard the pixel
390 * entirely and just display the pixels in the background
391 * color (black by default).
392 *
393 * This means that we effectively have only three valid
394 * configurations with alpha, all of them with the alpha being
395 * on pipe1 with the lowest position, which can be 1, 2 or 3
396 * depending on the number of planes and their zpos.
397 */
398 if (num_alpha_planes > SUN4I_BACKEND_NUM_ALPHA_LAYERS) {
399 DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n");
400 return -EINVAL;
401 }
402
403 if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
404 DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
405 return -EINVAL;
406 }
407
408 DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n",
409 num_planes, num_alpha_planes, num_frontend_planes);
410
411 return 0;
412}
413
414static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
415{
416 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
417 struct sun4i_frontend *frontend = backend->frontend;
418
419 if (!frontend)
420 return;
421
422 /*
423 * In a teardown scenario with the frontend involved, we have
424 * to keep the frontend enabled until the next vblank, and
425 * only then disable it.
426 *
427 * This is due to the fact that the backend will not take into
428 * account the new configuration (with the plane that used to
429 * be fed by the frontend now disabled) until we write to the
430 * commit bit and the hardware fetches the new configuration
431 * during the next vblank.
432 *
433 * So we keep the frontend around in order to prevent any
434 * visual artifacts.
435 */
436 spin_lock(&backend->frontend_lock);
437 if (backend->frontend_teardown) {
438 sun4i_frontend_exit(frontend);
439 backend->frontend_teardown = false;
440 }
441 spin_unlock(&backend->frontend_lock);
442};
443
249static int sun4i_backend_init_sat(struct device *dev) { 444static int sun4i_backend_init_sat(struct device *dev) {
250 struct sun4i_backend *backend = dev_get_drvdata(dev); 445 struct sun4i_backend *backend = dev_get_drvdata(dev);
251 int ret; 446 int ret;
@@ -330,11 +525,43 @@ static int sun4i_backend_of_get_id(struct device_node *node)
330 return ret; 525 return ret;
331} 526}
332 527
528/* TODO: This needs to take multiple pipelines into account */
529static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
530 struct device_node *node)
531{
532 struct device_node *port, *ep, *remote;
533 struct sun4i_frontend *frontend;
534
535 port = of_graph_get_port_by_id(node, 0);
536 if (!port)
537 return ERR_PTR(-EINVAL);
538
539 for_each_available_child_of_node(port, ep) {
540 remote = of_graph_get_remote_port_parent(ep);
541 if (!remote)
542 continue;
543
544 /* does this node match any registered engines? */
545 list_for_each_entry(frontend, &drv->frontend_list, list) {
546 if (remote == frontend->node) {
547 of_node_put(remote);
548 of_node_put(port);
549 return frontend;
550 }
551 }
552 }
553
554 return ERR_PTR(-EINVAL);
555}
556
333static const struct sunxi_engine_ops sun4i_backend_engine_ops = { 557static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
558 .atomic_begin = sun4i_backend_atomic_begin,
559 .atomic_check = sun4i_backend_atomic_check,
334 .commit = sun4i_backend_commit, 560 .commit = sun4i_backend_commit,
335 .layers_init = sun4i_layers_init, 561 .layers_init = sun4i_layers_init,
336 .apply_color_correction = sun4i_backend_apply_color_correction, 562 .apply_color_correction = sun4i_backend_apply_color_correction,
337 .disable_color_correction = sun4i_backend_disable_color_correction, 563 .disable_color_correction = sun4i_backend_disable_color_correction,
564 .vblank_quirk = sun4i_backend_vblank_quirk,
338}; 565};
339 566
340static struct regmap_config sun4i_backend_regmap_config = { 567static struct regmap_config sun4i_backend_regmap_config = {
@@ -360,6 +587,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
360 if (!backend) 587 if (!backend)
361 return -ENOMEM; 588 return -ENOMEM;
362 dev_set_drvdata(dev, backend); 589 dev_set_drvdata(dev, backend);
590 spin_lock_init(&backend->frontend_lock);
363 591
364 backend->engine.node = dev->of_node; 592 backend->engine.node = dev->of_node;
365 backend->engine.ops = &sun4i_backend_engine_ops; 593 backend->engine.ops = &sun4i_backend_engine_ops;
@@ -367,6 +595,10 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
367 if (backend->engine.id < 0) 595 if (backend->engine.id < 0)
368 return backend->engine.id; 596 return backend->engine.id;
369 597
598 backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
599 if (IS_ERR(backend->frontend))
600 dev_warn(dev, "Couldn't find matching frontend, frontend features disabled\n");
601
370 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 602 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
371 regs = devm_ioremap_resource(dev, res); 603 regs = devm_ioremap_resource(dev, res);
372 if (IS_ERR(regs)) 604 if (IS_ERR(regs))