aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2017-12-20 03:39:14 -0500
committerThierry Reding <treding@nvidia.com>2017-12-21 08:55:55 -0500
commitebae8d07435ae91314f4a28d69b530d09c625815 (patch)
treefbe41c4c436502a2f073a3c352d3b14a3886cf15
parent4c69ac12e39d3d623686d1c421b05d604e1c6db9 (diff)
drm/tegra: dc: Implement legacy blending
This implements alpha blending on legacy display controllers (Tegra20, Tegra30 and Tegra114). While it's theoretically possible to support the zpos property to enable userspace to specify the Z-order of each plane individually, this is not currently supported and the same fixed Z- order as previously defined is used. Reverts commit 71835caa00e8 ("drm/tegra: fb: Force alpha formats") since the opaque formats are now supported. Reported-by: Dmitry Osipenko <digetx@gmail.com> Fixes: 7772fdaef939 ("drm/tegra: Support ARGB and ABGR formats") Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/dc.c81
-rw-r--r--drivers/gpu/drm/tegra/dc.h12
-rw-r--r--drivers/gpu/drm/tegra/fb.c12
-rw-r--r--drivers/gpu/drm/tegra/plane.c138
-rw-r--r--drivers/gpu/drm/tegra/plane.h8
5 files changed, 226 insertions, 25 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 2a0c1e93f82e..4507063029e0 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -154,30 +154,53 @@ static inline u32 compute_initial_dda(unsigned int in)
154 154
155static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane) 155static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
156{ 156{
157 u32 background[3] = {
158 BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
159 BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
160 BLEND_WEIGHT1(0) | BLEND_WEIGHT0(0) | BLEND_COLOR_KEY_NONE,
161 };
162 u32 foreground = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255) |
163 BLEND_COLOR_KEY_NONE;
164 u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
165 struct tegra_plane_state *state;
166 unsigned int i;
167
168 state = to_tegra_plane_state(plane->base.state);
169
170 /* alpha contribution is 1 minus sum of overlapping windows */
171 for (i = 0; i < 3; i++) {
172 if (state->dependent[i])
173 background[i] |= BLEND_CONTROL_DEPENDENT;
174 }
175
176 /* enable alpha blending if pixel format has an alpha component */
177 if (!state->opaque)
178 foreground |= BLEND_CONTROL_ALPHA;
179
157 /* 180 /*
158 * Disable blending and assume Window A is the bottom-most window, 181 * Disable blending and assume Window A is the bottom-most window,
159 * Window C is the top-most window and Window B is in the middle. 182 * Window C is the top-most window and Window B is in the middle.
160 */ 183 */
161 tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY); 184 tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);
162 tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN); 185 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);
163 186
164 switch (plane->index) { 187 switch (plane->index) {
165 case 0: 188 case 0:
166 tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X); 189 tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X);
167 tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y); 190 tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
168 tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY); 191 tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
169 break; 192 break;
170 193
171 case 1: 194 case 1:
172 tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X); 195 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
173 tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y); 196 tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
174 tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY); 197 tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
175 break; 198 break;
176 199
177 case 2: 200 case 2:
178 tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X); 201 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
179 tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y); 202 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_Y);
180 tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY); 203 tegra_plane_writel(plane, foreground, DC_WIN_BLEND_3WIN_XY);
181 break; 204 break;
182 } 205 }
183} 206}
@@ -353,6 +376,11 @@ static const u32 tegra20_primary_formats[] = {
353 DRM_FORMAT_RGBA5551, 376 DRM_FORMAT_RGBA5551,
354 DRM_FORMAT_ABGR8888, 377 DRM_FORMAT_ABGR8888,
355 DRM_FORMAT_ARGB8888, 378 DRM_FORMAT_ARGB8888,
379 /* non-native formats */
380 DRM_FORMAT_XRGB1555,
381 DRM_FORMAT_RGBX5551,
382 DRM_FORMAT_XBGR8888,
383 DRM_FORMAT_XRGB8888,
356}; 384};
357 385
358static const u32 tegra114_primary_formats[] = { 386static const u32 tegra114_primary_formats[] = {
@@ -409,18 +437,40 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
409 struct tegra_bo_tiling *tiling = &plane_state->tiling; 437 struct tegra_bo_tiling *tiling = &plane_state->tiling;
410 struct tegra_plane *tegra = to_tegra_plane(plane); 438 struct tegra_plane *tegra = to_tegra_plane(plane);
411 struct tegra_dc *dc = to_tegra_dc(state->crtc); 439 struct tegra_dc *dc = to_tegra_dc(state->crtc);
440 unsigned int format;
412 int err; 441 int err;
413 442
414 /* no need for further checks if the plane is being disabled */ 443 /* no need for further checks if the plane is being disabled */
415 if (!state->crtc) 444 if (!state->crtc)
416 return 0; 445 return 0;
417 446
418 err = tegra_plane_format(state->fb->format->format, 447 err = tegra_plane_format(state->fb->format->format, &format,
419 &plane_state->format,
420 &plane_state->swap); 448 &plane_state->swap);
421 if (err < 0) 449 if (err < 0)
422 return err; 450 return err;
423 451
452 /*
453 * Tegra20 and Tegra30 are special cases here because they support
454 * only variants of specific formats with an alpha component, but not
455 * the corresponding opaque formats. However, the opaque formats can
456 * be emulated by disabling alpha blending for the plane.
457 */
458 if (!dc->soc->supports_blending) {
459 if (!tegra_plane_format_has_alpha(format)) {
460 err = tegra_plane_format_get_alpha(format, &format);
461 if (err < 0)
462 return err;
463
464 plane_state->opaque = true;
465 } else {
466 plane_state->opaque = false;
467 }
468
469 tegra_plane_check_dependent(tegra, plane_state);
470 }
471
472 plane_state->format = format;
473
424 err = tegra_fb_get_tiling(state->fb, tiling); 474 err = tegra_fb_get_tiling(state->fb, tiling);
425 if (err < 0) 475 if (err < 0)
426 return err; 476 return err;
@@ -737,6 +787,11 @@ static const u32 tegra20_overlay_formats[] = {
737 DRM_FORMAT_RGBA5551, 787 DRM_FORMAT_RGBA5551,
738 DRM_FORMAT_ABGR8888, 788 DRM_FORMAT_ABGR8888,
739 DRM_FORMAT_ARGB8888, 789 DRM_FORMAT_ARGB8888,
790 /* non-native formats */
791 DRM_FORMAT_XRGB1555,
792 DRM_FORMAT_RGBX5551,
793 DRM_FORMAT_XBGR8888,
794 DRM_FORMAT_XRGB8888,
740 /* planar formats */ 795 /* planar formats */
741 DRM_FORMAT_UYVY, 796 DRM_FORMAT_UYVY,
742 DRM_FORMAT_YUYV, 797 DRM_FORMAT_YUYV,
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index e2831e96ea96..096a81ad6d8d 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -649,8 +649,20 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
649#define DC_WIN_DV_CONTROL 0x70e 649#define DC_WIN_DV_CONTROL 0x70e
650 650
651#define DC_WIN_BLEND_NOKEY 0x70f 651#define DC_WIN_BLEND_NOKEY 0x70f
652#define BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
653#define BLEND_WEIGHT0(x) (((x) & 0xff) << 8)
654
652#define DC_WIN_BLEND_1WIN 0x710 655#define DC_WIN_BLEND_1WIN 0x710
656#define BLEND_CONTROL_FIX (0 << 2)
657#define BLEND_CONTROL_ALPHA (1 << 2)
658#define BLEND_COLOR_KEY_NONE (0 << 0)
659#define BLEND_COLOR_KEY_0 (1 << 0)
660#define BLEND_COLOR_KEY_1 (2 << 0)
661#define BLEND_COLOR_KEY_BOTH (3 << 0)
662
653#define DC_WIN_BLEND_2WIN_X 0x711 663#define DC_WIN_BLEND_2WIN_X 0x711
664#define BLEND_CONTROL_DEPENDENT (2 << 2)
665
654#define DC_WIN_BLEND_2WIN_Y 0x712 666#define DC_WIN_BLEND_2WIN_Y 0x712
655#define DC_WIN_BLEND_3WIN_XY 0x713 667#define DC_WIN_BLEND_3WIN_XY 0x713
656 668
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 1af4ef9241f1..e05fde7172f8 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -254,18 +254,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
254 cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel, 254 cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
255 tegra->pitch_align); 255 tegra->pitch_align);
256 256
257 /*
258 * Early generations of Tegra (Tegra20 and Tegra30) do not support any
259 * of the X* or *X formats, only their A* or *A equivalents. Force the
260 * legacy framebuffer format to include an alpha component so that the
261 * framebuffer emulation can be supported on all generations.
262 */
263 if (sizes->surface_bpp == 32 && sizes->surface_depth == 24)
264 sizes->surface_depth = 32;
265
266 if (sizes->surface_bpp == 16 && sizes->surface_depth == 15)
267 sizes->surface_depth = 16;
268
269 cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, 257 cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
270 sizes->surface_depth); 258 sizes->surface_depth);
271 259
diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c
index 9146aead973b..154b4d337d0a 100644
--- a/drivers/gpu/drm/tegra/plane.c
+++ b/drivers/gpu/drm/tegra/plane.c
@@ -43,6 +43,7 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
43{ 43{
44 struct tegra_plane_state *state = to_tegra_plane_state(plane->state); 44 struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
45 struct tegra_plane_state *copy; 45 struct tegra_plane_state *copy;
46 unsigned int i;
46 47
47 copy = kmalloc(sizeof(*copy), GFP_KERNEL); 48 copy = kmalloc(sizeof(*copy), GFP_KERNEL);
48 if (!copy) 49 if (!copy)
@@ -52,6 +53,10 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
52 copy->tiling = state->tiling; 53 copy->tiling = state->tiling;
53 copy->format = state->format; 54 copy->format = state->format;
54 copy->swap = state->swap; 55 copy->swap = state->swap;
56 copy->opaque = state->opaque;
57
58 for (i = 0; i < 3; i++)
59 copy->dependent[i] = state->dependent[i];
55 60
56 return &copy->base; 61 return &copy->base;
57} 62}
@@ -238,3 +243,136 @@ bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
238 243
239 return false; 244 return false;
240} 245}
246
247static bool __drm_format_has_alpha(u32 format)
248{
249 switch (format) {
250 case DRM_FORMAT_ARGB1555:
251 case DRM_FORMAT_RGBA5551:
252 case DRM_FORMAT_ABGR8888:
253 case DRM_FORMAT_ARGB8888:
254 return true;
255 }
256
257 return false;
258}
259
260/*
261 * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
262 * be emulated using the alpha formats and alpha blending disabled.
263 */
264bool tegra_plane_format_has_alpha(unsigned int format)
265{
266 switch (format) {
267 case WIN_COLOR_DEPTH_B5G5R5A1:
268 case WIN_COLOR_DEPTH_A1B5G5R5:
269 case WIN_COLOR_DEPTH_R8G8B8A8:
270 case WIN_COLOR_DEPTH_B8G8R8A8:
271 return true;
272 }
273
274 return false;
275}
276
277int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
278{
279 switch (opaque) {
280 case WIN_COLOR_DEPTH_B5G5R5X1:
281 *alpha = WIN_COLOR_DEPTH_B5G5R5A1;
282 return 0;
283
284 case WIN_COLOR_DEPTH_X1B5G5R5:
285 *alpha = WIN_COLOR_DEPTH_A1B5G5R5;
286 return 0;
287
288 case WIN_COLOR_DEPTH_R8G8B8X8:
289 *alpha = WIN_COLOR_DEPTH_R8G8B8A8;
290 return 0;
291
292 case WIN_COLOR_DEPTH_B8G8R8X8:
293 *alpha = WIN_COLOR_DEPTH_B8G8R8A8;
294 return 0;
295 }
296
297 return -EINVAL;
298}
299
300unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
301 struct tegra_plane *other)
302{
303 unsigned int index = 0, i;
304
305 WARN_ON(plane == other);
306
307 for (i = 0; i < 3; i++) {
308 if (i == plane->index)
309 continue;
310
311 if (i == other->index)
312 break;
313
314 index++;
315 }
316
317 return index;
318}
319
320void tegra_plane_check_dependent(struct tegra_plane *tegra,
321 struct tegra_plane_state *state)
322{
323 struct drm_plane_state *old, *new;
324 struct drm_plane *plane;
325 unsigned int zpos[2];
326 unsigned int i;
327
328 for (i = 0; i < 3; i++)
329 state->dependent[i] = false;
330
331 for (i = 0; i < 2; i++)
332 zpos[i] = 0;
333
334 for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {
335 struct tegra_plane *p = to_tegra_plane(plane);
336 unsigned index;
337
338 /* skip this plane and planes on different CRTCs */
339 if (p == tegra || new->crtc != state->base.crtc)
340 continue;
341
342 index = tegra_plane_get_overlap_index(tegra, p);
343
344 /*
345 * If any of the other planes is on top of this plane and uses
346 * a format with an alpha component, mark this plane as being
347 * dependent, meaning it's alpha value will be 1 minus the sum
348 * of alpha components of the overlapping planes.
349 */
350 if (p->index > tegra->index) {
351 if (__drm_format_has_alpha(new->fb->format->format))
352 state->dependent[index] = true;
353
354 /* keep track of the Z position */
355 zpos[index] = p->index;
356 }
357 }
358
359 /*
360 * The region where three windows overlap is the intersection of the
361 * two regions where two windows overlap. It contributes to the area
362 * if any of the windows on top of it have an alpha component.
363 */
364 for (i = 0; i < 2; i++)
365 state->dependent[2] = state->dependent[2] ||
366 state->dependent[i];
367
368 /*
369 * However, if any of the windows on top of this window is opaque, it
370 * will completely conceal this window within that area, so avoid the
371 * window from contributing to the area.
372 */
373 for (i = 0; i < 2; i++) {
374 if (zpos[i] > tegra->index)
375 state->dependent[2] = state->dependent[2] &&
376 state->dependent[i];
377 }
378}
diff --git a/drivers/gpu/drm/tegra/plane.h b/drivers/gpu/drm/tegra/plane.h
index dca66cb95d25..6938719e7e5d 100644
--- a/drivers/gpu/drm/tegra/plane.h
+++ b/drivers/gpu/drm/tegra/plane.h
@@ -40,6 +40,10 @@ struct tegra_plane_state {
40 struct tegra_bo_tiling tiling; 40 struct tegra_bo_tiling tiling;
41 u32 format; 41 u32 format;
42 u32 swap; 42 u32 swap;
43
44 /* used for legacy blending support only */
45 bool opaque;
46 bool dependent[3];
43}; 47};
44 48
45static inline struct tegra_plane_state * 49static inline struct tegra_plane_state *
@@ -58,5 +62,9 @@ int tegra_plane_state_add(struct tegra_plane *plane,
58 62
59int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap); 63int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap);
60bool tegra_plane_format_is_yuv(unsigned int format, bool *planar); 64bool tegra_plane_format_is_yuv(unsigned int format, bool *planar);
65bool tegra_plane_format_has_alpha(unsigned int format);
66int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha);
67void tegra_plane_check_dependent(struct tegra_plane *tegra,
68 struct tegra_plane_state *state);
61 69
62#endif /* TEGRA_PLANE_H */ 70#endif /* TEGRA_PLANE_H */