linux-tegra.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@gmail.com>
To: dri-devel@lists.freedesktop.org
Cc: linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 32/36] drm/tegra: Atomic conversion, phase 3, step 3
Date: Tue, 20 Jan 2015 11:48:51 +0100	[thread overview]
Message-ID: <1421750935-4023-33-git-send-email-thierry.reding@gmail.com> (raw)
In-Reply-To: <1421750935-4023-1-git-send-email-thierry.reding@gmail.com>

From: Thierry Reding <treding@nvidia.com>

Provide a custom ->atomic_commit() implementation which supports async
commits. The generic atomic page-flip helper can use this to implement
page-flipping.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpu/drm/tegra/dc.c  | 129 ++++----------------------------------------
 drivers/gpu/drm/tegra/drm.c |  84 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/tegra/drm.h |   6 +++
 3 files changed, 100 insertions(+), 119 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 9a934a6077a6..52ae563cb531 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -827,99 +827,6 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
 	return 0;
 }
 
-static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
-			     struct drm_framebuffer *fb)
-{
-	struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
-	unsigned int h_offset = 0, v_offset = 0;
-	struct tegra_bo_tiling tiling;
-	unsigned long value, flags;
-	unsigned int format, swap;
-	int err;
-
-	err = tegra_fb_get_tiling(fb, &tiling);
-	if (err < 0)
-		return err;
-
-	spin_lock_irqsave(&dc->lock, flags);
-
-	tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
-
-	value = fb->offsets[0] + y * fb->pitches[0] +
-		x * fb->bits_per_pixel / 8;
-
-	tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
-	tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
-
-	format = tegra_dc_format(fb->pixel_format, &swap);
-	tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
-	tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP);
-
-	if (dc->soc->supports_block_linear) {
-		unsigned long height = tiling.value;
-
-		switch (tiling.mode) {
-		case TEGRA_BO_TILING_MODE_PITCH:
-			value = DC_WINBUF_SURFACE_KIND_PITCH;
-			break;
-
-		case TEGRA_BO_TILING_MODE_TILED:
-			value = DC_WINBUF_SURFACE_KIND_TILED;
-			break;
-
-		case TEGRA_BO_TILING_MODE_BLOCK:
-			value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
-				DC_WINBUF_SURFACE_KIND_BLOCK;
-			break;
-		}
-
-		tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
-	} else {
-		switch (tiling.mode) {
-		case TEGRA_BO_TILING_MODE_PITCH:
-			value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
-				DC_WIN_BUFFER_ADDR_MODE_LINEAR;
-			break;
-
-		case TEGRA_BO_TILING_MODE_TILED:
-			value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
-				DC_WIN_BUFFER_ADDR_MODE_TILE;
-			break;
-
-		case TEGRA_BO_TILING_MODE_BLOCK:
-			DRM_ERROR("hardware doesn't support block linear mode\n");
-			spin_unlock_irqrestore(&dc->lock, flags);
-			return -EINVAL;
-		}
-
-		tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
-	}
-
-	/* make sure bottom-up buffers are properly displayed */
-	if (tegra_fb_is_bottom_up(fb)) {
-		value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-		value |= V_DIRECTION;
-		tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-
-		v_offset += fb->height - 1;
-	} else {
-		value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
-		value &= ~V_DIRECTION;
-		tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-	}
-
-	tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
-	tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
-
-	value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
-	tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
-	tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
-
-	spin_unlock_irqrestore(&dc->lock, flags);
-
-	return 0;
-}
-
 void tegra_dc_enable_vblank(struct tegra_dc *dc)
 {
 	unsigned long value, flags;
@@ -998,30 +905,6 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
 	spin_unlock_irqrestore(&drm->event_lock, flags);
 }
 
