aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/plane.c
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2018-05-04 10:39:59 -0400
committerThierry Reding <treding@nvidia.com>2018-05-17 08:08:44 -0400
commit3dae08bc076b93487ed2df50bcfa892113e89d9d (patch)
treeddbb3a4b0de1dca357b921ff037aedaea72a59bf /drivers/gpu/drm/tegra/plane.c
parentacc6a3a9afdd4e0537342012656cdb5c4a3127c5 (diff)
drm/tegra: plane: Implement zpos plane property for older Tegras
Older Tegra's do not support plane's Z position handling in hardware, but the hardware provides knobs to implement it in software. Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/plane.c')
-rw-r--r--drivers/gpu/drm/tegra/plane.c193
1 files changed, 139 insertions, 54 deletions
diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c
index 176ef46c615c..0406c2ef432c 100644
--- a/drivers/gpu/drm/tegra/plane.c
+++ b/drivers/gpu/drm/tegra/plane.c
@@ -23,6 +23,7 @@ static void tegra_plane_destroy(struct drm_plane *plane)
23 23
24static void tegra_plane_reset(struct drm_plane *plane) 24static void tegra_plane_reset(struct drm_plane *plane)
25{ 25{
26 struct tegra_plane *p = to_tegra_plane(plane);
26 struct tegra_plane_state *state; 27 struct tegra_plane_state *state;
27 28
28 if (plane->state) 29 if (plane->state)
@@ -35,6 +36,8 @@ static void tegra_plane_reset(struct drm_plane *plane)
35 if (state) { 36 if (state) {
36 plane->state = &state->base; 37 plane->state = &state->base;
37 plane->state->plane = plane; 38 plane->state->plane = plane;
39 plane->state->zpos = p->index;
40 plane->state->normalized_zpos = p->index;
38 } 41 }
39} 42}
40 43
@@ -55,8 +58,8 @@ tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
55 copy->swap = state->swap; 58 copy->swap = state->swap;
56 copy->opaque = state->opaque; 59 copy->opaque = state->opaque;
57 60
58 for (i = 0; i < 3; i++) 61 for (i = 0; i < 2; i++)
59 copy->dependent[i] = state->dependent[i]; 62 copy->blending[i] = state->blending[i];
60 63
61 return &copy->base; 64 return &copy->base;
62} 65}
@@ -267,24 +270,8 @@ static bool __drm_format_has_alpha(u32 format)
267 return false; 270 return false;
268} 271}
269 272
270/* 273static int tegra_plane_format_get_alpha(unsigned int opaque,
271 * This is applicable to Tegra20 and Tegra30 only where the opaque formats can 274 unsigned int *alpha)
272 * be emulated using the alpha formats and alpha blending disabled.
273 */
274bool tegra_plane_format_has_alpha(unsigned int format)
275{
276 switch (format) {
277 case WIN_COLOR_DEPTH_B5G5R5A1:
278 case WIN_COLOR_DEPTH_A1B5G5R5:
279 case WIN_COLOR_DEPTH_R8G8B8A8:
280 case WIN_COLOR_DEPTH_B8G8R8A8:
281 return true;
282 }
283
284 return false;
285}
286
287int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
288{ 275{
289 if (tegra_plane_format_is_yuv(opaque, NULL)) { 276 if (tegra_plane_format_is_yuv(opaque, NULL)) {
290 *alpha = opaque; 277 *alpha = opaque;
@@ -316,6 +303,67 @@ int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
316 return -EINVAL; 303 return -EINVAL;
317} 304}
318 305
306/*
307 * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
308 * be emulated using the alpha formats and alpha blending disabled.
309 */
310static int tegra_plane_setup_opacity(struct tegra_plane *tegra,
311 struct tegra_plane_state *state)
312{
313 unsigned int format;
314 int err;
315
316 switch (state->format) {
317 case WIN_COLOR_DEPTH_B5G5R5A1:
318 case WIN_COLOR_DEPTH_A1B5G5R5:
319 case WIN_COLOR_DEPTH_R8G8B8A8:
320 case WIN_COLOR_DEPTH_B8G8R8A8:
321 state->opaque = false;
322 break;
323
324 default:
325 err = tegra_plane_format_get_alpha(state->format, &format);
326 if (err < 0)
327 return err;
328
329 state->format = format;
330 state->opaque = true;
331 break;
332 }
333
334 return 0;
335}
336
337static int tegra_plane_check_transparency(struct tegra_plane *tegra,
338 struct tegra_plane_state *state)
339{
340 struct drm_plane_state *old, *plane_state;
341 struct drm_plane *plane;
342
343 old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base);
344
345 /* check if zpos / transparency changed */
346 if (old->normalized_zpos == state->base.normalized_zpos &&
347 to_tegra_plane_state(old)->opaque == state->opaque)
348 return 0;
349
350 /* include all sibling planes into this commit */
351 drm_for_each_plane(plane, tegra->base.dev) {
352 struct tegra_plane *p = to_tegra_plane(plane);
353
354 /* skip this plane and planes on different CRTCs */
355 if (p == tegra || p->dc != tegra->dc)
356 continue;
357
358 plane_state = drm_atomic_get_plane_state(state->base.state,
359 plane);
360 if (IS_ERR(plane_state))
361 return PTR_ERR(plane_state);
362 }
363
364 return 1;
365}
366
319static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, 367static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
320 struct tegra_plane *other) 368 struct tegra_plane *other)
321{ 369{
@@ -336,61 +384,98 @@ static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
336 return index; 384 return index;
337} 385}
338 386
339void tegra_plane_check_dependent(struct tegra_plane *tegra, 387static void tegra_plane_update_transparency(struct tegra_plane *tegra,
340 struct tegra_plane_state *state) 388 struct tegra_plane_state *state)
341{ 389{
342 struct drm_plane_state *old, *new; 390 struct drm_plane_state *new;
343 struct drm_plane *plane; 391 struct drm_plane *plane;
344 unsigned int zpos[2];
345 unsigned int i; 392 unsigned int i;
346 393
347 for (i = 0; i < 2; i++) 394 for_each_new_plane_in_state(state->base.state, plane, new, i) {
348 zpos[i] = 0;
349
350 for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {
351 struct tegra_plane *p = to_tegra_plane(plane); 395 struct tegra_plane *p = to_tegra_plane(plane);
352 unsigned index; 396 unsigned index;
353 397
354 /* skip this plane and planes on different CRTCs */ 398 /* skip this plane and planes on different CRTCs */
355 if (p == tegra || new->crtc != state->base.crtc) 399 if (p == tegra || p->dc != tegra->dc)
356 continue; 400 continue;
357 401
358 index = tegra_plane_get_overlap_index(tegra, p); 402 index = tegra_plane_get_overlap_index(tegra, p);
359 403
360 state->dependent[index] = false; 404 if (new->fb && __drm_format_has_alpha(new->fb->format->format))
405 state->blending[index].alpha = true;
406 else
407 state->blending[index].alpha = false;
408
409 if (new->normalized_zpos > state->base.normalized_zpos)
410 state->blending[index].top = true;
411 else
412 state->blending[index].top = false;
361 413
362 /* 414 /*
363 * If any of the other planes is on top of this plane and uses 415 * Missing framebuffer means that plane is disabled, in this
364 * a format with an alpha component, mark this plane as being 416 * case mark B / C window as top to be able to differentiate
365 * dependent, meaning it's alpha value will be 1 minus the sum 417 * windows indices order in regards to zPos for the middle
366 * of alpha components of the overlapping planes. 418 * window X / Y registers programming.
367 */ 419 */
368 if (p->index > tegra->index) { 420 if (!new->fb)
369 if (__drm_format_has_alpha(new->fb->format->format)) 421 state->blending[index].top = (index == 1);
370 state->dependent[index] = true;
371
372 /* keep track of the Z position */
373 zpos[index] = p->index;
374 }
375 } 422 }
423}
424
425static int tegra_plane_setup_transparency(struct tegra_plane *tegra,
426 struct tegra_plane_state *state)
427{
428 struct tegra_plane_state *tegra_state;
429 struct drm_plane_state *new;
430 struct drm_plane *plane;
431 int err;
376 432
377 /* 433 /*
378 * The region where three windows overlap is the intersection of the 434 * If planes zpos / transparency changed, sibling planes blending
379 * two regions where two windows overlap. It contributes to the area 435 * state may require adjustment and in this case they will be included
380 * if any of the windows on top of it have an alpha component. 436 * into this atom commit, otherwise blending state is unchanged.
381 */ 437 */
382 for (i = 0; i < 2; i++) 438 err = tegra_plane_check_transparency(tegra, state);
383 state->dependent[2] = state->dependent[2] || 439 if (err <= 0)
384 state->dependent[i]; 440 return err;
385 441
386 /* 442 /*
387 * However, if any of the windows on top of this window is opaque, it 443 * All planes are now in the atomic state, walk them up and update
388 * will completely conceal this window within that area, so avoid the 444 * transparency state for each plane.
389 * window from contributing to the area.
390 */ 445 */
391 for (i = 0; i < 2; i++) { 446 drm_for_each_plane(plane, tegra->base.dev) {
392 if (zpos[i] > tegra->index) 447 struct tegra_plane *p = to_tegra_plane(plane);
393 state->dependent[2] = state->dependent[2] && 448
394 state->dependent[i]; 449 /* skip planes on different CRTCs */
450 if (p->dc != tegra->dc)
451 continue;
452
453 new = drm_atomic_get_new_plane_state(state->base.state, plane);
454 tegra_state = to_tegra_plane_state(new);
455
456 /*
457 * There is no need to update blending state for the disabled
458 * plane.
459 */
460 if (new->fb)
461 tegra_plane_update_transparency(p, tegra_state);
395 } 462 }
463
464 return 0;
465}
466
467int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
468 struct tegra_plane_state *state)
469{
470 int err;
471
472 err = tegra_plane_setup_opacity(tegra, state);
473 if (err < 0)
474 return err;
475
476 err = tegra_plane_setup_transparency(tegra, state);
477 if (err < 0)
478 return err;
479
480 return 0;
396} 481}