funcs->atomic_disable(plane, old_state);
} else if (new_plane_state->crtc || disabling) {
funcs->atomic_update(plane, old_state);
+
+ if (!disabling && funcs->atomic_enable) {
+ if (drm_atomic_plane_enabling(old_plane_state, new_plane_state))
+ funcs->atomic_enable(plane, old_state);
+ }
}
}
struct drm_plane_state *new_plane_state =
drm_atomic_get_new_plane_state(old_state, plane);
const struct drm_plane_helper_funcs *plane_funcs;
+ bool disabling;
plane_funcs = plane->helper_private;
WARN_ON(new_plane_state->crtc &&
new_plane_state->crtc != crtc);
- if (drm_atomic_plane_disabling(old_plane_state, new_plane_state) &&
- plane_funcs->atomic_disable)
+ disabling = drm_atomic_plane_disabling(old_plane_state, new_plane_state);
+
+ if (disabling && plane_funcs->atomic_disable) {
plane_funcs->atomic_disable(plane, old_state);
- else if (new_plane_state->crtc ||
- drm_atomic_plane_disabling(old_plane_state, new_plane_state))
+ } else if (new_plane_state->crtc || disabling) {
plane_funcs->atomic_update(plane, old_state);
+
+ if (!disabling && plane_funcs->atomic_enable) {
+ if (drm_atomic_plane_enabling(old_plane_state, new_plane_state))
+ plane_funcs->atomic_enable(plane, old_state);
+ }
+ }
}
if (crtc_funcs && crtc_funcs->atomic_flush)
plane)))
/**
+ * drm_atomic_plane_enabling - check whether a plane is being enabled
+ * @old_plane_state: old atomic plane state
+ * @new_plane_state: new atomic plane state
+ *
+ * Checks the atomic state of a plane to determine whether it's being enabled
+ * or not. This also WARNs if it detects an invalid state (both CRTC and FB
+ * need to either both be NULL or both be non-NULL).
+ *
+ * RETURNS:
+ * True if the plane is being enabled, false otherwise.
+ */
+static inline bool drm_atomic_plane_enabling(struct drm_plane_state *old_plane_state,
+ struct drm_plane_state *new_plane_state)
+{
+ /*
+ * When enabling a plane, CRTC and FB should always be set together.
+ * Anything else should be considered a bug in the atomic core, so we
+ * gently warn about it.
+ */
+ WARN_ON((!new_plane_state->crtc && new_plane_state->fb) ||
+ (new_plane_state->crtc && !new_plane_state->fb));
+
+ return !old_plane_state->crtc && new_plane_state->crtc;
+}
+
+/**
* drm_atomic_plane_disabling - check whether a plane is being disabled
* @old_plane_state: old atomic plane state
* @new_plane_state: new atomic plane state
*/
void (*atomic_update)(struct drm_plane *plane,
struct drm_atomic_state *state);
+
+ /**
+ * @atomic_enable:
+ *
+ * Drivers should use this function to unconditionally enable a plane.
+ * This hook is called in-between the &drm_crtc_helper_funcs.atomic_begin
+ * and drm_crtc_helper_funcs.atomic_flush callbacks. It is called after
+ * @atomic_update, which will be called for all enabled planes. Drivers
+ * that use @atomic_enable should set up a plane in @atomic_update and
+ * afterwards enable the plane in @atomic_enable. If a plane needs to be
+ * enabled before installing the scanout buffer, drivers can still do
+ * so in @atomic_update.
+ *
+ * Note that the power state of the display pipe when this function is
+ * called depends upon the exact helpers and calling sequence the driver
+ * has picked. See drm_atomic_helper_commit_planes() for a discussion of
+ * the tradeoffs and variants of plane commit helpers.
+ *
+ * This callback is used by the atomic modeset helpers, but it is
+ * optional. If implemented, @atomic_enable should be the inverse of
+ * @atomic_disable. Drivers that don't want to use either can still
+ * implement the complete plane update in @atomic_update.
+ */
+ void (*atomic_enable)(struct drm_plane *plane,
+ struct drm_atomic_state *state);
+
/**
* @atomic_disable:
*
* the tradeoffs and variants of plane commit helpers.
*
* This callback is used by the atomic modeset helpers and by the
- * transitional plane helpers, but it is optional.
+ * transitional plane helpers, but it is optional. It's intended to
+ * reverse the effects of @atomic_enable.
*/
void (*atomic_disable)(struct drm_plane *plane,
struct drm_atomic_state *state);