-static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-			      struct drm_pending_vblank_event *event, uint32_t page_flip_flags)
-{
-	unsigned int pipe = drm_crtc_index(crtc);
-	struct tegra_dc *dc = to_tegra_dc(crtc);
-
-	if (dc->event)
-		return -EBUSY;
-
-	if (event) {
-		event->pipe = pipe;
-		dc->event = event;
-		drm_crtc_vblank_get(crtc);
-	}
-
-	if (crtc->primary->state)
-		drm_atomic_set_fb_for_plane(crtc->primary->state, fb);
-
-	tegra_dc_set_base(dc, 0, 0, fb);
-	crtc->primary->fb = fb;
-
-	return 0;
-}
-
 static void tegra_dc_destroy(struct drm_crtc *crtc)
 {
 	drm_crtc_cleanup(crtc);
@@ -1063,7 +946,7 @@ static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
 }
 
 static const struct drm_crtc_funcs tegra_crtc_funcs = {
-	.page_flip = tegra_dc_page_flip,
+	.page_flip = drm_atomic_helper_page_flip,
 	.set_config = drm_atomic_helper_set_config,
 	.destroy = tegra_dc_destroy,
 	.reset = tegra_crtc_reset,
@@ -1338,6 +1221,16 @@ static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
 
 static void tegra_crtc_atomic_begin(struct drm_crtc *crtc)
 {
+	struct tegra_dc *dc = to_tegra_dc(crtc);
+
+	if (crtc->state->event) {
+		crtc->state->event->pipe = drm_crtc_index(crtc);
+
+		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+		dc->event = crtc->state->event;
+		crtc->state->event = NULL;
+	}
 }
 
 static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 0dd81d050ccb..5b81b44af9e4 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -10,6 +10,7 @@
 #include <linux/host1x.h>
 #include <linux/iommu.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 
 #include "drm.h"
@@ -26,13 +27,90 @@ struct tegra_drm_file {
 	struct list_head contexts;
 };
 
+static void tegra_atomic_schedule(struct tegra_drm *tegra,
+				  struct drm_atomic_state *state)
+{
+	tegra->commit.state = state;
+	schedule_work(&tegra->commit.work);
+}
+
+static void tegra_atomic_complete(struct tegra_drm *tegra,
+				  struct drm_atomic_state *state)
+{
+	struct drm_device *drm = tegra->drm;
+
+	/*
+	 * Everything below can be run asynchronously without the need to grab
+	 * any modeset locks at all under one condition: It must be guaranteed
+	 * that the asynchronous work has either been cancelled (if the driver
+	 * supports it, which at least requires that the framebuffers get
+	 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+	 * before the new state gets committed on the software side with
+	 * drm_atomic_helper_swap_state().
+	 *
+	 * This scheme allows new atomic state updates to be prepared and
+	 * checked in parallel to the asynchronous completion of the previous
+	 * update. Which is important since compositors need to figure out the
+	 * composition of the next frame right after having submitted the
+	 * current layout.
+	 */
+
+	drm_atomic_helper_commit_pre_planes(drm, state);
+	drm_atomic_helper_commit_planes(drm, state);
+	drm_atomic_helper_commit_post_planes(drm, state);
+
+	drm_atomic_helper_wait_for_vblanks(drm, state);
+
+	drm_atomic_helper_cleanup_planes(drm, state);
+	drm_atomic_state_free(state);
+}
+
+static void tegra_atomic_work(struct work_struct *work)
+{
+	struct tegra_drm *tegra = container_of(work, struct tegra_drm,
+					       commit.work);
+
+	tegra_atomic_complete(tegra, tegra->commit.state);
+}
+
+static int tegra_atomic_commit(struct drm_device *drm,
+			       struct drm_atomic_state *state, bool async)
+{
+	struct tegra_drm *tegra = drm->dev_private;
+	int err;
+
+	err = drm_atomic_helper_prepare_planes(drm, state);
+	if (err)
+		return err;
+
+	/* serialize outstanding asynchronous commits */
+	mutex_lock(&tegra->commit.lock);
+	flush_work(&tegra->commit.work);
+
+	/*
+	 * This is the point of no return - everything below never fails except
+	 * when the hw goes bonghits. Which means we can commit the new state on
+	 * the software side now.
+	 */
+
+	drm_atomic_helper_swap_state(drm, state);
+
+	if (async)
+		tegra_atomic_schedule(tegra, state);
+	else
+		tegra_atomic_complete(tegra, state);
+
+	mutex_unlock(&tegra->commit.lock);
+	return 0;
+}
+
 static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
 	.fb_create = tegra_fb_create,
 #ifdef CONFIG_DRM_TEGRA_FBDEV
 	.output_poll_changed = tegra_fb_output_poll_changed,
 #endif
 	.atomic_check = drm_atomic_helper_check,
-	.atomic_commit = drm_atomic_helper_commit,
+	.atomic_commit = tegra_atomic_commit,
 };
 
 static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
@@ -58,6 +136,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
 
 	mutex_init(&tegra->clients_lock);
 	INIT_LIST_HEAD(&tegra->clients);
+
+	mutex_init(&tegra->commit.lock);
+	INIT_WORK(&tegra->commit.work, tegra_atomic_work);
+
 	drm->dev_private = tegra;
 	tegra->drm = drm;
 
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 3db719de312f..b1c7027b26e7 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -50,6 +50,12 @@ struct tegra_drm {
 #endif
 
 	unsigned int pitch_align;
+
+	struct {
+		struct drm_atomic_state *state;
+		struct work_struct work;
+		struct mutex lock;
+	} commit;
 };
 
 struct tegra_drm_client;
-- 
2.1.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2015-01-20 10:48 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-20 10:48 [PATCH 00/36] drm/tegra: Atomic mode-setting conversion Thierry Reding
2015-01-20 10:48 ` [PATCH 01/36] clk: Introduce clk_try_parent() Thierry Reding
2015-01-20 18:02   ` Mike Turquette
2015-01-20 18:16     ` Rob Clark
2015-01-21 15:12       ` Thierry Reding
     [not found]   ` <1421750935-4023-2-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-20 19:21     ` Stephen Boyd
2015-01-21 15:05       ` Thierry Reding
2015-01-21 16:13   ` [PATCH v2] clk: Introduce clk_has_parent() Thierry Reding
     [not found]     ` <1421856780-32103-1-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-22  0:16       ` Stephen Boyd
     [not found]         ` <54C04145.1010906-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-01-22  7:37           ` Thierry Reding
2015-01-22 20:25             ` Stephen Boyd
2015-01-23  9:34               ` Thierry Reding
2015-01-25  1:02                 ` Mike Turquette
2015-01-20 10:48 ` [PATCH 02/36] drm/plane: Make ->atomic_update() mandatory Thierry Reding
2015-01-20 11:10   ` Daniel Vetter
     [not found]   ` <1421750935-4023-3-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-20 13:51     ` Rob Clark
2015-01-23  9:18       ` Thierry Reding
2015-01-23  9:26     ` [PATCH v2] " Thierry Reding
2015-01-20 10:48 ` [PATCH 03/36] drm/plane: Add optional ->atomic_disable() callback Thierry Reding
2015-01-20 11:13   ` Daniel Vetter
2015-01-22 18:57   ` Gustavo Padovan
2015-01-23  9:28   ` [PATCH v4] " Thierry Reding
2015-01-20 10:48 ` [PATCH 04/36] drm/atomic: Add ->atomic_check() to encoder helpers Thierry Reding
2015-01-20 11:07   ` Daniel Vetter
2015-01-20 10:48 ` [PATCH 05/36] drm/atomic: Add drm_atomic_plane_get_crtc_state() Thierry Reding
2015-01-20 11:10   ` Daniel Vetter
     [not found]     ` <20150120111011.GX10113-dv86pmgwkMBes7Z6vYuT8azUEOm+Xw19@public.gmane.org>
2015-01-23  9:32       ` Thierry Reding
2015-01-20 10:48 ` [PATCH 06/36] drm/tegra: Use tegra_commit_dc() in output drivers Thierry Reding
2015-01-20 10:48 ` [PATCH 07/36] drm/tegra: Stop CRTC at CRTC disable time Thierry Reding
2015-01-20 10:48 ` [PATCH 08/36] drm/tegra: dc: Wait for idle when disabled Thierry Reding
2015-01-20 10:48 ` [PATCH 09/36] drm/tegra: Move tegra_drm_mode_funcs to the core Thierry Reding
2015-01-20 10:48 ` [PATCH 10/36] drm/tegra: dc: No longer disable planes at CRTC disable Thierry Reding
2015-01-20 10:48 ` [PATCH 11/36] drm/tegra: Convert output midlayer to helpers Thierry Reding
2015-01-20 10:48 ` [PATCH 12/36] drm/tegra: output: Make ->setup_clock() optional Thierry Reding
2015-01-20 10:48 ` [PATCH 13/36] drm/tegra: Add tegra_dc_setup_clock() helper Thierry Reding
2015-01-20 10:48 ` [PATCH 14/36] drm/tegra: rgb: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 15/36] drm/tegra: hdmi: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 16/36] drm/tegra: dsi: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 17/36] drm/tegra: sor: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 18/36] drm/tegra: debugfs cleanup cannot fail Thierry Reding
2015-01-20 10:48 ` [PATCH 19/36] drm/tegra: Remove remnants of the output midlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 20/36] drm/tegra: Output cleanup functions cannot fail Thierry Reding
2015-01-20 10:48 ` [PATCH 21/36] drm/tegra: dc: Do not needlessly deassert reset Thierry Reding
2015-01-20 10:48 ` [PATCH 22/36] drm/tegra: Atomic conversion, phase 1 Thierry Reding
2015-01-20 10:48 ` [PATCH 23/36] drm/tegra: Atomic conversion, phase 2 Thierry Reding
2015-01-20 10:48 ` [PATCH 24/36] drm/tegra: Atomic conversion, phase 3, step 1 Thierry Reding
2015-01-20 10:48 ` [PATCH 25/36] drm/tegra: dc: Store clock setup in atomic state Thierry Reding
2015-01-20 10:48 ` [PATCH 26/36] drm/tegra: rgb: Implement ->atomic_check() Thierry Reding
2015-01-20 10:48 ` [PATCH 27/36] drm/tegra: dsi: " Thierry Reding
2015-01-20 10:48 ` [PATCH 28/36] drm/tegra: hdmi: " Thierry Reding
2015-01-20 10:48 ` [PATCH 29/36] drm/tegra: sor: " Thierry Reding
2015-01-20 10:48 ` [PATCH 30/36] drm/tegra: dc: Use atomic clock state in modeset Thierry Reding
2015-01-20 10:48 ` [PATCH 31/36] drm/tegra: Atomic conversion, phase 3, step 2 Thierry Reding
2015-01-20 10:48 ` Thierry Reding [this message]
2015-01-20 10:48 ` [PATCH 33/36] drm/tegra: Remove unused ->mode_fixup() callbacks Thierry Reding
2015-01-20 10:48 ` [PATCH 34/36] drm/tegra: Track active planes in CRTC state Thierry Reding
2015-01-20 11:18   ` Daniel Vetter
2015-01-20 11:43     ` Thierry Reding
     [not found]   ` <1421750935-4023-35-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2015-01-23  9:31     ` [PATCH v2] " Thierry Reding
2015-01-20 10:48 ` [PATCH 35/36] drm/tegra: Track tiling and format in plane state Thierry Reding
2015-01-20 10:48 ` [PATCH 36/36] drm/tegra: dc: Unify enabling the display controller Thierry Reding

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1421750935-4023-33-git-send-email-thierry.reding@gmail.com \
    --to=thierry.reding@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).