Blob Blame History Raw
From: Thierry Reding <treding@nvidia.com>
Date: Thu, 14 Dec 2017 13:46:20 +0100
Subject: drm/tegra: Implement zpos property
Git-commit: ab7d3f5826c55ad23101327eab435660caa83436
Patch-mainline: v4.16-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Implement the standard zpos property for planes on Tegra124 and later.
Earlier generations have a different blending unit that needs different
programming.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/tegra/dc.c    |   94 +++++++++++++++++++++++++++++-------------
 drivers/gpu/drm/tegra/dc.h    |    2 
 drivers/gpu/drm/tegra/drm.c   |   25 ++++++++++-
 drivers/gpu/drm/tegra/hub.c   |    5 +-
 drivers/gpu/drm/tegra/plane.h |    1 
 5 files changed, 95 insertions(+), 32 deletions(-)

--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -152,6 +152,55 @@ static inline u32 compute_initial_dda(un
 	return dfixed_frac(inf);
 }
 
+static void tegra_plane_setup_blending_legacy(struct tegra_plane *plane)
+{
+	/*
+	 * 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.
+	 */
+	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY);
+	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN);
+
+	switch (plane->index) {
+	case 0:
+		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
+		break;
+
+	case 1:
+		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
+		break;
+
+	case 2:
+		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
+		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y);
+		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY);
+		break;
+	}
+}
+
+static void tegra_plane_setup_blending(struct tegra_plane *plane,
+				       const struct tegra_dc_window *window)
+{
+	u32 value;
+
+	value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
+		BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
+		BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
+	tegra_plane_writel(plane, value, DC_WIN_BLEND_MATCH_SELECT);
+
+	value = BLEND_FACTOR_DST_ALPHA_ZERO | BLEND_FACTOR_SRC_ALPHA_K2 |
+		BLEND_FACTOR_DST_COLOR_NEG_K1_TIMES_SRC |
+		BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
+	tegra_plane_writel(plane, value, DC_WIN_BLEND_NOMATCH_SELECT);
+
+	value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - window->zpos);
+	tegra_plane_writel(plane, value, DC_WIN_BLEND_LAYER_CONTROL);
+}
+
 static void tegra_dc_setup_window(struct tegra_plane *plane,
 				  const struct tegra_dc_window *window)
 {
@@ -291,32 +340,10 @@ static void tegra_dc_setup_window(struct
 
 	tegra_plane_writel(plane, value, DC_WIN_WIN_OPTIONS);
 
-	/*
-	 * 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.
-	 */
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_NOKEY);
-	tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_1WIN);
-
-	switch (plane->index) {
-	case 0:
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
-		break;
-
-	case 1:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0x000000, DC_WIN_BLEND_3WIN_XY);
-		break;
-
-	case 2:
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_X);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_2WIN_Y);
-		tegra_plane_writel(plane, 0xffff00, DC_WIN_BLEND_3WIN_XY);
-		break;
-	}
+	if (dc->soc->supports_blending)
+		tegra_plane_setup_blending(plane, window);
+	else
+		tegra_plane_setup_blending_legacy(plane);
 }
 
 static const u32 tegra20_primary_formats[] = {
@@ -467,6 +494,7 @@ static void tegra_plane_atomic_update(st
 	window.bottom_up = tegra_fb_is_bottom_up(fb);
 
 	/* copy from state */
+	window.zpos = plane->state->normalized_zpos;
 	window.tiling = state->tiling;
 	window.format = state->format;
 	window.swap = state->swap;
@@ -523,7 +551,6 @@ static struct drm_plane *tegra_primary_p
 	/* Always use window A as primary window */
 	plane->offset = 0xa00;
 	plane->index = 0;
-	plane->depth = 255;
 	plane->dc = dc;
 
 	num_formats = dc->soc->num_primary_formats;
@@ -539,6 +566,9 @@ static struct drm_plane *tegra_primary_p
 
 	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);
+
 	return &plane->base;
 }
 
@@ -786,7 +816,6 @@ static struct drm_plane *tegra_dc_overla
 
 	plane->offset = 0xa00 + 0x200 * index;
 	plane->index = index;
-	plane->depth = 0;
 	plane->dc = dc;
 
 	num_formats = dc->soc->num_overlay_formats;
@@ -803,6 +832,9 @@ static struct drm_plane *tegra_dc_overla
 
 	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);
+
 	return &plane->base;
 }
 
@@ -1834,6 +1866,7 @@ static const struct tegra_dc_soc_info te
 	.supports_interlacing = false,
 	.supports_cursor = false,
 	.supports_block_linear = false,
+	.supports_blending = false,
 	.pitch_align = 8,
 	.has_powergate = false,
 	.broken_reset = true,
@@ -1849,6 +1882,7 @@ static const struct tegra_dc_soc_info te
 	.supports_interlacing = false,
 	.supports_cursor = false,
 	.supports_block_linear = false,
