The upcoming DRM_MODE_ATOMIC_RESET flag will need to create an atomic commit that brings the entire device back to a pristine state, as if no configuration had ever been applied.
Create drm_atomic_commit_fill_with_defaults() which iterates over all CRTCs, planes, connectors, and color operations in the device and inserts a fresh default state for each one into the commit. This uses the atomic_create_state() hooks rather than atomic_duplicate_state(), since atomic_create_state() provides exactly this pristine state on a per-object basis. Signed-off-by: Maxime Ripard <[email protected]> --- drivers/gpu/drm/drm_atomic.c | 112 +++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_atomic.h | 1 + 2 files changed, 113 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 79971d4b56a4..0c1a02d0e871 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1608,10 +1608,122 @@ drm_atomic_get_new_bridge_state(const struct drm_atomic_commit *state, return drm_priv_to_bridge_state(obj_state); } EXPORT_SYMBOL(drm_atomic_get_new_bridge_state); +/** + * drm_atomic_commit_fill_with_defaults - populate a commit with pristine states + * @commit: atomic commit to fill + * + * Iterate over all CRTCs, planes, connectors, and color operations in + * the device and insert a freshly created default state for each one + * into @commit. The states are created through the atomic_create_state() + * hooks, producing the same initial state the driver starts with rather + * than a copy of the current hardware state. + * + * This is meant to be used with the %DRM_MODE_ATOMIC_RESET flag, which + * needs to bring the device back to a known baseline before applying + * userspace property changes on top. + * + * Returns: + * 0 on success, or a negative error code on failure. + */ +int drm_atomic_commit_fill_with_defaults(struct drm_atomic_commit *commit) +{ + struct drm_device *dev = commit->dev; + struct drm_mode_config *config = &dev->mode_config; + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct drm_colorop *colorop; + int ret; + + WARN_ON(!commit->acquire_ctx); + + drm_for_each_crtc(crtc, dev) { + struct drm_crtc_state *crtc_state; + + ret = drm_modeset_lock(&crtc->mutex, commit->acquire_ctx); + if (ret) + return ret; + + crtc_state = crtc->funcs->atomic_create_state(crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + ret = drm_atomic_commit_set_crtc_state(commit, crtc, crtc_state); + if (ret) { + crtc->funcs->atomic_destroy_state(crtc, crtc_state); + return ret; + } + } + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + ret = drm_modeset_lock(&plane->mutex, commit->acquire_ctx); + if (ret) + return ret; + + plane_state = plane->funcs->atomic_create_state(plane); + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); + + ret = drm_atomic_commit_set_plane_state(commit, plane, plane_state); + if (ret) { + plane->funcs->atomic_destroy_state(plane, plane_state); + return ret; + } + } + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + struct drm_connector_state *connector_state; + + ret = drm_modeset_lock(&config->connection_mutex, commit->acquire_ctx); + if (ret) { + drm_connector_list_iter_end(&conn_iter); + return ret; + } + + connector_state = connector->funcs->atomic_create_state(connector); + if (IS_ERR(connector_state)) { + drm_connector_list_iter_end(&conn_iter); + ret = PTR_ERR(connector_state); + return ret; + } + + ret = drm_atomic_commit_set_connector_state(commit, connector, connector_state); + if (ret) { + connector->funcs->atomic_destroy_state(connector, connector_state); + drm_connector_list_iter_end(&conn_iter); + return ret; + } + } + drm_connector_list_iter_end(&conn_iter); + + drm_for_each_colorop(colorop, dev) { + struct drm_colorop_state *colorop_state; + + colorop_state = drm_atomic_helper_colorop_create_state(colorop); + if (IS_ERR(colorop_state)) + return PTR_ERR(colorop_state); + + drm_modeset_lock_assert_held(&colorop->plane->mutex); + + ret = drm_atomic_commit_set_colorop_state(commit, colorop, colorop_state); + if (ret) { + drm_colorop_atomic_destroy_state(colorop, colorop_state); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_commit_fill_with_defaults); + /** * drm_atomic_add_encoder_bridges - add bridges attached to an encoder * @state: atomic state * @encoder: DRM encoder * diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 00b3e9fc429a..e61a1bcd278b 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -698,10 +698,11 @@ static inline void drm_crtc_commit_put(struct drm_crtc_commit *commit) int drm_crtc_commit_wait(struct drm_crtc_commit *commit); struct drm_atomic_commit * __must_check drm_atomic_commit_alloc(struct drm_device *dev); +int drm_atomic_commit_fill_with_defaults(struct drm_atomic_commit *commit); void drm_atomic_commit_clear(struct drm_atomic_commit *state); /** * drm_atomic_commit_get - acquire a reference to the atomic state * @state: The atomic state -- 2.54.0
