The simple-kms helper provides a reset_plane hook to let drivers override the default plane reset. However, the reset hook is overloaded: it is used to create the initial software state at probe time, but also to reset both the hardware and software state during suspend/resume. These two roles have different expectations, and reset is not fallible which makes error handling difficult.
The atomic_create_state pattern was introduced to untangle this by providing a hook that only allocates and initializes a pristine state without any side effect. Add a create_plane_state hook to struct drm_simple_display_pipe_funcs. When provided, drm_simple_kms_plane_reset() will use it to allocate a fresh state, falling back to reset_plane and then to the default drm_atomic_helper_plane_reset(). This will allow simple-kms drivers to be converted to the atomic_create_state pattern. Signed-off-by: Maxime Ripard <[email protected]> --- drivers/gpu/drm/drm_simple_kms_helper.c | 26 ++++++++++++++++++++++++-- include/drm/drm_simple_kms_helper.h | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 8e1d07b9f1e3..528968ea5c4b 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -279,19 +279,41 @@ static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = { .end_fb_access = drm_simple_kms_plane_end_fb_access, .atomic_check = drm_simple_kms_plane_atomic_check, .atomic_update = drm_simple_kms_plane_atomic_update, }; +static void drm_simple_kms_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state); + static void drm_simple_kms_plane_reset(struct drm_plane *plane) { struct drm_simple_display_pipe *pipe; pipe = container_of(plane, struct drm_simple_display_pipe, plane); - if (!pipe->funcs || !pipe->funcs->reset_plane) + if (!pipe->funcs) return drm_atomic_helper_plane_reset(plane); - return pipe->funcs->reset_plane(pipe); + if (pipe->funcs->create_plane_state) { + struct drm_plane_state *state; + + if (plane->state) { + drm_simple_kms_plane_destroy_state(plane, plane->state); + plane->state = NULL; + } + + state = pipe->funcs->create_plane_state(pipe); + if (WARN_ON(IS_ERR(state))) + return; + + plane->state = state; + return; + } + + if (pipe->funcs->reset_plane) + return pipe->funcs->reset_plane(pipe); + + return drm_atomic_helper_plane_reset(plane); } static struct drm_plane_state *drm_simple_kms_plane_duplicate_state(struct drm_plane *plane) { struct drm_simple_display_pipe *pipe; diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h index cb672ce0e856..b58f6d532820 100644 --- a/include/drm/drm_simple_kms_helper.h +++ b/include/drm/drm_simple_kms_helper.h @@ -42,10 +42,11 @@ struct drm_simple_display_pipe_funcs { void (*reset_crtc)(struct drm_simple_display_pipe *pipe); struct drm_crtc_state * (*duplicate_crtc_state)(struct drm_simple_display_pipe *pipe); void (*destroy_crtc_state)(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state); void (*reset_plane)(struct drm_simple_display_pipe *pipe); + struct drm_plane_state * (*create_plane_state)(struct drm_simple_display_pipe *pipe); struct drm_plane_state * (*duplicate_plane_state)(struct drm_simple_display_pipe *pipe); void (*destroy_plane_state)(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state); }; -- 2.55.0
