* [PATCH v2 00/28] drm: Implement state readout support
@ 2026-04-23 10:06 Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 01/28] drm/atomic: Fix unused but set warning in state iterator macros Maxime Ripard
` (16 more replies)
0 siblings, 17 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard,
Laurent Pinchart
Hi,
Here's a series that implement what i915 calls "fastboot", ie,
initializing the initial KMS state from the hardware state at boot, to
skip the first modeset if the firmware already set up the display.
This series creates the infrastructure in KMS to create that state by
relying on driver specific hooks. It also implements some infrastructure
to check during non-blocking commits that the readout helpers work
properly by reading out the state that was just committed and comparing
it to what was supposed to be commited.
This relies on another set of driver hooks to compare the entities
states, with helpers providing the default implementation.
It then implements the readout support in the TIDSS driver, and was
tested with the SK-AM62 board. This board in particular is pretty
interesting, since it relies on an DPI to HDMI bridge, and uses the
drm_bridge_connector infrastructure.
So the readout works with the current state of the art on embedded-ish
It's now in a much better state than the v1 was, but there's still some
notable things broken:
- Bridges do not read their input and output bus formats and flags
- The tidss_crtc_state fields are not read properly at the moment
either.
- It looks like, when left unattended, we get some atomic_flush
WARN eventually, maybe because of something broken around
hotplugging and the monitor shutting itself down?
- If readout is disabled for any reason, the hardware isn't reset
anymore.
The main thing works though: the state is picked up properly, doesn't
trigger a modeset if what was programmed is the one the first modeset
tries to pick as well, will switch properly if it isn't, etc.
Let me know what you think,
Maxime
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
Changes in v2:
- Get rid of patches already applied
- Rebase on top of the current atomic_create_state work
- Use the SRO prefix everywhere
- Create our own states container structure instead of trying to plumb
it into a drm_atomic_state
- Make a lot more use of helpers
- Add a hook to enable the hardware resources when the readout state
becomes active
- Move all the tidss readout code into tidss_dispc.c
- Write documentation
- Add drm_private_obj and drm_bridge name for easier debugging
- Add drm_private_obj_is_bridge()
- Link to v1: https://lore.kernel.org/r/20250902-drm-state-readout-v1-0-14ad5315da3f@kernel.org
---
Maxime Ripard (28):
drm/atomic: Fix unused but set warning in state iterator macros
drm/atomic_helper: Skip over NULL private_obj pointers
drm/atomic_state_helper: Remove memset in __drm_atomic_helper_bridge_reset()
drm/atomic: Convert drm_priv_to_bridge_state to container_of_const
drm/atomic: Add drm_private_obj name
drm/bridge: Add drm_private_obj_is_bridge()
drm/bridge: Implement atomic_print_state
drm/atomic: Export drm_atomic_*_print_state
drm/atomic: Only call atomic_destroy_state on a !NULL pointer
drm/atomic_sro: Create drm_atomic_sro_state container
drm/atomic_sro: Create kernel parameter to force or disable readout
drm/atomic_sro: Add atomic state readout infrastructure
drm/atomic_sro: Add function to install state into drm objects
drm/atomic_sro: Create documentation
drm/bridge: Handle bridges with hardware state readout
drm/mode_config: Read out hardware state in drm_mode_config_create_state
drm/atomic_sro: Provide helpers to implement hardware state readout
drm/atomic_helper: Pass nonblock to commit_tail
drm/atomic_helper: Compare actual and readout states once the commit is done
drm/atomic_state_helper: Provide comparison macros
drm/atomic_state_helper: Provide atomic_compare_state helpers
drm/encoder: Create atomic_sro_get_current_crtc hook
drm/bridge: display-connector: Implement readout support
drm/bridge_connector: Implement hw readout for connector
drm/tidss: dispc: Improve mode checking logs
drm/tidss: Implement readout support
drm/tidss: encoder: Implement atomic_sro_get_current_crtc
drm/bridge: sii902x: Implement hw state readout
drivers/gpu/drm/Makefile | 2 +
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 +
.../drm/arm/display/komeda/komeda_private_obj.c | 8 +
drivers/gpu/drm/bridge/display-connector.c | 15 +
drivers/gpu/drm/bridge/sii902x.c | 56 +-
drivers/gpu/drm/display/drm_bridge_connector.c | 31 +
drivers/gpu/drm/display/drm_dp_mst_topology.c | 2 +-
drivers/gpu/drm/display/drm_dp_tunnel.c | 1 +
drivers/gpu/drm/drm_atomic.c | 46 +-
drivers/gpu/drm/drm_atomic_helper.c | 46 +-
drivers/gpu/drm/drm_atomic_sro.c | 854 +++++++++++++++++++++
drivers/gpu/drm/drm_atomic_sro_helper.c | 677 ++++++++++++++++
drivers/gpu/drm/drm_atomic_state_helper.c | 3 +-
drivers/gpu/drm/drm_bridge.c | 133 +++-
drivers/gpu/drm/drm_internal.h | 12 +
drivers/gpu/drm/drm_mode_config.c | 5 +
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 1 +
drivers/gpu/drm/ingenic/ingenic-ipu.c | 1 +
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 +
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 1 +
drivers/gpu/drm/omapdrm/omap_drv.c | 1 +
drivers/gpu/drm/tegra/hub.c | 1 +
drivers/gpu/drm/tidss/tidss_crtc.c | 93 +++
drivers/gpu/drm/tidss/tidss_dispc.c | 332 ++++++--
drivers/gpu/drm/tidss/tidss_dispc.h | 14 +
drivers/gpu/drm/tidss/tidss_encoder.c | 37 +-
drivers/gpu/drm/tidss/tidss_kms.c | 6 +-
drivers/gpu/drm/tidss/tidss_plane.c | 154 ++++
drivers/gpu/drm/vc4/vc4_kms.c | 3 +
include/drm/drm_atomic.h | 144 +++-
include/drm/drm_atomic_sro.h | 59 ++
include/drm/drm_atomic_sro_helper.h | 275 +++++++
include/drm/drm_bridge.h | 87 +++
include/drm/drm_connector.h | 69 ++
include/drm/drm_crtc.h | 69 ++
include/drm/drm_encoder.h | 18 +
include/drm/drm_mode_config.h | 18 +
include/drm/drm_modeset_helper_vtables.h | 23 +
include/drm/drm_plane.h | 69 ++
39 files changed, 3255 insertions(+), 113 deletions(-)
---
base-commit: ea61048876a7137897da26dac49ee234fb38a35a
change-id: 20250730-drm-state-readout-108f089c1c30
prerequisite-change-id: 20260310-drm-mode-config-init-1e1f52b745d0:v2
prerequisite-patch-id: 8831e320ca55e930e6dd8db8abfd2a79179fc1a0
prerequisite-patch-id: 5d2ae478dfb0a8b1eed30431b52a63141f1a3edb
prerequisite-patch-id: be3ef2f85cc3bba3ce65cbe4c1bf73b26c59b46c
prerequisite-patch-id: ad4de3b4f7bf5861d8e74d15042fb1d17cf6f071
prerequisite-patch-id: 6af92ef1aef1541ba0c504c3618612a89f5433a4
prerequisite-patch-id: d7b9200d7155e7ae2a76121adb50ce974aa78ddc
prerequisite-patch-id: 811a936fa6b38549807256e718b4c1faf49e90dd
prerequisite-patch-id: 3816a4bdc28e3353dba2811cc82d6680cf9ada11
prerequisite-patch-id: e156096dae812cab909877d7d614f56374652c6a
prerequisite-patch-id: fa0187e85c3587e7b28e411f2198b7c070793fbb
prerequisite-patch-id: f97b4088a1357121e4b35c4822839e45d952cba9
prerequisite-patch-id: 2e942d5540fc208b0c94f9f9215f85cc59dd6c1c
prerequisite-patch-id: 45ce20ef439a538b6c71c7aedb251bd62c882a11
prerequisite-patch-id: 86674e487ba650461e29c284308ff9ba321a48e4
prerequisite-patch-id: 1d7744840555f74f310c1d48642bfc755ac645c9
prerequisite-patch-id: b01716030f5f9b3cedb4a6096b2d4769f625741a
prerequisite-patch-id: 0372103622aa6006a3fe645b4c2eb2387d7d3b5a
prerequisite-patch-id: 24a0b772f6fc53c41892a37b52cba95bbd261ca2
prerequisite-patch-id: 80ec7eea600ad3be7b94a182e274695b7c5cf17f
prerequisite-patch-id: 273773ea001ab348b4e85b47b20b45f48d4c1cbc
Best regards,
--
Maxime Ripard <mripard@kernel.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 01/28] drm/atomic: Fix unused but set warning in state iterator macros
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 02/28] drm/atomic_helper: Skip over NULL private_obj pointers Maxime Ripard
` (15 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
A number of state iterator macros trigger a compiler warning if an
iterator parameter isn't used in the code block.
Add a similar workaround than in most other macros.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
include/drm/drm_atomic.h | 64 +++++++++++++++++++++++++++++++-----------------
1 file changed, 42 insertions(+), 22 deletions(-)
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index f03cd199aee7..b9e7281cfc97 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -946,13 +946,15 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
for ((__i) = 0; \
(__i) < (__state)->num_connector; \
(__i)++) \
for_each_if ((__state)->connectors[__i].ptr && \
((connector) = (__state)->connectors[__i].ptr, \
- (void)(connector) /* Only to avoid unused-but-set-variable warning */, \
- (old_connector_state) = (__state)->connectors[__i].old_state, \
- (new_connector_state) = (__state)->connectors[__i].new_state, 1))
+ (void)(connector) /* Only to avoid unused-but-set-variable warning */, \
+ (old_connector_state) = (__state)->connectors[__i].old_state, \
+ (void)(old_connector_state) /* Only to avoid unused-but-set-variable warning */, \
+ (new_connector_state) = (__state)->connectors[__i].new_state, \
+ (void)(new_connector_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_old_connector_in_state - iterate over all connectors in an atomic update
* @__state: &struct drm_atomic_state pointer
* @connector: &struct drm_connector iteration cursor
@@ -968,12 +970,13 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
for ((__i) = 0; \
(__i) < (__state)->num_connector; \
(__i)++) \
for_each_if ((__state)->connectors[__i].ptr && \
((connector) = (__state)->connectors[__i].ptr, \
- (void)(connector) /* Only to avoid unused-but-set-variable warning */, \
- (old_connector_state) = (__state)->connectors[__i].old_state, 1))
+ (void)(connector) /* Only to avoid unused-but-set-variable warning */, \
+ (old_connector_state) = (__state)->connectors[__i].old_state, \
+ (void)(old_connector_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_new_connector_in_state - iterate over all connectors in an atomic update
* @__state: &struct drm_atomic_state pointer
* @connector: &struct drm_connector iteration cursor
@@ -989,13 +992,13 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
for ((__i) = 0; \
(__i) < (__state)->num_connector; \
(__i)++) \
for_each_if ((__state)->connectors[__i].ptr && \
((connector) = (__state)->connectors[__i].ptr, \
- (void)(connector) /* Only to avoid unused-but-set-variable warning */, \
- (new_connector_state) = (__state)->connectors[__i].new_state, \
- (void)(new_connector_state) /* Only to avoid unused-but-set-variable warning */, 1))
+ (void)(connector) /* Only to avoid unused-but-set-variable warning */, \
+ (new_connector_state) = (__state)->connectors[__i].new_state, \
+ (void)(new_connector_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update
* @__state: &struct drm_atomic_state pointer
* @crtc: &struct drm_crtc iteration cursor
@@ -1012,14 +1015,14 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
(__i) < (__state)->dev->mode_config.num_crtc; \
(__i)++) \
for_each_if ((__state)->crtcs[__i].ptr && \
((crtc) = (__state)->crtcs[__i].ptr, \
(void)(crtc) /* Only to avoid unused-but-set-variable warning */, \
- (old_crtc_state) = (__state)->crtcs[__i].old_state, \
- (void)(old_crtc_state) /* Only to avoid unused-but-set-variable warning */, \
- (new_crtc_state) = (__state)->crtcs[__i].new_state, \
- (void)(new_crtc_state) /* Only to avoid unused-but-set-variable warning */, 1))
+ (old_crtc_state) = (__state)->crtcs[__i].old_state, \
+ (void)(old_crtc_state) /* Only to avoid unused-but-set-variable warning */, \
+ (new_crtc_state) = (__state)->crtcs[__i].new_state, \
+ (void)(new_crtc_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_old_crtc_in_state - iterate over all CRTCs in an atomic update
* @__state: &struct drm_atomic_state pointer
* @crtc: &struct drm_crtc iteration cursor
@@ -1035,11 +1038,12 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
(__i) < (__state)->dev->mode_config.num_crtc; \
(__i)++) \
for_each_if ((__state)->crtcs[__i].ptr && \
((crtc) = (__state)->crtcs[__i].ptr, \
(void)(crtc) /* Only to avoid unused-but-set-variable warning */, \
- (old_crtc_state) = (__state)->crtcs[__i].old_state, 1))
+ (old_crtc_state) = (__state)->crtcs[__i].old_state, \
+ (void)(old_crtc_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_new_crtc_in_state - iterate over all CRTCs in an atomic update
* @__state: &struct drm_atomic_state pointer
* @crtc: &struct drm_crtc iteration cursor
@@ -1120,12 +1124,14 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
(__i) < (__state)->dev->mode_config.num_total_plane; \
(__i)++) \
for_each_if ((__state)->planes[__i].ptr && \
((plane) = (__state)->planes[__i].ptr, \
(void)(plane) /* Only to avoid unused-but-set-variable warning */, \
- (old_plane_state) = (__state)->planes[__i].old_state,\
- (new_plane_state) = (__state)->planes[__i].new_state, 1))
+ (old_plane_state) = (__state)->planes[__i].old_state, \
+ (void)(old_plane_state) /* Only to avoid unused-but-set-variable warning */, \
+ (new_plane_state) = (__state)->planes[__i].new_state, \
+ (void)(new_plane_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_oldnew_plane_in_state_reverse - iterate over all planes in an atomic
* update in reverse order
* @__state: &struct drm_atomic_state pointer
@@ -1142,12 +1148,15 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
for ((__i) = ((__state)->dev->mode_config.num_total_plane - 1); \
(__i) >= 0; \
(__i)--) \
for_each_if ((__state)->planes[__i].ptr && \
((plane) = (__state)->planes[__i].ptr, \
- (old_plane_state) = (__state)->planes[__i].old_state,\
- (new_plane_state) = (__state)->planes[__i].new_state, 1))
+ (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
+ (old_plane_state) = (__state)->planes[__i].old_state, \
+ (void)(old_plane_state) /* Only to avoid unused-but-set-variable warning */, \
+ (new_plane_state) = (__state)->planes[__i].new_state, \
+ (void)(new_plane_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_new_plane_in_state_reverse - other than only tracking new state,
* it's the same as for_each_oldnew_plane_in_state_reverse
* @__state: &struct drm_atomic_state pointer
@@ -1159,11 +1168,13 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
for ((__i) = ((__state)->dev->mode_config.num_total_plane - 1); \
(__i) >= 0; \
(__i)--) \
for_each_if ((__state)->planes[__i].ptr && \
((plane) = (__state)->planes[__i].ptr, \
- (new_plane_state) = (__state)->planes[__i].new_state, 1))
+ (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
+ (new_plane_state) = (__state)->planes[__i].new_state, \
+ (void)(new_plane_state) /* Only to avoid unused-but-set-variable warning */, 1))
/**
* for_each_old_plane_in_state - iterate over all planes in an atomic update
* @__state: &struct drm_atomic_state pointer
* @plane: &struct drm_plane iteration cursor
@@ -1178,11 +1189,14 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
for ((__i) = 0; \
(__i) < (__state)->dev->mode_config.num_total_plane; \
(__i)++) \
for_each_if ((__state)->planes[__i].ptr && \
((plane) = (__state)->planes[__i].ptr, \
- (old_plane_state) = (__state)->planes[__i].old_state, 1))
+ (void)(plane) /* Only to avoid unused-but-set-variable warning */, \
+ (old_plane_state) = (__state)->planes[__i].old_state, \
+ (void)(old_plane_state) /* Only to avoid unused-but-set-variable warning */, 1))
+
/**
* for_each_new_plane_in_state - iterate over all planes in an atomic update
* @__state: &struct drm_atomic_state pointer
* @plane: &struct drm_plane iteration cursor
* @new_plane_state: &struct drm_plane_state iteration cursor for the new state
@@ -1216,12 +1230,15 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
*/
#define for_each_oldnew_private_obj_in_state(__state, obj, old_obj_state, new_obj_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->num_private_objs && \
((obj) = (__state)->private_objs[__i].ptr, \
+ (void)(obj) /* Only to avoid unused-but-set-variable warning */, \
(old_obj_state) = (__state)->private_objs[__i].old_state, \
- (new_obj_state) = (__state)->private_objs[__i].new_state, 1); \
+ (void)(old_obj_state) /* Only to avoid unused-but-set-variable warning */, \
+ (new_obj_state) = (__state)->private_objs[__i].new_state, \
+ (void)(new_obj_state) /* Only to avoid unused-but-set-variable warning */, 1); \
(__i)++)
/**
* for_each_old_private_obj_in_state - iterate over all private objects in an atomic update
* @__state: &struct drm_atomic_state pointer
@@ -1235,11 +1252,13 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
*/
#define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->num_private_objs && \
((obj) = (__state)->private_objs[__i].ptr, \
- (old_obj_state) = (__state)->private_objs[__i].old_state, 1); \
+ (void)(obj) /* Only to avoid unused-but-set-variable warning */, \
+ (old_obj_state) = (__state)->private_objs[__i].old_state, \
+ (void)(old_obj_state) /* Only to avoid unused-but-set-variable warning */, 1); \
(__i)++)
/**
* for_each_new_private_obj_in_state - iterate over all private objects in an atomic update
* @__state: &struct drm_atomic_state pointer
@@ -1254,11 +1273,12 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
#define for_each_new_private_obj_in_state(__state, obj, new_obj_state, __i) \
for ((__i) = 0; \
(__i) < (__state)->num_private_objs && \
((obj) = (__state)->private_objs[__i].ptr, \
(void)(obj) /* Only to avoid unused-but-set-variable warning */, \
- (new_obj_state) = (__state)->private_objs[__i].new_state, 1); \
+ (new_obj_state) = (__state)->private_objs[__i].new_state, \
+ (void)(new_obj_state) /* Only to avoid unused-but-set-variable warning */, 1); \
(__i)++)
/**
* drm_atomic_crtc_needs_modeset - compute combined modeset need
* @state: &drm_crtc_state for the CRTC
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 02/28] drm/atomic_helper: Skip over NULL private_obj pointers
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 01/28] drm/atomic: Fix unused but set warning in state iterator macros Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 03/28] drm/atomic_state_helper: Remove memset in __drm_atomic_helper_bridge_reset() Maxime Ripard
` (14 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Just like for connectors, drm_atomic_state contains an array of
drm_private_state, with the number of states found in num_private_objs.
If we are to clean up a state by hand for some reason before calling
drm_atomic_state_put(), chances are that the pointer to the affected
drm_private_obj and drm_private_states would have been cleared to avoid
any use-after-free.
However, since it's just an array, as we progress and free the items, we
can't update num_private_objs as we go since we would reduce the array
size, preventing us to remove the final elements.
And if the caller was to forget to update num_private_objs after it
iterated over the whole array, we're left with a (valid) array with a
non-zero number of NULL elements.
If we were to call drm_atomic_state_put() at this point, chances are
that drm_atomic_state_default_clear() would be called and it would
iterate over all those empty NULL items.
However, unlike what is found for connectors, crtcs and planes, we don't
test that our pointers are non-NULL before dereferencing them, leading
to a NULL pointer dereference.
Such callers should obviously be fixed, but there's no reason to not do
such a simple check, if only to be consistent.
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3bd52602fe30..84bc91886b4c 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -334,10 +334,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
}
for (i = 0; i < state->num_private_objs; i++) {
struct drm_private_obj *obj = state->private_objs[i].ptr;
+ if (!obj)
+ continue;
+
obj->funcs->atomic_destroy_state(obj,
state->private_objs[i].state_to_destroy);
state->private_objs[i].ptr = NULL;
state->private_objs[i].state_to_destroy = NULL;
state->private_objs[i].old_state = NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 03/28] drm/atomic_state_helper: Remove memset in __drm_atomic_helper_bridge_reset()
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 01/28] drm/atomic: Fix unused but set warning in state iterator macros Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 02/28] drm/atomic_helper: Skip over NULL private_obj pointers Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 04/28] drm/atomic: Convert drm_priv_to_bridge_state to container_of_const Maxime Ripard
` (13 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The general consensus is that reset helpers shouldn't call memset
directly because the object it initializes is supposed to have been
zeroed out.
Remove the memset call from
__drm_atomic_helper_bridge_reset() and document the expectation.
It should not have any impact on the current code base since there's
only two callers: drm_atomic_helper_bridge_reset() and
cdns-mhdp8546-core's cdns_mhdp_bridge_atomic_reset(), both allocating
the object using kzalloc_obj().
Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index c7eb3ce8c282..1a6f55329fee 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -952,15 +952,16 @@ EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state);
* @state: bridge state to initialize
*
* Initializes the bridge state to default values. This is meant to be called
* by the bridge &drm_bridge_funcs.atomic_reset hook for bridges that subclass
* the bridge state.
+ *
+ * The object @state points to is assumed to have been initialized to zero.
*/
void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
struct drm_bridge_state *state)
{
- memset(state, 0, sizeof(*state));
__drm_atomic_helper_private_obj_create_state(&bridge->base, &state->base);
state->bridge = bridge;
}
EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 04/28] drm/atomic: Convert drm_priv_to_bridge_state to container_of_const
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (2 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 03/28] drm/atomic_state_helper: Remove memset in __drm_atomic_helper_bridge_reset() Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 05/28] drm/atomic: Add drm_private_obj name Maxime Ripard
` (12 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
container_of_const is more flexible than container_of when
it comes to mixing pointers constness. Switch to it.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
include/drm/drm_atomic.h | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index b9e7281cfc97..537092d3ed16 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -1375,15 +1375,12 @@ struct drm_bridge_state {
* @output_bus_cfg: output bus configuration
*/
struct drm_bus_cfg output_bus_cfg;
};
-static inline struct drm_bridge_state *
-drm_priv_to_bridge_state(struct drm_private_state *priv)
-{
- return container_of(priv, struct drm_bridge_state, base);
-}
+#define drm_priv_to_bridge_state(priv) \
+ container_of_const(priv, struct drm_bridge_state, base)
struct drm_bridge_state *
drm_atomic_get_bridge_state(struct drm_atomic_state *state,
struct drm_bridge *bridge);
struct drm_bridge_state *
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 05/28] drm/atomic: Add drm_private_obj name
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (3 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 04/28] drm/atomic: Convert drm_priv_to_bridge_state to container_of_const Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 06/28] drm/bridge: Add drm_private_obj_is_bridge() Maxime Ripard
` (11 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
drm_private_obj does not carry a human-readable name, which makes
debug messages hard to interpret when multiple private objects are
registered on the same device.
Add a name field to drm_private_obj, passed through
drm_atomic_private_obj_init() and freed in
drm_atomic_private_obj_fini(). Update the existing callers to pass a
name.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 +
drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c | 8 ++++++++
drivers/gpu/drm/display/drm_dp_mst_topology.c | 2 +-
drivers/gpu/drm/display/drm_dp_tunnel.c | 1 +
drivers/gpu/drm/drm_atomic.c | 4 ++++
drivers/gpu/drm/drm_bridge.c | 3 ++-
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 1 +
drivers/gpu/drm/ingenic/ingenic-ipu.c | 1 +
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 +
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 1 +
drivers/gpu/drm/omapdrm/omap_drv.c | 1 +
drivers/gpu/drm/tegra/hub.c | 1 +
drivers/gpu/drm/vc4/vc4_kms.c | 3 +++
include/drm/drm_atomic.h | 7 ++++++-
include/drm/drm_bridge.h | 2 ++
15 files changed, 34 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index c2066319772b..d993f6e5f3e6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -5020,10 +5020,11 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
/* indicates support for immediate flip */
adev_to_drm(adev)->mode_config.async_page_flip = true;
drm_atomic_private_obj_init(adev_to_drm(adev),
&adev->dm.atomic_obj,
+ "amdgpu_dc_state",
&dm_atomic_state_funcs);
r = amdgpu_display_modeset_create_props(adev);
if (r)
return r;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
index 77b3f361091f..8a3c9fcf3844 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -64,10 +64,11 @@ static const struct drm_private_state_funcs komeda_layer_obj_funcs = {
static int komeda_layer_obj_add(struct komeda_kms_dev *kms,
struct komeda_layer *layer)
{
drm_atomic_private_obj_init(&kms->base, &layer->base.obj,
+ "komeda_layer",
&komeda_layer_obj_funcs);
return 0;
}
static struct drm_private_state *
@@ -117,10 +118,11 @@ static const struct drm_private_state_funcs komeda_scaler_obj_funcs = {
static int komeda_scaler_obj_add(struct komeda_kms_dev *kms,
struct komeda_scaler *scaler)
{
drm_atomic_private_obj_init(&kms->base,
&scaler->base.obj,
+ "komeda_scaler",
&komeda_scaler_obj_funcs);
return 0;
}
static struct drm_private_state *
@@ -169,10 +171,11 @@ static const struct drm_private_state_funcs komeda_compiz_obj_funcs = {
static int komeda_compiz_obj_add(struct komeda_kms_dev *kms,
struct komeda_compiz *compiz)
{
drm_atomic_private_obj_init(&kms->base, &compiz->base.obj,
+ "komeda_compiz",
&komeda_compiz_obj_funcs);
return 0;
}
@@ -223,10 +226,11 @@ static const struct drm_private_state_funcs komeda_splitter_obj_funcs = {
static int komeda_splitter_obj_add(struct komeda_kms_dev *kms,
struct komeda_splitter *splitter)
{
drm_atomic_private_obj_init(&kms->base,
&splitter->base.obj,
+ "komeda_splitter",
&komeda_splitter_obj_funcs);
return 0;
}
@@ -276,10 +280,11 @@ static const struct drm_private_state_funcs komeda_merger_obj_funcs = {
static int komeda_merger_obj_add(struct komeda_kms_dev *kms,
struct komeda_merger *merger)
{
drm_atomic_private_obj_init(&kms->base,
&merger->base.obj,
+ "komeda_merger",
&komeda_merger_obj_funcs);
return 0;
}
@@ -329,10 +334,11 @@ static const struct drm_private_state_funcs komeda_improc_obj_funcs = {
static int komeda_improc_obj_add(struct komeda_kms_dev *kms,
struct komeda_improc *improc)
{
drm_atomic_private_obj_init(&kms->base, &improc->base.obj,
+ "komeda_improc",
&komeda_improc_obj_funcs);
return 0;
}
@@ -382,10 +388,11 @@ static const struct drm_private_state_funcs komeda_timing_ctrlr_obj_funcs = {
static int komeda_timing_ctrlr_obj_add(struct komeda_kms_dev *kms,
struct komeda_timing_ctrlr *ctrlr)
{
drm_atomic_private_obj_init(&kms->base, &ctrlr->base.obj,
+ "komeda_timing_ctrlr",
&komeda_timing_ctrlr_obj_funcs);
return 0;
}
@@ -436,10 +443,11 @@ static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
struct komeda_pipeline *pipe)
{
drm_atomic_private_obj_init(&kms->base, &pipe->obj,
+ "komeda_pipeline",
&komeda_pipeline_obj_funcs);
return 0;
}
diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
index 8757972e8e24..7936bb7e0bf6 100644
--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
@@ -5762,11 +5762,11 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
mgr->aux = aux;
mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes;
mgr->max_payloads = max_payloads;
mgr->conn_base_id = conn_base_id;
- drm_atomic_private_obj_init(dev, &mgr->base,
+ drm_atomic_private_obj_init(dev, &mgr->base, "drm_dp_mst_topology",
&drm_dp_mst_topology_state_funcs);
return 0;
}
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
diff --git a/drivers/gpu/drm/display/drm_dp_tunnel.c b/drivers/gpu/drm/display/drm_dp_tunnel.c
index 6519b4244728..ff32ac855780 100644
--- a/drivers/gpu/drm/display/drm_dp_tunnel.c
+++ b/drivers/gpu/drm/display/drm_dp_tunnel.c
@@ -1599,10 +1599,11 @@ static bool init_group(struct drm_dp_tunnel_mgr *mgr, struct drm_dp_tunnel_group
group->mgr = mgr;
group->available_bw = -1;
INIT_LIST_HEAD(&group->tunnels);
drm_atomic_private_obj_init(mgr->dev, &group->base,
+ group->name,
&tunnel_group_funcs);
return true;
}
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 84bc91886b4c..0a9f5e9fc69b 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,10 +985,11 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
/**
* drm_atomic_private_obj_init - initialize private object
* @dev: DRM device this object will be attached to
* @obj: private object
+ * @name: human-readable name for debug messages
* @funcs: pointer to the struct of function pointers that identify the object
* type
*
* Initialize the private object, which can be embedded into any
* driver private object that needs its own atomic state.
@@ -996,17 +997,19 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
* RETURNS:
* Zero on success, error code on failure
*/
int drm_atomic_private_obj_init(struct drm_device *dev,
struct drm_private_obj *obj,
+ const char *name,
const struct drm_private_state_funcs *funcs)
{
memset(obj, 0, sizeof(*obj));
drm_modeset_lock_init(&obj->lock);
obj->dev = dev;
+ obj->name = kstrdup(name, GFP_KERNEL);
obj->funcs = funcs;
list_add_tail(&obj->head, &dev->mode_config.privobj_list);
return 0;
}
@@ -1021,10 +1024,11 @@ EXPORT_SYMBOL(drm_atomic_private_obj_init);
void
drm_atomic_private_obj_fini(struct drm_private_obj *obj)
{
list_del(&obj->head);
obj->funcs->atomic_destroy_state(obj, obj->state);
+ kfree(obj->name);
drm_modeset_lock_fini(&obj->lock);
}
EXPORT_SYMBOL(drm_atomic_private_obj_fini);
/**
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 986e4c79a4e0..44d53906e4c5 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -379,10 +379,11 @@ void *__devm_drm_bridge_alloc(struct device *dev, size_t size, size_t offset,
bridge = container + offset;
INIT_LIST_HEAD(&bridge->list);
bridge->container = container;
bridge->funcs = funcs;
+ bridge->name = devm_kasprintf(dev, GFP_KERNEL, "bridge-%s", dev_name(dev));
kref_init(&bridge->refcount);
err = devm_add_action_or_reset(dev, drm_bridge_put_void, bridge);
if (err)
return ERR_PTR(err);
@@ -586,11 +587,11 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
if (ret < 0)
goto err_reset_bridge;
}
if (drm_bridge_is_atomic(bridge))
- drm_atomic_private_obj_init(bridge->dev, &bridge->base,
+ drm_atomic_private_obj_init(bridge->dev, &bridge->base, bridge->name,
&drm_bridge_priv_state_funcs);
return 0;
err_reset_bridge:
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index 4068114adf8c..135d8b08f213 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -1400,10 +1400,11 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
dev_err(dev, "Unable to register clock notifier\n");
goto err_devclk_disable;
}
drm_atomic_private_obj_init(drm, &priv->private_obj,
+ "ingenic_drm",
&ingenic_drm_private_state_funcs);
ret = drmm_add_action_or_reset(drm, ingenic_drm_atomic_private_obj_fini,
&priv->private_obj);
if (ret)
diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c b/drivers/gpu/drm/ingenic/ingenic-ipu.c
index 34545b9c8c33..17a0e5dc6df0 100644
--- a/drivers/gpu/drm/ingenic/ingenic-ipu.c
+++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c
@@ -900,10 +900,11 @@ static int ingenic_ipu_bind(struct device *dev, struct device *master, void *d)
dev_err(dev, "Unable to prepare clock\n");
return err;
}
drm_atomic_private_obj_init(drm, &ipu->private_obj,
+ "ingenic_ipu_state",
&ingenic_ipu_private_state_funcs);
return 0;
}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 35f7af4743d7..f72b94a60e9d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1153,10 +1153,11 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
dev->mode_config.cursor_width = 512;
dev->mode_config.cursor_height = 512;
drm_atomic_private_obj_init(dpu_kms->dev, &dpu_kms->global_state,
+ "dpu_kms_global_state",
&dpu_kms_global_state_funcs);
atomic_set(&dpu_kms->bandwidth_ref, 0);
rc = pm_runtime_resume_and_get(&dpu_kms->pdev->dev);
diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
index 2d26b07b06f5..1177f53a85fc 100644
--- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
@@ -715,10 +715,11 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
int ret;
mdp5_kms->dev = dev;
drm_atomic_private_obj_init(mdp5_kms->dev, &mdp5_kms->glob_state,
+ "mdp5_global_state",
&mdp5_global_state_funcs);
/* we need to set a default rate before enabling. Set a safe
* rate first, then figure out hw revision, and then set a
* more optimal rate:
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index ae678696fbac..da7722e9b538 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -298,10 +298,11 @@ static const struct drm_private_state_funcs omap_global_state_funcs = {
static int omap_global_obj_init(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
drm_atomic_private_obj_init(dev, &priv->glob_obj,
+ "omap_global",
&omap_global_state_funcs);
return 0;
}
static void omap_global_obj_fini(struct omap_drm_private *priv)
diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c
index 10d993b8d043..94f9aa690f59 100644
--- a/drivers/gpu/drm/tegra/hub.c
+++ b/drivers/gpu/drm/tegra/hub.c
@@ -956,10 +956,11 @@ static int tegra_display_hub_init(struct host1x_client *client)
struct tegra_display_hub *hub = to_tegra_display_hub(client);
struct drm_device *drm = dev_get_drvdata(client->host);
struct tegra_drm *tegra = drm->dev_private;
drm_atomic_private_obj_init(drm, &hub->base,
+ "tegra_display_hub",
&tegra_display_hub_state_funcs);
tegra->hub = hub;
return 0;
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 264b5e80c24d..f6ac2a20576e 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -115,10 +115,11 @@ static void vc4_ctm_obj_fini(struct drm_device *dev, void *unused)
static int vc4_ctm_obj_init(struct vc4_dev *vc4)
{
drm_modeset_lock_init(&vc4->ctm_state_lock);
drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager,
+ "vc4_ctm",
&vc4_ctm_state_funcs);
return drmm_add_action_or_reset(&vc4->base, vc4_ctm_obj_fini, NULL);
}
@@ -755,10 +756,11 @@ static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused)
}
static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
{
drm_atomic_private_obj_init(&vc4->base, &vc4->load_tracker,
+ "vc4_load_tracker",
&vc4_load_tracker_state_funcs);
return drmm_add_action_or_reset(&vc4->base, vc4_load_tracker_obj_fini, NULL);
}
@@ -846,10 +848,11 @@ static void vc4_hvs_channels_obj_fini(struct drm_device *dev, void *unused)
}
static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4)
{
drm_atomic_private_obj_init(&vc4->base, &vc4->hvs_channels,
+ "vc4_hvs_channels",
&vc4_hvs_state_funcs);
return drmm_add_action_or_reset(&vc4->base, vc4_hvs_channels_obj_fini, NULL);
}
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 537092d3ed16..4f58289d3a34 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -354,10 +354,15 @@ struct drm_private_obj {
/**
* @dev: parent DRM device
*/
struct drm_device *dev;
+ /**
+ * @name: human-readable name for debug messages
+ */
+ const char *name;
+
/**
* @head: List entry used to attach a private object to a &drm_device
* (queued to &drm_mode_config.privobj_list).
*/
struct list_head head;
@@ -735,11 +740,11 @@ drm_atomic_get_new_colorop_state(struct drm_atomic_state *state,
struct drm_connector_state * __must_check
drm_atomic_get_connector_state(struct drm_atomic_state *state,
struct drm_connector *connector);
int drm_atomic_private_obj_init(struct drm_device *dev,
- struct drm_private_obj *obj,
+ struct drm_private_obj *obj, const char *name,
const struct drm_private_state_funcs *funcs);
void drm_atomic_private_obj_fini(struct drm_private_obj *obj);
struct drm_private_state * __must_check
drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index d6cd0f5af045..84b5517726c1 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1100,10 +1100,12 @@ enum drm_bridge_ops {
struct drm_bridge {
/** @base: inherit from &drm_private_object */
struct drm_private_obj base;
/** @dev: DRM device this bridge belongs to */
struct drm_device *dev;
+ /** @name: human-readable name for debug messages */
+ const char *name;
/** @encoder: encoder to which this bridge is connected */
struct drm_encoder *encoder;
/** @chain_node: used to form a bridge chain */
struct list_head chain_node;
/** @of_node: device node pointer to the bridge */
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 06/28] drm/bridge: Add drm_private_obj_is_bridge()
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (4 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 05/28] drm/atomic: Add drm_private_obj name Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 07/28] drm/bridge: Implement atomic_print_state Maxime Ripard
` (10 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The SRO readout helpers need to distinguish bridge-backed private
objects from other private objects, because bridges require special
readout ordering through the encoder bridge chains.
Add drm_private_obj_is_bridge() which checks whether a private
object's funcs pointer matches the bridge private state funcs.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_bridge.c | 15 +++++++++++++++
include/drm/drm_bridge.h | 2 ++
2 files changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 44d53906e4c5..5b8e171afbe5 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -512,10 +512,25 @@ static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
.atomic_create_state = drm_bridge_atomic_create_priv_state,
.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
};
+/**
+ * drm_private_obj_is_bridge - check if a private object backs a bridge
+ * @obj: private object to check
+ *
+ * RETURNS:
+ *
+ * True if @obj is the &drm_private_obj embedded in a &struct drm_bridge,
+ * false otherwise.
+ */
+bool drm_private_obj_is_bridge(struct drm_private_obj *obj)
+{
+ return obj->funcs && obj->funcs == &drm_bridge_priv_state_funcs;
+}
+EXPORT_SYMBOL(drm_private_obj_is_bridge);
+
static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
{
return bridge->funcs->atomic_reset != NULL;
}
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 84b5517726c1..425f3ca03d95 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1285,10 +1285,12 @@ static inline struct drm_bridge *
drm_priv_to_bridge(struct drm_private_obj *priv)
{
return container_of(priv, struct drm_bridge, base);
}
+bool drm_private_obj_is_bridge(struct drm_private_obj *obj);
+
bool drm_bridge_enter(struct drm_bridge *bridge, int *idx);
void drm_bridge_exit(int idx);
void drm_bridge_unplug(struct drm_bridge *bridge);
struct drm_bridge *drm_bridge_get(struct drm_bridge *bridge);
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 07/28] drm/bridge: Implement atomic_print_state
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (5 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 06/28] drm/bridge: Add drm_private_obj_is_bridge() Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 08/28] drm/atomic: Export drm_atomic_*_print_state Maxime Ripard
` (9 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard,
Laurent Pinchart
Bridges have some fields in their state worth printing, but we don't
provide an atomic_print_state implementation to show those fields.
Provide one.
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_bridge.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 5b8e171afbe5..fba440bddcb3 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -506,14 +506,35 @@ drm_bridge_atomic_create_priv_state(struct drm_private_obj *obj)
return ERR_CAST(state);
return &state->base;
}
+static void
+drm_bridge_atomic_print_priv_state(struct drm_printer *p,
+ const struct drm_private_state *s)
+{
+ const struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
+ struct drm_bridge *bridge = drm_priv_to_bridge(s->obj);
+
+ if (bridge->of_node)
+ drm_printf(p, "bridge: %ps (%pOFfc)\n", bridge->funcs, bridge->of_node);
+ else
+ drm_printf(p, "bridge: %ps\n", bridge->funcs);
+
+ drm_printf(p, "\tinput bus configuration:");
+ drm_printf(p, "\t\tcode: %04x", state->input_bus_cfg.format);
+ drm_printf(p, "\t\tflags: %08x", state->input_bus_cfg.flags);
+ drm_printf(p, "\toutput bus configuration:");
+ drm_printf(p, "\t\tcode: %04x", state->output_bus_cfg.format);
+ drm_printf(p, "\t\tflags: %08x", state->output_bus_cfg.flags);
+}
+
static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
.atomic_create_state = drm_bridge_atomic_create_priv_state,
.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
+ .atomic_print_state = drm_bridge_atomic_print_priv_state,
};
/**
* drm_private_obj_is_bridge - check if a private object backs a bridge
* @obj: private object to check
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 08/28] drm/atomic: Export drm_atomic_*_print_state
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (6 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 07/28] drm/bridge: Implement atomic_print_state Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 09/28] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
` (8 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The drm_atomic_plane_print_state(), drm_atomic_crtc_print_state(),
drm_atomic_connector_print_state(), and
drm_atomic_private_obj_print_state() functions are currently static.
The SRO infrastructure needs to call them from drm_atomic_sro.c to
print the readout state for debugging purposes. Make them available
by dropping the static qualifier and declaring them in drm_internal.h.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 16 ++++++++--------
drivers/gpu/drm/drm_internal.h | 12 ++++++++++++
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 0a9f5e9fc69b..c714a6e6e9ae 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -521,12 +521,12 @@ static int drm_atomic_crtc_check(const struct drm_crtc_state *old_crtc_state,
}
return 0;
}
-static void drm_atomic_crtc_print_state(struct drm_printer *p,
- const struct drm_crtc_state *state)
+void drm_atomic_crtc_print_state(struct drm_printer *p,
+ const struct drm_crtc_state *state)
{
struct drm_crtc *crtc = state->crtc;
drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
drm_printf(p, "\tenable=%d\n", state->enable);
@@ -916,12 +916,12 @@ static void drm_atomic_colorop_print_state(struct drm_printer *p,
}
drm_printf(p, "\tnext=%d\n", colorop->next ? colorop->next->base.id : 0);
}
-static void drm_atomic_plane_print_state(struct drm_printer *p,
- const struct drm_plane_state *state)
+void drm_atomic_plane_print_state(struct drm_printer *p,
+ const struct drm_plane_state *state)
{
struct drm_plane *plane = state->plane;
struct drm_rect src = drm_plane_state_src(state);
struct drm_rect dest = drm_plane_state_dest(state);
@@ -1402,12 +1402,12 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
return connector_state;
}
EXPORT_SYMBOL(drm_atomic_get_connector_state);
-static void drm_atomic_connector_print_state(struct drm_printer *p,
- const struct drm_connector_state *state)
+void drm_atomic_connector_print_state(struct drm_printer *p,
+ const struct drm_connector_state *state)
{
struct drm_connector *connector = state->connector;
drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
@@ -2048,12 +2048,12 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
return 0;
}
EXPORT_SYMBOL(__drm_atomic_helper_set_config);
-static void drm_atomic_private_obj_print_state(struct drm_printer *p,
- const struct drm_private_state *state)
+void drm_atomic_private_obj_print_state(struct drm_printer *p,
+ const struct drm_private_state *state)
{
struct drm_private_obj *obj = state->obj;
if (obj->funcs->atomic_print_state)
obj->funcs->atomic_print_state(p, state);
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index f893b1e3a596..91ce23f69ec4 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -38,18 +38,30 @@
struct dentry;
struct dma_buf;
struct iosys_map;
struct drm_connector;
struct drm_crtc;
+struct drm_crtc_state;
struct drm_framebuffer;
struct drm_gem_object;
struct drm_master;
struct drm_minor;
+struct drm_plane_state;
struct drm_prime_file_private;
struct drm_printer;
+struct drm_private_state;
struct drm_vblank_crtc;
+/* drm_atomic.c */
+void drm_atomic_plane_print_state(struct drm_printer *p,
+ const struct drm_plane_state *state);
+void drm_atomic_crtc_print_state(struct drm_printer *p,
+ const struct drm_crtc_state *state);
+void drm_atomic_connector_print_state(struct drm_printer *p,
+ const struct drm_connector_state *state);
+void drm_atomic_private_obj_print_state(struct drm_printer *p,
+ const struct drm_private_state *state);
/* drm_client_event.c */
#if defined(CONFIG_DRM_CLIENT)
void drm_client_debugfs_init(struct drm_device *dev);
#else
static inline void drm_client_debugfs_init(struct drm_device *dev)
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 09/28] drm/atomic: Only call atomic_destroy_state on a !NULL pointer
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (7 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 08/28] drm/atomic: Export drm_atomic_*_print_state Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 10/28] drm/atomic_sro: Create drm_atomic_sro_state container Maxime Ripard
` (7 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard,
Laurent Pinchart
The drm_atomic_state structure is freed through the
drm_atomic_state_put() function, that eventually calls
drm_atomic_state_default_clear() by default when there's no active
users of that state.
It then iterates over all objects with a state, and will call the
atomic_destroy_state callback on the state pointer. The state pointer is
mostly used these days to point to which of the old or new state needs
to be freed, depending on whether the state was committed or not.
So it all makes sense.
However, with the hardware state readout support approaching, we might
have a state, with multiple objects in it, but no state to free because
we want them to persist. In such a case, the state pointer is going to
be NULL, and thus we'll end up with NULL pointer dereference.
Test if the state pointer is non-NULL before calling
atomic_destroy_state on it.
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index c714a6e6e9ae..6449a4fd4ae0 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -274,12 +274,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_connector *connector = state->connectors[i].ptr;
if (!connector)
continue;
- connector->funcs->atomic_destroy_state(connector,
- state->connectors[i].state_to_destroy);
+ if (state->connectors[i].state_to_destroy)
+ connector->funcs->atomic_destroy_state(connector,
+ state->connectors[i].state_to_destroy);
+
state->connectors[i].ptr = NULL;
state->connectors[i].state_to_destroy = NULL;
state->connectors[i].old_state = NULL;
state->connectors[i].new_state = NULL;
drm_connector_put(connector);
@@ -289,12 +291,13 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_crtc *crtc = state->crtcs[i].ptr;
if (!crtc)
continue;
- crtc->funcs->atomic_destroy_state(crtc,
- state->crtcs[i].state_to_destroy);
+ if (state->crtcs[i].state_to_destroy)
+ crtc->funcs->atomic_destroy_state(crtc,
+ state->crtcs[i].state_to_destroy);
state->crtcs[i].ptr = NULL;
state->crtcs[i].state_to_destroy = NULL;
state->crtcs[i].old_state = NULL;
state->crtcs[i].new_state = NULL;
@@ -309,12 +312,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_plane *plane = state->planes[i].ptr;
if (!plane)
continue;
- plane->funcs->atomic_destroy_state(plane,
- state->planes[i].state_to_destroy);
+ if (state->planes[i].state_to_destroy)
+ plane->funcs->atomic_destroy_state(plane,
+ state->planes[i].state_to_destroy);
+
state->planes[i].ptr = NULL;
state->planes[i].state_to_destroy = NULL;
state->planes[i].old_state = NULL;
state->planes[i].new_state = NULL;
}
@@ -337,12 +342,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
struct drm_private_obj *obj = state->private_objs[i].ptr;
if (!obj)
continue;
- obj->funcs->atomic_destroy_state(obj,
- state->private_objs[i].state_to_destroy);
+ if (state->private_objs[i].state_to_destroy)
+ obj->funcs->atomic_destroy_state(obj,
+ state->private_objs[i].state_to_destroy);
+
state->private_objs[i].ptr = NULL;
state->private_objs[i].state_to_destroy = NULL;
state->private_objs[i].old_state = NULL;
state->private_objs[i].new_state = NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 10/28] drm/atomic_sro: Create drm_atomic_sro_state container
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (8 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 09/28] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 11/28] drm/atomic_sro: Create kernel parameter to force or disable readout Maxime Ripard
` (6 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The SRO infrastructure needs a state container to collect the readout
states for all KMS objects. Unlike drm_atomic_state which tracks old
and new states for atomic commits, this container only holds a single
state per object: the one read out from the hardware.
Create struct drm_atomic_sro_state with arrays for planes, CRTCs,
connectors, and private objects, along with accessors to get and set
individual object states within it.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/drm_atomic_sro.c | 424 +++++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic_sro.h | 51 +++++
3 files changed, 476 insertions(+)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e97faabcd783..64705ac96bd1 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -32,10 +32,11 @@ endif
# Enable -Werror in CI and development
subdir-ccflags-$(CONFIG_DRM_WERROR) += -Werror
drm-y := \
drm_atomic.o \
+ drm_atomic_sro.o \
drm_atomic_uapi.o \
drm_auth.o \
drm_blend.o \
drm_bridge.o \
drm_cache.o \
diff --git a/drivers/gpu/drm/drm_atomic_sro.c b/drivers/gpu/drm/drm_atomic_sro.c
new file mode 100644
index 000000000000..177b97d451f5
--- /dev/null
+++ b/drivers/gpu/drm/drm_atomic_sro.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_sro.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_print.h>
+#include <linux/module.h>
+
+#include "drm_internal.h"
+#include "drm_crtc_internal.h"
+
+struct __drm_atomic_sro_plane {
+ struct drm_plane *ptr;
+ struct drm_plane_state *state;
+};
+
+struct __drm_atomic_sro_crtc {
+ struct drm_crtc *ptr;
+ struct drm_crtc_state *state;
+};
+
+struct __drm_atomic_sro_connector {
+ struct drm_connector *ptr;
+ struct drm_connector_state *state;
+};
+
+struct __drm_atomic_sro_private_obj {
+ struct drm_private_obj *ptr;
+ struct drm_private_state *state;
+};
+
+struct drm_atomic_sro_state {
+ struct drm_device *dev;
+ struct __drm_atomic_sro_plane *planes;
+ struct __drm_atomic_sro_crtc *crtcs;
+ struct __drm_atomic_sro_connector *connectors;
+ struct __drm_atomic_sro_private_obj *private_objs;
+ unsigned int num_private_objs;
+};
+
+static unsigned int count_private_obj(struct drm_device *dev)
+{
+ struct drm_mode_config *config = &dev->mode_config;
+ struct drm_private_obj *obj;
+ unsigned int count = 0;
+
+ list_for_each_entry(obj, &config->privobj_list, head)
+ count++;
+
+ return count;
+}
+
+/**
+ * drm_atomic_sro_state_get_device - get the DRM device from an SRO state
+ * @state: SRO state
+ *
+ * RETURNS:
+ *
+ * The &struct drm_device associated with the SRO state.
+ */
+struct drm_device *
+drm_atomic_sro_state_get_device(struct drm_atomic_sro_state *state)
+{
+ return state->dev;
+}
+
+static int drm_atomic_sro_state_init(struct drm_device *dev,
+ struct drm_atomic_sro_state *state)
+{
+ state->planes =
+ kzalloc_objs(*state->planes, dev->mode_config.num_total_plane);
+ if (!state->planes)
+ return -ENOMEM;
+
+ state->crtcs = kzalloc_objs(*state->crtcs, dev->mode_config.num_crtc);
+ if (!state->crtcs)
+ return -ENOMEM;
+
+ state->connectors = kzalloc_objs(*state->connectors,
+ dev->mode_config.num_connector);
+ if (!state->connectors)
+ return -ENOMEM;
+
+ state->private_objs =
+ kzalloc_objs(*state->private_objs, count_private_obj(dev));
+ if (!state->private_objs)
+ return -ENOMEM;
+ state->num_private_objs = 0;
+
+ drm_dev_get(dev);
+ state->dev = dev;
+
+ return 0;
+}
+
+/**
+ * drm_atomic_sro_state_alloc - allocate an SRO state container
+ * @dev: DRM device to allocate the state for
+ *
+ * Allocates and initializes a &struct drm_atomic_sro_state that can hold
+ * readout states for all KMS objects on @dev.
+ *
+ * The returned state must be freed with drm_atomic_sro_state_free().
+ *
+ * RETURNS:
+ *
+ * A new &struct drm_atomic_sro_state on success, an error pointer on
+ * failure.
+ */
+struct drm_atomic_sro_state *drm_atomic_sro_state_alloc(struct drm_device *dev)
+{
+ struct drm_atomic_sro_state *state;
+ int ret;
+
+ state = kzalloc_obj(*state);
+ if (!state)
+ return ERR_PTR(-EINVAL);
+
+ ret = drm_atomic_sro_state_init(dev, state);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_sro_state_alloc);
+
+/**
+ * drm_atomic_sro_state_free - free an SRO state container
+ * @state: SRO state to free
+ *
+ * Frees a &struct drm_atomic_sro_state previously allocated with
+ * drm_atomic_sro_state_alloc(). Any states that have not been
+ * installed via drm_atomic_sro_install_state() are also freed.
+ */
+void drm_atomic_sro_state_free(struct drm_atomic_sro_state *state)
+{
+ struct drm_device *dev = state->dev;
+ unsigned int i;
+
+ for (i = 0; i < state->num_private_objs; i++) {
+ struct drm_private_obj *obj = state->private_objs[i].ptr;
+ struct drm_private_state *obj_state = state->private_objs[i].state;
+
+ if (!obj || !obj_state)
+ continue;
+
+ obj->funcs->atomic_destroy_state(obj, obj_state);
+ state->private_objs[i].state = NULL;
+ state->private_objs[i].ptr = NULL;
+ }
+
+ kfree(state->private_objs);
+
+ for (i = 0; i < state->dev->mode_config.num_connector; i++) {
+ struct drm_connector *conn = state->connectors[i].ptr;
+ struct drm_connector_state *conn_state =
+ state->connectors[i].state;
+
+ if (!conn || !conn_state)
+ continue;
+
+ conn->funcs->atomic_destroy_state(conn, conn_state);
+ state->connectors[i].state = NULL;
+ state->connectors[i].ptr = NULL;
+ drm_connector_put(conn);
+ }
+
+ kfree(state->connectors);
+
+ for (i = 0; i < state->dev->mode_config.num_crtc; i++) {
+ struct drm_crtc *crtc = state->crtcs[i].ptr;
+ struct drm_crtc_state *crtc_state =
+ state->crtcs[i].state;
+
+ if (!crtc || !crtc_state)
+ continue;
+
+ crtc->funcs->atomic_destroy_state(crtc, crtc_state);
+ state->crtcs[i].state = NULL;
+ state->crtcs[i].ptr = NULL;
+ }
+
+ kfree(state->crtcs);
+
+ for (i = 0; i < state->dev->mode_config.num_total_plane; i++) {
+ struct drm_plane *plane = state->planes[i].ptr;
+ struct drm_plane_state *plane_state =
+ state->planes[i].state;
+
+ if (!plane || !plane_state)
+ continue;
+
+ plane->funcs->atomic_destroy_state(plane, plane_state);
+ state->planes[i].state = NULL;
+ state->planes[i].ptr = NULL;
+ }
+
+ kfree(state->planes);
+ kfree(state);
+
+ drm_dev_put(dev);
+}
+EXPORT_SYMBOL(drm_atomic_sro_state_free);
+
+/**
+ * drm_atomic_sro_state_print - prints drm atomic SRO state
+ * @state: SRO state to print
+ * @p: drm printer
+ *
+ * This function prints the SRO state snapshot using the drm printer which is
+ * passed to it. This snapshot can be used for debugging purposes.
+ */
+void drm_atomic_sro_state_print(const struct drm_atomic_sro_state *state,
+ struct drm_printer *p)
+{
+ struct drm_mode_config *config = &state->dev->mode_config;
+ int i;
+
+ if (!p) {
+ drm_err(state->dev, "invalid drm printer\n");
+ return;
+ }
+
+ drm_dbg_atomic(state->dev, "Printing readout state %p\n", state);
+
+ for (i = 0; i < config->num_total_plane; i++) {
+ struct drm_plane_state *plane_state = state->planes[i].state;
+
+ drm_atomic_plane_print_state(p, plane_state);
+ }
+
+ for (i = 0; i < config->num_crtc; i++) {
+ struct drm_crtc_state *crtc_state = state->crtcs[i].state;
+
+ drm_atomic_crtc_print_state(p, crtc_state);
+ }
+
+ for (i = 0; i < config->num_connector; i++) {
+ struct drm_connector_state *conn_state = state->connectors[i].state;
+
+ drm_atomic_connector_print_state(p, conn_state);
+ }
+
+ for (i = 0; i < state->num_private_objs; i++) {
+ struct drm_private_state *obj_state = state->private_objs[i].state;
+
+ drm_atomic_private_obj_print_state(p, obj_state);
+ }
+}
+EXPORT_SYMBOL(drm_atomic_sro_state_print);
+
+/**
+ * drm_atomic_sro_get_plane_state - get the plane state from an SRO state
+ * @state: SRO state container
+ * @plane: plane to get the state for
+ *
+ * RETURNS:
+ *
+ * The &struct drm_plane_state for @plane, or NULL if not yet read out.
+ */
+struct drm_plane_state *
+drm_atomic_sro_get_plane_state(struct drm_atomic_sro_state *state,
+ struct drm_plane *plane)
+{
+ unsigned int index = drm_plane_index(plane);
+
+ return state->planes[index].state;
+};
+EXPORT_SYMBOL(drm_atomic_sro_get_plane_state);
+
+/**
+ * drm_atomic_sro_set_plane_state - store a plane state into an SRO state
+ * @state: SRO state container
+ * @plane: plane the state belongs to
+ * @plane_state: plane state to store
+ */
+void drm_atomic_sro_set_plane_state(struct drm_atomic_sro_state *state,
+ struct drm_plane *plane,
+ struct drm_plane_state *plane_state)
+{
+ unsigned int index = drm_plane_index(plane);
+
+ state->planes[index].ptr = plane;
+ state->planes[index].state = plane_state;
+
+ drm_dbg_atomic(plane->dev,
+ "Added [PLANE:%d:%s] %p state to readout state %p\n",
+ plane->base.id, plane->name, plane_state, state);
+}
+EXPORT_SYMBOL(drm_atomic_sro_set_plane_state);
+
+/**
+ * drm_atomic_sro_get_crtc_state - get the CRTC state from an SRO state
+ * @state: SRO state container
+ * @crtc: CRTC to get the state for
+ *
+ * RETURNS:
+ *
+ * The &struct drm_crtc_state for @crtc, or NULL if not yet read out.
+ */
+struct drm_crtc_state *
+drm_atomic_sro_get_crtc_state(struct drm_atomic_sro_state *state,
+ struct drm_crtc *crtc)
+{
+ unsigned int index = drm_crtc_index(crtc);
+
+ return state->crtcs[index].state;
+};
+EXPORT_SYMBOL(drm_atomic_sro_get_crtc_state);
+
+/**
+ * drm_atomic_sro_set_crtc_state - store a CRTC state into an SRO state
+ * @state: SRO state container
+ * @crtc: CRTC the state belongs to
+ * @crtc_state: CRTC state to store
+ */
+void drm_atomic_sro_set_crtc_state(struct drm_atomic_sro_state *state,
+ struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ unsigned int index = drm_crtc_index(crtc);
+
+ state->crtcs[index].ptr = crtc;
+ state->crtcs[index].state = crtc_state;
+
+ drm_dbg_atomic(state->dev,
+ "Added [CRTC:%d:%s] %p state to readout state %p\n",
+ crtc->base.id, crtc->name, crtc_state, state);
+}
+EXPORT_SYMBOL(drm_atomic_sro_set_crtc_state);
+
+/**
+ * drm_atomic_sro_get_connector_state - get the connector state from an SRO state
+ * @state: SRO state container
+ * @connector: connector to get the state for
+ *
+ * RETURNS:
+ *
+ * The &struct drm_connector_state for @connector, or NULL if not yet
+ * read out.
+ */
+struct drm_connector_state *
+drm_atomic_sro_get_connector_state(struct drm_atomic_sro_state *state,
+ struct drm_connector *connector)
+{
+ unsigned int index = drm_connector_index(connector);
+
+ return state->connectors[index].state;
+};
+EXPORT_SYMBOL(drm_atomic_sro_get_connector_state);
+
+/**
+ * drm_atomic_sro_set_connector_state - store a connector state into an SRO state
+ * @state: SRO state container
+ * @conn: connector the state belongs to
+ * @conn_state: connector state to store
+ *
+ * Takes a reference on @conn which is released when the state is
+ * installed or freed.
+ */
+void drm_atomic_sro_set_connector_state(struct drm_atomic_sro_state *state,
+ struct drm_connector *conn,
+ struct drm_connector_state *conn_state)
+{
+ unsigned int index = drm_connector_index(conn);
+
+ drm_connector_get(conn);
+ state->connectors[index].ptr = conn;
+ state->connectors[index].state = conn_state;
+
+ drm_dbg_atomic(conn->dev,
+ "Added [CONNECTOR:%d:%s] %p state to readout state %p\n",
+ conn->base.id, conn->name, conn_state, state);
+}
+EXPORT_SYMBOL(drm_atomic_sro_set_connector_state);
+
+/**
+ * drm_atomic_sro_get_private_obj_state - get a private object state from an SRO state
+ * @state: SRO state container
+ * @obj: private object to get the state for
+ *
+ * RETURNS:
+ *
+ * The &struct drm_private_state for @obj, or NULL if not yet read out.
+ */
+struct drm_private_state *
+drm_atomic_sro_get_private_obj_state(struct drm_atomic_sro_state *state,
+ struct drm_private_obj *obj)
+{
+ unsigned int i;
+
+ for (i = 0; i < state->num_private_objs; i++)
+ if (obj == state->private_objs[i].ptr)
+ return state->private_objs[i].state;
+
+ return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_sro_get_private_obj_state);
+
+/**
+ * drm_atomic_sro_set_private_obj_state - store a private object state into an SRO state
+ * @state: SRO state container
+ * @obj: private object the state belongs to
+ * @obj_state: private object state to store
+ */
+void drm_atomic_sro_set_private_obj_state(struct drm_atomic_sro_state *state,
+ struct drm_private_obj *obj,
+ struct drm_private_state *obj_state)
+{
+ unsigned int index = state->num_private_objs;
+
+ state->private_objs[index].ptr = obj;
+ state->private_objs[index].state = obj_state;
+ state->num_private_objs += 1;
+
+ drm_dbg_atomic(state->dev,
+ "Added new private object %p state %p to readout state %p\n", obj,
+ obj_state, state);
+}
+EXPORT_SYMBOL(drm_atomic_sro_set_private_obj_state);
diff --git a/include/drm/drm_atomic_sro.h b/include/drm/drm_atomic_sro.h
new file mode 100644
index 000000000000..5a9333a05796
--- /dev/null
+++ b/include/drm/drm_atomic_sro.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef DRM_ATOMIC_SRO_H_
+#define DRM_ATOMIC_SRO_H_
+
+struct drm_atomic_sro_state;
+struct drm_connector;
+struct drm_connector_state;
+struct drm_crtc;
+struct drm_crtc_state;
+struct drm_device;
+struct drm_plane;
+struct drm_plane_state;
+struct drm_printer;
+struct drm_private_obj;
+struct drm_private_state;
+
+struct drm_atomic_sro_state *drm_atomic_sro_state_alloc(struct drm_device *dev);
+void drm_atomic_sro_state_free(struct drm_atomic_sro_state *state);
+void drm_atomic_sro_state_print(const struct drm_atomic_sro_state *state,
+ struct drm_printer *p);
+
+struct drm_device *
+drm_atomic_sro_state_get_device(struct drm_atomic_sro_state *state);
+
+struct drm_plane_state *
+drm_atomic_sro_get_plane_state(struct drm_atomic_sro_state *state,
+ struct drm_plane *plane);
+void drm_atomic_sro_set_plane_state(struct drm_atomic_sro_state *state,
+ struct drm_plane *plane,
+ struct drm_plane_state *plane_state);
+struct drm_crtc_state *
+drm_atomic_sro_get_crtc_state(struct drm_atomic_sro_state *state,
+ struct drm_crtc *crtc);
+void drm_atomic_sro_set_crtc_state(struct drm_atomic_sro_state *state,
+ struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state);
+struct drm_connector_state *
+drm_atomic_sro_get_connector_state(struct drm_atomic_sro_state *state,
+ struct drm_connector *connector);
+void drm_atomic_sro_set_connector_state(struct drm_atomic_sro_state *state,
+ struct drm_connector *conn,
+ struct drm_connector_state *conn_state);
+struct drm_private_state *
+drm_atomic_sro_get_private_obj_state(struct drm_atomic_sro_state *state,
+ struct drm_private_obj *private_obj);
+void drm_atomic_sro_set_private_obj_state(struct drm_atomic_sro_state *state,
+ struct drm_private_obj *obj,
+ struct drm_private_state *obj_state);
+
+#endif /* DRM_ATOMIC_SRO_H_ */
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 11/28] drm/atomic_sro: Create kernel parameter to force or disable readout
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (9 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 10/28] drm/atomic_sro: Create drm_atomic_sro_state container Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 12/28] drm/atomic_sro: Add atomic state readout infrastructure Maxime Ripard
` (5 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The hardware state readout is useful, but might need to be disabled
in case of bugs, or its checks relaxed during development when not
all hooks are implemented yet.
Add a module parameter to control the readout behavior: it can be
disabled entirely, or the checks for missing compare or readout hooks
can be skipped independently.
Suggested-by: Simona Vetter <simona@ffwll.ch>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_sro.c | 36 ++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic_sro.h | 2 ++
2 files changed, 38 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_sro.c b/drivers/gpu/drm/drm_atomic_sro.c
index 177b97d451f5..a46f06e75c4e 100644
--- a/drivers/gpu/drm/drm_atomic_sro.c
+++ b/drivers/gpu/drm/drm_atomic_sro.c
@@ -11,10 +11,46 @@
#include <linux/module.h>
#include "drm_internal.h"
#include "drm_crtc_internal.h"
+enum drm_atomic_readout_status {
+ DRM_ATOMIC_READOUT_DISABLED = 0,
+ DRM_ATOMIC_READOUT_ENABLED,
+ DRM_ATOMIC_READOUT_SKIP_MISSING_COMPARE,
+ DRM_ATOMIC_READOUT_SKIP_MISSING_READOUT,
+};
+
+static unsigned int atomic_readout = DRM_ATOMIC_READOUT_ENABLED;
+module_param_unsafe(atomic_readout, uint, 0);
+MODULE_PARM_DESC(atomic_readout,
+ "Enable Hardware State Readout (0 = disabled, 1 = enabled, 2 = ignore missing compares, 3 = ignore missing readouts and compares, default = 1)");
+
+/**
+ * drm_atomic_sro_device_can_readout - check if a device supports hardware state readout
+ * @dev: DRM device to check
+ *
+ * Verifies that the device is an atomic driver, that readout is
+ * enabled, and that all KMS objects implement the relevant hooks.
+ *
+ * RETURNS:
+ *
+ * True if the device supports full hardware state readout, false
+ * otherwise.
+ */
+bool drm_atomic_sro_device_can_readout(struct drm_device *dev)
+{
+ if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
+ return false;
+
+ if (atomic_readout == DRM_ATOMIC_READOUT_DISABLED)
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL(drm_atomic_sro_device_can_readout);
+
struct __drm_atomic_sro_plane {
struct drm_plane *ptr;
struct drm_plane_state *state;
};
diff --git a/include/drm/drm_atomic_sro.h b/include/drm/drm_atomic_sro.h
index 5a9333a05796..6e5262384c71 100644
--- a/include/drm/drm_atomic_sro.h
+++ b/include/drm/drm_atomic_sro.h
@@ -13,10 +13,12 @@ struct drm_plane;
struct drm_plane_state;
struct drm_printer;
struct drm_private_obj;
struct drm_private_state;
+bool drm_atomic_sro_device_can_readout(struct drm_device *dev);
+
struct drm_atomic_sro_state *drm_atomic_sro_state_alloc(struct drm_device *dev);
void drm_atomic_sro_state_free(struct drm_atomic_sro_state *state);
void drm_atomic_sro_state_print(const struct drm_atomic_sro_state *state,
struct drm_printer *p);
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 12/28] drm/atomic_sro: Add atomic state readout infrastructure
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (10 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 11/28] drm/atomic_sro: Create kernel parameter to force or disable readout Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 13/28] drm/atomic_sro: Add function to install state into drm objects Maxime Ripard
` (4 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
In order to enable drivers to read their initial state from the
hardware, each KMS object needs a hook to fill a pre-allocated state
from the hardware registers.
Introduce the atomic_sro_readout_state hook in every KMS object funcs
vtable: drm_crtc_funcs, drm_plane_funcs, drm_connector_funcs,
drm_bridge_funcs, and drm_private_state_funcs.
Also introduce the drm_mode_config_funcs.atomic_sro_readout_state and
drm_mode_config_helper_funcs.atomic_sro_build_state hooks, which are the
top-level entry points for drivers and helpers respectively.
Finally, add drm_atomic_sro_can_readout() to verify that all objects on
a device implement the readout hook, and wire it into
drm_atomic_sro_device_can_readout().
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_sro.c | 59 ++++++++++++++++++++++++++++++++
include/drm/drm_atomic.h | 25 ++++++++++++++
include/drm/drm_bridge.h | 31 +++++++++++++++++
include/drm/drm_connector.h | 26 ++++++++++++++
include/drm/drm_crtc.h | 26 ++++++++++++++
include/drm/drm_mode_config.h | 18 ++++++++++
include/drm/drm_modeset_helper_vtables.h | 23 +++++++++++++
include/drm/drm_plane.h | 26 ++++++++++++++
8 files changed, 234 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_sro.c b/drivers/gpu/drm/drm_atomic_sro.c
index a46f06e75c4e..3eb22c654973 100644
--- a/drivers/gpu/drm/drm_atomic_sro.c
+++ b/drivers/gpu/drm/drm_atomic_sro.c
@@ -4,10 +4,11 @@
#include <drm/drm_atomic_sro.h>
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_drv.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <linux/module.h>
#include "drm_internal.h"
@@ -23,10 +24,62 @@ enum drm_atomic_readout_status {
static unsigned int atomic_readout = DRM_ATOMIC_READOUT_ENABLED;
module_param_unsafe(atomic_readout, uint, 0);
MODULE_PARM_DESC(atomic_readout,
"Enable Hardware State Readout (0 = disabled, 1 = enabled, 2 = ignore missing compares, 3 = ignore missing readouts and compares, default = 1)");
+static bool drm_atomic_sro_can_readout(struct drm_device *dev)
+{
+ struct drm_crtc *crtc;
+ struct drm_plane *plane;
+ struct drm_connector *connector;
+ struct drm_private_obj *privobj;
+ struct drm_connector_list_iter conn_iter;
+
+ if (atomic_readout == DRM_ATOMIC_READOUT_SKIP_MISSING_READOUT)
+ return true;
+
+ if (!dev->mode_config.funcs->atomic_sro_readout_state)
+ return false;
+
+ drm_for_each_privobj(privobj, dev) {
+ if (!privobj->funcs->atomic_sro_readout_state) {
+ drm_dbg_atomic(dev,
+ "Private object %s missing readout callback",
+ privobj->name);
+ return false;
+ }
+ }
+
+ drm_for_each_plane(plane, dev) {
+ if (!plane->funcs->atomic_sro_readout_state) {
+ drm_dbg_atomic(dev, "Plane %s missing readout callback",
+ plane->name);
+ return false;
+ }
+ }
+
+ drm_for_each_crtc(crtc, dev) {
+ if (!crtc->funcs->atomic_sro_readout_state) {
+ drm_dbg_atomic(dev, "CRTC %s missing readout callback",
+ crtc->name);
+ return false;
+ }
+ }
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ if (!connector->funcs->atomic_sro_readout_state) {
+ drm_dbg_atomic(dev, "Connector %s missing readout callback",
+ connector->name);
+ return false;
+ }
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return true;
+}
+
/**
* drm_atomic_sro_device_can_readout - check if a device supports hardware state readout
* @dev: DRM device to check
*
* Verifies that the device is an atomic driver, that readout is
@@ -37,16 +90,22 @@ MODULE_PARM_DESC(atomic_readout,
* True if the device supports full hardware state readout, false
* otherwise.
*/
bool drm_atomic_sro_device_can_readout(struct drm_device *dev)
{
+ bool ret;
+
if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
return false;
if (atomic_readout == DRM_ATOMIC_READOUT_DISABLED)
return false;
+ ret = drm_atomic_sro_can_readout(dev);
+ if (!ret)
+ return false;
+
return true;
}
EXPORT_SYMBOL(drm_atomic_sro_device_can_readout);
struct __drm_atomic_sro_plane {
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 4f58289d3a34..554dde45b799 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -293,10 +293,35 @@ struct drm_private_state_funcs {
* Frees the private object state created with @atomic_duplicate_state.
*/
void (*atomic_destroy_state)(struct drm_private_obj *obj,
struct drm_private_state *state);
+ /**
+ * @atomic_sro_readout_state:
+ *
+ * Initializes @obj_state to reflect the current hardware state
+ * of the private object.
+ *
+ * It is meant to be used by drivers that want to implement
+ * flicker-free boot (also called fastboot by i915) and allows
+ * to initialize the atomic state from the hardware state left
+ * by the firmware.
+ *
+ * It is used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * This hook is mandatory for drivers implementing SRO, but can
+ * be left unassigned otherwise.
+ *
+ * RETURNS:
+ *
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*atomic_sro_readout_state)(struct drm_private_obj *obj,
+ struct drm_atomic_sro_state *state,
+ struct drm_private_state *obj_state);
+
/**
* @atomic_print_state:
*
* If driver subclasses &struct drm_private_state, it should implement
* this optional hook for printing additional driver specific state.
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 425f3ca03d95..e0f9b7e6353a 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -373,10 +373,41 @@ struct drm_bridge_funcs {
* The @atomic_post_disable callback is optional.
*/
void (*atomic_post_disable)(struct drm_bridge *bridge,
struct drm_atomic_state *state);
+ /**
+ * @atomic_sro_readout_state:
+ *
+ * Initializes @bridge_state to reflect the current hardware
+ * state of the bridge.
+ *
+ * It is meant to be used by drivers that want to implement
+ * flicker-free boot (also called fastboot by i915) and allows
+ * to initialize the atomic state from the hardware state left
+ * by the firmware.
+ *
+ * It is used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * The @crtc_state and @conn_state parameters point to the CRTC
+ * and connector states for the pipeline this bridge is part
+ * of.
+ *
+ * This hook is mandatory for drivers implementing SRO, but can
+ * be left unassigned otherwise.
+ *
+ * RETURNS:
+ *
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*atomic_sro_readout_state)(struct drm_bridge *bridge,
+ struct drm_atomic_sro_state *state,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current bridge state object (which is guaranteed to be
* non-NULL).
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a2c6c87065b6..db0d2bb80bd5 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -32,10 +32,11 @@
#include <drm/drm_util.h>
#include <drm/drm_property.h>
#include <uapi/drm/drm_mode.h>
+struct drm_atomic_sro_state;
struct drm_connector_helper_funcs;
struct drm_modeset_acquire_ctx;
struct drm_device;
struct drm_crtc;
struct drm_display_mode;
@@ -1582,10 +1583,35 @@ struct drm_connector_funcs {
* A new, pristine, connector state instance or an error pointer
* on failure.
*/
struct drm_connector_state *(*atomic_create_state)(struct drm_connector *connector);
+ /**
+ * @atomic_sro_readout_state:
+ *
+ * Initializes @conn_state to reflect the current hardware
+ * state of the connector.
+ *
+ * It is meant to be used by drivers that want to implement
+ * flicker-free boot (also called fastboot by i915) and allows
+ * to initialize the atomic state from the hardware state left
+ * by the firmware.
+ *
+ * It is used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * This hook is mandatory for drivers implementing SRO, but can
+ * be left unassigned otherwise.
+ *
+ * RETURNS:
+ *
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*atomic_sro_readout_state)(struct drm_connector *connector,
+ struct drm_atomic_sro_state *state,
+ struct drm_connector_state *conn_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this connector and return it.
* The core and helpers guarantee that any atomic state duplicated with
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 9e410191683c..b6d4a2341776 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -33,10 +33,11 @@
#include <drm/drm_device.h>
#include <drm/drm_plane.h>
#include <drm/drm_debugfs_crc.h>
#include <drm/drm_mode_config.h>
+struct drm_atomic_sro_state;
struct drm_connector;
struct drm_device;
struct drm_framebuffer;
struct drm_mode_set;
struct drm_file;
@@ -649,10 +650,35 @@ struct drm_crtc_funcs {
* A new, pristine, crtc state instance or an error pointer
* on failure.
*/
struct drm_crtc_state *(*atomic_create_state)(struct drm_crtc *crtc);
+ /**
+ * @atomic_sro_readout_state:
+ *
+ * Initializes @crtc_state to reflect the current hardware
+ * state of the CRTC.
+ *
+ * It is meant to be used by drivers that want to implement
+ * flicker-free boot (also called fastboot by i915) and allows
+ * to initialize the atomic state from the hardware state left
+ * by the firmware.
+ *
+ * It is used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * This hook is mandatory for drivers implementing SRO, but can
+ * be left unassigned otherwise.
+ *
+ * RETURNS:
+ *
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*atomic_sro_readout_state)(struct drm_crtc *crtc,
+ struct drm_atomic_sro_state *state,
+ struct drm_crtc_state *crtc_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this CRTC and return it.
* The core and helpers guarantee that any atomic state duplicated with
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 22c7e767a2e9..ce2b4115b417 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -319,10 +319,28 @@ struct drm_mode_config_funcs {
*
* Subclassing of &drm_atomic_state is deprecated in favour of using
* &drm_private_state and &drm_private_obj.
*/
void (*atomic_state_free)(struct drm_atomic_state *state);
+
+ /**
+ * @atomic_sro_readout_state:
+ *
+ * This optional hook is called at initialization time to read
+ * out the hardware state and initialize the DRM objects' atomic
+ * states from it.
+ *
+ * When implemented, the framework will prefer hardware state
+ * readout over creating pristine default states, enabling the
+ * first modeset to be skipped if the firmware already set up
+ * the display (flicker-free boot).
+ *
+ * RETURNS:
+ *
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*atomic_sro_readout_state)(struct drm_device *dev);
};
/**
* struct drm_mode_config - Mode configuration control structure
* @min_width: minimum fb pixel width on this device
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index 3e68213958dd..8c886c5ea9d3 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1550,8 +1550,31 @@ struct drm_mode_config_helper_funcs {
* how one should implement this.
*
* This hook is optional.
*/
int (*atomic_commit_setup)(struct drm_atomic_state *state);
+
+ /**
+ * @atomic_sro_build_state:
+ *
+ * Builds a &struct drm_atomic_sro_state from the current
+ * hardware state by calling the atomic_sro_readout_state hooks
+ * on every KMS object.
+ *
+ * This hook is called both at initialization time, to create
+ * the initial state from what the firmware programmed, and
+ * after blocking commits, to read back the hardware state and
+ * compare it to what was committed.
+ *
+ * The default implementation is
+ * drm_atomic_helper_sro_build_state().
+ *
+ * RETURNS:
+ *
+ * A &struct drm_atomic_sro_state on success, an error pointer
+ * otherwise.
+ */
+ struct drm_atomic_sro_state *
+ (*atomic_sro_build_state)(struct drm_device *dev);
};
#endif
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 4d4d511b681d..22a16bc63f3e 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -30,10 +30,11 @@
#include <drm/drm_color_mgmt.h>
#include <drm/drm_rect.h>
#include <drm/drm_modeset_lock.h>
#include <drm/drm_util.h>
+struct drm_atomic_sro_state;
struct drm_crtc;
struct drm_plane_size_hint;
struct drm_printer;
struct drm_modeset_acquire_ctx;
@@ -399,10 +400,35 @@ struct drm_plane_funcs {
* A new, pristine, plane state instance or an error pointer
* on failure.
*/
struct drm_plane_state *(*atomic_create_state)(struct drm_plane *plane);
+ /**
+ * @atomic_sro_readout_state:
+ *
+ * Initializes @plane_state to reflect the current hardware
+ * state of the plane.
+ *
+ * It is meant to be used by drivers that want to implement
+ * flicker-free boot (also called fastboot by i915) and allows
+ * to initialize the atomic state from the hardware state left
+ * by the firmware.
+ *
+ * It is used at initialization time, so drivers must make sure
+ * that the power state is sensible when accessing the hardware.
+ *
+ * This hook is mandatory for drivers implementing SRO, but can
+ * be left unassigned otherwise.
+ *
+ * RETURNS:
+ *
+ * 0 on success, a negative error code otherwise.
+ */
+ int (*atomic_sro_readout_state)(struct drm_plane *plane,
+ struct drm_atomic_sro_state *state,
+ struct drm_plane_state *plane_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this plane and return it.
* The core and helpers guarantee that any atomic state duplicated with
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 13/28] drm/atomic_sro: Add function to install state into drm objects
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (11 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 12/28] drm/atomic_sro: Add atomic state readout infrastructure Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 14/28] drm/atomic_sro: Create documentation Maxime Ripard
` (3 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Once the SRO state has been built from hardware, it needs to be
installed as the current state of each KMS object.
Add drm_atomic_sro_install_state() which walks through the SRO state
container and assigns each readout state to its object's state
pointer. Before each assignment, it calls the optional
atomic_sro_install_state hook to give drivers a chance to acquire the
resources they need to keep the hardware state active.
Also introduce the atomic_sro_install_state hook in the plane, CRTC,
connector, and private object funcs vtables.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_sro.c | 97 ++++++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic.h | 18 ++++++++
include/drm/drm_atomic_sro.h | 2 +
include/drm/drm_connector.h | 18 ++++++++
include/drm/drm_crtc.h | 18 ++++++++
include/drm/drm_plane.h | 18 ++++++++
6 files changed, 171 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_sro.c b/drivers/gpu/drm/drm_atomic_sro.c
index 3eb22c654973..7ff67c140ff2 100644
--- a/drivers/gpu/drm/drm_atomic_sro.c
+++ b/drivers/gpu/drm/drm_atomic_sro.c
@@ -515,5 +515,102 @@ void drm_atomic_sro_set_private_obj_state(struct drm_atomic_sro_state *state,
drm_dbg_atomic(state->dev,
"Added new private object %p state %p to readout state %p\n", obj,
obj_state, state);
}
EXPORT_SYMBOL(drm_atomic_sro_set_private_obj_state);
+
+/**
+ * drm_atomic_sro_install_state - install readout state into DRM objects
+ * @state: SRO state to install
+ *
+ * Takes a &struct drm_atomic_sro_state built by
+ * drm_atomic_helper_sro_build_state() and installs its contents as the
+ * current state of each DRM object (setting &drm_crtc.state,
+ * &drm_plane.state, &drm_connector.state and &drm_private_obj.state).
+ *
+ * For each object, the optional atomic_sro_install_state hook is
+ * called before the state pointer is updated, allowing drivers to
+ * perform any needed action.
+ */
+void drm_atomic_sro_install_state(struct drm_atomic_sro_state *state)
+{
+ unsigned int i;
+
+ for (i = 0; i < state->dev->mode_config.num_connector; i++) {
+ struct drm_connector *conn = state->connectors[i].ptr;
+ const struct drm_connector_funcs *conn_funcs = conn->funcs;
+ struct drm_connector_state *conn_state =
+ state->connectors[i].state;
+
+ if (conn->state) {
+ conn_funcs->atomic_destroy_state(conn, conn->state);
+ conn->state = NULL;
+ }
+
+ if (conn_funcs->atomic_sro_install_state)
+ conn_funcs->atomic_sro_install_state(conn, conn_state);
+
+ conn->state = conn_state;
+ state->connectors[i].state = NULL;
+ state->connectors[i].ptr = NULL;
+ drm_connector_put(conn);
+ }
+
+ for (i = 0; i < state->dev->mode_config.num_crtc; i++) {
+ struct drm_crtc *crtc = state->crtcs[i].ptr;
+ const struct drm_crtc_funcs *crtc_funcs = crtc->funcs;
+ struct drm_crtc_state *crtc_state = state->crtcs[i].state;
+
+ if (crtc->state) {
+ crtc_funcs->atomic_destroy_state(crtc, crtc->state);
+ crtc->state = NULL;
+ }
+
+ if (crtc_funcs->atomic_sro_install_state)
+ crtc_funcs->atomic_sro_install_state(crtc, crtc_state);
+
+ crtc->state = crtc_state;
+ state->crtcs[i].state = NULL;
+ state->crtcs[i].ptr = NULL;
+ }
+
+ for (i = 0; i < state->dev->mode_config.num_total_plane; i++) {
+ struct drm_plane *plane = state->planes[i].ptr;
+ const struct drm_plane_funcs *plane_funcs = plane->funcs;
+ struct drm_plane_state *plane_state = state->planes[i].state;
+
+ if (plane->state) {
+ plane_funcs->atomic_destroy_state(plane, plane->state);
+ plane->state = NULL;
+ }
+
+ if (plane_funcs->atomic_sro_install_state)
+ plane_funcs->atomic_sro_install_state(plane,
+ plane_state);
+
+ plane->state = plane_state;
+ state->planes[i].state = NULL;
+ state->planes[i].ptr = NULL;
+ }
+
+ for (i = 0; i < count_private_obj(state->dev); i++) {
+ struct drm_private_obj *obj = state->private_objs[i].ptr;
+ const struct drm_private_state_funcs *obj_funcs = obj->funcs;
+ struct drm_private_state *obj_state =
+ state->private_objs[i].state;
+
+ if (obj->state) {
+ obj_funcs->atomic_destroy_state(obj, obj->state);
+ obj->state = NULL;
+ }
+
+ if (obj_funcs->atomic_sro_install_state)
+ obj_funcs->atomic_sro_install_state(obj,
+ obj_state);
+
+ obj->state = obj_state;
+ state->private_objs[i].state = NULL;
+ state->private_objs[i].ptr = NULL;
+ }
+ state->num_private_objs = 0;
+}
+EXPORT_SYMBOL(drm_atomic_sro_install_state);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 554dde45b799..81290c4a5ad3 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -318,10 +318,28 @@ struct drm_private_state_funcs {
*/
int (*atomic_sro_readout_state)(struct drm_private_obj *obj,
struct drm_atomic_sro_state *state,
struct drm_private_state *obj_state);
+ /**
+ * @atomic_sro_install_state:
+ *
+ * This optional hook is called when a state read out from
+ * hardware is about to be installed as the private object's
+ * current state.
+ *
+ * It allows drivers to acquire the resources needed to keep
+ * the current hardware state active, such as power domains,
+ * clocks, or interrupts.
+ *
+ * This hook cannot fail. It is called during
+ * drm_atomic_sro_install_state(), which is part of the
+ * hardware state readout initialization sequence.
+ */
+ void (*atomic_sro_install_state)(struct drm_private_obj *obj,
+ struct drm_private_state *obj_state);
+
/**
* @atomic_print_state:
*
* If driver subclasses &struct drm_private_state, it should implement
* this optional hook for printing additional driver specific state.
diff --git a/include/drm/drm_atomic_sro.h b/include/drm/drm_atomic_sro.h
index 6e5262384c71..195154850ab4 100644
--- a/include/drm/drm_atomic_sro.h
+++ b/include/drm/drm_atomic_sro.h
@@ -48,6 +48,8 @@ drm_atomic_sro_get_private_obj_state(struct drm_atomic_sro_state *state,
struct drm_private_obj *private_obj);
void drm_atomic_sro_set_private_obj_state(struct drm_atomic_sro_state *state,
struct drm_private_obj *obj,
struct drm_private_state *obj_state);
+void drm_atomic_sro_install_state(struct drm_atomic_sro_state *state);
+
#endif /* DRM_ATOMIC_SRO_H_ */
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index db0d2bb80bd5..3cd20198a5e7 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1608,10 +1608,28 @@ struct drm_connector_funcs {
*/
int (*atomic_sro_readout_state)(struct drm_connector *connector,
struct drm_atomic_sro_state *state,
struct drm_connector_state *conn_state);
+ /**
+ * @atomic_sro_install_state:
+ *
+ * This optional hook is called when a state read out from
+ * hardware is about to be installed as the connector's current
+ * state.
+ *
+ * It allows drivers to acquire the resources needed to keep
+ * the current hardware state active, such as power domains,
+ * clocks, or interrupts.
+ *
+ * This hook cannot fail. It is called during
+ * drm_atomic_sro_install_state(), which is part of the
+ * hardware state readout initialization sequence.
+ */
+ void (*atomic_sro_install_state)(struct drm_connector *conn,
+ struct drm_connector_state *conn_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this connector and return it.
* The core and helpers guarantee that any atomic state duplicated with
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b6d4a2341776..146da65448dc 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -675,10 +675,28 @@ struct drm_crtc_funcs {
*/
int (*atomic_sro_readout_state)(struct drm_crtc *crtc,
struct drm_atomic_sro_state *state,
struct drm_crtc_state *crtc_state);
+ /**
+ * @atomic_sro_install_state:
+ *
+ * This optional hook is called when a state read out from
+ * hardware is about to be installed as the CRTC's current
+ * state.
+ *
+ * It allows drivers to acquire the resources needed to keep
+ * the current hardware state active, such as power domains,
+ * clocks, or interrupts.
+ *
+ * This hook cannot fail. It is called during
+ * drm_atomic_sro_install_state(), which is part of the
+ * hardware state readout initialization sequence.
+ */
+ void (*atomic_sro_install_state)(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this CRTC and return it.
* The core and helpers guarantee that any atomic state duplicated with
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 22a16bc63f3e..1e02728838e2 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -425,10 +425,28 @@ struct drm_plane_funcs {
*/
int (*atomic_sro_readout_state)(struct drm_plane *plane,
struct drm_atomic_sro_state *state,
struct drm_plane_state *plane_state);
+ /**
+ * @atomic_sro_install_state:
+ *
+ * This optional hook is called when a state read out from
+ * hardware is about to be installed as the plane's current
+ * state.
+ *
+ * It allows drivers to acquire the resources needed to keep
+ * the current hardware state active, such as power domains,
+ * clocks, or interrupts.
+ *
+ * This hook cannot fail. It is called during
+ * drm_atomic_sro_install_state(), which is part of the
+ * hardware state readout initialization sequence.
+ */
+ void (*atomic_sro_install_state)(struct drm_plane *plane,
+ struct drm_plane_state *plane_state);
+
/**
* @atomic_duplicate_state:
*
* Duplicate the current atomic state for this plane and return it.
* The core and helpers guarantee that any atomic state duplicated with
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 14/28] drm/atomic_sro: Create documentation
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (12 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 13/28] drm/atomic_sro: Add function to install state into drm objects Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 15/28] drm/bridge: Handle bridges with hardware state readout Maxime Ripard
` (2 subsequent siblings)
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
The SRO infrastructure has grown to span multiple files and hooks
but lacks an overview section explaining the overall design and how
drivers should integrate with it.
Add a DOC: overview section to drm_atomic_sro.c describing the various
SRO phases and how drivers wire up the callbacks.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_sro.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_sro.c b/drivers/gpu/drm/drm_atomic_sro.c
index 7ff67c140ff2..0e62e9d22ecc 100644
--- a/drivers/gpu/drm/drm_atomic_sro.c
+++ b/drivers/gpu/drm/drm_atomic_sro.c
@@ -12,10 +12,44 @@
#include <linux/module.h>
#include "drm_internal.h"
#include "drm_crtc_internal.h"
+/**
+ * DOC: overview
+ *
+ * The atomic State Read-Out (SRO) infrastructure allows drivers to
+ * initialize the KMS atomic state from the hardware state left by the
+ * firmware at boot, rather than programming a new state. This enables
+ * flicker-free boot (also called "fastboot" by i915): if the
+ * firmware already configured the display, the first userspace
+ * modeset can be skipped when the requested mode matches.
+ *
+ * The SRO lifecycle has two phases. The first phase is the readout
+ * itself: at driver registration time, each KMS object (CRTCs, planes,
+ * connectors, bridges, private objects) has its
+ * atomic_sro_readout_state hook called to populate a
+ * &struct drm_atomic_sro_state from hardware registers.
+ *
+ * The second phase is the installation. Once all states have been read
+ * out, drm_atomic_sro_install_state() walks through the
+ * &struct drm_atomic_sro_state and assigns each readout state as the
+ * object's current state. Before doing so, it calls the optional
+ * atomic_sro_install_state hook on each object. This gives drivers a
+ * chance to acquire the resources needed to keep the hardware state
+ * active, such as power domains, clocks, or interrupts. This hook
+ * cannot fail.
+ *
+ * Drivers integrate with SRO by implementing the readout and compare
+ * hooks in their object funcs vtables and setting the
+ * &drm_mode_config_funcs.atomic_sro_readout_state and
+ * &drm_mode_config_helper_funcs.atomic_sro_build_state callbacks. The
+ * default helpers drm_atomic_helper_sro_readout_state() and
+ * drm_atomic_helper_sro_build_state() handle the standard readout
+ * sequence.
+ */
+
enum drm_atomic_readout_status {
DRM_ATOMIC_READOUT_DISABLED = 0,
DRM_ATOMIC_READOUT_ENABLED,
DRM_ATOMIC_READOUT_SKIP_MISSING_COMPARE,
DRM_ATOMIC_READOUT_SKIP_MISSING_READOUT,
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 15/28] drm/bridge: Handle bridges with hardware state readout
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (13 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 14/28] drm/atomic_sro: Create documentation Maxime Ripard
@ 2026-04-23 10:06 ` Maxime Ripard
2026-04-23 10:21 ` [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
2026-04-23 10:50 ` Jani Nikula
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:06 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard
Bridges use drm_private_obj for their atomic state, but their readout
needs special handling compared to other private objects.
Bridge drivers need the CRTC and connector states for their pipeline
to properly read out their own state. Since bridge registration does
not guarantee ordering, the readout must traverse each encoder's
bridge chain to ensure each bridge can query the state of preceding
bridges.
Add a drm_bridge_atomic_readout_priv_state() wrapper that looks up
the connector and CRTC states for the bridge's encoder, then forwards
to the bridge's atomic_sro_readout_state hook. Create a separate
drm_private_state_funcs vtable for bridges that support SRO so that
drm_atomic_sro_device_can_readout() can properly discriminate bridges
with and without SRO support.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_bridge.c | 81 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 77 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index fba440bddcb3..08226af6b82a 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -27,10 +27,11 @@
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/srcu.h>
+#include <drm/drm_atomic_sro.h>
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_edid.h>
#include <drm/drm_encoder.h>
@@ -506,10 +507,66 @@ drm_bridge_atomic_create_priv_state(struct drm_private_obj *obj)
return ERR_CAST(state);
return &state->base;
}
+static struct drm_connector_state *
+find_connector_state_for_encoder(struct drm_atomic_sro_state *state,
+ struct drm_encoder *encoder)
+{
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *connector;
+
+ drm_connector_list_iter_begin(drm_atomic_sro_state_get_device(state),
+ &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ struct drm_connector_state *conn_state =
+ drm_atomic_sro_get_connector_state(state, connector);
+
+ if (WARN_ON(!conn_state))
+ continue;
+
+ if (encoder == conn_state->best_encoder)
+ return conn_state;
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return NULL;
+}
+
+static int
+drm_bridge_atomic_readout_priv_state(struct drm_private_obj *obj,
+ struct drm_atomic_sro_state *state,
+ struct drm_private_state *priv_state)
+{
+ struct drm_bridge *bridge = drm_priv_to_bridge(obj);
+ struct drm_encoder *encoder = bridge->encoder;
+ const struct drm_bridge_funcs *bridge_funcs = bridge->funcs;
+ struct drm_crtc_state *crtc_state;
+ struct drm_bridge_state *bridge_state;
+ struct drm_connector_state *conn_state;
+ int ret;
+
+ conn_state = find_connector_state_for_encoder(state, encoder);
+ if (!conn_state)
+ return -EINVAL;
+
+ crtc_state = drm_atomic_sro_get_crtc_state(state, conn_state->crtc);
+ if (!crtc_state)
+ return -EINVAL;
+
+ bridge_state = drm_priv_to_bridge_state(priv_state);
+ if (bridge_funcs->atomic_sro_readout_state) {
+ ret = bridge_funcs->atomic_sro_readout_state(
+ bridge, state, bridge_state, crtc_state, conn_state);
+ if (WARN_ON(ret))
+ return ret;
+ }
+
+ return 0;
+}
+
static void
drm_bridge_atomic_print_priv_state(struct drm_printer *p,
const struct drm_private_state *s)
{
const struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
@@ -533,10 +590,18 @@ static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
.atomic_print_state = drm_bridge_atomic_print_priv_state,
};
+static const struct drm_private_state_funcs drm_bridge_priv_state_funcs_with_sro = {
+ .atomic_sro_readout_state = drm_bridge_atomic_readout_priv_state,
+ .atomic_create_state = drm_bridge_atomic_create_priv_state,
+ .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
+ .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
+ .atomic_print_state = drm_bridge_atomic_print_priv_state,
+};
+
/**
* drm_private_obj_is_bridge - check if a private object backs a bridge
* @obj: private object to check
*
* RETURNS:
@@ -544,11 +609,13 @@ static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
* True if @obj is the &drm_private_obj embedded in a &struct drm_bridge,
* false otherwise.
*/
bool drm_private_obj_is_bridge(struct drm_private_obj *obj)
{
- return obj->funcs && obj->funcs == &drm_bridge_priv_state_funcs;
+ return obj->funcs &&
+ (obj->funcs == &drm_bridge_priv_state_funcs ||
+ obj->funcs == &drm_bridge_priv_state_funcs_with_sro);
}
EXPORT_SYMBOL(drm_private_obj_is_bridge);
static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
{
@@ -622,13 +689,19 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
ret = bridge->funcs->attach(bridge, encoder, flags);
if (ret < 0)
goto err_reset_bridge;
}
- if (drm_bridge_is_atomic(bridge))
- drm_atomic_private_obj_init(bridge->dev, &bridge->base, bridge->name,
- &drm_bridge_priv_state_funcs);
+ if (drm_bridge_is_atomic(bridge)) {
+ if (bridge->funcs &&
+ bridge->funcs->atomic_sro_readout_state)
+ drm_atomic_private_obj_init(bridge->dev, &bridge->base, bridge->name,
+ &drm_bridge_priv_state_funcs_with_sro);
+ else
+ drm_atomic_private_obj_init(bridge->dev, &bridge->base, bridge->name,
+ &drm_bridge_priv_state_funcs);
+ }
return 0;
err_reset_bridge:
bridge->dev = NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v2 00/28] drm: Implement state readout support
@ 2026-04-23 10:18 Maxime Ripard
0 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard,
Laurent Pinchart
Hi,
Here's a series that implement what i915 calls "fastboot", ie,
initializing the initial KMS state from the hardware state at boot, to
skip the first modeset if the firmware already set up the display.
This series creates the infrastructure in KMS to create that state by
relying on driver specific hooks. It also implements some infrastructure
to check during non-blocking commits that the readout helpers work
properly by reading out the state that was just committed and comparing
it to what was supposed to be commited.
This relies on another set of driver hooks to compare the entities
states, with helpers providing the default implementation.
It then implements the readout support in the TIDSS driver, and was
tested with the SK-AM62 board. This board in particular is pretty
interesting, since it relies on an DPI to HDMI bridge, and uses the
drm_bridge_connector infrastructure.
So the readout works with the current state of the art on embedded-ish
It's now in a much better state than the v1 was, but there's still some
notable things broken:
- Bridges do not read their input and output bus formats and flags
- The tidss_crtc_state fields are not read properly at the moment
either.
- It looks like, when left unattended, we get some atomic_flush
WARN eventually, maybe because of something broken around
hotplugging and the monitor shutting itself down?
- If readout is disabled for any reason, the hardware isn't reset
anymore.
The main thing works though: the state is picked up properly, doesn't
trigger a modeset if what was programmed is the one the first modeset
tries to pick as well, will switch properly if it isn't, etc.
Let me know what you think,
Maxime
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
Changes in v2:
- Get rid of patches already applied
- Rebase on top of the current atomic_create_state work
- Use the SRO prefix everywhere
- Create our own states container structure instead of trying to plumb
it into a drm_atomic_state
- Make a lot more use of helpers
- Add a hook to enable the hardware resources when the readout state
becomes active
- Move all the tidss readout code into tidss_dispc.c
- Write documentation
- Add drm_private_obj and drm_bridge name for easier debugging
- Add drm_private_obj_is_bridge()
- Link to v1: https://lore.kernel.org/r/20250902-drm-state-readout-v1-0-14ad5315da3f@kernel.org
---
Maxime Ripard (28):
drm/atomic: Fix unused but set warning in state iterator macros
drm/atomic_helper: Skip over NULL private_obj pointers
drm/atomic_state_helper: Remove memset in __drm_atomic_helper_bridge_reset()
drm/atomic: Convert drm_priv_to_bridge_state to container_of_const
drm/atomic: Add drm_private_obj name
drm/bridge: Add drm_private_obj_is_bridge()
drm/bridge: Implement atomic_print_state
drm/atomic: Export drm_atomic_*_print_state
drm/atomic: Only call atomic_destroy_state on a !NULL pointer
drm/atomic_sro: Create drm_atomic_sro_state container
drm/atomic_sro: Create kernel parameter to force or disable readout
drm/atomic_sro: Add atomic state readout infrastructure
drm/atomic_sro: Add function to install state into drm objects
drm/atomic_sro: Create documentation
drm/bridge: Handle bridges with hardware state readout
drm/mode_config: Read out hardware state in drm_mode_config_create_state
drm/atomic_sro: Provide helpers to implement hardware state readout
drm/atomic_helper: Pass nonblock to commit_tail
drm/atomic_helper: Compare actual and readout states once the commit is done
drm/atomic_state_helper: Provide comparison macros
drm/atomic_state_helper: Provide atomic_compare_state helpers
drm/encoder: Create atomic_sro_get_current_crtc hook
drm/bridge: display-connector: Implement readout support
drm/bridge_connector: Implement hw readout for connector
drm/tidss: dispc: Improve mode checking logs
drm/tidss: Implement readout support
drm/tidss: encoder: Implement atomic_sro_get_current_crtc
drm/bridge: sii902x: Implement hw state readout
drivers/gpu/drm/Makefile | 2 +
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 1 +
.../drm/arm/display/komeda/komeda_private_obj.c | 8 +
drivers/gpu/drm/bridge/display-connector.c | 15 +
drivers/gpu/drm/bridge/sii902x.c | 56 +-
drivers/gpu/drm/display/drm_bridge_connector.c | 31 +
drivers/gpu/drm/display/drm_dp_mst_topology.c | 2 +-
drivers/gpu/drm/display/drm_dp_tunnel.c | 1 +
drivers/gpu/drm/drm_atomic.c | 46 +-
drivers/gpu/drm/drm_atomic_helper.c | 46 +-
drivers/gpu/drm/drm_atomic_sro.c | 854 +++++++++++++++++++++
drivers/gpu/drm/drm_atomic_sro_helper.c | 677 ++++++++++++++++
drivers/gpu/drm/drm_atomic_state_helper.c | 3 +-
drivers/gpu/drm/drm_bridge.c | 133 +++-
drivers/gpu/drm/drm_internal.h | 12 +
drivers/gpu/drm/drm_mode_config.c | 5 +
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 1 +
drivers/gpu/drm/ingenic/ingenic-ipu.c | 1 +
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 1 +
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c | 1 +
drivers/gpu/drm/omapdrm/omap_drv.c | 1 +
drivers/gpu/drm/tegra/hub.c | 1 +
drivers/gpu/drm/tidss/tidss_crtc.c | 93 +++
drivers/gpu/drm/tidss/tidss_dispc.c | 332 ++++++--
drivers/gpu/drm/tidss/tidss_dispc.h | 14 +
drivers/gpu/drm/tidss/tidss_encoder.c | 37 +-
drivers/gpu/drm/tidss/tidss_kms.c | 6 +-
drivers/gpu/drm/tidss/tidss_plane.c | 154 ++++
drivers/gpu/drm/vc4/vc4_kms.c | 3 +
include/drm/drm_atomic.h | 144 +++-
include/drm/drm_atomic_sro.h | 59 ++
include/drm/drm_atomic_sro_helper.h | 275 +++++++
include/drm/drm_bridge.h | 87 +++
include/drm/drm_connector.h | 69 ++
include/drm/drm_crtc.h | 69 ++
include/drm/drm_encoder.h | 18 +
include/drm/drm_mode_config.h | 18 +
include/drm/drm_modeset_helper_vtables.h | 23 +
include/drm/drm_plane.h | 69 ++
39 files changed, 3255 insertions(+), 113 deletions(-)
---
base-commit: ea61048876a7137897da26dac49ee234fb38a35a
change-id: 20250730-drm-state-readout-108f089c1c30
prerequisite-change-id: 20260310-drm-mode-config-init-1e1f52b745d0:v2
prerequisite-patch-id: 8831e320ca55e930e6dd8db8abfd2a79179fc1a0
prerequisite-patch-id: 5d2ae478dfb0a8b1eed30431b52a63141f1a3edb
prerequisite-patch-id: be3ef2f85cc3bba3ce65cbe4c1bf73b26c59b46c
prerequisite-patch-id: ad4de3b4f7bf5861d8e74d15042fb1d17cf6f071
prerequisite-patch-id: 6af92ef1aef1541ba0c504c3618612a89f5433a4
prerequisite-patch-id: d7b9200d7155e7ae2a76121adb50ce974aa78ddc
prerequisite-patch-id: 811a936fa6b38549807256e718b4c1faf49e90dd
prerequisite-patch-id: 3816a4bdc28e3353dba2811cc82d6680cf9ada11
prerequisite-patch-id: e156096dae812cab909877d7d614f56374652c6a
prerequisite-patch-id: fa0187e85c3587e7b28e411f2198b7c070793fbb
prerequisite-patch-id: f97b4088a1357121e4b35c4822839e45d952cba9
prerequisite-patch-id: 2e942d5540fc208b0c94f9f9215f85cc59dd6c1c
prerequisite-patch-id: 45ce20ef439a538b6c71c7aedb251bd62c882a11
prerequisite-patch-id: 86674e487ba650461e29c284308ff9ba321a48e4
prerequisite-patch-id: 1d7744840555f74f310c1d48642bfc755ac645c9
prerequisite-patch-id: b01716030f5f9b3cedb4a6096b2d4769f625741a
prerequisite-patch-id: 0372103622aa6006a3fe645b4c2eb2387d7d3b5a
prerequisite-patch-id: 24a0b772f6fc53c41892a37b52cba95bbd261ca2
prerequisite-patch-id: 80ec7eea600ad3be7b94a182e274695b7c5cf17f
prerequisite-patch-id: 273773ea001ab348b4e85b47b20b45f48d4c1cbc
Best regards,
--
Maxime Ripard <mripard@kernel.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 00/28] drm: Implement state readout support
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (14 preceding siblings ...)
2026-04-23 10:06 ` [PATCH v2 15/28] drm/bridge: Handle bridges with hardware state readout Maxime Ripard
@ 2026-04-23 10:21 ` Maxime Ripard
2026-04-23 10:50 ` Jani Nikula
16 siblings, 0 replies; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 10:21 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Laurent Pinchart
[-- Attachment #1: Type: text/plain, Size: 1972 bytes --]
Hi,
On Thu, Apr 23, 2026 at 12:06:38PM +0200, Maxime Ripard wrote:
> Here's a series that implement what i915 calls "fastboot", ie,
> initializing the initial KMS state from the hardware state at boot, to
> skip the first modeset if the firmware already set up the display.
>
> This series creates the infrastructure in KMS to create that state by
> relying on driver specific hooks. It also implements some infrastructure
> to check during non-blocking commits that the readout helpers work
> properly by reading out the state that was just committed and comparing
> it to what was supposed to be commited.
>
> This relies on another set of driver hooks to compare the entities
> states, with helpers providing the default implementation.
>
> It then implements the readout support in the TIDSS driver, and was
> tested with the SK-AM62 board. This board in particular is pretty
> interesting, since it relies on an DPI to HDMI bridge, and uses the
> drm_bridge_connector infrastructure.
>
> So the readout works with the current state of the art on embedded-ish
>
> It's now in a much better state than the v1 was, but there's still some
> notable things broken:
>
> - Bridges do not read their input and output bus formats and flags
>
> - The tidss_crtc_state fields are not read properly at the moment
> either.
>
> - It looks like, when left unattended, we get some atomic_flush
> WARN eventually, maybe because of something broken around
> hotplugging and the monitor shutting itself down?
>
> - If readout is disabled for any reason, the hardware isn't reset
> anymore.
>
> The main thing works though: the state is picked up properly, doesn't
> trigger a modeset if what was programmed is the one the first modeset
> tries to pick as well, will switch properly if it isn't, etc.
Sorry, my smtp server spuriously failed halfway through sending the
series. I just resent it.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 00/28] drm: Implement state readout support
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
` (15 preceding siblings ...)
2026-04-23 10:21 ` [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
@ 2026-04-23 10:50 ` Jani Nikula
2026-04-23 11:04 ` Maxime Ripard
16 siblings, 1 reply; 21+ messages in thread
From: Jani Nikula @ 2026-04-23 10:50 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jyri Sarha,
Tomi Valkeinen
Cc: Devarsh Thakkar, dri-devel, linux-kernel, Maxime Ripard,
Laurent Pinchart
On Thu, 23 Apr 2026, Maxime Ripard <mripard@kernel.org> wrote:
> Here's a series that implement what i915 calls "fastboot", ie,
> initializing the initial KMS state from the hardware state at boot, to
> skip the first modeset if the firmware already set up the display.
FWIW, in i915 we also use the state readout for atomic commit
verification. Write software state to hardware, read hardware state
back, compare with the original state, complain if there's a difference.
BR,
Jani.
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 00/28] drm: Implement state readout support
2026-04-23 10:50 ` Jani Nikula
@ 2026-04-23 11:04 ` Maxime Ripard
2026-04-23 12:07 ` Jani Nikula
0 siblings, 1 reply; 21+ messages in thread
From: Maxime Ripard @ 2026-04-23 11:04 UTC (permalink / raw)
To: Jani Nikula
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen,
Devarsh Thakkar, dri-devel, linux-kernel, Laurent Pinchart
[-- Attachment #1: Type: text/plain, Size: 689 bytes --]
Hi Jani,
On Thu, Apr 23, 2026 at 01:50:59PM +0300, Jani Nikula wrote:
> On Thu, 23 Apr 2026, Maxime Ripard <mripard@kernel.org> wrote:
> > Here's a series that implement what i915 calls "fastboot", ie,
> > initializing the initial KMS state from the hardware state at boot, to
> > skip the first modeset if the firmware already set up the display.
>
> FWIW, in i915 we also use the state readout for atomic commit
> verification. Write software state to hardware, read hardware state
> back, compare with the original state, complain if there's a difference.
I know, and this series implement it as well. Is there anything you
wanted to point out in particular?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 00/28] drm: Implement state readout support
2026-04-23 11:04 ` Maxime Ripard
@ 2026-04-23 12:07 ` Jani Nikula
0 siblings, 0 replies; 21+ messages in thread
From: Jani Nikula @ 2026-04-23 12:07 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jyri Sarha, Tomi Valkeinen,
Devarsh Thakkar, dri-devel, linux-kernel, Laurent Pinchart
On Thu, 23 Apr 2026, Maxime Ripard <mripard@kernel.org> wrote:
> Hi Jani,
>
> On Thu, Apr 23, 2026 at 01:50:59PM +0300, Jani Nikula wrote:
>> On Thu, 23 Apr 2026, Maxime Ripard <mripard@kernel.org> wrote:
>> > Here's a series that implement what i915 calls "fastboot", ie,
>> > initializing the initial KMS state from the hardware state at boot, to
>> > skip the first modeset if the firmware already set up the display.
>>
>> FWIW, in i915 we also use the state readout for atomic commit
>> verification. Write software state to hardware, read hardware state
>> back, compare with the original state, complain if there's a difference.
>
> I know, and this series implement it as well. Is there anything you
> wanted to point out in particular?
Oh, I didn't get that far, obviously. Just wanted to mention the feature
is not only about fastboot. Sorry for the noise.
BR,
Jani.
--
Jani Nikula, Intel
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2026-04-23 12:07 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-23 10:06 [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 01/28] drm/atomic: Fix unused but set warning in state iterator macros Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 02/28] drm/atomic_helper: Skip over NULL private_obj pointers Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 03/28] drm/atomic_state_helper: Remove memset in __drm_atomic_helper_bridge_reset() Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 04/28] drm/atomic: Convert drm_priv_to_bridge_state to container_of_const Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 05/28] drm/atomic: Add drm_private_obj name Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 06/28] drm/bridge: Add drm_private_obj_is_bridge() Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 07/28] drm/bridge: Implement atomic_print_state Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 08/28] drm/atomic: Export drm_atomic_*_print_state Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 09/28] drm/atomic: Only call atomic_destroy_state on a !NULL pointer Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 10/28] drm/atomic_sro: Create drm_atomic_sro_state container Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 11/28] drm/atomic_sro: Create kernel parameter to force or disable readout Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 12/28] drm/atomic_sro: Add atomic state readout infrastructure Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 13/28] drm/atomic_sro: Add function to install state into drm objects Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 14/28] drm/atomic_sro: Create documentation Maxime Ripard
2026-04-23 10:06 ` [PATCH v2 15/28] drm/bridge: Handle bridges with hardware state readout Maxime Ripard
2026-04-23 10:21 ` [PATCH v2 00/28] drm: Implement state readout support Maxime Ripard
2026-04-23 10:50 ` Jani Nikula
2026-04-23 11:04 ` Maxime Ripard
2026-04-23 12:07 ` Jani Nikula
-- strict thread matches above, loose matches on Subject: below --
2026-04-23 10:18 Maxime Ripard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox