Commit f5e7840b authored by Thierry Reding's avatar Thierry Reding

drm/atomic: Add helpers for state-subclassing drivers

Drivers that subclass CRTC, plane or connector state need to carefully
duplicate the code that the atomic helpers have. This is bound to cause
breakage eventually because it requires auditing all drivers and update
them when code is added to the helpers.

In order to avoid that, implement new helpers that perform the required
steps when copying and destroying state. These new helpers are exported
so that state-subclassing drivers can use them. The default helpers are
implemented using them as well, providing a single location that needs
to be changed when adding to base atomic states.
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: default avatarEric Anholt <eric@anholt.net>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 42e9ce05
...@@ -2049,6 +2049,26 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) ...@@ -2049,6 +2049,26 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
} }
EXPORT_SYMBOL(drm_atomic_helper_crtc_reset); EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
/**
* __drm_atomic_helper_crtc_duplicate_state - copy atomic CRTC state
* @crtc: CRTC object
* @state: atomic CRTC state
*
* Copies atomic state from a CRTC's current state and resets inferred values.
* This is useful for drivers that subclass the CRTC state.
*/
void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
memcpy(state, crtc->state, sizeof(*state));
state->mode_changed = false;
state->active_changed = false;
state->planes_changed = false;
state->event = NULL;
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
/** /**
* drm_atomic_helper_crtc_duplicate_state - default state duplicate hook * drm_atomic_helper_crtc_duplicate_state - default state duplicate hook
* @crtc: drm CRTC * @crtc: drm CRTC
...@@ -2064,19 +2084,34 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) ...@@ -2064,19 +2084,34 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
if (WARN_ON(!crtc->state)) if (WARN_ON(!crtc->state))
return NULL; return NULL;
state = kmemdup(crtc->state, sizeof(*crtc->state), GFP_KERNEL); state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state)
if (state) { __drm_atomic_helper_crtc_duplicate_state(crtc, state);
state->mode_changed = false;
state->active_changed = false;
state->planes_changed = false;
state->event = NULL;
}
return state; return state;
} }
EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
/**
* __drm_atomic_helper_crtc_destroy_state - release CRTC state
* @crtc: CRTC object
* @state: CRTC state object to release
*
* Releases all resources stored in the CRTC state without actually freeing
* the memory of the CRTC state. This is useful for drivers that subclass the
* CRTC state.
*/
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
/*
* This is currently a placeholder so that drivers that subclass the
* state will automatically do the right thing if code is ever added
* to this function.
*/
}
EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state);
/** /**
* drm_atomic_helper_crtc_destroy_state - default state destroy hook * drm_atomic_helper_crtc_destroy_state - default state destroy hook
* @crtc: drm CRTC * @crtc: drm CRTC
...@@ -2088,6 +2123,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); ...@@ -2088,6 +2123,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state) struct drm_crtc_state *state)
{ {
__drm_atomic_helper_crtc_destroy_state(crtc, state);
kfree(state); kfree(state);
} }
EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state); EXPORT_SYMBOL(drm_atomic_helper_crtc_destroy_state);
...@@ -2112,6 +2148,24 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane) ...@@ -2112,6 +2148,24 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
} }
EXPORT_SYMBOL(drm_atomic_helper_plane_reset); EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
/**
* __drm_atomic_helper_plane_duplicate_state - copy atomic plane state
* @plane: plane object
* @state: atomic plane state
*
* Copies atomic state from a plane's current state. This is useful for
* drivers that subclass the plane state.
*/
void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
memcpy(state, plane->state, sizeof(*state));
if (state->fb)
drm_framebuffer_reference(state->fb);
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
/** /**
* drm_atomic_helper_plane_duplicate_state - default state duplicate hook * drm_atomic_helper_plane_duplicate_state - default state duplicate hook
* @plane: drm plane * @plane: drm plane
...@@ -2127,15 +2181,31 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane) ...@@ -2127,15 +2181,31 @@ drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane)
if (WARN_ON(!plane->state)) if (WARN_ON(!plane->state))
return NULL; return NULL;
state = kmemdup(plane->state, sizeof(*plane->state), GFP_KERNEL); state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state)
if (state && state->fb) __drm_atomic_helper_plane_duplicate_state(plane, state);
drm_framebuffer_reference(state->fb);
return state; return state;
} }
EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
/**
* __drm_atomic_helper_plane_destroy_state - release plane state
* @plane: plane object
* @state: plane state object to release
*
* Releases all resources stored in the plane state without actually freeing
* the memory of the plane state. This is useful for drivers that subclass the
* plane state.
*/
void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
if (state->fb)
drm_framebuffer_unreference(state->fb);
}
EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state);
/** /**
* drm_atomic_helper_plane_destroy_state - default state destroy hook * drm_atomic_helper_plane_destroy_state - default state destroy hook
* @plane: drm plane * @plane: drm plane
...@@ -2147,9 +2217,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state); ...@@ -2147,9 +2217,7 @@ EXPORT_SYMBOL(drm_atomic_helper_plane_duplicate_state);
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
if (state->fb) __drm_atomic_helper_plane_destroy_state(plane, state);
drm_framebuffer_unreference(state->fb);
kfree(state); kfree(state);
} }
EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state); EXPORT_SYMBOL(drm_atomic_helper_plane_destroy_state);
...@@ -2172,6 +2240,22 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector) ...@@ -2172,6 +2240,22 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
} }
EXPORT_SYMBOL(drm_atomic_helper_connector_reset); EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
/**
* __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
* @connector: connector object
* @state: atomic connector state
*
* Copies atomic state from a connector's current state. This is useful for
* drivers that subclass the connector state.
*/
void
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
struct drm_connector_state *state)
{
memcpy(state, connector->state, sizeof(*state));
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
/** /**
* drm_atomic_helper_connector_duplicate_state - default state duplicate hook * drm_atomic_helper_connector_duplicate_state - default state duplicate hook
* @connector: drm connector * @connector: drm connector
...@@ -2182,13 +2266,40 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset); ...@@ -2182,13 +2266,40 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
struct drm_connector_state * struct drm_connector_state *
drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector) drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector)
{ {
struct drm_connector_state *state;
if (WARN_ON(!connector->state)) if (WARN_ON(!connector->state))
return NULL; return NULL;
return kmemdup(connector->state, sizeof(*connector->state), GFP_KERNEL); state = kmalloc(sizeof(*state), GFP_KERNEL);
if (state)
__drm_atomic_helper_connector_duplicate_state(connector, state);
return state;
} }
EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
/**
* __drm_atomic_helper_connector_destroy_state - release connector state
* @connector: connector object
* @state: connector state object to release
*
* Releases all resources stored in the connector state without actually
* freeing the memory of the connector state. This is useful for drivers that
* subclass the connector state.
*/
void
__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state)
{
/*
* This is currently a placeholder so that drivers that subclass the
* state will automatically do the right thing if code is ever added
* to this function.
*/
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
/** /**
* drm_atomic_helper_connector_destroy_state - default state destroy hook * drm_atomic_helper_connector_destroy_state - default state destroy hook
* @connector: drm connector * @connector: drm connector
...@@ -2200,6 +2311,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); ...@@ -2200,6 +2311,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state);
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state) struct drm_connector_state *state)
{ {
__drm_atomic_helper_connector_destroy_state(connector, state);
kfree(state); kfree(state);
} }
EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state);
...@@ -87,20 +87,34 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector, ...@@ -87,20 +87,34 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
/* default implementations for state handling */ /* default implementations for state handling */
void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
struct drm_crtc_state * struct drm_crtc_state *
drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc); drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc);
void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, void drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state); struct drm_crtc_state *state);
void drm_atomic_helper_plane_reset(struct drm_plane *plane); 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);
struct drm_plane_state * struct drm_plane_state *
drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane); drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane);
void __drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state);
void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane, void drm_atomic_helper_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state); struct drm_plane_state *state);
void drm_atomic_helper_connector_reset(struct drm_connector *connector); void drm_atomic_helper_connector_reset(struct drm_connector *connector);
void
__drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
struct drm_connector_state *state);
struct drm_connector_state * struct drm_connector_state *
drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector);
void
__drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state);
void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
struct drm_connector_state *state); struct drm_connector_state *state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment