[Intel-gfx] [PATCH] drm/i915: Prepare for atomic plane helpers (v5)

Matt Roper matthew.d.roper at intel.com
Wed Nov 26 20:24:03 CET 2014


Add the new driver entrypoints that will be called by the atomic plane
helpers.

This patch does not actually switch over to the new plane helpers yet,
so there should be no functional change here.  Also note that although
plane programming was already split into check/prepare/commit steps,
some of the semantics of those individual functions will need to change
slightly when we do make the jump so that they match the behavior the
plane helpers expect.

v2:
 - Renamed file from intel_atomic.c to intel_atomic_plane.c (Daniel)
 - Fix a copy/paste comment mistake (Bob)

v3:
 - Use prepare/cleanup functions that we've already factored out
 - Use newly refactored pre_commit/commit/post_commit to avoid sleeping
   during vblank evasion

v4:
 - Rebase to latest di-nightly requires adding an 'old_state' parameter
   to atomic_update;

v5:
 - Must have botched a rebase somewhere and lost some work.  Restore
   state 'dirty' flag to let begin/end code know which planes to
   run the pre_commit/post_commit hooks for.  This would have actually
   shown up as broken in the next commit rather than this one.

Signed-off-by: Matt Roper <matthew.d.roper at intel.com>
---
 drivers/gpu/drm/i915/Makefile             |   1 +
 drivers/gpu/drm/i915/intel_atomic_plane.c | 219 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c      |  22 ++-
 drivers/gpu/drm/i915/intel_drv.h          |  12 ++
 drivers/gpu/drm/i915/intel_sprite.c       |  11 ++
 5 files changed, 264 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/intel_atomic_plane.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index e4083e4..f44fe9f 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -64,6 +64,7 @@ i915-y += dvo_ch7017.o \
 	  dvo_ns2501.o \
 	  dvo_sil164.o \
 	  dvo_tfp410.o \
