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>
This commit is contained in:

committed by
Thierry Reding

parent
acc6a3a9af
commit
3dae08bc07
@@ -163,28 +163,89 @@ static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
|
||||
BLEND_COLOR_KEY_NONE;
|
||||
u32 blendnokey = BLEND_WEIGHT1(255) | BLEND_WEIGHT0(255);
|
||||
struct tegra_plane_state *state;
|
||||
u32 blending[2];
|
||||
unsigned int i;
|
||||
|
||||
state = to_tegra_plane_state(plane->base.state);
|
||||
|
||||
/* alpha contribution is 1 minus sum of overlapping windows */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (state->dependent[i])
|
||||
background[i] |= BLEND_CONTROL_DEPENDENT;
|
||||
}
|
||||
|
||||
/* enable alpha blending if pixel format has an alpha component */
|
||||
if (!state->opaque)
|
||||
foreground |= BLEND_CONTROL_ALPHA;
|
||||
|
||||
/*
|
||||
* Disable blending and assume Window A is the bottom-most window,
|
||||
* Window C is the top-most window and Window B is in the middle.
|
||||
*/
|
||||
/* disable blending for non-overlapping case */
|
||||
tegra_plane_writel(plane, blendnokey, DC_WIN_BLEND_NOKEY);
|
||||
tegra_plane_writel(plane, foreground, DC_WIN_BLEND_1WIN);
|
||||
|
||||
switch (plane->index) {
|
||||
state = to_tegra_plane_state(plane->base.state);
|
||||
|
||||
if (state->opaque) {
|
||||
/*
|
||||
* Since custom fix-weight blending isn't utilized and weight
|
||||
* of top window is set to max, we can enforce dependent
|
||||
* blending which in this case results in transparent bottom
|
||||
* window if top window is opaque and if top window enables
|
||||
* alpha blending, then bottom window is getting alpha value
|
||||
* of 1 minus the sum of alpha components of the overlapping
|
||||
* plane.
|
||||
*/
|
||||
background[0] |= BLEND_CONTROL_DEPENDENT;
|
||||
background[1] |= BLEND_CONTROL_DEPENDENT;
|
||||
|
||||
/*
|
||||
* The region where three windows overlap is the intersection
|
||||
* of the two regions where two windows overlap. It contributes
|
||||
* to the area if all of the windows on top of it have an alpha
|
||||
* component.
|
||||
*/
|
||||
switch (state->base.normalized_zpos) {
|
||||
case 0:
|
||||
if (state->blending[0].alpha &&
|
||||
state->blending[1].alpha)
|
||||
background[2] |= BLEND_CONTROL_DEPENDENT;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
background[2] |= BLEND_CONTROL_DEPENDENT;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Enable alpha blending if pixel format has an alpha
|
||||
* component.
|
||||
*/
|
||||
foreground |= BLEND_CONTROL_ALPHA;
|
||||
|
||||
/*
|
||||
* If any of the windows on top of this window is opaque, it
|
||||
* will completely conceal this window within that area. If
|
||||
* top window has an alpha component, it is blended over the
|
||||
* bottom window.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (state->blending[i].alpha &&
|
||||
state->blending[i].top)
|
||||
background[i] |= BLEND_CONTROL_DEPENDENT;
|
||||
}
|
||||
|
||||
switch (state->base.normalized_zpos) {
|
||||
case 0:
|
||||
if (state->blending[0].alpha &&
|
||||
state->blending[1].alpha)
|
||||
background[2] |= BLEND_CONTROL_DEPENDENT;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/*
|
||||
* When both middle and topmost windows have an alpha,
|
||||
* these windows a mixed together and then the result
|
||||
* is blended over the bottom window.
|
||||
*/
|
||||
if (state->blending[0].alpha &&
|
||||
state->blending[0].top)
|
||||
background[2] |= BLEND_CONTROL_ALPHA;
|
||||
|
||||
if (state->blending[1].alpha &&
|
||||
state->blending[1].top)
|
||||
background[2] |= BLEND_CONTROL_ALPHA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state->base.normalized_zpos) {
|
||||
case 0:
|
||||
tegra_plane_writel(plane, background[0], DC_WIN_BLEND_2WIN_X);
|
||||
tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
|
||||
@@ -192,8 +253,21 @@ static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
|
||||
break;
|
||||
|
||||
case 1:
|
||||
tegra_plane_writel(plane, foreground, DC_WIN_BLEND_2WIN_X);
|
||||
tegra_plane_writel(plane, background[1], DC_WIN_BLEND_2WIN_Y);
|
||||
/*
|
||||
* If window B / C is topmost, then X / Y registers are
|
||||
* matching the order of blending[...] state indices,
|
||||
* otherwise a swap is required.
|
||||
*/
|
||||
if (!state->blending[0].top && state->blending[1].top) {
|
||||
blending[0] = foreground;
|
||||
blending[1] = background[1];
|
||||
} else {
|
||||
blending[0] = background[0];
|
||||
blending[1] = foreground;
|
||||
}
|
||||
|
||||
tegra_plane_writel(plane, blending[0], DC_WIN_BLEND_2WIN_X);
|
||||
tegra_plane_writel(plane, blending[1], DC_WIN_BLEND_2WIN_Y);
|
||||
tegra_plane_writel(plane, background[2], DC_WIN_BLEND_3WIN_XY);
|
||||
break;
|
||||
|
||||
@@ -525,14 +599,14 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
|
||||
struct tegra_bo_tiling *tiling = &plane_state->tiling;
|
||||
struct tegra_plane *tegra = to_tegra_plane(plane);
|
||||
struct tegra_dc *dc = to_tegra_dc(state->crtc);
|
||||
unsigned int format;
|
||||
int err;
|
||||
|
||||
/* no need for further checks if the plane is being disabled */
|
||||
if (!state->crtc)
|
||||
return 0;
|
||||
|
||||
err = tegra_plane_format(state->fb->format->format, &format,
|
||||
err = tegra_plane_format(state->fb->format->format,
|
||||
&plane_state->format,
|
||||
&plane_state->swap);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -544,21 +618,11 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
|
||||
* be emulated by disabling alpha blending for the plane.
|
||||
*/
|
||||
if (!dc->soc->supports_blending) {
|
||||
if (!tegra_plane_format_has_alpha(format)) {
|
||||
err = tegra_plane_format_get_alpha(format, &format);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
plane_state->opaque = true;
|
||||
} else {
|
||||
plane_state->opaque = false;
|
||||
}
|
||||
|
||||
tegra_plane_check_dependent(tegra, plane_state);
|
||||
err = tegra_plane_setup_legacy_state(tegra, plane_state);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
plane_state->format = format;
|
||||
|
||||
err = tegra_fb_get_tiling(state->fb, tiling);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -710,9 +774,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
|
||||
}
|
||||
|
||||
drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
|
||||
|
||||
if (dc->soc->supports_blending)
|
||||
drm_plane_create_zpos_property(&plane->base, 0, 0, 255);
|
||||
drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255);
|
||||
|
||||
return &plane->base;
|
||||
}
|
||||
@@ -989,9 +1051,7 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
|
||||
}
|
||||
|
||||
drm_plane_helper_add(&plane->base, &tegra_plane_helper_funcs);
|
||||
|
||||
if (dc->soc->supports_blending)
|
||||
drm_plane_create_zpos_property(&plane->base, 0, 0, 255);
|
||||
drm_plane_create_zpos_property(&plane->base, plane->index, 0, 255);
|
||||
|
||||
return &plane->base;
|
||||
}
|
||||
|
Reference in New Issue
Block a user