summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2015-06-29 13:55:30 -0700
committerEric Anholt <eric@anholt.net>2015-06-29 15:37:14 -0700
commite87405ac875a260133b9f9b28e672b7bce077a28 (patch)
treeecbbd3be671fb4ee6a90ae1de76ee6318ceba268
parent2422739db1e6cb7d88f5bc3739ccd9282514efd3 (diff)
downloadlinux-e87405ac875a260133b9f9b28e672b7bce077a28.tar.gz
drm/vc4: Implement custom atomic commit in vc4.
This is just drm_atomic_helper_commit(), with wait_for_fence replaced with V3D seqno waits based on msm's atomic commit's wait loop. This means we now synchronize to our own rendering. The old wait_for_fence loop did nothing since we never attached a dmabuf fence to our plane state. Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c91
1 files changed, 90 insertions, 1 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 98b57bd0fc80..e498696fe21f 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -7,15 +7,104 @@
*/
#include "drm_crtc.h"
+#include "drm_atomic.h"
#include "drm_atomic_helper.h"
#include "drm_crtc_helper.h"
#include "drm_plane_helper.h"
#include "drm_fb_cma_helper.h"
#include "vc4_drv.h"
+
+/**
+ * vc4_atomic_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a with drm_atomic_helper_check() pre-validated state
+ * object. This can still fail when e.g. the framebuffer reservation fails. For
+ * now this doesn't implement asynchronous commits.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+static int vc4_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ int ret;
+ int i;
+ uint64_t wait_seqno = 0;
+
+ if (async) {
+ DRM_ERROR("async\n");
+ return -EBUSY;
+ }
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+ struct drm_plane *plane = state->planes[i];
+ struct drm_plane_state *new_state = state->plane_states[i];
+
+ if (!plane)
+ continue;
+
+ if ((plane->state->fb != new_state->fb) && new_state->fb) {
+ struct drm_gem_cma_object *cma_bo;
+ struct vc4_bo *bo;
+ cma_bo = drm_fb_cma_get_gem_obj(plane->state->fb, 0);
+ bo = to_vc4_bo(&cma_bo->base);
+ wait_seqno = max(bo->seqno, wait_seqno);
+ }
+ }
+
+ /*
+ * 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(dev, state);
+
+ /*
+ * 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.
+ */
+
+ vc4_wait_for_seqno(dev, wait_seqno, ~0ull, false);
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+
+ drm_atomic_state_free(state);
+
+ return 0;
+}
+
static const struct drm_mode_config_funcs vc4_mode_funcs = {
.atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
+ .atomic_commit = vc4_atomic_commit,
.fb_create = drm_fb_cma_create,
};