aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/sun4i/sun4i_layer.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2018-02-15 18:29:27 -0500
committerDave Airlie <airlied@redhat.com>2018-02-15 18:29:27 -0500
commit76ea0f334e7fb13226e64ee7de928611f5303faf (patch)
tree4a6b8d8f1b19a68072f2ce8f33add59be9a67be7 /drivers/gpu/drm/sun4i/sun4i_layer.c
parentf0308d76906a5b65ec4fcc3b133394caa9f00638 (diff)
parent1bc3d3cce8c3b44c2b5ac6cee98c830bb40e6b0f (diff)
Merge tag 'drm-misc-next-2018-02-13' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 4.17: UAPI Changes: - drm/vc4: Expose performance counters to userspace (Boris) Cross-subsystem Changes: - MAINTAINERS: Linus to maintain panel-arm-versatile in -misc (Linus) Core Changes: - Only use swiotlb when necessary (Chunming) Driver Changes: - drm/panel: Add support for ARM Versatile panels (Linus) - pl111: Improvements around versatile panel support (Linus) ---------------------------------------- Tagged on 2018-02-06: drm-misc-next for 4.17: UAPI Changes: - Validate mode flags + type (Ville) - Deprecate unused mode flags PIXMUX, BCAST (Ville) - Deprecate unused mode types BUILTIN, CRTC_C, CLOCK_C, DEFAULT (Ville) Cross-subsystem Changes: - MAINTAINERS: s/Daniel/Maarten/ for drm-misc (Daniel) Core Changes: - gem: Export gem functions for drivers to use (Samuel) - bridge: Introduce bridge timings in drm_bridge (Linus) - dma-buf: Allow exclusive fence to be bundled in fence array when calling reservation_object_get_fences_rcu (Christian) - dp: Add training pattern 4 and HBR3 support to dp helpers (Manasi) - fourcc: Add alpha bit to formats to avoid driver format LUTs (Maxime) - mode: Various cleanups + add new device-wide .mode_valid hook (Ville) - atomic: Fix state leak when non-blocking commits fail (Leo) NOTE: IIRC, this was cross-picked to -fixes so it might fall out - crc: Allow polling on the data fd (Maarten) Driver Changes: - bridge/vga-dac: Add THS8134* support (Linus) - tinydrm: Various MIPI DBI improvements/cleanups (Noralf) - bridge/dw-mipi-dsi: Cleanups + use create_packet helper (Brian) - drm/sun4i: Add Display Engine frontend support (Maxime) - drm/sun4i: Add zpos support + increase num planes from 2 to 4 (Maxime) - various: Use drm_mode_get_hv_timing() to fill plane clip rectangle (Ville) - stm: Add 8-bit clut support, add dsi phy v1.31 support, +fixes (Phillipe) Cc: Boris Brezillon <boris.brezillon@free-electrons.com> Cc: Chunming Zhou <david1.zhou@amd.com> Cc: Samuel Li <Samuel.Li@amd.com> Cc: Linus Walleij <linus.walleij@linaro.org> Cc: Noralf Trønnes <noralf@tronnes.org> Cc: Brian Norris <briannorris@chromium.org> Cc: Maxime Ripard <maxime.ripard@free-electrons.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Cc: Christian König <christian.koenig@amd.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Cc: Philippe Cornu <philippe.cornu@st.com> Cc: Leo (Sunpeng) Li <sunpeng.li@amd.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> * tag 'drm-misc-next-2018-02-13' of git://anongit.freedesktop.org/drm/drm-misc: (115 commits) drm/radeon: only enable swiotlb path when need v2 drm/amdgpu: only enable swiotlb alloc when need v2 drm: add func to get max iomem address v2 drm/vc4: Expose performance counters to userspace drm: Print the pid when debug logging an ioctl error. drm/stm: ltdc: remove non-alpha color formats on layer 2 for older hw drm/stm: ltdc: add non-alpha color formats drm/bridge/synopsys: dsi: Add 1.31 version support drm/bridge/synopsys: dsi: Add read feature drm/pl111: Support multiple endpoints on the CLCD drm/pl111: Support variants with broken VBLANK drm/pl111: Support variants with broken clock divider drm/pl111: Handle the Versatile RGB/BGR565 mode drm/pl111: Properly detect the ARM PL110 variants drm/panel: Add support for ARM Versatile panels drm/panel: Device tree bindings for ARM Versatile panels drm/bridge: Rename argument from crtc to bridge drm/crc: Add support for polling on the data fd. drm/sun4i: Use drm_mode_get_hv_timing() to populate plane clip rectangle drm/rcar-du: Use drm_mode_get_hv_timing() to populate plane clip rectangle ...
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_layer.c')
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.c117
1 files changed, 86 insertions, 31 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index 7bddf12548d3..19be798e4fac 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -15,34 +15,107 @@
15#include <drm/drmP.h> 15#include <drm/drmP.h>
16 16
17#include "sun4i_backend.h" 17#include "sun4i_backend.h"
18#include "sun4i_frontend.h"
18#include "sun4i_layer.h" 19#include "sun4i_layer.h"
19#include "sunxi_engine.h" 20#include "sunxi_engine.h"
20 21
21struct sun4i_plane_desc { 22struct sun4i_plane_desc {
22 enum drm_plane_type type; 23 enum drm_plane_type type;
23 u8 pipe; 24 u8 pipe;
24 const uint32_t *formats; 25 const uint32_t *formats;
25 uint32_t nformats; 26 uint32_t nformats;
26}; 27};
27 28
29static void sun4i_backend_layer_reset(struct drm_plane *plane)
30{
31 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
32 struct sun4i_layer_state *state;
33
34 if (plane->state) {
35 state = state_to_sun4i_layer_state(plane->state);
36
37 __drm_atomic_helper_plane_destroy_state(&state->state);
38
39 kfree(state);
40 plane->state = NULL;
41 }
42
43 state = kzalloc(sizeof(*state), GFP_KERNEL);
44 if (state) {
45 plane->state = &state->state;
46 plane->state->plane = plane;
47 plane->state->zpos = layer->id;
48 }
49}
50
51static struct drm_plane_state *
52sun4i_backend_layer_duplicate_state(struct drm_plane *plane)
53{
54 struct sun4i_layer_state *orig = state_to_sun4i_layer_state(plane->state);
55 struct sun4i_layer_state *copy;
56
57 copy = kzalloc(sizeof(*copy), GFP_KERNEL);
58 if (!copy)
59 return NULL;
60
61 __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
62 copy->uses_frontend = orig->uses_frontend;
63
64 return &copy->state;
65}
66
67static void sun4i_backend_layer_destroy_state(struct drm_plane *plane,
68 struct drm_plane_state *state)
69{
70 struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(state);
71
72 __drm_atomic_helper_plane_destroy_state(state);
73
74 kfree(s_state);
75}
76
28static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane, 77static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
29 struct drm_plane_state *old_state) 78 struct drm_plane_state *old_state)
30{ 79{
80 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(old_state);
31 struct sun4i_layer *layer = plane_to_sun4i_layer(plane); 81 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
32 struct sun4i_backend *backend = layer->backend; 82 struct sun4i_backend *backend = layer->backend;
33 83
34 sun4i_backend_layer_enable(backend, layer->id, false); 84 sun4i_backend_layer_enable(backend, layer->id, false);
85
86 if (layer_state->uses_frontend) {
87 unsigned long flags;
88
89 spin_lock_irqsave(&backend->frontend_lock, flags);
90 backend->frontend_teardown = true;
91 spin_unlock_irqrestore(&backend->frontend_lock, flags);
92 }
35} 93}
36 94
37static void sun4i_backend_layer_atomic_update(struct drm_plane *plane, 95static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
38 struct drm_plane_state *old_state) 96 struct drm_plane_state *old_state)
39{ 97{
98 struct sun4i_layer_state *layer_state = state_to_sun4i_layer_state(plane->state);
40 struct sun4i_layer *layer = plane_to_sun4i_layer(plane); 99 struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
41 struct sun4i_backend *backend = layer->backend; 100 struct sun4i_backend *backend = layer->backend;
101 struct sun4i_frontend *frontend = backend->frontend;
102
103 if (layer_state->uses_frontend) {
104 sun4i_frontend_init(frontend);
105 sun4i_frontend_update_coord(frontend, plane);
106 sun4i_frontend_update_buffer(frontend, plane);
107 sun4i_frontend_update_formats(frontend, plane,
108 DRM_FORMAT_ARGB8888);
109 sun4i_backend_update_layer_frontend(backend, layer->id,
110 DRM_FORMAT_ARGB8888);
111 sun4i_frontend_enable(frontend);
112 } else {
113 sun4i_backend_update_layer_formats(backend, layer->id, plane);
114 sun4i_backend_update_layer_buffer(backend, layer->id, plane);
115 }
42 116
43 sun4i_backend_update_layer_coord(backend, layer->id, plane); 117 sun4i_backend_update_layer_coord(backend, layer->id, plane);
44 sun4i_backend_update_layer_formats(backend, layer->id, plane); 118 sun4i_backend_update_layer_zpos(backend, layer->id, plane);
45 sun4i_backend_update_layer_buffer(backend, layer->id, plane);
46 sun4i_backend_layer_enable(backend, layer->id, true); 119 sun4i_backend_layer_enable(backend, layer->id, true);
47} 120}
48 121
@@ -52,11 +125,11 @@ static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
52}; 125};
53 126
54static const struct drm_plane_funcs sun4i_backend_layer_funcs = { 127static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
55 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 128 .atomic_destroy_state = sun4i_backend_layer_destroy_state,
56 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 129 .atomic_duplicate_state = sun4i_backend_layer_duplicate_state,
57 .destroy = drm_plane_cleanup, 130 .destroy = drm_plane_cleanup,
58 .disable_plane = drm_atomic_helper_disable_plane, 131 .disable_plane = drm_atomic_helper_disable_plane,
59 .reset = drm_atomic_helper_plane_reset, 132 .reset = sun4i_backend_layer_reset,
60 .update_plane = drm_atomic_helper_update_plane, 133 .update_plane = drm_atomic_helper_update_plane,
61}; 134};
62 135
@@ -128,32 +201,12 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
128 struct sun4i_backend *backend = engine_to_sun4i_backend(engine); 201 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
129 int i; 202 int i;
130 203
131 planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1, 204 /* We need to have a sentinel at the need, hence the overallocation */
205 planes = devm_kcalloc(drm->dev, SUN4I_BACKEND_NUM_LAYERS + 1,
132 sizeof(*planes), GFP_KERNEL); 206 sizeof(*planes), GFP_KERNEL);
133 if (!planes) 207 if (!planes)
134 return ERR_PTR(-ENOMEM); 208 return ERR_PTR(-ENOMEM);
135 209
136 /*
137 * The hardware is a bit unusual here.
138 *
139 * Even though it supports 4 layers, it does the composition
140 * in two separate steps.
141 *
142 * The first one is assigning a layer to one of its two
143 * pipes. If more that 1 layer is assigned to the same pipe,
144 * and if pixels overlaps, the pipe will take the pixel from
145 * the layer with the highest priority.
146 *
147 * The second step is the actual alpha blending, that takes
148 * the two pipes as input, and uses the eventual alpha
149 * component to do the transparency between the two.
150 *
151 * This two steps scenario makes us unable to guarantee a
152 * robust alpha blending between the 4 layers in all
153 * situations. So we just expose two layers, one per pipe. On
154 * SoCs that support it, sprites could fill the need for more
155 * layers.
156 */
157 for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) { 210 for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
158 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i]; 211 const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
159 struct sun4i_layer *layer; 212 struct sun4i_layer *layer;
@@ -165,6 +218,8 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
165 return ERR_CAST(layer); 218 return ERR_CAST(layer);
166 }; 219 };
167 220
221 drm_plane_create_zpos_immutable_property(&layer->plane, i);
222
168 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", 223 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
169 i ? "overlay" : "primary", plane->pipe); 224 i ? "overlay" : "primary", plane->pipe);
170 regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i), 225 regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),