+	  intel_atomic_plane.o \
 	  intel_crt.o \
 	  intel_ddi.o \
 	  intel_dp.o \
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
new file mode 100644
index 0000000..5b68b52
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "intel_drv.h"
+
+/**
+ * intel_plane_duplicate_state - duplicate plane state
+ * @plane: drm plane
+ *
+ * Allocates and returns a copy of the plane state (both common and
+ * Intel-specific) for the specified plane.
+ */
+struct drm_plane_state *
+intel_plane_duplicate_state(struct drm_plane *plane)
+{
+	struct intel_plane_state *state;
+
+	if (plane->state)
+		state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
+	else
+		state = kzalloc(sizeof(*state), GFP_KERNEL);
+
+	if (state && state->base.fb)
+		drm_framebuffer_reference(state->base.fb);
+	state->dirty = true;
+
+	return &state->base;
+}
+
+/**
+ * intel_plane_destroy_state - destroy plane state
+ * @plane: drm plane
+ *
+ * Destroys the plane state (both common and Intel-specific) for the
+ * specified plane.
+ */
+void
+intel_plane_destroy_state(struct drm_plane *plane,
+			  struct drm_plane_state *state)
+{
+	drm_atomic_helper_plane_destroy_state(plane, state);
+}
+
+
+/**
+ * intel_crtc_atomic_begin - Begins an atomic commit on a CRTC
+ * @crtc: drm crtc
+ *
+ * Prepares to write registers associated with the atomic commit of a CRTC
+ * by using vblank evasion to ensure that all register writes happen within
+ * the same vblank period.
+ */
+void intel_crtc_atomic_begin(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_plane *primary = to_intel_plane(crtc->primary);
+	struct intel_plane *cursor = to_intel_plane(crtc->cursor);
+	struct intel_plane *sprite;
+	struct intel_plane_state *primary_state =
+		to_intel_plane_state(primary->base.state);
+	struct intel_plane_state *cursor_state =
+		to_intel_plane_state(cursor->base.state);
+	struct intel_plane_state *sprite_state;
+	struct drm_plane *p;
+
+	WARN_ON(intel_crtc->atomic_vbl_count != 0);
+
+	/* Pre-commit operations before irq disable; may sleep */
+	if (primary_state->dirty)
+		primary->pre_commit(&primary->base, primary_state);
+	if (cursor_state->dirty)
+		cursor->pre_commit(&cursor->base, cursor_state);
+	drm_for_each_legacy_plane(p, &dev->mode_config.plane_list) {
+		sprite = to_intel_plane(p);
+		sprite_state = to_intel_plane_state(p->state);
+		if (sprite->pipe == intel_crtc->pipe && sprite_state->dirty)
+			sprite->pre_commit(p, sprite_state);
+	}
+
+	/* Perform real plane programming with irqs disabled */
+	if (intel_crtc->active)
+		intel_pipe_update_start(intel_crtc,
+					&intel_crtc->atomic_vbl_count);
+	else
+		intel_crtc->atomic_vbl_count = 0;
+}
+
+/**
+ * intel_crtc_atomic_flush - Finishes an atomic commit on a CRTC
+ * @crtc: drm crtc
+ *
+ * Concludes the writing of registers for an atomic commit of a CRTC.
+ */
+void intel_crtc_atomic_flush(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_plane *primary = to_intel_plane(crtc->primary);
+	struct intel_plane *cursor = to_intel_plane(crtc->cursor);
+	struct intel_plane *sprite;
+	struct intel_plane_state *primary_state =
+		to_intel_plane_state(primary->base.state);
+	struct intel_plane_state *cursor_state =
+		to_intel_plane_state(cursor->base.state);
+	struct intel_plane_state *sprite_state;
+	struct drm_plane *p;
+
+	/* End vblank evasion and reenable interrupts */
+	if (intel_crtc->atomic_vbl_count)
+		intel_pipe_update_end(intel_crtc, intel_crtc->atomic_vbl_count);
+	intel_crtc->atomic_vbl_count = 0;
+
+	/* Post-commit operations after irq re-enabled; may sleep */
+	if (primary_state->dirty) {
+		primary->post_commit(&primary->base, primary_state);
+		primary_state->dirty = false;
+	}
+	if (cursor_state->dirty) {
+		cursor->post_commit(&cursor->base, cursor_state);
+		cursor_state->dirty = false;
+	}
+	drm_for_each_legacy_plane(p, &dev->mode_config.plane_list) {
+		sprite = to_intel_plane(p);
+		sprite_state = to_intel_plane_state(p->state);
+		if (sprite->pipe == intel_crtc->pipe && sprite_state->dirty) {
+			sprite->post_commit(p, sprite_state);
+			sprite_state->dirty = false;
+		}
+	}
+}
+
+
+static int intel_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc);
+	struct intel_plane_state *intel_state = to_intel_plane_state(state);
+
+	if (state->crtc && plane->type == DRM_PLANE_TYPE_PRIMARY) {
+		intel_crtc_wait_for_pending_flips(state->crtc);
+		if (intel_crtc_has_pending_flip(state->crtc)) {
+			DRM_ERROR("pipe is still busy with an old pageflip\n");
+			return -EBUSY;
+		}
+	}
+
+	/* Disabling a plane is always okay */
+	if (state->fb == NULL)
+		return 0;
+
+	/*
+	 * The original src/dest coordinates are stored in state->base, but
+	 * we want to keep another copy internal to our driver that we can
+	 * clip/modify ourselves.
+	 */
+	intel_state->src.x1 = state->src_x;
+	intel_state->src.y1 = state->src_y;
+	intel_state->src.x2 = state->src_x + state->src_w;
+	intel_state->src.y2 = state->src_y + state->src_h;
+	intel_state->dst.x1 = state->crtc_x;
+	intel_state->dst.y1 = state->crtc_y;
+	intel_state->dst.x2 = state->crtc_x + state->crtc_w;
+	intel_state->dst.y2 = state->crtc_y + state->crtc_h;
+
+	/* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
+	if (intel_crtc) {
+		intel_state->clip.x1 = 0;
+		intel_state->clip.y1 = 0;
+		intel_state->clip.x2 =
+			intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
+		intel_state->clip.y2 =
+			intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
+	}
+
+	return intel_plane->check_plane(plane, intel_state);
+}
+
+static void intel_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct intel_plane *intel_plane = to_intel_plane(plane);
+	struct intel_plane_state *intel_state =
+		to_intel_plane_state(plane->state);
+
+	intel_plane->commit_plane(plane, intel_state);
+}
+
+const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
+	.prepare_fb = intel_prepare_plane_fb,
+	.cleanup_fb = intel_cleanup_plane_fb,
+	.atomic_check = intel_plane_atomic_check,
+	.atomic_update = intel_plane_atomic_update,
+};
+
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 7e5206f..3ecbeb7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9792,6 +9792,8 @@ out_hang:
 static struct drm_crtc_helper_funcs intel_helper_funcs = {
 	.mode_set_base_atomic = intel_pipe_set_base_atomic,
 	.load_lut = intel_crtc_load_lut,
+	.atomic_begin = intel_crtc_atomic_begin,
+	.atomic_flush = intel_crtc_atomic_flush,
 };
 
 /**
@@ -11930,6 +11932,7 @@ intel_disable_plane(struct drm_plane *plane)
 void intel_plane_destroy(struct drm_plane *plane)
 {
 	struct intel_plane *intel_plane = to_intel_plane(plane);
+	intel_plane_destroy_state(plane, plane->state);
 	drm_plane_cleanup(plane);
 	kfree(intel_plane);
 }
@@ -11938,13 +11941,17 @@ static const struct drm_plane_funcs intel_primary_plane_funcs = {
 	.update_plane = intel_update_plane,
 	.disable_plane = intel_disable_plane,
 	.destroy = intel_plane_destroy,
-	.set_property = intel_plane_set_property
+	.set_property = intel_plane_set_property,
+	.atomic_duplicate_state = intel_plane_duplicate_state,
+	.atomic_destroy_state = intel_plane_destroy_state,
+
 };
 
 static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
 						    int pipe)
 {
 	struct intel_plane *primary;
+	struct intel_plane_state *state;
 	const uint32_t *intel_primary_formats;
 	int num_formats;
 
@@ -11952,6 +11959,9 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
 	if (primary == NULL)
 		return NULL;
 
+	primary->base.state = intel_plane_duplicate_state(&primary->base);
+	state = to_intel_plane_state(primary->base.state);
+	state->dirty = false;
 	primary->can_scale = false;
 	primary->max_downscale = 1;
 	primary->pipe = pipe;
@@ -11989,6 +11999,8 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
 				primary->rotation);
 	}
 
+	drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
+
 	return &primary->base;
 }
 
@@ -12137,17 +12149,23 @@ static const struct drm_plane_funcs intel_cursor_plane_funcs = {
 	.disable_plane = intel_disable_plane,
 	.destroy = intel_plane_destroy,
 	.set_property = intel_plane_set_property,
+	.atomic_duplicate_state = intel_plane_duplicate_state,
+	.atomic_destroy_state = intel_plane_destroy_state,
 };
 
 static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
 						   int pipe)
 {
 	struct intel_plane *cursor;
+	struct intel_plane_state *state;
 
 	cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
 	if (cursor == NULL)
 		return NULL;
 
+	cursor->base.state = intel_plane_duplicate_state(&cursor->base);
+	state = to_intel_plane_state(cursor->base.state);
+	state->dirty = false;
 	cursor->can_scale = false;
 	cursor->max_downscale = 1;
 	cursor->pipe = pipe;
@@ -12176,6 +12194,8 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
 				cursor->rotation);
 	}
 
+	drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
+
 	return &cursor->base;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8f3798f..c73a397 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -251,6 +251,7 @@ struct intel_plane_state {
 	struct drm_rect orig_src;
 	struct drm_rect orig_dst;
 	bool visible;
+	bool dirty;
 
 	/*
 	 * used only for sprite planes to determine when to implicitly
@@ -479,6 +480,8 @@ struct intel_crtc {
 
 	int scanline_offset;
 	struct intel_mmio_flip mmio_flip;
+
+	uint32_t atomic_vbl_count;
 };
 
 struct intel_plane_wm_parameters {
@@ -557,6 +560,7 @@ struct cxsr_latency {
 #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 #define to_intel_plane(x) container_of(x, struct intel_plane, base)
+#define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
 #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
 
 struct intel_hdmi {
@@ -1230,4 +1234,12 @@ void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
 /* intel_tv.c */
 void intel_tv_init(struct drm_device *dev);
 
