drm/mode-config: Create drm_mode_config_create_initial_state()

drm_mode_config_reset() can be used to create the initial state, but
also to return to the initial state, when doing a suspend/resume cycle
for example.

It also affects both the software and the hardware, and drivers can
choose to reset the hardware as well. Most will just create an empty
state and the synchronisation between hardware and software states will
effectively be done when the first commit is done.

That dual role can be harmful, since some objects do need to be
initialized but also need to be preserved across a suspend/resume cycle.
drm_private_obj are such objects for example.

Thus, create another helper for drivers to call to initialize their
state when the driver is loaded, so we can make
drm_mode_config_reset() only about handling suspend/resume and similar.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260526-drm-mode-config-init-v6-16-852346394200@kernel.org
Signed-off-by: Maxime Ripard <mripard@kernel.org>
This commit is contained in:
Maxime Ripard 2026-05-26 18:46:28 +02:00
parent 6db0e11f48
commit c9497dda31
No known key found for this signature in database
GPG Key ID: 275FCE19A23DBE76
3 changed files with 100 additions and 2 deletions

View File

@ -60,8 +60,16 @@
*
* Their respective lifetimes are:
*
* - at reset time, the object reset implementation allocates a new
* default state and stores it in the object state pointer.
* - at driver initialization time, the driver calls
* drm_mode_config_create_initial_state() to allocate an initial,
* pristine, state for each object and stores it in the objects state
* pointer. Historically, this was one of drm_mode_config_reset() job,
* so one might still encounter it in a driver.
*
* - When resuming from suspend, drm_mode_config_reset() resets the
* software and hardware state to a known default and stores it in the
* object's state pointer. Not all objects are affected by
* drm_mode_config_reset() though.
*
* - whenever a new update is needed:
*

View File

@ -23,6 +23,7 @@
#include <linux/export.h>
#include <linux/uaccess.h>
#include <drm/drm_atomic.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_file.h>
@ -316,6 +317,94 @@ void drm_mode_config_reset(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_mode_config_reset);
/**
* drm_mode_config_create_initial_state - Allocates the initial state
* @dev: drm device
*
* This functions creates the initial state for all the objects. Drivers
* can use this in e.g. probe to initialize their software state.
*
* It has two main differences with drm_mode_config_reset(): the reset()
* hooks aren't called and thus the hardware will be left untouched, but
* also the &drm_private_obj structures will be initialized as opposed
* to drm_mode_config_reset() that skips them.
*
* Returns: 0 on success, negative error value on failure.
*/
int drm_mode_config_create_initial_state(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_colorop *colorop;
struct drm_plane *plane;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct drm_private_obj *privobj;
int ret;
drm_for_each_privobj(privobj, dev) {
struct drm_private_state *privobj_state;
if (privobj->state)
continue;
if (!privobj->funcs->atomic_create_state)
continue;
privobj_state = privobj->funcs->atomic_create_state(privobj);
if (IS_ERR(privobj_state))
return PTR_ERR(privobj_state);
privobj->state = privobj_state;
}
drm_for_each_colorop(colorop, dev) {
struct drm_colorop_state *colorop_state;
if (colorop->state)
continue;
colorop_state = drm_atomic_helper_colorop_create_state(colorop);
if (IS_ERR(colorop_state))
return PTR_ERR(colorop_state);
colorop->state = colorop_state;
}
drm_for_each_plane(plane, dev) {
if (plane->state)
continue;
ret = drm_mode_config_plane_create_state(plane);
if (ret)
return ret;
}
drm_for_each_crtc(crtc, dev) {
if (crtc->state)
continue;
ret = drm_mode_config_crtc_create_state(crtc);
if (ret)
return ret;
}
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->state)
continue;
ret = drm_mode_config_connector_create_state(connector);
if (ret) {
drm_connector_list_iter_end(&conn_iter);
return ret;
}
}
drm_connector_list_iter_end(&conn_iter);
return 0;
}
EXPORT_SYMBOL(drm_mode_config_create_initial_state);
/*
* Global properties
*/

View File

@ -1007,6 +1007,7 @@ static inline int drm_mode_config_init(struct drm_device *dev)
return drmm_mode_config_init(dev);
}
int drm_mode_config_create_initial_state(struct drm_device *dev);
void drm_mode_config_reset(struct drm_device *dev);
void drm_mode_config_cleanup(struct drm_device *dev);