summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_atomic_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_atomic_helper.c')
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c117
1 files changed, 90 insertions, 27 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index b82ef6262469..a900858fa265 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -283,14 +283,11 @@ mode_fixup(struct drm_atomic_state *state)
if (!funcs)
continue;
- if (encoder->bridge && encoder->bridge->funcs->mode_fixup) {
- ret = encoder->bridge->funcs->mode_fixup(
- encoder->bridge, &crtc_state->mode,
- &crtc_state->adjusted_mode);
- if (!ret) {
- DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
- return -EINVAL;
- }
+ ret = drm_bridge_mode_fixup(encoder->bridge, &crtc_state->mode,
+ &crtc_state->adjusted_mode);
+ if (!ret) {
+ DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
+ return -EINVAL;
}
if (funcs->atomic_check) {
@@ -429,6 +426,10 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
if (ret != 0)
return ret;
+ ret = drm_atomic_add_affected_planes(state, crtc);
+ if (ret != 0)
+ return ret;
+
num_connectors = drm_atomic_connectors_for_crtc(state,
crtc);
@@ -583,8 +584,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
* Each encoder has at most one connector (since we always steal
* it away), so we won't call disable hooks twice.
*/
- if (encoder->bridge)
- encoder->bridge->funcs->disable(encoder->bridge);
+ drm_bridge_disable(encoder->bridge);
/* Right function depends upon target state. */
if (connector->state->crtc && funcs->prepare)
@@ -594,8 +594,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
else
funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
- if (encoder->bridge)
- encoder->bridge->funcs->post_disable(encoder->bridge);
+ drm_bridge_post_disable(encoder->bridge);
}
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
@@ -737,9 +736,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
if (funcs->mode_set)
funcs->mode_set(encoder, mode, adjusted_mode);
- if (encoder->bridge && encoder->bridge->funcs->mode_set)
- encoder->bridge->funcs->mode_set(encoder->bridge,
- mode, adjusted_mode);
+ drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
}
}
@@ -835,16 +832,14 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
* Each encoder has at most one connector (since we always steal
* it away), so we won't call enable hooks twice.
*/
- if (encoder->bridge)
- encoder->bridge->funcs->pre_enable(encoder->bridge);
+ drm_bridge_pre_enable(encoder->bridge);
if (funcs->enable)
funcs->enable(encoder);
else
funcs->commit(encoder);
- if (encoder->bridge)
- encoder->bridge->funcs->enable(encoder->bridge);
+ drm_bridge_enable(encoder->bridge);
}
}
EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_enables);
@@ -1127,6 +1122,10 @@ EXPORT_SYMBOL(drm_atomic_helper_prepare_planes);
*
* It still requires the global state object @old_state to know which planes and
* crtcs need to be updated though.
+ *
+ * Note that this function does all plane updates across all CRTCs in one step.
+ * If the hardware can't support this approach look at
+ * drm_atomic_helper_commit_planes_on_crtc() instead.
*/
void drm_atomic_helper_commit_planes(struct drm_device *dev,
struct drm_atomic_state *old_state)
@@ -1181,6 +1180,64 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
EXPORT_SYMBOL(drm_atomic_helper_commit_planes);
/**
+ * drm_atomic_helper_commit_planes_on_crtc - commit plane state for a crtc
+ * @old_crtc_state: atomic state object with the old crtc state
+ *
+ * This function commits the new plane state using the plane and atomic helper
+ * functions for planes on the specific crtc. It assumes that the atomic state
+ * has already been pushed into the relevant object state pointers, since this
+ * step can no longer fail.
+ *
+ * This function is useful when plane updates should be done crtc-by-crtc
+ * instead of one global step like drm_atomic_helper_commit_planes() does.
+ *
+ * This function can only be savely used when planes are not allowed to move
+ * between different CRTCs because this function doesn't handle inter-CRTC
+ * depencies. Callers need to ensure that either no such depencies exist,
+ * resolve them through ordering of commit calls or through some other means.
+ */
+void
+drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state)
+{
+ const struct drm_crtc_helper_funcs *crtc_funcs;
+ struct drm_crtc *crtc = old_crtc_state->crtc;
+ struct drm_atomic_state *old_state = old_crtc_state->state;
+ struct drm_plane *plane;
+ unsigned plane_mask;
+
+ plane_mask = old_crtc_state->plane_mask;
+ plane_mask |= crtc->state->plane_mask;
+
+ crtc_funcs = crtc->helper_private;
+ if (crtc_funcs && crtc_funcs->atomic_begin)
+ crtc_funcs->atomic_begin(crtc);
+
+ drm_for_each_plane_mask(plane, crtc->dev, plane_mask) {
+ struct drm_plane_state *old_plane_state =
+ drm_atomic_get_existing_plane_state(old_state, plane);
+ const struct drm_plane_helper_funcs *plane_funcs;
+
+ plane_funcs = plane->helper_private;
+
+ if (!old_plane_state || !plane_funcs)
+ continue;
+
+ WARN_ON(plane->state->crtc && plane->state->crtc != crtc);
+
+ if (drm_atomic_plane_disabling(plane, old_plane_state) &&
+ plane_funcs->atomic_disable)
+ plane_funcs->atomic_disable(plane, old_plane_state);
+ else if (plane->state->crtc ||
+ drm_atomic_plane_disabling(plane, old_plane_state))
+ plane_funcs->atomic_update(plane, old_plane_state);
+ }
+
+ if (crtc_funcs && crtc_funcs->atomic_flush)
+ crtc_funcs->atomic_flush(crtc);
+}
+EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc);
+
+/**
* drm_atomic_helper_cleanup_planes - cleanup plane resources after commit
* @dev: DRM device
* @old_state: atomic state object with old state structures
@@ -1550,7 +1607,10 @@ retry:
WARN_ON(set->fb);
WARN_ON(set->num_connectors);
- crtc_state->enable = false;
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
+ if (ret != 0)
+ goto fail;
+
crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
@@ -1565,9 +1625,11 @@ retry:
WARN_ON(!set->fb);
WARN_ON(!set->num_connectors);
- crtc_state->enable = true;
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
+ if (ret != 0)
+ goto fail;
+
crtc_state->active = true;
- drm_mode_copy(&crtc_state->mode, set->mode);
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
if (ret != 0)
@@ -1982,6 +2044,8 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
*/
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
{
+ if (crtc->state && crtc->state->mode_blob)
+ drm_property_unreference_blob(crtc->state->mode_blob);
kfree(crtc->state);
crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
@@ -2003,6 +2067,8 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
{
memcpy(state, crtc->state, sizeof(*state));
+ if (state->mode_blob)
+ drm_property_reference_blob(state->mode_blob);
state->mode_changed = false;
state->active_changed = false;
state->planes_changed = false;
@@ -2045,11 +2111,8 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
- /*
- * This is currently a placeholder so that drivers that subclass the
- * state will automatically do the right thing if code is ever added
- * to this function.
- */
+ if (state->mode_blob)
+ drm_property_unreference_blob(state->mode_blob);
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);