+	.supports_blending = false,
 	.pitch_align = 8,
 	.has_powergate = false,
 	.broken_reset = false,
@@ -1864,6 +1898,7 @@ static const struct tegra_dc_soc_info te
 	.supports_interlacing = false,
 	.supports_cursor = false,
 	.supports_block_linear = false,
+	.supports_blending = false,
 	.pitch_align = 64,
 	.has_powergate = true,
 	.broken_reset = false,
@@ -1879,6 +1914,7 @@ static const struct tegra_dc_soc_info te
 	.supports_interlacing = true,
 	.supports_cursor = true,
 	.supports_block_linear = true,
+	.supports_blending = true,
 	.pitch_align = 64,
 	.has_powergate = true,
 	.broken_reset = false,
@@ -1894,6 +1930,7 @@ static const struct tegra_dc_soc_info te
 	.supports_interlacing = true,
 	.supports_cursor = true,
 	.supports_block_linear = true,
+	.supports_blending = true,
 	.pitch_align = 64,
 	.has_powergate = true,
 	.broken_reset = false,
@@ -1943,6 +1980,7 @@ static const struct tegra_dc_soc_info te
 	.supports_interlacing = true,
 	.supports_cursor = true,
 	.supports_block_linear = true,
+	.supports_blending = true,
 	.pitch_align = 64,
 	.has_powergate = false,
 	.broken_reset = false,
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -55,6 +55,7 @@ struct tegra_dc_soc_info {
 	bool supports_interlacing;
 	bool supports_cursor;
 	bool supports_block_linear;
+	bool supports_blending;
 	unsigned int pitch_align;
 	bool has_powergate;
 	bool broken_reset;
@@ -136,6 +137,7 @@ struct tegra_dc_window {
 	unsigned int bits_per_pixel;
 	unsigned int stride[2];
 	unsigned long base[3];
+	unsigned int zpos;
 	bool bottom_up;
 
 	struct tegra_bo_tiling tiling;
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -33,6 +33,29 @@ struct tegra_drm_file {
 	struct mutex lock;
 };
 
+static int tegra_atomic_check(struct drm_device *drm,
+			      struct drm_atomic_state *state)
+{
+	int err;
+
+	err = drm_atomic_helper_check_modeset(drm, state);
+	if (err < 0)
+		return err;
+
+	err = drm_atomic_normalize_zpos(drm, state);
+	if (err < 0)
+		return err;
+
+	err = drm_atomic_helper_check_planes(drm, state);
+	if (err < 0)
+		return err;
+
+	if (state->legacy_cursor_update)
+		state->async_update = !drm_atomic_helper_async_check(drm, state);
+
+	return 0;
+}
+
 static struct drm_atomic_state *
 tegra_atomic_state_alloc(struct drm_device *drm)
 {
@@ -67,7 +90,7 @@ static const struct drm_mode_config_func
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 	.output_poll_changed = drm_fb_helper_output_poll_changed,
 #endif
-	.atomic_check = drm_atomic_helper_check,
+	.atomic_check = tegra_atomic_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_state_alloc = tegra_atomic_state_alloc,
 	.atomic_state_clear = tegra_atomic_state_clear,
--- a/drivers/gpu/drm/tegra/hub.c
+++ b/drivers/gpu/drm/tegra/hub.c
@@ -399,6 +399,7 @@ static void tegra_shared_plane_atomic_up
 {
 	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
 	struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
+	unsigned int zpos = plane->state->normalized_zpos;
 	struct drm_framebuffer *fb = plane->state->fb;
 	struct tegra_plane *p = to_tegra_plane(plane);
 	struct tegra_bo *bo;
@@ -431,7 +432,7 @@ static void tegra_shared_plane_atomic_up
 		BLEND_FACTOR_SRC_COLOR_K1_TIMES_SRC;
 	tegra_plane_writel(p, value, DC_WIN_BLEND_NOMATCH_SELECT);
 
-	value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(p->depth);
+	value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos);
 	tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL);
 
 	/* bypass scaling */
@@ -536,7 +537,6 @@ struct drm_plane *tegra_shared_plane_cre
 
 	plane->base.offset = 0x0a00 + 0x0300 * index;
 	plane->base.index = index;
-	plane->base.depth = 0;
 
 	plane->wgrp = &hub->wgrps[wgrp];
 	plane->wgrp->parent = dc->dev;
@@ -555,6 +555,7 @@ struct drm_plane *tegra_shared_plane_cre
 	}
 
 	drm_plane_helper_add(p, &tegra_shared_plane_helper_funcs);
+	drm_plane_create_zpos_property(p, 0, 0, 255);
 
 	return p;
 }
--- a/drivers/gpu/drm/tegra/plane.h
+++ b/drivers/gpu/drm/tegra/plane.h
@@ -19,7 +19,6 @@ struct tegra_plane {
 	struct tegra_dc *dc;
 	unsigned int offset;
 	unsigned int index;
-	unsigned int depth;
 };
 
 struct tegra_cursor {