+/* intel_atomic.c */
+struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
+void intel_plane_destroy_state(struct drm_plane *plane,
+			       struct drm_plane_state *state);
+void intel_crtc_atomic_begin(struct drm_crtc *crtc);
+void intel_crtc_atomic_flush(struct drm_crtc *crtc);
+extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
+
 #endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 8e3b29d..9aaf991 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -33,6 +33,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_rect.h>
+#include <drm/drm_plane_helper.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -1421,6 +1422,8 @@ static const struct drm_plane_funcs intel_plane_funcs = {
 	.disable_plane = intel_disable_plane,
 	.destroy = intel_plane_destroy,
 	.set_property = intel_plane_set_property,
+	.atomic_duplicate_state = intel_plane_duplicate_state,
+	.atomic_destroy_state = intel_plane_destroy_state,
 };
 
 static uint32_t ilk_plane_formats[] = {
@@ -1470,6 +1473,7 @@ int
 intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 {
 	struct intel_plane *intel_plane;
+	struct intel_plane_state *state;
 	unsigned long possible_crtcs;
 	const uint32_t *plane_formats;
 	int num_plane_formats;
@@ -1482,6 +1486,11 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 	if (!intel_plane)
 		return -ENOMEM;
 
+	intel_plane->base.state =
+		intel_plane_duplicate_state(&intel_plane->base);
+	state = to_intel_plane_state(intel_plane->base.state);
+	state->dirty = false;
+
 	switch (INTEL_INFO(dev)->gen) {
 	case 5:
 	case 6:
@@ -1577,6 +1586,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 					   dev->mode_config.rotation_property,
 					   intel_plane->rotation);
 
+	drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
+
  out:
 	return ret;
 }
-- 
1.8.5.1




More information about the Intel-gfx mailing list