* [PATCH v3 05/20] drm/mode-config: Document drm_private_obj exclusion from drm_mode_config_reset()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
drm_mode_config_reset() does not reset drm_private_states by design.
This is especially significant for the DP MST and tunneling code that
expect to be preserved across a suspend/resume cycle, where
drm_mode_config_reset() is also used.
Document this expectation.
Link: https://lore.kernel.org/dri-devel/aOaQLx-7EpsHRwkH@ideak-desk/
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_mode_config.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 66f7dc37b597..c33382a38191 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -187,10 +187,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
* @dev: drm device
*
* This functions calls all the crtc's, encoder's and connector's ->reset
* callback. Drivers can use this in e.g. their driver load or resume code to
* reset hardware and software state.
+ *
+ * Note that &drm_private_obj structures are expected to be stable across
+ * suspend/resume cycles, and drm_mode_config_reset() does not affect these
+ * structures.
*/
void drm_mode_config_reset(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct drm_colorop *colorop;
--
2.53.0
^ permalink raw reply related
* [PATCH v3 06/20] drm/colorop: Rename __drm_colorop_state_reset()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
__drm_colorop_state_reset() is used to initialize a newly allocated
drm_colorop_state, and is being typically called by drm_colorop_reset().
Since we want to consolidate DRM objects state allocation around the
atomic_create_state callback that will only allocate and initialize a
new drm_colorop_state instance, we will need to call
__drm_colorop_state_reset() from both the reset and atomic_create paths.
To avoid any confusion, we can thus rename __drm_colorop_state_reset()
to __drm_colorop_state_init().
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_colorop.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 48d0b7ae3fc9..4c4d0a953e35 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -498,19 +498,19 @@ void drm_colorop_atomic_destroy_state(struct drm_colorop *colorop,
__drm_atomic_helper_colorop_destroy_state(state);
kfree(state);
}
/**
- * __drm_colorop_state_reset - resets colorop state to default values
+ * __drm_colorop_state_init - Initializes colorop state to default values
* @colorop_state: atomic colorop state, must not be NULL
* @colorop: colorop object, must not be NULL
*
* Initializes the newly allocated @colorop_state with default
* values. This is useful for drivers that subclass the colorop state.
*/
-static void __drm_colorop_state_reset(struct drm_colorop_state *colorop_state,
- struct drm_colorop *colorop)
+static void __drm_colorop_state_init(struct drm_colorop_state *colorop_state,
+ struct drm_colorop *colorop)
{
u64 val;
colorop_state->colorop = colorop;
colorop_state->bypass = true;
@@ -537,11 +537,11 @@ static void __drm_colorop_state_reset(struct drm_colorop_state *colorop_state,
*/
static void __drm_colorop_reset(struct drm_colorop *colorop,
struct drm_colorop_state *colorop_state)
{
if (colorop_state)
- __drm_colorop_state_reset(colorop_state, colorop);
+ __drm_colorop_state_init(colorop_state, colorop);
colorop->state = colorop_state;
}
void drm_colorop_reset(struct drm_colorop *colorop)
--
2.53.0
^ permalink raw reply related
* [PATCH v3 07/20] drm/colorop: Create drm_atomic_helper_colorop_create_state()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
Commit 47b5ac7daa46 ("drm/atomic: Add new atomic_create_state callback
to drm_private_obj") introduced a new pattern for allocating drm object
states.
Instead of relying on the reset() callback, it created a new
atomic_create_state hook. This is helpful because reset is a bit
overloaded: it's used to create the initial software state, reset it,
but also reset the hardware.
It can also be used either at probe time, to create the initial state
and possibly reset the hardware to an expected default, but also during
suspend/resume.
Both these cases come with different expectations too: during the
initialization, we want to initialize all states, but during
suspend/resume, drm_private_states for example are expected to be kept
around.
reset() also isn't fallible, which makes it harder to handle
initialization errors properly. This is only really relevant for some
drivers though, since all the helpers for reset only create a new
state, and don't touch the hardware at all.
It was thus decided to create a new hook that would allocate and
initialize a pristine state without any side effect:
atomic_create_state to untangle a bit some of it, and to separate the
initialization with the actual reset one might need during a
suspend/resume.
Continue the transition to the new pattern with drm_colorop.
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_colorop.c | 23 +++++++++++++++++++++++
include/drm/drm_colorop.h | 2 ++
2 files changed, 25 insertions(+)
diff --git a/drivers/gpu/drm/drm_colorop.c b/drivers/gpu/drm/drm_colorop.c
index 4c4d0a953e35..c0eecde8c176 100644
--- a/drivers/gpu/drm/drm_colorop.c
+++ b/drivers/gpu/drm/drm_colorop.c
@@ -521,10 +521,33 @@ static void __drm_colorop_state_init(struct drm_colorop_state *colorop_state,
&val))
colorop_state->curve_1d_type = val;
}
}
+/**
+ * drm_atomic_helper_colorop_create_state - Allocates and initializes colorop atomic state
+ * @colorop: drm colorop
+ *
+ * Initializes a pristine @drm_colorop_state.
+ *
+ * RETURNS:
+ * Pointer to new colorop state, or ERR_PTR on failure.
+ */
+struct drm_colorop_state *
+drm_atomic_helper_colorop_create_state(struct drm_colorop *colorop)
+{
+ struct drm_colorop_state *state;
+
+ state = kzalloc_obj(*state);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_colorop_state_init(state, colorop);
+
+ return state;
+}
+
/**
* __drm_colorop_reset - reset state on colorop
* @colorop: drm colorop
* @colorop_state: colorop state to assign
*
diff --git a/include/drm/drm_colorop.h b/include/drm/drm_colorop.h
index bd082854ca74..874ed693329c 100644
--- a/include/drm/drm_colorop.h
+++ b/include/drm/drm_colorop.h
@@ -423,10 +423,12 @@ int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *col
struct drm_plane *plane, const struct drm_colorop_funcs *funcs,
uint32_t lut_size,
enum drm_colorop_lut3d_interpolation_type interpolation,
uint32_t flags);
+struct drm_colorop_state *
+drm_atomic_helper_colorop_create_state(struct drm_colorop *colorop);
struct drm_colorop_state *
drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop);
void drm_colorop_atomic_destroy_state(struct drm_colorop *colorop,
struct drm_colorop_state *state);
--
2.53.0
^ permalink raw reply related
* [PATCH v3 09/20] drm/atomic-state-helper: Rename __drm_atomic_helper_plane_state_reset()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
__drm_atomic_helper_plane_state_reset() is used to initialize a newly
allocated drm_plane_state, and is being typically called by the
drm_plane_funcs.reset implementation.
Since we want to consolidate DRM objects state allocation around the
atomic_create_state callback that will only allocate and initialize a
new drm_plane_state instance, we will need to call
__drm_atomic_helper_plane_state_reset() from both the reset and
atomic_create hooks.
To avoid any confusion, we can thus rename
__drm_atomic_helper_plane_state_reset() to
__drm_atomic_helper_plane_state_init().
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 12 ++++++------
drivers/gpu/drm/i915/display/intel_plane.c | 2 +-
include/drm/drm_atomic_state_helper.h | 2 +-
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index e1f3d05ad347..285efbf29520 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -235,19 +235,19 @@ void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
/**
- * __drm_atomic_helper_plane_state_reset - resets plane state to default values
+ * __drm_atomic_helper_plane_state_init - Initializes the plane state
* @plane_state: atomic plane state, must not be NULL
* @plane: plane object, must not be NULL
*
* Initializes the newly allocated @plane_state with default
- * values. This is useful for drivers that subclass the CRTC state.
+ * values. This is useful for drivers that subclass the plane state.
*/
-void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state,
- struct drm_plane *plane)
+void __drm_atomic_helper_plane_state_init(struct drm_plane_state *plane_state,
+ struct drm_plane *plane)
{
u64 val;
plane_state->plane = plane;
plane_state->rotation = DRM_MODE_ROTATE_0;
@@ -295,11 +295,11 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state,
plane->hotspot_y_property,
&val))
plane_state->hotspot_y = val;
}
}
-EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset);
+EXPORT_SYMBOL(__drm_atomic_helper_plane_state_init);
/**
* __drm_atomic_helper_plane_reset - reset state on plane
* @plane: drm plane
* @plane_state: plane state to assign
@@ -313,11 +313,11 @@ EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset);
*/
void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
struct drm_plane_state *plane_state)
{
if (plane_state)
- __drm_atomic_helper_plane_state_reset(plane_state, plane);
+ __drm_atomic_helper_plane_state_init(plane_state, plane);
plane->state = plane_state;
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_reset);
diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c
index 5390ceb21ca4..d013d9228d0b 100644
--- a/drivers/gpu/drm/i915/display/intel_plane.c
+++ b/drivers/gpu/drm/i915/display/intel_plane.c
@@ -65,11 +65,11 @@
static void intel_plane_state_reset(struct intel_plane_state *plane_state,
struct intel_plane *plane)
{
memset(plane_state, 0, sizeof(*plane_state));
- __drm_atomic_helper_plane_state_reset(&plane_state->uapi, &plane->base);
+ __drm_atomic_helper_plane_state_init(&plane_state->uapi, &plane->base);
plane_state->scaler_id = -1;
}
struct intel_plane *intel_plane_alloc(void)
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 900672c6ea90..44e8850aae7f 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -51,11 +51,11 @@ struct drm_crtc_state *
drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
-void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *state,
+void __drm_atomic_helper_plane_state_init(struct drm_plane_state *state,
struct drm_plane *plane);
void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
struct drm_plane_state *state);
void drm_atomic_helper_plane_reset(struct drm_plane *plane);
void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
--
2.53.0
^ permalink raw reply related
* [PATCH v3 08/20] drm/atomic-state-helper: Fix __drm_atomic_helper_plane_reset() doc typo
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
A typo has slipped through in the __drm_atomic_helper_plane_reset()
documentation, probably due to copy and paste. It will not assign
drm_crtc state pointer, but rather the drm_plane's.
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
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_state_helper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 875149494b00..e1f3d05ad347 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -303,11 +303,11 @@ EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset);
* __drm_atomic_helper_plane_reset - reset state on plane
* @plane: drm plane
* @plane_state: plane state to assign
*
* Initializes the newly allocated @plane_state and assigns it to
- * the &drm_crtc->state pointer of @plane, usually required when
+ * the &drm_plane->state pointer of @plane, usually required when
* initializing the drivers or when called from the &drm_plane_funcs.reset
* hook.
*
* This is useful for drivers that subclass the plane state.
*/
--
2.53.0
^ permalink raw reply related
* [PATCH v3 10/20] drm/plane: Add new atomic_create_state callback
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
Commit 47b5ac7daa46 ("drm/atomic: Add new atomic_create_state callback
to drm_private_obj") introduced a new pattern for allocating drm object
states.
Instead of relying on the reset() callback, it created a new
atomic_create_state hook. This is helpful because reset is a bit
overloaded: it's used to create the initial software state, reset it,
but also reset the hardware.
It can also be used either at probe time, to create the initial state
and possibly reset the hardware to an expected default, but also during
suspend/resume.
Both these cases come with different expectations too: during the
initialization, we want to initialize all states, but during
suspend/resume, drm_private_states for example are expected to be kept
around.
reset() also isn't fallible, which makes it harder to handle
initialization errors properly. This is only really relevant for some
drivers though, since all the helpers for reset only create a new
state, and don't touch the hardware at all.
It was thus decided to create a new hook that would allocate and
initialize a pristine state without any side effect:
atomic_create_state to untangle a bit some of it, and to separate the
initialization with the actual reset one might need during a
suspend/resume.
Continue the transition to the new pattern with planes.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 25 +++++++++++++++++++++++++
drivers/gpu/drm/drm_mode_config.c | 21 ++++++++++++++++++++-
include/drm/drm_atomic_state_helper.h | 2 ++
include/drm/drm_plane.h | 16 ++++++++++++++++
4 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 285efbf29520..50fe4eec41a8 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -338,10 +338,35 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
if (plane->state)
__drm_atomic_helper_plane_reset(plane, plane->state);
}
EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
+/**
+ * drm_atomic_helper_plane_create_state - default &drm_plane_funcs.atomic_create_state hook for planes
+ * @plane: plane object
+ *
+ * Initializes a pristine @drm_plane_state.
+ *
+ * This is useful for drivers that don't subclass @drm_plane_state.
+ *
+ * RETURNS:
+ * Pointer to new plane state, or ERR_PTR on failure.
+ */
+struct drm_plane_state *drm_atomic_helper_plane_create_state(struct drm_plane *plane)
+{
+ struct drm_plane_state *state;
+
+ state = kzalloc_obj(*state);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_plane_state_init(state, plane);
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_plane_create_state);
+
/**
* __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
* @plane: plane object
* @state: atomic plane state
*
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index c33382a38191..10b7815cbe48 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -180,10 +180,26 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
drm_connector_list_iter_end(&conn_iter);
return ret;
}
+static int drm_mode_config_plane_create_state(struct drm_plane *plane)
+{
+ struct drm_plane_state *plane_state;
+
+ if (!plane->funcs->atomic_create_state)
+ return 0;
+
+ plane_state = plane->funcs->atomic_create_state(plane);
+ if (IS_ERR(plane_state))
+ return PTR_ERR(plane_state);
+
+ plane->state = plane_state;
+
+ return 0;
+}
+
/**
* drm_mode_config_reset - call ->reset callbacks
* @dev: drm device
*
* This functions calls all the crtc's, encoder's and connector's ->reset
@@ -204,13 +220,16 @@ void drm_mode_config_reset(struct drm_device *dev)
struct drm_connector_list_iter conn_iter;
drm_for_each_colorop(colorop, dev)
drm_colorop_reset(colorop);
- drm_for_each_plane(plane, dev)
+ drm_for_each_plane(plane, dev) {
if (plane->funcs->reset)
plane->funcs->reset(plane);
+ else if (plane->funcs->atomic_create_state)
+ drm_mode_config_plane_create_state(plane);
+ }
drm_for_each_crtc(crtc, dev)
if (crtc->funcs->reset)
crtc->funcs->reset(crtc);
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 44e8850aae7f..df371b2eef3e 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -53,10 +53,12 @@ void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
void __drm_atomic_helper_plane_state_init(struct drm_plane_state *state,
struct drm_plane *plane);
+struct drm_plane_state *
+drm_atomic_helper_plane_create_state(struct drm_plane *plane);
void __drm_atomic_helper_plane_reset(struct drm_plane *plane,
struct drm_plane_state *state);
void drm_atomic_helper_plane_reset(struct drm_plane *plane);
void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
struct drm_plane_state *state);
diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
index 703ef4d1bbbc..886e219c4609 100644
--- a/include/drm/drm_plane.h
+++ b/include/drm/drm_plane.h
@@ -386,10 +386,26 @@ struct drm_plane_funcs {
* 0 on success or a negative error code on failure.
*/
int (*set_property)(struct drm_plane *plane,
struct drm_property *property, uint64_t val);
+ /**
+ * @atomic_create_state:
+ *
+ * Allocates a pristine, initialized, state for the plane object
+ * and returns it. This callback must have no side effects: in
+ * particular, the returned state must not be assigned to the
+ * object's state pointer and it must not affect the hardware
+ * state.
+ *
+ * RETURNS:
+ *
+ * A new, pristine, plane state instance or an error pointer
+ * on failure.
+ */
+ struct drm_plane_state *(*atomic_create_state)(struct drm_plane *plane);
+
/**
* @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
* [PATCH v3 12/20] drm/crtc: Add new atomic_create_state callback
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
Commit 47b5ac7daa46 ("drm/atomic: Add new atomic_create_state callback
to drm_private_obj") introduced a new pattern for allocating drm object
states.
Instead of relying on the reset() callback, it created a new
atomic_create_state hook. This is helpful because reset is a bit
overloaded: it's used to create the initial software state, reset it,
but also reset the hardware.
It can also be used either at probe time, to create the initial state
and possibly reset the hardware to an expected default, but also during
suspend/resume.
Both these cases come with different expectations too: during the
initialization, we want to initialize all states, but during
suspend/resume, drm_private_states for example are expected to be kept
around.
reset() also isn't fallible, which makes it harder to handle
initialization errors properly. This is only really relevant for some
drivers though, since all the helpers for reset only create a new
state, and don't touch the hardware at all.
It was thus decided to create a new hook that would allocate and
initialize a pristine state without any side effect:
atomic_create_state to untangle a bit some of it, and to separate the
initialization with the actual reset one might need during a
suspend/resume.
Continue the transition to the new pattern with CRTCs.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 47 +++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_mode_config.c | 21 +++++++++++++-
include/drm/drm_atomic_state_helper.h | 4 +++
include/drm/drm_crtc.h | 16 +++++++++++
4 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 9cd8550cabb7..b7da134c8c50 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -103,10 +103,32 @@ __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc,
crtc->state = crtc_state;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_reset);
+/**
+ * __drm_atomic_helper_crtc_create_state - initializes crtc state
+ * @crtc: crtc object
+ * @state: new state to initialize
+ *
+ * Initializes the newly allocated @state, usually required when
+ * initializing the drivers.
+ *
+ * @state is assumed to be zeroed.
+ *
+ * This is useful for drivers that subclass @drm_crtc_state.
+ */
+void __drm_atomic_helper_crtc_create_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ __drm_atomic_helper_crtc_state_init(state, crtc);
+
+ if (drm_dev_has_vblank(crtc->dev))
+ drm_crtc_vblank_reset(crtc);
+}
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_create_state);
+
/**
* drm_atomic_helper_crtc_reset - default &drm_crtc_funcs.reset hook for CRTCs
* @crtc: drm CRTC
*
* Resets the atomic state for @crtc by freeing the state pointer (which might
@@ -122,10 +144,35 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
__drm_atomic_helper_crtc_reset(crtc, crtc_state);
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
+/**
+ * drm_atomic_helper_crtc_create_state - default &drm_crtc_funcs.atomic_create_state hook for crtcs
+ * @crtc: crtc object
+ *
+ * Initializes a pristine @drm_crtc_state.
+ *
+ * This is useful for drivers that don't subclass @drm_crtc_state.
+ *
+ * RETURNS:
+ * Pointer to new crtc state, or ERR_PTR on failure.
+ */
+struct drm_crtc_state *drm_atomic_helper_crtc_create_state(struct drm_crtc *crtc)
+{
+ struct drm_crtc_state *state;
+
+ state = kzalloc_obj(*state);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_crtc_create_state(crtc, state);
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_create_state);
+
/**
* __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
* @crtc: CRTC object
* @state: atomic CRTC state
*
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 10b7815cbe48..182d9a8104e7 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -196,10 +196,26 @@ static int drm_mode_config_plane_create_state(struct drm_plane *plane)
plane->state = plane_state;
return 0;
}
+static int drm_mode_config_crtc_create_state(struct drm_crtc *crtc)
+{
+ struct drm_crtc_state *crtc_state;
+
+ if (!crtc->funcs->atomic_create_state)
+ return 0;
+
+ crtc_state = crtc->funcs->atomic_create_state(crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ crtc->state = crtc_state;
+
+ return 0;
+}
+
/**
* drm_mode_config_reset - call ->reset callbacks
* @dev: drm device
*
* This functions calls all the crtc's, encoder's and connector's ->reset
@@ -227,13 +243,16 @@ void drm_mode_config_reset(struct drm_device *dev)
plane->funcs->reset(plane);
else if (plane->funcs->atomic_create_state)
drm_mode_config_plane_create_state(plane);
}
- drm_for_each_crtc(crtc, dev)
+ drm_for_each_crtc(crtc, dev) {
if (crtc->funcs->reset)
crtc->funcs->reset(crtc);
+ else if (crtc->funcs->atomic_create_state)
+ drm_mode_config_crtc_create_state(crtc);
+ }
drm_for_each_encoder(encoder, dev)
if (encoder->funcs && encoder->funcs->reset)
encoder->funcs->reset(encoder);
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index e7fbbfdc5d69..129762b99de6 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -43,10 +43,14 @@ struct drm_device;
void __drm_atomic_helper_crtc_state_init(struct drm_crtc_state *state,
struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc,
struct drm_crtc_state *state);
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
+void __drm_atomic_helper_crtc_create_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state);
+struct drm_crtc_state *
+drm_atomic_helper_crtc_create_state(struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
struct drm_crtc_state *
drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 312fc1e745d2..41ea6eadf36f 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -636,10 +636,26 @@ struct drm_crtc_funcs {
* 0 on success or a negative error code on failure.
*/
int (*set_property)(struct drm_crtc *crtc,
struct drm_property *property, uint64_t val);
+ /**
+ * @atomic_create_state:
+ *
+ * Allocates a pristine, initialized, state for the CRTC object
+ * and returns it. This callback must have no side effects: in
+ * particular, the returned state must not be assigned to the
+ * object's state pointer and it must not affect the hardware
+ * state.
+ *
+ * RETURNS:
+ *
+ * A new, pristine, CRTC state instance or an error pointer
+ * on failure.
+ */
+ struct drm_crtc_state *(*atomic_create_state)(struct drm_crtc *crtc);
+
/**
* @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
--
2.53.0
^ permalink raw reply related
* [PATCH v3 11/20] drm/atomic-state-helper: Rename __drm_atomic_helper_crtc_state_reset()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
__drm_atomic_helper_crtc_state_reset() is used to initialize a newly
allocated drm_crtc_state, and is being typically called by the
drm_crtc_funcs.reset implementation.
Since we want to consolidate DRM objects state allocation around the
atomic_create_state callback that will only allocate and initialize a
new drm_crtc_state instance, we will need to call
__drm_atomic_helper_crtc_state_reset() from both the reset and
atomic_create hooks.
To avoid any confusion, we can thus rename
__drm_atomic_helper_crtc_state_reset() to
__drm_atomic_helper_crtc_state_init().
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 10 +++++-----
drivers/gpu/drm/i915/display/intel_crtc.c | 2 +-
include/drm/drm_atomic_state_helper.h | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 50fe4eec41a8..9cd8550cabb7 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -61,25 +61,25 @@
* For other drivers the building blocks are split out, see the documentation
* for these functions.
*/
/**
- * __drm_atomic_helper_crtc_state_reset - reset the CRTC state
+ * __drm_atomic_helper_crtc_state_init - Initializes the CRTC state
* @crtc_state: atomic CRTC state, must not be NULL
* @crtc: CRTC object, must not be NULL
*
* Initializes the newly allocated @crtc_state with default
* values. This is useful for drivers that subclass the CRTC state.
*/
void
-__drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *crtc_state,
- struct drm_crtc *crtc)
+__drm_atomic_helper_crtc_state_init(struct drm_crtc_state *crtc_state,
+ struct drm_crtc *crtc)
{
crtc_state->crtc = crtc;
crtc_state->background_color = DRM_ARGB64_PREP(0xffff, 0, 0, 0);
}
-EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset);
+EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_init);
/**
* __drm_atomic_helper_crtc_reset - reset state on CRTC
* @crtc: drm CRTC
* @crtc_state: CRTC state to assign
@@ -94,11 +94,11 @@ EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset);
void
__drm_atomic_helper_crtc_reset(struct drm_crtc *crtc,
struct drm_crtc_state *crtc_state)
{
if (crtc_state)
- __drm_atomic_helper_crtc_state_reset(crtc_state, crtc);
+ __drm_atomic_helper_crtc_state_init(crtc_state, crtc);
if (drm_dev_has_vblank(crtc->dev))
drm_crtc_vblank_reset(crtc);
crtc->state = crtc_state;
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
index b8189cd5d864..a2ed4a76e061 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -179,11 +179,11 @@ struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
struct intel_crtc *crtc)
{
memset(crtc_state, 0, sizeof(*crtc_state));
- __drm_atomic_helper_crtc_state_reset(&crtc_state->uapi, &crtc->base);
+ __drm_atomic_helper_crtc_state_init(&crtc_state->uapi, &crtc->base);
crtc_state->cpu_transcoder = INVALID_TRANSCODER;
crtc_state->master_transcoder = INVALID_TRANSCODER;
crtc_state->hsw_workaround_pipe = INVALID_PIPE;
crtc_state->scaler_state.scaler_id = -1;
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index df371b2eef3e..e7fbbfdc5d69 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -38,11 +38,11 @@ struct drm_connector_state;
struct drm_private_obj;
struct drm_private_state;
struct drm_modeset_acquire_ctx;
struct drm_device;
-void __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *state,
+void __drm_atomic_helper_crtc_state_init(struct drm_crtc_state *state,
struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_reset(struct drm_crtc *crtc,
struct drm_crtc_state *state);
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
--
2.53.0
^ permalink raw reply related
* [PATCH v3 13/20] drm/atomic-state-helper: Rename __drm_atomic_helper_connector_state_reset()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
__drm_atomic_helper_connector_state_reset() is used to initialize a
newly allocated drm_connector_state, and is being typically called by
the drm_connector_funcs.reset implementation.
Since we want to consolidate DRM objects state allocation around the
atomic_create_state callback that will only allocate and initialize a
new drm_connector_state instance, we will need to call
__drm_atomic_helper_connector_state_reset() from both the reset and
atomic_create hooks.
To avoid any confusion, we can thus rename
__drm_atomic_helper_connector_state_reset() to
__drm_atomic_helper_connector_state_init().
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 12 ++++++------
include/drm/drm_atomic_state_helper.h | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index b7da134c8c50..f67aacaa3b6e 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -496,24 +496,24 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
kfree(state);
}
EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
/**
- * __drm_atomic_helper_connector_state_reset - reset the connector state
+ * __drm_atomic_helper_connector_state_init - Initializes the connector state
* @conn_state: atomic connector state, must not be NULL
- * @connector: connectotr object, must not be NULL
+ * @connector: connector object, must not be NULL
*
* Initializes the newly allocated @conn_state with default
* values. This is useful for drivers that subclass the connector state.
*/
void
-__drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_state,
- struct drm_connector *connector)
+__drm_atomic_helper_connector_state_init(struct drm_connector_state *conn_state,
+ struct drm_connector *connector)
{
conn_state->connector = connector;
}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_state_reset);
+EXPORT_SYMBOL(__drm_atomic_helper_connector_state_init);
/**
* __drm_atomic_helper_connector_reset - reset state on connector
* @connector: drm connector
* @conn_state: connector state to assign
@@ -528,11 +528,11 @@ EXPORT_SYMBOL(__drm_atomic_helper_connector_state_reset);
void
__drm_atomic_helper_connector_reset(struct drm_connector *connector,
struct drm_connector_state *conn_state)
{
if (conn_state)
- __drm_atomic_helper_connector_state_reset(conn_state, connector);
+ __drm_atomic_helper_connector_state_init(conn_state, connector);
connector->state = conn_state;
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_reset);
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 129762b99de6..e7c097e6dfe3 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -70,11 +70,11 @@ struct drm_plane_state *
drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state);
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state);
-void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_state,
+void __drm_atomic_helper_connector_state_init(struct drm_connector_state *conn_state,
struct drm_connector *connector);
void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
struct drm_connector_state *conn_state);
void drm_atomic_helper_connector_reset(struct drm_connector *connector);
void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
--
2.53.0
^ permalink raw reply related
* [PATCH v3 15/20] drm/connector: Add new atomic_create_state callback
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
Commit 47b5ac7daa46 ("drm/atomic: Add new atomic_create_state callback
to drm_private_obj") introduced a new pattern for allocating drm object
states.
Instead of relying on the reset() callback, it created a new
atomic_create_state hook. This is helpful because reset is a bit
overloaded: it's used to create the initial software state, reset it,
but also reset the hardware.
It can also be used either at probe time, to create the initial state
and possibly reset the hardware to an expected default, but also during
suspend/resume.
Both these cases come with different expectations too: during the
initialization, we want to initialize all states, but during
suspend/resume, drm_private_states for example are expected to be kept
around.
reset() also isn't fallible, which makes it harder to handle
initialization errors properly. This is only really relevant for some
drivers though, since all the helpers for reset only create a new
state, and don't touch the hardware at all.
It was thus decided to create a new hook that would allocate and
initialize a pristine state without any side effect:
atomic_create_state to untangle a bit some of it, and to separate the
initialization with the actual reset one might need during a
suspend/resume.
Continue the transition to the new pattern with connectors.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 26 ++++++++++++++++++++++++++
drivers/gpu/drm/drm_mode_config.c | 21 ++++++++++++++++++++-
include/drm/drm_atomic_state_helper.h | 2 ++
include/drm/drm_connector.h | 16 ++++++++++++++++
4 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index f67aacaa3b6e..6140926f4605 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -554,10 +554,36 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
kfree(connector->state);
__drm_atomic_helper_connector_reset(connector, conn_state);
}
EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
+/**
+ * drm_atomic_helper_connector_create_state - default &drm_connector_funcs.atomic_create_state hook for connectors
+ * @connector: connector object
+ *
+ * Initializes a pristine @drm_connector_state.
+ *
+ * This is useful for drivers that don't subclass @drm_connector_state.
+ *
+ * RETURNS:
+ * Pointer to new connector state, or ERR_PTR on failure.
+ */
+struct drm_connector_state *
+drm_atomic_helper_connector_create_state(struct drm_connector *connector)
+{
+ struct drm_connector_state *state;
+
+ state = kzalloc_obj(*state);
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_connector_state_init(state, connector);
+
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_create_state);
+
/**
* drm_atomic_helper_connector_tv_margins_reset - Resets TV connector properties
* @connector: DRM connector
*
* Resets the TV-related properties attached to a connector.
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 182d9a8104e7..92ff907f2485 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -212,10 +212,26 @@ static int drm_mode_config_crtc_create_state(struct drm_crtc *crtc)
crtc->state = crtc_state;
return 0;
}
+static int drm_mode_config_connector_create_state(struct drm_connector *connector)
+{
+ struct drm_connector_state *conn_state;
+
+ if (!connector->funcs->atomic_create_state)
+ return 0;
+
+ conn_state = connector->funcs->atomic_create_state(connector);
+ if (IS_ERR(conn_state))
+ return PTR_ERR(conn_state);
+
+ connector->state = conn_state;
+
+ return 0;
+}
+
/**
* drm_mode_config_reset - call ->reset callbacks
* @dev: drm device
*
* This functions calls all the crtc's, encoder's and connector's ->reset
@@ -255,13 +271,16 @@ void drm_mode_config_reset(struct drm_device *dev)
drm_for_each_encoder(encoder, dev)
if (encoder->funcs && encoder->funcs->reset)
encoder->funcs->reset(encoder);
drm_connector_list_iter_begin(dev, &conn_iter);
- drm_for_each_connector_iter(connector, &conn_iter)
+ drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->funcs->reset)
connector->funcs->reset(connector);
+ else if (connector->funcs->atomic_create_state)
+ drm_mode_config_connector_create_state(connector);
+ }
drm_connector_list_iter_end(&conn_iter);
}
EXPORT_SYMBOL(drm_mode_config_reset);
/*
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index e7c097e6dfe3..8576cd256737 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -75,10 +75,12 @@ void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
void __drm_atomic_helper_connector_state_init(struct drm_connector_state *conn_state,
struct drm_connector *connector);
void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
struct drm_connector_state *conn_state);
void drm_atomic_helper_connector_reset(struct drm_connector *connector);
+struct drm_connector_state *
+drm_atomic_helper_connector_create_state(struct drm_connector *connector);
void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
struct drm_atomic_state *state);
void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector);
void
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 3e422a4f2e72..9fb794957d23 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1569,10 +1569,26 @@ struct drm_connector_funcs {
* when a connector is being hot-unplugged for drivers that support
* connector hotplugging (e.g. DisplayPort MST).
*/
void (*destroy)(struct drm_connector *connector);
+ /**
+ * @atomic_create_state:
+ *
+ * Allocates a pristine, initialized, state for the connector object
+ * and returns it. This callback must have no side effects: in
+ * particular, the returned state must not be assigned to the
+ * object's state pointer and it must not affect the hardware
+ * state.
+ *
+ * RETURNS:
+ *
+ * A new, pristine, connector state instance or an error pointer
+ * on failure.
+ */
+ struct drm_connector_state *(*atomic_create_state)(struct drm_connector *connector);
+
/**
* @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
--
2.53.0
^ permalink raw reply related
* [PATCH v3 14/20] drm/hdmi: Rename __drm_atomic_helper_connector_hdmi_reset()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
__drm_atomic_helper_connector_hdmi_reset() is typically used to
initialize a newly allocated drm_connector_state when the connector is
using the HDMI helpers, and is being called by the
drm_connector_funcs.reset implementation.
Since we want to consolidate DRM objects state allocation around the
atomic_create_state callback that will only allocate and initialize a
new drm_connector_state instance, we will need to call
__drm_atomic_helper_connector_hdmi_reset() from both the reset and
atomic_create hooks.
To avoid any confusion, we can thus rename
__drm_atomic_helper_connector_hdmi_reset() to
__drm_atomic_helper_connector_hdmi_state_init().
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 4 ++--
drivers/gpu/drm/display/drm_hdmi_state_helper.c | 13 +++++++------
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 +-
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 2 +-
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +-
include/drm/display/drm_hdmi_state_helper.h | 4 ++--
6 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 39cc18f78eda..d72f29b73be3 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -270,12 +270,12 @@ static void drm_bridge_connector_reset(struct drm_connector *connector)
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
drm_atomic_helper_connector_reset(connector);
if (bridge_connector->bridge_hdmi)
- __drm_atomic_helper_connector_hdmi_reset(connector,
- connector->state);
+ __drm_atomic_helper_connector_hdmi_state_init(connector,
+ connector->state);
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
.reset = drm_bridge_connector_reset,
.detect = drm_bridge_connector_detect,
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index 9f3b696aceeb..8bf7ad3c99fb 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -304,29 +304,30 @@
* --kunitconfig=drivers/gpu/drm/tests \
* drm_atomic_helper_connector_hdmi_*
*/
/**
- * __drm_atomic_helper_connector_hdmi_reset() - Initializes all HDMI @drm_connector_state resources
+ * __drm_atomic_helper_connector_hdmi_state_init() - Initializes all HDMI @drm_connector_state resources
* @connector: DRM connector
* @new_conn_state: connector state to reset
*
* Initializes all HDMI resources from a @drm_connector_state without
* actually allocating it. This is useful for HDMI drivers, in
- * combination with __drm_atomic_helper_connector_reset() or
- * drm_atomic_helper_connector_reset().
+ * combination with __drm_atomic_helper_connector_state_init(),
+ * drm_atomic_helper_connector_reset(), or
+ * drm_atomic_helper_connector_create_state() .
*/
-void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
- struct drm_connector_state *new_conn_state)
+void __drm_atomic_helper_connector_hdmi_state_init(struct drm_connector *connector,
+ struct drm_connector_state *new_conn_state)
{
unsigned int max_bpc = connector->max_bpc;
new_conn_state->max_bpc = max_bpc;
new_conn_state->max_requested_bpc = max_bpc;
new_conn_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO;
}
-EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
+EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_state_init);
static enum hdmi_colorspace
output_color_format_to_hdmi_colorspace(const struct drm_connector *connector,
enum drm_output_color_format fmt)
{
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index dd2a78defdb4..29dfff4f0055 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -283,11 +283,11 @@ sun4i_hdmi_connector_detect(struct drm_connector *connector, bool force)
}
static void sun4i_hdmi_connector_reset(struct drm_connector *connector)
{
drm_atomic_helper_connector_reset(connector);
- __drm_atomic_helper_connector_hdmi_reset(connector, connector->state);
+ __drm_atomic_helper_connector_hdmi_state_init(connector, connector->state);
}
static const struct drm_connector_funcs sun4i_hdmi_connector_funcs = {
.detect = sun4i_hdmi_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index a4357efaa983..5d671b281f28 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -166,11 +166,11 @@ static const struct drm_connector_helper_funcs dummy_connector_helper_funcs = {
};
static void dummy_hdmi_connector_reset(struct drm_connector *connector)
{
drm_atomic_helper_connector_reset(connector);
- __drm_atomic_helper_connector_hdmi_reset(connector, connector->state);
+ __drm_atomic_helper_connector_hdmi_state_init(connector, connector->state);
}
static const struct drm_connector_funcs dummy_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index a99f53dadb28..14fcee05e133 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -506,11 +506,11 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector,
}
static void vc4_hdmi_connector_reset(struct drm_connector *connector)
{
drm_atomic_helper_connector_reset(connector);
- __drm_atomic_helper_connector_hdmi_reset(connector, connector->state);
+ __drm_atomic_helper_connector_hdmi_state_init(connector, connector->state);
drm_atomic_helper_connector_tv_margins_reset(connector);
}
static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
.force = drm_atomic_helper_connector_hdmi_force,
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index 2349c0d0f00f..f7600aabdd5f 100644
--- a/include/drm/display/drm_hdmi_state_helper.h
+++ b/include/drm/display/drm_hdmi_state_helper.h
@@ -9,12 +9,12 @@ struct drm_connector_state;
struct drm_display_mode;
struct hdmi_audio_infoframe;
enum drm_connector_status;
-void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector,
- struct drm_connector_state *new_conn_state);
+void __drm_atomic_helper_connector_hdmi_state_init(struct drm_connector *connector,
+ struct drm_connector_state *new_conn_state);
int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
struct drm_atomic_state *state);
int drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector,
--
2.53.0
^ permalink raw reply related
* [PATCH v3 16/20] drm/mode-config: Create drm_mode_config_create_initial_state()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
drm_mode_config_reset() can be used to create the initial state, but
also to return to the initial state, when doing a suspend/resume cycle
for example.
It also affects both the software and the hardware, and drivers can
choose to reset the hardware as well. Most will just create an empty
state and the synchronisation between hardware and software states will
effectively be done when the first commit is done.
That dual role can be harmful, since some objects do need to be
initialized but also need to be preserved across a suspend/resume cycle.
drm_private_obj are such objects for example.
Thus, create another helper for drivers to call to initialize their
state when the driver is loaded, so we can make
drm_mode_config_reset() only about handling suspend/resume and similar.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 12 +++++-
drivers/gpu/drm/drm_mode_config.c | 87 +++++++++++++++++++++++++++++++++++++++
include/drm/drm_mode_config.h | 1 +
3 files changed, 98 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 253a00f450b0..f31b6147e682 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -59,12 +59,20 @@
* when preparing the update and kept alive as long as they are active
* in the device.
*
* Their respective lifetimes are:
*
- * - at reset time, the object reset implementation will allocate a new
- * default state and will store it in the object state pointer.
+ * - at driver initialization time, the driver will allocate an initial,
+ * pristine, state and will store it using
+ * drm_mode_config_create_initial_state(). Historically, this was one
+ * of drm_mode_config_reset() job, so one might still encounter it in
+ * a driver.
+ *
+ * - at reset time, for example during suspend/resume,
+ * drm_mode_config_reset() will reset the software and hardware state
+ * to a known default and will store it in the object's state pointer.
+ * Not all objects are affected by drm_mode_config_reset() though.
*
* - whenever a new update is needed:
*
* + A new &struct drm_atomic_state is allocated using
* drm_atomic_state_alloc().
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index 92ff907f2485..a43eb825671b 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -21,10 +21,11 @@
*/
#include <linux/export.h>
#include <linux/uaccess.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_file.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_managed.h>
@@ -281,10 +282,96 @@ void drm_mode_config_reset(struct drm_device *dev)
}
drm_connector_list_iter_end(&conn_iter);
}
EXPORT_SYMBOL(drm_mode_config_reset);
+/**
+ * drm_mode_config_create_initial_state - Allocates the initial state
+ * @dev: drm device
+ *
+ * This functions creates the initial state for all the objects. Drivers
+ * can use this in e.g. probe to initialize their software state.
+ *
+ * It has two main differences with drm_mode_config_reset(): the reset()
+ * hooks aren't called and thus the hardware will be left untouched, but
+ * also the &drm_private_obj structures will be initialized as opposed
+ * to drm_mode_config_reset() that skips them.
+ *
+ * Returns: 0 on success, negative error value on failure.
+ */
+int drm_mode_config_create_initial_state(struct drm_device *dev)
+{
+ struct drm_crtc *crtc;
+ struct drm_colorop *colorop;
+ struct drm_plane *plane;
+ struct drm_connector *connector;
+ struct drm_connector_list_iter conn_iter;
+ struct drm_private_obj *privobj;
+ int ret;
+
+ drm_for_each_privobj(privobj, dev) {
+ struct drm_private_state *privobj_state;
+
+ if (privobj->state)
+ continue;
+
+ if (!privobj->funcs->atomic_create_state)
+ continue;
+
+ privobj_state = privobj->funcs->atomic_create_state(privobj);
+ if (IS_ERR(privobj_state))
+ return PTR_ERR(privobj_state);
+
+ privobj->state = privobj_state;
+ }
+
+ drm_for_each_colorop(colorop, dev) {
+ struct drm_colorop_state *colorop_state;
+
+ if (colorop->state)
+ continue;
+
+ colorop_state = drm_atomic_helper_colorop_create_state(colorop);
+ if (IS_ERR(colorop_state))
+ return PTR_ERR(colorop_state);
+
+ colorop->state = colorop_state;
+ }
+
+ drm_for_each_plane(plane, dev) {
+ if (plane->state)
+ continue;
+
+ ret = drm_mode_config_plane_create_state(plane);
+ if (ret)
+ return ret;
+ }
+
+ drm_for_each_crtc(crtc, dev) {
+ if (crtc->state)
+ continue;
+
+ ret = drm_mode_config_crtc_create_state(crtc);
+ if (ret)
+ return ret;
+ }
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ if (connector->state)
+ continue;
+
+ ret = drm_mode_config_connector_create_state(connector);
+ if (ret)
+ return ret;
+ }
+ drm_connector_list_iter_end(&conn_iter);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_mode_config_create_initial_state);
+
/*
* Global properties
*/
static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 687c0ee163d2..00009250fde4 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -1005,9 +1005,10 @@ int __must_check drmm_mode_config_init(struct drm_device *dev);
static inline int drm_mode_config_init(struct drm_device *dev)
{
return drmm_mode_config_init(dev);
}
+int drm_mode_config_create_initial_state(struct drm_device *dev);
void drm_mode_config_reset(struct drm_device *dev);
void drm_mode_config_cleanup(struct drm_device *dev);
#endif
--
2.53.0
^ permalink raw reply related
* [PATCH v3 17/20] drm/drv: Switch skeleton to drm_mode_config_create_initial_state()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
The driver skeleton currently recommends calling
drm_mode_config_reset() at probe time to create the initial state.
Now that drm_mode_config_create_initial_state() exists to handle
initial state allocation without hardware side effects, update the
skeleton to recommend it instead.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_drv.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 985c283cf59f..f537556b06a8 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -340,11 +340,13 @@ void drm_minor_release(struct drm_minor *minor)
*
* // Further setup, display pipeline etc
*
* platform_set_drvdata(pdev, drm);
*
- * drm_mode_config_reset(drm);
+ * ret = drm_mode_config_create_initial_state(drm);
+ * if (ret)
+ * return ret;
*
* ret = drm_dev_register(drm);
* if (ret)
* return ret;
*
--
2.53.0
^ permalink raw reply related
* [PATCH v3 18/20] drm/tidss: Switch to drm_mode_config_create_initial_state()
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
Now that drm_mode_config_create_initial_state() exists to create the
initial state, use it instead of drm_mode_config_reset() during
driver probe.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_drv.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tidss/tidss_drv.c b/drivers/gpu/drm/tidss/tidss_drv.c
index 1c8cc18bc53c..f5099d5d6e32 100644
--- a/drivers/gpu/drm/tidss/tidss_drv.c
+++ b/drivers/gpu/drm/tidss/tidss_drv.c
@@ -169,11 +169,15 @@ static int tidss_probe(struct platform_device *pdev)
goto err_runtime_suspend;
}
drm_kms_helper_poll_init(ddev);
- drm_mode_config_reset(ddev);
+ ret = drm_mode_config_create_initial_state(ddev);
+ if (ret) {
+ dev_err(dev, "failed to create initial state: %d\n", ret);
+ goto err_irq_uninstall;
+ }
ret = drm_dev_register(ddev, 0);
if (ret) {
dev_err(dev, "failed to register DRM device\n");
goto err_irq_uninstall;
--
2.53.0
^ permalink raw reply related
* [PATCH v3 20/20] drm/bridge_connector: Convert to atomic_create_state
From: Maxime Ripard @ 2026-04-24 10:19 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
The connector created by drm_bridge_connector only initializes a
pristine state in reset, which is equivalent to what
atomic_create_state would expect. Convert to it.
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/display/drm_bridge_connector.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index d72f29b73be3..4b310fe505b4 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -263,26 +263,33 @@ static void drm_bridge_connector_debugfs_init(struct drm_connector *connector,
if (bridge->funcs->debugfs_init)
bridge->funcs->debugfs_init(bridge, root);
}
}
-static void drm_bridge_connector_reset(struct drm_connector *connector)
+static struct drm_connector_state *
+drm_bridge_connector_create_state(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
+ struct drm_connector_state *conn_state;
+
+ conn_state = drm_atomic_helper_connector_create_state(connector);
+ if (IS_ERR(conn_state))
+ return conn_state;
- drm_atomic_helper_connector_reset(connector);
if (bridge_connector->bridge_hdmi)
__drm_atomic_helper_connector_hdmi_state_init(connector,
- connector->state);
+ conn_state);
+
+ return conn_state;
}
static const struct drm_connector_funcs drm_bridge_connector_funcs = {
- .reset = drm_bridge_connector_reset,
.detect = drm_bridge_connector_detect,
.force = drm_bridge_connector_force,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .atomic_create_state = drm_bridge_connector_create_state,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.debugfs_init = drm_bridge_connector_debugfs_init,
.oob_hotplug_event = drm_bridge_connector_oob_hotplug_event,
};
--
2.53.0
^ permalink raw reply related
* [PATCH v3 19/20] drm/tidss: Convert to atomic_create_state
From: Maxime Ripard @ 2026-04-24 10:18 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Jonathan Corbet, Shuah Khan, Dmitry Baryshkov, Jyri Sarha,
Tomi Valkeinen, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Simon Ser,
Harry Wentland, Melissa Wen, Sebastian Wick, Alex Hung,
Jani Nikula, Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin,
Chen-Yu Tsai, Samuel Holland, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance
Cc: dri-devel, linux-doc, linux-kernel, Daniel Stone, intel-gfx,
intel-xe, linux-arm-kernel, linux-sunxi, Maxime Ripard,
Laurent Pinchart
In-Reply-To: <20260424-drm-mode-config-init-v3-0-8b68d9db0d8b@kernel.org>
Our driver uses reset to create the various object states, but only
calls the helper that allocate a new state. They are thus strictly
equivalent to the new atomic_create_state helpers, so let's switch to
these.
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 17 +++++++----------
drivers/gpu/drm/tidss/tidss_plane.c | 2 +-
2 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index a31c21c5f855..66e3d161c60b 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -355,24 +355,21 @@ static void tidss_crtc_destroy_state(struct drm_crtc *crtc,
__drm_atomic_helper_crtc_destroy_state(&tstate->base);
kfree(tstate);
}
-static void tidss_crtc_reset(struct drm_crtc *crtc)
+static struct drm_crtc_state *tidss_crtc_create_state(struct drm_crtc *crtc)
{
struct tidss_crtc_state *tstate;
- if (crtc->state)
- tidss_crtc_destroy_state(crtc, crtc->state);
-
tstate = kzalloc_obj(*tstate);
- if (!tstate) {
- crtc->state = NULL;
- return;
- }
+ if (!tstate)
+ return ERR_PTR(-ENOMEM);
- __drm_atomic_helper_crtc_reset(crtc, &tstate->base);
+ __drm_atomic_helper_crtc_create_state(crtc, &tstate->base);
+
+ return &tstate->base;
}
static struct drm_crtc_state *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct tidss_crtc_state *state, *current_state;
@@ -403,14 +400,14 @@ static void tidss_crtc_destroy(struct drm_crtc *crtc)
drm_crtc_cleanup(crtc);
kfree(tcrtc);
}
static const struct drm_crtc_funcs tidss_crtc_funcs = {
- .reset = tidss_crtc_reset,
.destroy = tidss_crtc_destroy,
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
+ .atomic_create_state = tidss_crtc_create_state,
.atomic_duplicate_state = tidss_crtc_duplicate_state,
.atomic_destroy_state = tidss_crtc_destroy_state,
.enable_vblank = tidss_crtc_enable_vblank,
.disable_vblank = tidss_crtc_disable_vblank,
};
diff --git a/drivers/gpu/drm/tidss/tidss_plane.c b/drivers/gpu/drm/tidss/tidss_plane.c
index aaa02c851c59..518498d45765 100644
--- a/drivers/gpu/drm/tidss/tidss_plane.c
+++ b/drivers/gpu/drm/tidss/tidss_plane.c
@@ -176,12 +176,12 @@ static const struct drm_plane_helper_funcs tidss_primary_plane_helper_funcs = {
};
static const struct drm_plane_funcs tidss_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
- .reset = drm_atomic_helper_plane_reset,
.destroy = drm_plane_destroy,
+ .atomic_create_state = drm_atomic_helper_plane_create_state,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v5 0/6] Add Rockchip RK3576 PWM Support Through MFPWM
From: Uwe Kleine-König @ 2026-04-24 10:43 UTC (permalink / raw)
To: Nicolas Frattaroli
Cc: Jonathan Cameron, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, Lee Jones, William Breathitt Gray, Damon Ding,
kernel, Alexey Charkov, linux-rockchip, linux-pwm, devicetree,
linux-arm-kernel, linux-kernel, linux-iio, Conor Dooley
In-Reply-To: <dB_doorKQsK5TdJ40Tv8Lw@collabora.com>
[-- Attachment #1: Type: text/plain, Size: 2784 bytes --]
[Dropped Jonas Karlman from Cc:, their email bounced for me in the past]
Hello Nicolas,
On Wed, Apr 22, 2026 at 01:31:14PM +0200, Nicolas Frattaroli wrote:
> On Tuesday, 21 April 2026 17:56:56 Central European Summer Time Jonathan Cameron wrote:
> > On Mon, 20 Apr 2026 15:52:37 +0200
> > Nicolas Frattaroli <nicolas.frattaroli@collabora.com> wrote:
> >
> > > This series introduces support for some of the functions of the new PWM
> > > silicon found on Rockchip's RK3576 SoC. Due to the wide range of
> > > functionalities offered by it, including many parts which this series'
> > > first iteration does not attempt to implement for now. The drivers are
> > > modelled as an MFD, with no leakage of the MFD-ness into the binding, as
> > > it's a Linux implementation detail.
> >
> > Just thought I'd point out that as this includes the linux-iio
> > list sashiko took a look at it. Quite a few things and at least
> > the first one I looked at was valid (a dereference before a validity
> > check)
> >
> > https://sashiko.dev/#/patchset/20260420-rk3576-pwm-v5-0-ae7cfbbe5427%40collabora.com
> >
> > Whilst this tool does generate some false positives, it also finds
> > quite a few things it seems us humans fail to spot.
> >
> > Jonathan
> >
>
> While I'm not entirely opposed to this, I do think reviews should happen
> on-list when possible. Sashiko is a Google service, so it has about a 50%
> chance of still being around in 2 years time. One of the benefits of the
> kernel development workflow is that discussion going back decades is still
> accessible.
I mostly agree to your point. A possibility that I would consider
compatible with on-list review is looking through what Sashiko found and
address that on the list. Something like
https://lore.kernel.org/all/20260420204647.1713944-2-u.kleine-koenig@baylibre.com/
> The reason why these aren't posted to list goes into the other thing
> that I currently am not stoked about, which is that I'd have to act as
> a filter for a Bring-Your-Own-Brain noise generator to pick out the
> parts that aren't convincing lies.
I didn't look through the complete feedback, but the part that I looked
at (I'd say the rough half) seems to be legitimate.
I'm also have reservations about AI, but my (little) experience with
this one seems to show that it's in the better half of the scale between
helpful and useless time consumer. So when I come around to review your
series I will for sure look through their feedback in more detail. That
means that if I'm too slow for you, looking through the feedback
yourself and addressing that (or deciding against it) might be a good
way to spend the waiting time and maybe even making it easier for me.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v2] pwm: atmel-tcb: Cache clock rates and mark chip as atomic
From: Uwe Kleine-König @ 2026-04-24 10:46 UTC (permalink / raw)
To: Sangyun Kim
Cc: nicolas.ferre, alexandre.belloni, claudiu.beznea, linux-pwm,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260422044940.tse3ek7jlv3x2dbt@nunu>
[-- Attachment #1: Type: text/plain, Size: 1370 bytes --]
Hello Sangyun,
On Wed, Apr 22, 2026 at 01:49:40PM +0900, Sangyun Kim wrote:
> > On Sun, Apr 19, 2026 at 05:08:38PM +0900, Sangyun Kim wrote:
> > > @@ -438,16 +441,33 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
> > > if (err)
> > > goto err_gclk;
> > >
> > > + err = clk_rate_exclusive_get(tcbpwmc->clk);
> > > + if (err)
> > > + goto err_disable_clk;
> > > +
> > > + err = clk_rate_exclusive_get(tcbpwmc->slow_clk);
> > > + if (err)
> > > + goto err_clk_unlock;
> > > +
> > > + tcbpwmc->rate = clk_get_rate(tcbpwmc->clk);
> > > + tcbpwmc->slow_rate = clk_get_rate(tcbpwmc->slow_clk);
> > > +
> >
> > Only one concern left: clk_get_rate() should only be called on enabled
> > clocks. I don't know the architecture details and how expensive it is to
> > have .clk enabled (or if it's enabled anyhow).
> >
> > If you're ok, I'd squash the following diff into your patch:
>
> That makes sense. clk_get_rate() should indeed only be used on enabled
> clocks, and your change is the simplest way to ensure correctness while
> respecting the clk API constraints. I’m happy with squashing your diff
> into my patch.
Just for the record: I did that, the result is already in Linus' tree
at https://git.kernel.org/linus/68637b68afcc3cb4d56aca14a3a1d1b47b879369
and will be part of v7.1-rc1.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v3 3/3] ARM: at91: remove unnecessary of_platform_default_populate calls
From: Alexander Dahl @ 2026-04-24 10:56 UTC (permalink / raw)
To: Rob Herring (Arm), Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Nicolas Ferre, Alexandre Belloni,
Claudiu Beznea, Russell King, linux-mtd, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260423-stoke-ocean-139dbe306256@thorsis.com>
Hei hei,
after few hints in IRC yesterday, I tried to understand why neither
the ebi driver nor the nand driver are probed, but I failed. See below.
Am Thu, Apr 23, 2026 at 10:24:46AM +0200 schrieb Alexander Dahl:
> Hello everyone,
>
> I'm afraid this patch breaks finding rootfs on raw nand on sam9x60,
> see below:
>
> Am Mon, Jan 05, 2026 at 03:06:45PM -0600 schrieb Rob Herring (Arm):
> > The DT core will call of_platform_default_populate, so it is not
> > necessary for machine specific code to call it unless there are custom
> > match entries, auxdata or parent device. Neither of those apply here, so
> > remove the call.
> >
> > Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> > Tested-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> > Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
>
> Not sure what was actually tested, but this change breaks booting from
> raw NAND flash on our sam9x60 based board. I bisected the boot
> failure to this exact change. Before the change I see the nand
> controller messages in the kernel log like this:
>
> atmel-nand-controller 10000000.ebi:nand-controller: using dma0chan5 for DMA transfers
> nand: device found, Manufacturer ID: 0x01, Chip ID: 0xda
> nand: AMD/Spansion S34ML02G1
> nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
>
> After the change, there are no kernel log messages related to nand at
> all, the driver does not seem to load. This of course leads to no mtd
> and ubi devices created, no ubi volumes found, no rootfs, and
> eventually this message:
>
> VFS: Cannot open root device "ubi0:rootfs2" or unknown-block(0,253): error -19
>
> I tried to understand the whole patch series, and to my understanding
> the intend was the device nodes still get populated, and the drivers
> loaded, right? Patch 1/3 is related to the atmel nand controller, and
> that one is not in the tree yet when bisecting to the end. However it
> is present in v7.0-rc1 (and later) and trying to boot that kernel (or
> 7.0 or todays master) fails, too. (Also I don't see those probe defer
> messages related to SRAM on v7.0-rc1, so I assume that's not the
> problem?)
>
> Now the strange thing is: on a different hardware based on sama5d2
> v7.0-rc1 boots fine from raw nand flash. I wonder what's the
> difference which makes it work on one atmel platform and not work on
> the other?
>
> I compared kernel .config of both boards, no obvious pieces missing.
> Looking at the dts (and included dtsi) files of both boards I could
> spot no mistake. Also no obvious flaws in sama5d2.dtsi or
> sam9x60.dtsi.
>
> Note: raw NAND flash is the only storage for rootfs on our platforms,
> we can not simply put rootfs to a different storage. I could try
> setting up NFS boot for further investigation, but that will take a
> while.
Meanwhile I got to boot the device over NFS and did some
instrumentation of the atmel-ebi driver and the atmel rawnand driver.
Can confirm, that the probe functions of those drivers are not called
(still v7.0-rc1 on sam9x60). The atmel-pmecc driver however actually
is probed/loaded, but that device node sits in a different area of the
device tree.
> Does anyone have an idea how to make booting from raw NAND flash work
> on sam9x60 again (despite the obviously not desired revert)? What can
> I try? What information would be interesting for debugging?
Tried booting with cmdline option 'fw_devlink=off' but that did not
change anything.
When mounting debugfs, the file /sys/kernel/debug/devices_deferred is
empty, so deferred devices waiting on something seems not the cause.
Strange thing is /sys/bus/platform/devices/ has an entry
'10000000.ebi' but none for the child node of the nand-controller.
And /sys/bus/platform/drivers has an entry for 'atmel-nand-controller'
but 'atmel-ebi' is missing (it is not on the sama5d2 system).
I don't get what the key difference between those systems is and
what's necessary so the atmel-ebi probe function gets called?
The fw_devlink stuff also does not really make sense to me. FWIW,
from the sam9x60 system:
$ ls -1 /sys/class/devlink/
platform:ahb:apb:pinctrl@fffff400--platform:10000000.ebi
platform:ahb:apb:pinctrl@fffff400--platform:f0014000.spi
platform:ahb:apb:pinctrl@fffff400--platform:f802c000.ethernet
platform:ahb:apb:pinctrl@fffff400--platform:fffff200.serial
platform:ahb:apb:pinctrl@fffff400--platform:gpio-keys
platform:ahb:apb:pinctrl@fffff400--platform:led-controller-0
platform:ahb:apb:pinctrl@fffff400--platform:spi-gpio-1
platform:fffff400.gpio--platform:spi-gpio-1
platform:fffff600.gpio--mdio_bus:f802c000.ethernet-ffffffff:03
platform:fffff600.gpio--spi:spi1.0
platform:fffffa00.gpio--platform:10000000.ebi
The sama5d2 system (which successfully loads the nand-controller
driver) has this:
$ ls -1 /sys/class/devlink/
platform:ahb:apb--platform:f8034200.serial
platform:f802c000.pwm--platform:led-controller-1
platform:fc038000.pinctrl--platform:10000000.ebi
platform:fc038000.pinctrl--platform:f8000000.spi
platform:fc038000.pinctrl--platform:f8008000.ethernet
platform:fc038000.pinctrl--platform:f8020000.serial
platform:fc038000.pinctrl--platform:f802c000.pwm
platform:fc038000.pinctrl--platform:f8034000.flexcom
platform:fc038000.pinctrl--platform:gpio-keys
platform:fc038000.pinctrl--spi:spi0.0
So both platforms use different pinctrl drivers (pinctrl-at91-pio4.c
vs. pinctrl-at91.c) but can that be the issue?
I know not many people use raw nand on at91, but any ideas welcome.
Also where I should look in sysfs, debugfs, or code?
Greets
Alex
> Greets
> Alex
>
> > ---
> > v3:
> > - Fixup split between patch 2 and 3.
> >
> > v2:
> > - Dust off and rebase to 6.18-rc1
> > - Add new platforms added since v1
> > ---
> > arch/arm/mach-at91/at91rm9200.c | 9 ---------
> > arch/arm/mach-at91/at91sam9.c | 9 ---------
> > arch/arm/mach-at91/sam9x60.c | 9 ---------
> > arch/arm/mach-at91/sam9x7.c | 9 ---------
> > arch/arm/mach-at91/sama5.c | 16 ----------------
> > arch/arm/mach-at91/sama7.c | 9 ---------
> > 6 files changed, 61 deletions(-)
> >
> > diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
> > index 2ac564eb8bbb..d15997fff5d7 100644
> > --- a/arch/arm/mach-at91/at91rm9200.c
> > +++ b/arch/arm/mach-at91/at91rm9200.c
> > @@ -7,18 +7,10 @@
> > * 2012 Joachim Eastwood <manabian@gmail.com>
> > */
> >
> > -#include <linux/of.h>
> > -#include <linux/of_platform.h>
> > -
> > #include <asm/mach/arch.h>
> >
> > #include "generic.h"
> >
> > -static void __init at91rm9200_dt_device_init(void)
> > -{
> > - of_platform_default_populate(NULL, NULL, NULL);
> > -}
> > -
> > static const char *const at91rm9200_dt_board_compat[] __initconst = {
> > "atmel,at91rm9200",
> > NULL
> > @@ -26,6 +18,5 @@ static const char *const at91rm9200_dt_board_compat[] __initconst = {
> >
> > DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200")
> > .init_late = at91rm9200_pm_init,
> > - .init_machine = at91rm9200_dt_device_init,
> > .dt_compat = at91rm9200_dt_board_compat,
> > MACHINE_END
> > diff --git a/arch/arm/mach-at91/at91sam9.c b/arch/arm/mach-at91/at91sam9.c
> > index cf07cba4ee5d..b9d2909d1b65 100644
> > --- a/arch/arm/mach-at91/at91sam9.c
> > +++ b/arch/arm/mach-at91/at91sam9.c
> > @@ -6,19 +6,11 @@
> > * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>
> > */
> >
> > -#include <linux/of.h>
> > -#include <linux/of_platform.h>
> > -
> > #include <asm/mach/arch.h>
> > #include <asm/system_misc.h>
> >
> > #include "generic.h"
> >
> > -static void __init at91sam9_init(void)
> > -{
> > - of_platform_default_populate(NULL, NULL, NULL);
> > -}
> > -
> > static const char *const at91_dt_board_compat[] __initconst = {
> > "atmel,at91sam9",
> > NULL
> > @@ -27,6 +19,5 @@ static const char *const at91_dt_board_compat[] __initconst = {
> > DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM9")
> > /* Maintainer: Atmel */
> > .init_late = at91sam9_pm_init,
> > - .init_machine = at91sam9_init,
> > .dt_compat = at91_dt_board_compat,
> > MACHINE_END
> > diff --git a/arch/arm/mach-at91/sam9x60.c b/arch/arm/mach-at91/sam9x60.c
> > index a31beaaeffcd..744bab2cbb92 100644
> > --- a/arch/arm/mach-at91/sam9x60.c
> > +++ b/arch/arm/mach-at91/sam9x60.c
> > @@ -7,19 +7,11 @@
> > * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
> > */
> >
> > -#include <linux/of.h>
> > -#include <linux/of_platform.h>
> > -
> > #include <asm/mach/arch.h>
> > #include <asm/system_misc.h>
> >
> > #include "generic.h"
> >
> > -static void __init sam9x60_init(void)
> > -{
> > - of_platform_default_populate(NULL, NULL, NULL);
> > -}
> > -
> > static const char *const sam9x60_dt_board_compat[] __initconst = {
> > "microchip,sam9x60",
> > NULL
> > @@ -28,6 +20,5 @@ static const char *const sam9x60_dt_board_compat[] __initconst = {
> > DT_MACHINE_START(sam9x60_dt, "Microchip SAM9X60")
> > /* Maintainer: Microchip */
> > .init_late = sam9x60_pm_init,
> > - .init_machine = sam9x60_init,
> > .dt_compat = sam9x60_dt_board_compat,
> > MACHINE_END
> > diff --git a/arch/arm/mach-at91/sam9x7.c b/arch/arm/mach-at91/sam9x7.c
> > index 0c73f7fefd4f..166c8625509d 100644
> > --- a/arch/arm/mach-at91/sam9x7.c
> > +++ b/arch/arm/mach-at91/sam9x7.c
> > @@ -7,18 +7,10 @@
> > * Author: Varshini Rajendran <varshini.rajendran@microchip.com>
> > */
> >
> > -#include <linux/of.h>
> > -#include <linux/of_platform.h>
> > -
> > #include <asm/mach/arch.h>
> >
> > #include "generic.h"
> >
> > -static void __init sam9x7_init(void)
> > -{
> > - of_platform_default_populate(NULL, NULL, NULL);
> > -}
> > -
> > static const char * const sam9x7_dt_board_compat[] __initconst = {
> > "microchip,sam9x7",
> > NULL
> > @@ -27,6 +19,5 @@ static const char * const sam9x7_dt_board_compat[] __initconst = {
> > DT_MACHINE_START(sam9x7_dt, "Microchip SAM9X7")
> > /* Maintainer: Microchip */
> > .init_late = sam9x7_pm_init,
> > - .init_machine = sam9x7_init,
> > .dt_compat = sam9x7_dt_board_compat,
> > MACHINE_END
> > diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c
> > index 576654cba82d..e56022f00800 100644
> > --- a/arch/arm/mach-at91/sama5.c
> > +++ b/arch/arm/mach-at91/sama5.c
> > @@ -6,9 +6,6 @@
> > * 2013 Ludovic Desroches <ludovic.desroches@atmel.com>
> > */
> >
> > -#include <linux/of.h>
> > -#include <linux/of_platform.h>
> > -
> > #include <asm/hardware/cache-l2x0.h>
> > #include <asm/mach/arch.h>
> > #include <asm/mach/map.h>
> > @@ -30,11 +27,6 @@ static void __init sama5_secure_cache_init(void)
> > outer_cache.write_sec = sama5_l2c310_write_sec;
> > }
> >
> > -static void __init sama5_dt_device_init(void)
> > -{
> > - of_platform_default_populate(NULL, NULL, NULL);
> > -}
> > -
> > static const char *const sama5_dt_board_compat[] __initconst = {
> > "atmel,sama5",
> > NULL
> > @@ -43,7 +35,6 @@ static const char *const sama5_dt_board_compat[] __initconst = {
> > DT_MACHINE_START(sama5_dt, "Atmel SAMA5")
> > /* Maintainer: Atmel */
> > .init_late = sama5_pm_init,
> > - .init_machine = sama5_dt_device_init,
> > .dt_compat = sama5_dt_board_compat,
> > MACHINE_END
> >
> > @@ -54,17 +45,11 @@ static const char *const sama5_alt_dt_board_compat[] __initconst = {
> >
> > DT_MACHINE_START(sama5_alt_dt, "Atmel SAMA5")
> > /* Maintainer: Atmel */
> > - .init_machine = sama5_dt_device_init,
> > .init_late = sama5_pm_init,
> > .dt_compat = sama5_alt_dt_board_compat,
> > .l2c_aux_mask = ~0UL,
> > MACHINE_END
> >
> > -static void __init sama5d2_init(void)
> > -{
> > - of_platform_default_populate(NULL, NULL, NULL);
> > -}
> > -
> > static const char *const sama5d2_compat[] __initconst = {
> > "atmel,sama5d2",
> > NULL
> > @@ -72,7 +57,6 @@ static const char *const sama5d2_compat[] __initconst = {
> >
> > DT_MACHINE_START(sama5d2, "Atmel SAMA5")
> > /* Maintainer: Atmel */
> > - .init_machine = sama5d2_init,
> > .init_early = sama5_secure_cache_init,
> > .init_late = sama5d2_pm_init,
> > .dt_compat = sama5d2_compat,
> > diff --git a/arch/arm/mach-at91/sama7.c b/arch/arm/mach-at91/sama7.c
> > index 8bf57a020f1c..f56828d61199 100644
> > --- a/arch/arm/mach-at91/sama7.c
> > +++ b/arch/arm/mach-at91/sama7.c
> > @@ -6,19 +6,11 @@
> > *
> > */
> >
> > -#include <linux/of.h>
> > -#include <linux/of_platform.h>
> > -
> > #include <asm/mach/arch.h>
> > #include <asm/system_misc.h>
> >
> > #include "generic.h"
> >
> > -static void __init sama7_dt_device_init(void)
> > -{
> > - of_platform_default_populate(NULL, NULL, NULL);
> > -}
> > -
> > static const char *const sama7_dt_board_compat[] __initconst = {
> > "microchip,sama7",
> > NULL
> > @@ -27,7 +19,6 @@ static const char *const sama7_dt_board_compat[] __initconst = {
> > DT_MACHINE_START(sama7_dt, "Microchip SAMA7")
> > /* Maintainer: Microchip */
> > .init_late = sama7_pm_init,
> > - .init_machine = sama7_dt_device_init,
> > .dt_compat = sama7_dt_board_compat,
> > MACHINE_END
> >
> >
> > --
> > 2.51.0
> >
> >
>
^ permalink raw reply
* Re: [PATCH 0/6] KVM: arm64: pKVM init and feature detection fixes
From: Marc Zyngier @ 2026-04-24 11:02 UTC (permalink / raw)
To: Fuad Tabba
Cc: kvmarm, linux-arm-kernel, linux-kernel, catalin.marinas, will,
oupton, qperret, suzuki.poulose, joey.gouly, yuzenghui
In-Reply-To: <20260424084908.370776-1-tabba@google.com>
On Fri, 24 Apr 2026 09:49:02 +0100,
Fuad Tabba <tabba@google.com> wrote:
>
> Hi folks,
>
> These six patches are standalone correctness fixes I'd like to land
> before posting a follow-up to Will's pKVM infrastructure series [1]
> that moves vCPU state management to EL2. Sending them separately keeps
> the bigger series focused, but they are all valid fixes to have
> regardless.
Thanks for posting these, and splitting them from the largest series.
I've taken them as a whole, and marked the as Cc stable, except for
patch #2.
Cheers,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: (subset) [PATCH 1/3] KVM: arm64: vgic: Fix IIDR revision field extracted from wrong value
From: Marc Zyngier @ 2026-04-24 11:07 UTC (permalink / raw)
To: Oliver Upton, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Catalin Marinas, Will Deacon, Paolo Bonzini, Shuah Khan,
David Woodhouse, Raghavendra Rao Ananta, Eric Auger, Kees Cook,
Arnd Bergmann, Nathan Chancellor, linux-arm-kernel, kvmarm,
linux-kernel, kvm, linux-kselftest, David Woodhouse
In-Reply-To: <20260407210949.2076251-2-dwmw2@infradead.org>
On Tue, 07 Apr 2026 21:27:02 +0100, David Woodhouse wrote:
> The uaccess write handlers for GICD_IIDR in both GICv2 and GICv3
> extract the revision field from 'reg' (the current IIDR value read back
> from the emulated distributor) instead of 'val' (the value userspace is
> trying to write). This means userspace can never actually change the
> implementation revision — the extracted value is always the current one.
>
> Fix the FIELD_GET to use 'val' so that userspace can select a different
> revision for migration compatibility.
>
> [...]
Applied to fixes, thanks!
[1/3] KVM: arm64: vgic: Fix IIDR revision field extracted from wrong value
commit: a0e6ae45af17e8b27958830595799c702ffbab8d
Cheers,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH v2] KVM: arm64: Reject non compliant SMCCC function calls in pKVM
From: Marc Zyngier @ 2026-04-24 11:08 UTC (permalink / raw)
To: catalin.marinas, kvmarm, linux-arm-kernel, linux-kernel,
android-kvm, Sebastian Ene
Cc: joey.gouly, korneld, mrigendra.chaubey, oupton, perlarsen,
suzuki.poulose, will, yuzenghui
In-Reply-To: <20260408114118.422604-1-sebastianene@google.com>
On Wed, 08 Apr 2026 11:41:18 +0000, Sebastian Ene wrote:
> Prevent the propagation of a function-id that has the top bits set since
> this is not compliant with the SMCCC spec and can overlap with the
> already known function-id decoders. (eg. if we invoke an smc with
> 0xffffffffc4000012 it will be decoded as a PSCI reset call). Instead,
> make it clear that we don't support it and return an error.
>
>
> [...]
Applied to fixes, thanks!
[1/1] KVM: arm64: Reject non compliant SMCCC function calls in pKVM
commit: 480ea48cad873b49a1fabd07c0847c3cf1c32286
Cheers,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH 0/6] KVM: arm64: pKVM init and feature detection fixes
From: Marc Zyngier @ 2026-04-24 11:08 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, linux-kernel, Fuad Tabba
Cc: catalin.marinas, will, oupton, qperret, suzuki.poulose,
joey.gouly, yuzenghui
In-Reply-To: <20260424084908.370776-1-tabba@google.com>
On Fri, 24 Apr 2026 09:49:02 +0100, Fuad Tabba wrote:
> These six patches are standalone correctness fixes I'd like to land
> before posting a follow-up to Will's pKVM infrastructure series [1]
> that moves vCPU state management to EL2. Sending them separately keeps
> the bigger series focused, but they are all valid fixes to have
> regardless.
>
> The first patch fixes feature detection for FEAT_Debugv8p9: it was
> checking the wrong field in ID_AA64DFR0_EL1, causing KVM to treat
> certain EL2 control bits as RES0 on hardware that implements the
> feature.
>
> [...]
Applied to fixes, thanks!
[1/6] KVM: arm64: Fix FEAT_Debugv8p9 to check DebugVer, not PMUVer
commit: 7fe2cd4e1a3ad230d8fcc00cc99c4bcce4412a75
[2/6] KVM: arm64: Fix typo in feature check comments
commit: 2a623408112626d2625a6f00aed665861d59665c
[3/6] KVM: arm64: Fix FEAT_SPE_FnE to use PMSIDR_EL1.FnE, not PMSVer
commit: 08d715338287a1affb4c7ad5733decef4558a5c8
[4/6] KVM: arm64: Fix kvm_vcpu_initialized() macro parameter
commit: d89fdda7dd8a488f922e1175e6782f781ba8a23b
[5/6] KVM: arm64: Fix pin leak and publication ordering in __pkvm_init_vcpu()
commit: 73b9c1e5da84cd69b1a86e374e450817cd051371
[6/6] KVM: arm64: Fix initialisation order in __pkvm_init_finalise()
commit: 5bb0aed57ba944f8c201e4e82ec066e0187e0f85
Cheers,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* [PATCH v22 1/8] soc: cadence: Create helper functions for Cadence MHDP
From: Laurentiu Palcu @ 2026-04-24 11:07 UTC (permalink / raw)
To: Parshuram Thombare, Swapnil Jakhade, Dmitry Baryshkov,
Nikhil Devshatwar, Jayesh Choudhary
Cc: dri-devel, devicetree, linux-kernel, linux-phy, imx,
linux-arm-kernel, linux, Alexander Stein, Ying Liu
In-Reply-To: <20260424-dcss-hdmi-upstreaming-v22-0-30a28f89298d@oss.nxp.com>
From: Sandor Yu <Sandor.yu@nxp.com>
Cadence MHDP IP includes a firmware. Driver and firmware communicate
through a mailbox. The basic mailbox access functions in this patch are
derived from the DRM bridge MHDP8546 driver. New mailbox access
functions have been created based on different mailbox return values and
security types, making them reusable across different MHDP driver
versions and SOCs.
These helper fucntions will be reused in both the DRM bridge driver
MDHP8501 and the i.MX8MQ HDPTX PHY driver.
Six mailbox access helper functions are introduced.
Three for non-secure mailbox access:
- cdns_mhdp_mailbox_send()
- cdns_mhdp_mailbox_send_recv()
- cdns_mhdp_mailbox_send_recv_multi()
The other three for secure mailbox access:
- cdns_mhdp_secure_mailbox_send()
- cdns_mhdp_secure_mailbox_send_recv()
- cdns_mhdp_secure_mailbox_send_recv_multi()
All MHDP commands that need to be passed through the mailbox
should be rewritten using these new helper functions.
The register read/write and DP DPCD read/write command functions
are also included in this new helper driver.
Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
Co-developed-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
---
To: Parshuram Thombare <pthombar@cadence.com>
To: Swapnil Jakhade <sjakhade@cadence.com>
To: Dmitry Baryshkov <lumag@kernel.org>
To: Nikhil Devshatwar <nikhil.nd@ti.com>
To: Jayesh Choudhary <j-choudhary@ti.com>
---
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/cadence/Kconfig | 9 +
drivers/soc/cadence/Makefile | 3 +
drivers/soc/cadence/cdns-mhdp-helper.c | 611 +++++++++++++++++++++++++++++++++
include/soc/cadence/cdns-mhdp-helper.h | 143 ++++++++
6 files changed, 768 insertions(+)
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index a2d65adffb805..8f2114b9a6b7d 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -6,6 +6,7 @@ source "drivers/soc/apple/Kconfig"
source "drivers/soc/aspeed/Kconfig"
source "drivers/soc/atmel/Kconfig"
source "drivers/soc/bcm/Kconfig"
+source "drivers/soc/cadence/Kconfig"
source "drivers/soc/canaan/Kconfig"
source "drivers/soc/cirrus/Kconfig"
source "drivers/soc/fsl/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index c9e689080ceb7..33612ccdf5c47 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -7,6 +7,7 @@ obj-y += apple/
obj-y += aspeed/
obj-$(CONFIG_ARCH_AT91) += atmel/
obj-y += bcm/
+obj-y += cadence/
obj-$(CONFIG_ARCH_CANAAN) += canaan/
obj-$(CONFIG_EP93XX_SOC) += cirrus/
obj-$(CONFIG_ARCH_DOVE) += dove/
diff --git a/drivers/soc/cadence/Kconfig b/drivers/soc/cadence/Kconfig
new file mode 100644
index 0000000000000..d4a8e8e751882
--- /dev/null
+++ b/drivers/soc/cadence/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config CDNS_MHDP_HELPER
+ tristate
+ help
+ Enable Cadence MHDP helpers for mailbox, HDMI and DP.
+ This driver provides a foundational layer of mailbox communication for
+ various Cadence MHDP IP implementations, such as HDMI and DisplayPort.
+
diff --git a/drivers/soc/cadence/Makefile b/drivers/soc/cadence/Makefile
new file mode 100644
index 0000000000000..a1f42e1936ca5
--- /dev/null
+++ b/drivers/soc/cadence/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_CDNS_MHDP_HELPER) += cdns-mhdp-helper.o
diff --git a/drivers/soc/cadence/cdns-mhdp-helper.c b/drivers/soc/cadence/cdns-mhdp-helper.c
new file mode 100644
index 0000000000000..5657e88131ba1
--- /dev/null
+++ b/drivers/soc/cadence/cdns-mhdp-helper.c
@@ -0,0 +1,611 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, 2024 NXP Semiconductor, Inc.
+ *
+ */
+#include <linux/dev_printk.h>
+#include <linux/module.h>
+#include <soc/cadence/cdns-mhdp-helper.h>
+
+/* Mailbox helper functions */
+static int mhdp_mailbox_read(struct cdns_mhdp_base *base)
+{
+ int ret, empty;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->regs + CDNS_MAILBOX_EMPTY,
+ empty, !empty, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ return readl(base->regs + CDNS_MAILBOX_RX_DATA) & 0xff;
+}
+
+static int mhdp_mailbox_write(struct cdns_mhdp_base *base, u8 val)
+{
+ int ret, full;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->regs + CDNS_MAILBOX_FULL,
+ full, !full, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ writel(val, base->regs + CDNS_MAILBOX_TX_DATA);
+
+ return 0;
+}
+
+static int mhdp_mailbox_read_secure(struct cdns_mhdp_base *base)
+{
+ int ret, empty;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->sapb_regs + CDNS_MAILBOX_EMPTY,
+ empty, !empty, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ return readl(base->sapb_regs + CDNS_MAILBOX_RX_DATA) & 0xff;
+}
+
+static int mhdp_mailbox_write_secure(struct cdns_mhdp_base *base, u8 val)
+{
+ int ret, full;
+
+ lockdep_assert_held(&base->mailbox_mutex);
+
+ ret = readx_poll_timeout(readl, base->sapb_regs + CDNS_MAILBOX_FULL,
+ full, !full, MAILBOX_RETRY_US,
+ MAILBOX_TIMEOUT_US);
+ if (ret < 0)
+ return ret;
+
+ writel(val, base->sapb_regs + CDNS_MAILBOX_TX_DATA);
+
+ return 0;
+}
+
+static int mhdp_mailbox_recv_header(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 req_size, bool secure)
+{
+ u32 mbox_size, i;
+ u8 header[4];
+ int ret;
+
+ /* read the header of the message */
+ for (i = 0; i < sizeof(header); i++) {
+ if (secure)
+ ret = mhdp_mailbox_read_secure(base);
+ else
+ ret = mhdp_mailbox_read(base);
+ if (ret < 0)
+ return ret;
+
+ header[i] = ret;
+ }
+
+ mbox_size = get_unaligned_be16(header + 2);
+
+ /*
+ * If the message in mailbox is not what we want, we need to
+ * clear the mailbox by reading its contents.
+ * Response data length for HDCP TX HDCP_TRAN_IS_REC_ID_VALID depend on
+ * case.
+ */
+ if (opcode != header[0] ||
+ module_id != header[1] ||
+ (opcode != HDCP_TRAN_IS_REC_ID_VALID && req_size != mbox_size)) {
+ for (i = 0; i < mbox_size; i++) {
+ if (secure)
+ ret = mhdp_mailbox_read_secure(base);
+ else
+ ret = mhdp_mailbox_read(base);
+ if (ret < 0)
+ break;
+ }
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mhdp_mailbox_recv_data(struct cdns_mhdp_base *base,
+ u8 *buff, u16 buff_size, bool secure)
+{
+ u32 i;
+ int ret;
+
+ for (i = 0; i < buff_size; i++) {
+ if (secure)
+ ret = mhdp_mailbox_read_secure(base);
+ else
+ ret = mhdp_mailbox_read(base);
+ if (ret < 0)
+ return ret;
+
+ buff[i] = ret;
+ }
+
+ return 0;
+}
+
+static int mhdp_mailbox_send(struct cdns_mhdp_base *base, u8 module_id,
+ u8 opcode, u16 size, u8 *message, bool secure)
+{
+ u8 header[4];
+ int ret, i;
+
+ header[0] = opcode;
+ header[1] = module_id;
+ put_unaligned_be16(size, header + 2);
+
+ for (i = 0; i < sizeof(header); i++) {
+ if (secure)
+ ret = mhdp_mailbox_write_secure(base, header[i]);
+ else
+ ret = mhdp_mailbox_write(base, header[i]);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < size; i++) {
+ if (secure)
+ ret = mhdp_mailbox_write_secure(base, message[i]);
+ else
+ ret = mhdp_mailbox_write(base, message[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns_mhdp_mailbox_send - Sends a message via the MHDP mailbox.
+ *
+ * This function sends a message via the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @size: Size of the message data.
+ * @message: Pointer to the message data.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_base *base, u8 module_id,
+ u8 opcode, u16 size, u8 *message)
+{
+ guard(mutex)(&base->mailbox_mutex);
+
+ return mhdp_mailbox_send(base, module_id, opcode, size, message, false);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send);
+
+/**
+ * cdns_mhdp_mailbox_send_recv - Sends a message and receives a response.
+ *
+ * This function sends a message via the mailbox and then receives a response.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @resp_size: Size of the response buffer.
+ * @resp: Pointer to the response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode, resp_size, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv header failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp, resp_size, false);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv data failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send_recv);
+
+/**
+ * cdns_mhdp_mailbox_send_recv_multi - Sends a message and receives multiple
+ * responses.
+ *
+ * This function sends a message to a specified module via the MHDP mailbox and
+ * then receives multiple responses from the module.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @opcode_resp: Operation code of the response.
+ * @resp1_size: Size of the first response buffer.
+ * @resp1: Pointer to the first response buffer.
+ * @resp2_size: Size of the second response buffer.
+ * @resp2: Pointer to the second response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode_resp,
+ resp1_size + resp2_size, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv header failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp1, resp1_size, false);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data1 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp2, resp2_size, false);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data2 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send_recv_multi);
+
+/**
+ * cdns_mhdp_secure_mailbox_send - Sends a secure message via the mailbox.
+ *
+ * This function sends a secure message to a specified module via the MHDP
+ * mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @size: Size of the message data.
+ * @message: Pointer to the message data.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_base *base, u8 module_id,
+ u8 opcode, u16 size, u8 *message)
+{
+ guard(mutex)(&base->mailbox_mutex);
+
+ return mhdp_mailbox_send(base, module_id, opcode, size, message, true);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send);
+
+/**
+ * cdns_mhdp_secure_mailbox_send_recv - Sends a secure message and receives a
+ * response.
+ *
+ * This function sends a secure message to a specified module via the mailbox
+ * and then receives a response from the module.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @resp_size: Size of the response buffer.
+ * @resp: Pointer to the response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_secure_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode, resp_size, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv header failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp, resp_size, true);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, CMD=%d recv data failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send_recv);
+
+/**
+ * cdns_mhdp_secure_mailbox_send_recv_multi - Sends a secure message and
+ * receives multiple responses.
+ *
+ * This function sends a secure message to a specified module and receives
+ * multiple responses.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @module_id: ID of the module to send the message to.
+ * @opcode: Operation code of the message.
+ * @msg_size: Size of the message data.
+ * @msg: Pointer to the message data.
+ * @opcode_resp: Operation code of the response.
+ * @resp1_size: Size of the first response buffer.
+ * @resp1: Pointer to the first response buffer.
+ * @resp2_size: Size of the second response buffer.
+ * @resp2: Pointer to the second response buffer.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_secure_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2)
+{
+ int ret;
+
+ guard(mutex)(&base->mailbox_mutex);
+
+ ret = mhdp_mailbox_send(base, module_id, opcode, msg_size, msg, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, CMD=%d send failed: %d\n",
+ module_id, opcode, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_header(base, module_id, opcode_resp,
+ resp1_size + resp2_size, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv header failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ ret = mhdp_mailbox_recv_data(base, resp1, resp1_size, true);
+ if (ret) {
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data1 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+ }
+
+ /*
+ * Response data length for HDCP TX HDCP_TRAN_IS_REC_ID_VALID depend on
+ * the number of HDCP receivers in resp1[0].
+ * 1 for regular case, more can be in repeater.
+ */
+ if (module_id == MB_MODULE_ID_HDCP_TX &&
+ opcode == HDCP_TRAN_IS_REC_ID_VALID)
+ ret = mhdp_mailbox_recv_data(base, resp2, 5 * resp1[0], true);
+ else
+ ret = mhdp_mailbox_recv_data(base, resp2, resp2_size, true);
+ if (ret)
+ dev_err(base->dev, "ModuleID=%d, Resp_CMD=%d recv data2 failed: %d\n",
+ module_id, opcode_resp, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_secure_mailbox_send_recv_multi);
+
+/**
+ * cdns_mhdp_reg_read - Reads a general register value.
+ *
+ * This function reads the value from a general register
+ * using the mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the register to read.
+ * @value: Pointer to store the read value.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_reg_read(struct cdns_mhdp_base *base, u32 addr, u32 *value)
+{
+ u8 msg[4], resp[8];
+ int ret;
+
+ put_unaligned_be32(addr, msg);
+
+ ret = cdns_mhdp_mailbox_send_recv(base, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_READ,
+ sizeof(msg), msg, sizeof(resp), resp);
+ if (ret)
+ goto out;
+
+ /* Returned address value should be the same as requested */
+ if (memcmp(msg, resp, sizeof(msg))) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *value = get_unaligned_be32(resp + 4);
+out:
+ if (ret) {
+ dev_err(base->dev, "Failed to read register\n");
+ *value = 0;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_reg_read);
+
+/**
+ * cdns_mhdp_reg_write - Writes a value to a general register.
+ *
+ * This function writes a value to a general register using the mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the register to write to.
+ * @val: Value to write to the register.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_reg_write(struct cdns_mhdp_base *base, u32 addr, u32 val)
+{
+ u8 msg[8];
+
+ put_unaligned_be32(addr, msg);
+ put_unaligned_be32(val, msg + 4);
+
+ return cdns_mhdp_mailbox_send(base, MB_MODULE_ID_GENERAL,
+ GENERAL_REGISTER_WRITE,
+ sizeof(msg), msg);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_reg_write);
+
+/* DPTX helper functions */
+/**
+ * cdns_mhdp_dp_reg_write_bit - Writes a bit field to a DP register.
+ *
+ * This function writes a specific bit field within a DP register
+ * using the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the DP register.
+ * @start_bit: Starting bit position within the register.
+ * @bits_no: Number of bits to write.
+ * @val: Value to write to the bit field.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_dp_reg_write_bit(struct cdns_mhdp_base *base, u16 addr,
+ u8 start_bit, u8 bits_no, u32 val)
+{
+ u8 field[8];
+
+ put_unaligned_be16(addr, field);
+ field[2] = start_bit;
+ field[3] = bits_no;
+ put_unaligned_be32(val, field + 4);
+
+ return cdns_mhdp_mailbox_send(base, MB_MODULE_ID_DP_TX,
+ DPTX_WRITE_FIELD, sizeof(field), field);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_dp_reg_write_bit);
+
+/**
+ * cdns_mhdp_dpcd_read - Reads data from a DPCD register.
+ *
+ * This function reads data from a specified DPCD register
+ * using the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the DPCD register to read.
+ * @data: Buffer to store the read data.
+ * @len: Length of the data to read.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_base *base,
+ u32 addr, u8 *data, u16 len)
+{
+ u8 msg[5], reg[5];
+
+ put_unaligned_be16(len, msg);
+ put_unaligned_be24(addr, msg + 2);
+
+ return cdns_mhdp_mailbox_send_recv_multi(base,
+ MB_MODULE_ID_DP_TX,
+ DPTX_READ_DPCD,
+ sizeof(msg), msg,
+ DPTX_READ_DPCD,
+ sizeof(reg), reg,
+ len, data);
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_dpcd_read);
+
+/**
+ * cdns_mhdp_dpcd_write - Writes data to a DPCD register.
+ *
+ * This function writes data to a specified DPCD register
+ * using the MHDP mailbox.
+ *
+ * @base: Pointer to the CDNS MHDP base structure.
+ * @addr: Address of the DPCD register to write to.
+ * @value: Value to write to the register.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_base *base, u32 addr, u8 value)
+{
+ u8 msg[6], reg[5];
+ int ret;
+
+ put_unaligned_be16(1, msg);
+ put_unaligned_be24(addr, msg + 2);
+ msg[5] = value;
+
+ ret = cdns_mhdp_mailbox_send_recv(base, MB_MODULE_ID_DP_TX,
+ DPTX_WRITE_DPCD,
+ sizeof(msg), msg, sizeof(reg), reg);
+ if (ret) {
+ dev_err(base->dev, "dpcd write failed: %d\n", ret);
+ return ret;
+ }
+
+ if (addr != get_unaligned_be24(reg + 2)) {
+ dev_err(base->dev,
+ "Invalid response: expected address 0x%06x, got 0x%06x\n",
+ addr, get_unaligned_be24(reg + 2));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_mhdp_dpcd_write);
+
+MODULE_DESCRIPTION("Cadence MHDP Helper driver");
+MODULE_AUTHOR("Sandor Yu <Sandor.yu@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/soc/cadence/cdns-mhdp-helper.h b/include/soc/cadence/cdns-mhdp-helper.h
new file mode 100644
index 0000000000000..7e2ceb848fc2d
--- /dev/null
+++ b/include/soc/cadence/cdns-mhdp-helper.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023-2024 NXP Semiconductor, Inc.
+ */
+#ifndef __CDNS_MHDP_HELPER_H__
+#define __CDNS_MHDP_HELPER_H__
+
+#include <linux/iopoll.h>
+#include <linux/mutex.h>
+#include <linux/unaligned.h>
+
+/* mailbox regs offset */
+#define CDNS_MAILBOX_FULL 0x00008
+#define CDNS_MAILBOX_EMPTY 0x0000c
+#define CDNS_MAILBOX_TX_DATA 0x00010
+#define CDNS_MAILBOX_RX_DATA 0x00014
+
+#define MAILBOX_RETRY_US 1000
+#define MAILBOX_TIMEOUT_US 2000000
+
+/* Module ID Code */
+#define MB_MODULE_ID_DP_TX 0x01
+#define MB_MODULE_ID_HDMI_TX 0x03
+#define MB_MODULE_ID_HDCP_TX 0x07
+#define MB_MODULE_ID_HDCP_RX 0x08
+#define MB_MODULE_ID_HDCP_GENERAL 0x09
+#define MB_MODULE_ID_GENERAL 0x0A
+
+/* General Commands */
+#define GENERAL_MAIN_CONTROL 0x01
+#define GENERAL_TEST_ECHO 0x02
+#define GENERAL_BUS_SETTINGS 0x03
+#define GENERAL_TEST_ACCESS 0x04
+#define GENERAL_REGISTER_WRITE 0x05
+#define GENERAL_WRITE_FIELD 0x06
+#define GENERAL_REGISTER_READ 0x07
+#define GENERAL_GET_HPD_STATE 0x11
+
+/* DPTX Commands */
+#define DPTX_SET_POWER_MNG 0x00
+#define DPTX_SET_HOST_CAPABILITIES 0x01
+#define DPTX_GET_EDID 0x02
+#define DPTX_READ_DPCD 0x03
+#define DPTX_WRITE_DPCD 0x04
+#define DPTX_ENABLE_EVENT 0x05
+#define DPTX_WRITE_REGISTER 0x06
+#define DPTX_READ_REGISTER 0x07
+#define DPTX_WRITE_FIELD 0x08
+#define DPTX_TRAINING_CONTROL 0x09
+#define DPTX_READ_EVENT 0x0a
+#define DPTX_READ_LINK_STAT 0x0b
+#define DPTX_SET_VIDEO 0x0c
+#define DPTX_SET_AUDIO 0x0d
+#define DPTX_GET_LAST_AUX_STAUS 0x0e
+#define DPTX_SET_LINK_BREAK_POINT 0x0f
+#define DPTX_FORCE_LANES 0x10
+#define DPTX_HPD_STATE 0x11
+#define DPTX_ADJUST_LT 0x12
+
+/* HDMI TX Commands */
+#define HDMI_TX_READ 0x00
+#define HDMI_TX_WRITE 0x01
+#define HDMI_TX_UPDATE_READ 0x02
+#define HDMI_TX_EDID 0x03
+#define HDMI_TX_EVENTS 0x04
+#define HDMI_TX_HPD_STATUS 0x05
+
+/* HDCP TX Commands */
+#define HDCP_TRAN_CONFIGURATION 0x00
+#define HDCP2X_TX_SET_PUBLIC_KEY_PARAMS 0x01
+#define HDCP2X_TX_SET_DEBUG_RANDOM_NUMBERS 0x02
+#define HDCP2X_TX_RESPOND_KM 0x03
+#define HDCP1_TX_SEND_KEYS 0x04
+#define HDCP1_TX_SEND_RANDOM_AN 0x05
+#define HDCP_TRAN_STATUS_CHANGE 0x06
+#define HDCP2X_TX_IS_KM_STORED 0x07
+#define HDCP2X_TX_STORE_KM 0x08
+#define HDCP_TRAN_IS_REC_ID_VALID 0x09
+#define HDCP_TRAN_RESPOND_RECEIVER_ID_VALID 0x0a
+#define HDCP_TRAN_TEST_KEYS 0x0b
+#define HDCP2X_TX_SET_KM_KEY_PARAMS 0x0c
+#define HDCP_NUM_OF_SUPPORTED_MESSAGES 0x0d
+
+/**
+ * struct cdns_mhdp_base - Base structure for CDNS MHDP devices
+ * @dev: Pointer to the device structure
+ * @regs: Base address of the regular register space
+ * @sapb_regs: Base address of the secure APB register space
+ * @mailbox_mutex: Mutex to protect mailbox communications with firmware
+ *
+ * This structure contains the base resources needed for CDNS MHDP helper
+ * functions. Each device instance should have its own cdns_mhdp_base structure
+ * to ensure proper isolation of mailbox operations between multiple devices.
+ */
+struct cdns_mhdp_base {
+ struct device *dev;
+ void __iomem *regs;
+ void __iomem *sapb_regs;
+ struct mutex mailbox_mutex;
+};
+
+/* Mailbox helper functions */
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 size, u8 *message);
+int cdns_mhdp_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp);
+int cdns_mhdp_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2);
+
+/* Secure mailbox helper functions */
+int cdns_mhdp_secure_mailbox_send(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 size, u8 *message);
+int cdns_mhdp_secure_mailbox_send_recv(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u16 resp_size, u8 *resp);
+int cdns_mhdp_secure_mailbox_send_recv_multi(struct cdns_mhdp_base *base,
+ u8 module_id, u8 opcode,
+ u16 msg_size, u8 *msg,
+ u8 opcode_resp,
+ u16 resp1_size, u8 *resp1,
+ u16 resp2_size, u8 *resp2);
+
+/* General commands helper functions */
+int cdns_mhdp_reg_read(struct cdns_mhdp_base *base, u32 addr, u32 *value);
+int cdns_mhdp_reg_write(struct cdns_mhdp_base *base, u32 addr, u32 val);
+
+/* DPTX commands helper functions */
+int cdns_mhdp_dp_reg_write_bit(struct cdns_mhdp_base *base, u16 addr,
+ u8 start_bit, u8 bits_no, u32 val);
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_base *base,
+ u32 addr, u8 *data, u16 len);
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_base *base, u32 addr, u8 value);
+
+#endif /* __CDNS_MHDP_HELPER_H__ */
--
2.51.0
^ permalink raw reply related
* [PATCH v22 3/8] dt-bindings: display: bridge: Add Cadence MHDP8501
From: Laurentiu Palcu @ 2026-04-24 11:07 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, linux-phy, imx,
linux-arm-kernel, linux, Alexander Stein, Ying Liu
In-Reply-To: <20260424-dcss-hdmi-upstreaming-v22-0-30a28f89298d@oss.nxp.com>
From: Sandor Yu <Sandor.yu@nxp.com>
Add bindings for Cadence MHDP8501 DisplayPort/HDMI bridge.
Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
---
.../bindings/display/bridge/cdns,mhdp8501.yaml | 135 +++++++++++++++++++++
1 file changed, 135 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml
new file mode 100644
index 0000000000000..de549471c6859
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml
@@ -0,0 +1,135 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/cdns,mhdp8501.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cadence MHDP8501 DP/HDMI bridge
+
+maintainers:
+ - Sandor Yu <Sandor.yu@nxp.com>
+
+description:
+ Cadence MHDP8501 DisplayPort/HDMI interface.
+
+properties:
+ compatible:
+ enum:
+ - fsl,imx8mq-mhdp8501
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+ description: MHDP8501 DP/HDMI APB clock.
+
+ phys:
+ maxItems: 1
+ description:
+ phandle to the DP/HDMI PHY
+
+ interrupts:
+ items:
+ - description: Hotplug cable plugin.
+ - description: Hotplug cable plugout.
+
+ interrupt-names:
+ items:
+ - const: plug_in
+ - const: plug_out
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Input port from display controller output.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description:
+ Output port to DisplayPort or HDMI connector.
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ description: Lane reordering for HDMI or DisplayPort interface.
+ minItems: 4
+ maxItems: 4
+
+ required:
+ - data-lanes
+
+ required:
+ - port@0
+ - port@1
+
+ phy:
+ description:
+ Child node describing the Cadence HDP-TX DP/HDMI PHY, which shares
+ the same MMIO region as the bridge.
+ $ref: /schemas/phy/fsl,imx8mq-hdptx-phy.yaml#
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - interrupts
+ - interrupt-names
+ - phys
+ - ports
+ - phy
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/imx8mq-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ mhdp: display-bridge@32c00000 {
+ compatible = "fsl,imx8mq-mhdp8501";
+ reg = <0x32c00000 0x100000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "plug_in", "plug_out";
+ clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>;
+ phys = <&mhdp_phy>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ mhdp_in: endpoint {
+ remote-endpoint = <&dcss_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ mhdp_out: endpoint {
+ remote-endpoint = <&dp_connector>;
+ data-lanes = <2 1 0 3>;
+ };
+ };
+ };
+
+ mhdp_phy: phy {
+ compatible = "fsl,imx8mq-hdptx-phy";
+ #phy-cells = <0>;
+ clocks = <&hdmi_phy_27m>, <&clk IMX8MQ_CLK_DISP_APB_ROOT>;
+ clock-names = "ref", "apb";
+ };
+ };
--
2.51.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox