diff mbox series

[v5,5/8] drm/omap: Add global state as a private atomic object

Message ID 20210923070701.145377-6-narmstrong@baylibre.com (mailing list archive)
State New, archived
Headers show
Series drm/omap: Add virtual-planes support | expand

Commit Message

Neil Armstrong Sept. 23, 2021, 7:06 a.m. UTC
From: Benoit Parrot <bparrot@ti.com>

Global shared resources (like hw overlays) for omapdrm are implemented
as a part of atomic state using the drm_private_obj infrastructure
available in the atomic core.

omap_global_state is introduced as a drm atomic private object. The two
funcs omap_get_global_state() and omap_get_existing_global_state() are
the two variants that will be used to access omap_global_state.

drm_mode_config_init() needs to be called earlier because it
creates/initializes the private_obj link list maintained by the atomic
framework. The private_obj link list has to exist prior to calling
drm_atomic_private_obj_init(). Similarly the cleanup handler are
reordered appropriately.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/omapdrm/omap_drv.c | 91 +++++++++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h | 21 +++++++
 2 files changed, 109 insertions(+), 3 deletions(-)

Comments

Tomi Valkeinen Oct. 12, 2021, 10:44 a.m. UTC | #1
On 23/09/2021 10:06, Neil Armstrong wrote:
> From: Benoit Parrot <bparrot@ti.com>
> 
> Global shared resources (like hw overlays) for omapdrm are implemented
> as a part of atomic state using the drm_private_obj infrastructure
> available in the atomic core.
> 
> omap_global_state is introduced as a drm atomic private object. The two
> funcs omap_get_global_state() and omap_get_existing_global_state() are
> the two variants that will be used to access omap_global_state.
> 
> drm_mode_config_init() needs to be called earlier because it
> creates/initializes the private_obj link list maintained by the atomic
> framework. The private_obj link list has to exist prior to calling
> drm_atomic_private_obj_init(). Similarly the cleanup handler are
> reordered appropriately.

I'm not really familiar with the private object. Did you check how 
current drivers use it? These patches are 3 years old, and things might 
have changed around the private object.

> Signed-off-by: Benoit Parrot <bparrot@ti.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>   drivers/gpu/drm/omapdrm/omap_drv.c | 91 +++++++++++++++++++++++++++++-
>   drivers/gpu/drm/omapdrm/omap_drv.h | 21 +++++++
>   2 files changed, 109 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> index b994014b22e8..c7912374d393 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> @@ -128,6 +128,82 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
>   	.atomic_commit = drm_atomic_helper_commit,
>   };
>   
> +/* Global/shared object state funcs */
> +
> +/*
> + * This is a helper that returns the private state currently in operation.
> + * Note that this would return the "old_state" if called in the atomic check
> + * path, and the "new_state" after the atomic swap has been done.
> + */
> +struct omap_global_state *
> +omap_get_existing_global_state(struct omap_drm_private *priv)
> +{
> +	return to_omap_global_state(priv->glob_obj.state);
> +}
> +
> +/*
> + * This acquires the modeset lock set aside for global state, creates
> + * a new duplicated private object state.
> + */
> +struct omap_global_state *__must_check
> +omap_get_global_state(struct drm_atomic_state *s)
> +{
> +	struct omap_drm_private *priv = s->dev->dev_private;
> +	struct drm_private_state *priv_state;
> +
> +	priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_obj);
> +	if (IS_ERR(priv_state))
> +		return ERR_CAST(priv_state);
> +
> +	return to_omap_global_state(priv_state);
> +}
> +
> +static struct drm_private_state *
> +omap_global_duplicate_state(struct drm_private_obj *obj)
> +{
> +	struct omap_global_state *state;
> +
> +	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return NULL;
> +
> +	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
> +
> +	return &state->base;
> +}
> +
> +static void omap_global_destroy_state(struct drm_private_obj *obj,
> +				      struct drm_private_state *state)
> +{
> +	struct omap_global_state *omap_state = to_omap_global_state(state);
> +
> +	kfree(omap_state);
> +}
> +
> +static const struct drm_private_state_funcs omap_global_state_funcs = {
> +	.atomic_duplicate_state = omap_global_duplicate_state,
> +	.atomic_destroy_state = omap_global_destroy_state,
> +};
> +
> +static int omap_global_obj_init(struct drm_device *dev)
> +{
> +	struct omap_drm_private *priv = dev->dev_private;
> +	struct omap_global_state *state;
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return -ENOMEM;
> +
> +	drm_atomic_private_obj_init(dev, &priv->glob_obj, &state->base,
> +				    &omap_global_state_funcs);
> +	return 0;
> +}
> +
> +static void omap_global_obj_fini(struct omap_drm_private *priv)
> +{
> +	drm_atomic_private_obj_fini(&priv->glob_obj);
> +}
> +
>   static void omap_disconnect_pipelines(struct drm_device *ddev)
>   {
>   	struct omap_drm_private *priv = ddev->dev_private;
> @@ -231,8 +307,6 @@ static int omap_modeset_init(struct drm_device *dev)
>   	if (!omapdss_stack_is_ready())
>   		return -EPROBE_DEFER;
>   
> -	drm_mode_config_init(dev);
> -
>   	ret = omap_modeset_init_properties(dev);
>   	if (ret < 0)
>   		return ret;
> @@ -583,10 +657,16 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
>   
>   	omap_gem_init(ddev);
>   
> -	ret = omap_hwoverlays_init(priv);
> +	drm_mode_config_init(ddev);
> +
> +	ret = omap_global_obj_init(ddev);
>   	if (ret)
>   		goto err_gem_deinit;
>   
> +	ret = omap_hwoverlays_init(priv);
> +	if (ret)
> +		goto err_free_priv_obj;
> +
>   	ret = omap_modeset_init(ddev);
>   	if (ret) {
>   		dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
> @@ -624,7 +704,10 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
>   	omap_modeset_fini(ddev);
>   err_free_overlays:
>   	omap_hwoverlays_destroy(priv);
> +err_free_priv_obj:
> +	omap_global_obj_fini(priv);
>   err_gem_deinit:
> +	drm_mode_config_cleanup(ddev);
>   	omap_gem_deinit(ddev);
>   	destroy_workqueue(priv->wq);
>   	omap_disconnect_pipelines(ddev);
> @@ -649,6 +732,8 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
>   
>   	omap_modeset_fini(ddev);
>   	omap_hwoverlays_destroy(priv);
> +	omap_global_obj_fini(priv);
> +	drm_mode_config_cleanup(ddev);
>   	omap_gem_deinit(ddev);
>   
>   	destroy_workqueue(priv->wq);
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
> index b4d9c2062723..280cdd27bc8e 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.h
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.h
> @@ -14,6 +14,7 @@
>   #include "dss/omapdss.h"
>   #include "dss/dss.h"
>   
> +#include <drm/drm_atomic.h>
>   #include <drm/drm_gem.h>
>   #include <drm/omap_drm.h>
>   
> @@ -41,6 +42,15 @@ struct omap_drm_pipeline {
>   	unsigned int alias_id;
>   };
>   
> +/*
> + * Global private object state for tracking resources that are shared across
> + * multiple kms objects (planes/crtcs/etc).
> + */
> +#define to_omap_global_state(x) container_of(x, struct omap_global_state, base)

Add empty line here.

> +struct omap_global_state {
> +	struct drm_private_state base;
> +};
> +
>   struct omap_drm_private {
>   	struct drm_device *ddev;
>   	struct device *dev;
> @@ -61,6 +71,13 @@ struct omap_drm_private {
>   	unsigned int num_ovls;
>   	struct omap_hw_overlay *overlays[8];
>   
> +	/*
> +	 * Global private object state, Do not access directly, use
> +	 * omap_global_get_state()
> +	 */
> +	struct drm_modeset_lock glob_obj_lock;

This is not used... What am I missing?

> +	struct drm_private_obj glob_obj;
> +
>   	struct drm_fb_helper *fbdev;
>   
>   	struct workqueue_struct *wq;
> @@ -88,5 +105,9 @@ struct omap_drm_private {
>   
>   
>   void omap_debugfs_init(struct drm_minor *minor);
> +struct omap_global_state *__must_check
> +omap_get_global_state(struct drm_atomic_state *s);
> +struct omap_global_state *
> +omap_get_existing_global_state(struct omap_drm_private *priv);

These could also be separated by empty lines. At least to my eyes it 
gets confusing if those declarations are not separated.

  Tomi
Neil Armstrong Oct. 12, 2021, 1:23 p.m. UTC | #2
Hi,

On 12/10/2021 12:44, Tomi Valkeinen wrote:
> On 23/09/2021 10:06, Neil Armstrong wrote:
>> From: Benoit Parrot <bparrot@ti.com>
>>
>> Global shared resources (like hw overlays) for omapdrm are implemented
>> as a part of atomic state using the drm_private_obj infrastructure
>> available in the atomic core.
>>
>> omap_global_state is introduced as a drm atomic private object. The two
>> funcs omap_get_global_state() and omap_get_existing_global_state() are
>> the two variants that will be used to access omap_global_state.
>>
>> drm_mode_config_init() needs to be called earlier because it
>> creates/initializes the private_obj link list maintained by the atomic
>> framework. The private_obj link list has to exist prior to calling
>> drm_atomic_private_obj_init(). Similarly the cleanup handler are
>> reordered appropriately.
> 
> I'm not really familiar with the private object. Did you check how current drivers use it? These patches are 3 years old, and things might have changed around the private object.

Indeed, I checked and this is used in vc4/tegra/arm/amd & msm in the same as way.

> 
>> Signed-off-by: Benoit Parrot <bparrot@ti.com>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>   drivers/gpu/drm/omapdrm/omap_drv.c | 91 +++++++++++++++++++++++++++++-
>>   drivers/gpu/drm/omapdrm/omap_drv.h | 21 +++++++
>>   2 files changed, 109 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
>> index b994014b22e8..c7912374d393 100644
>> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
>> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
>> @@ -128,6 +128,82 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
>>       .atomic_commit = drm_atomic_helper_commit,
>>   };
>>   +/* Global/shared object state funcs */
>> +
>> +/*
>> + * This is a helper that returns the private state currently in operation.
>> + * Note that this would return the "old_state" if called in the atomic check
>> + * path, and the "new_state" after the atomic swap has been done.
>> + */
>> +struct omap_global_state *
>> +omap_get_existing_global_state(struct omap_drm_private *priv)
>> +{
>> +    return to_omap_global_state(priv->glob_obj.state);
>> +}
>> +
>> +/*
>> + * This acquires the modeset lock set aside for global state, creates
>> + * a new duplicated private object state.
>> + */
>> +struct omap_global_state *__must_check
>> +omap_get_global_state(struct drm_atomic_state *s)
>> +{
>> +    struct omap_drm_private *priv = s->dev->dev_private;
>> +    struct drm_private_state *priv_state;
>> +
>> +    priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_obj);
>> +    if (IS_ERR(priv_state))
>> +        return ERR_CAST(priv_state);
>> +
>> +    return to_omap_global_state(priv_state);
>> +}
>> +
>> +static struct drm_private_state *
>> +omap_global_duplicate_state(struct drm_private_obj *obj)
>> +{
>> +    struct omap_global_state *state;
>> +
>> +    state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
>> +    if (!state)
>> +        return NULL;
>> +
>> +    __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
>> +
>> +    return &state->base;
>> +}
>> +
>> +static void omap_global_destroy_state(struct drm_private_obj *obj,
>> +                      struct drm_private_state *state)
>> +{
>> +    struct omap_global_state *omap_state = to_omap_global_state(state);
>> +
>> +    kfree(omap_state);
>> +}
>> +
>> +static const struct drm_private_state_funcs omap_global_state_funcs = {
>> +    .atomic_duplicate_state = omap_global_duplicate_state,
>> +    .atomic_destroy_state = omap_global_destroy_state,
>> +};
>> +
>> +static int omap_global_obj_init(struct drm_device *dev)
>> +{
>> +    struct omap_drm_private *priv = dev->dev_private;
>> +    struct omap_global_state *state;
>> +
>> +    state = kzalloc(sizeof(*state), GFP_KERNEL);
>> +    if (!state)
>> +        return -ENOMEM;
>> +
>> +    drm_atomic_private_obj_init(dev, &priv->glob_obj, &state->base,
>> +                    &omap_global_state_funcs);
>> +    return 0;
>> +}
>> +
>> +static void omap_global_obj_fini(struct omap_drm_private *priv)
>> +{
>> +    drm_atomic_private_obj_fini(&priv->glob_obj);
>> +}
>> +
>>   static void omap_disconnect_pipelines(struct drm_device *ddev)
>>   {
>>       struct omap_drm_private *priv = ddev->dev_private;
>> @@ -231,8 +307,6 @@ static int omap_modeset_init(struct drm_device *dev)
>>       if (!omapdss_stack_is_ready())
>>           return -EPROBE_DEFER;
>>   -    drm_mode_config_init(dev);
>> -
>>       ret = omap_modeset_init_properties(dev);
>>       if (ret < 0)
>>           return ret;
>> @@ -583,10 +657,16 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
>>         omap_gem_init(ddev);
>>   -    ret = omap_hwoverlays_init(priv);
>> +    drm_mode_config_init(ddev);
>> +
>> +    ret = omap_global_obj_init(ddev);
>>       if (ret)
>>           goto err_gem_deinit;
>>   +    ret = omap_hwoverlays_init(priv);
>> +    if (ret)
>> +        goto err_free_priv_obj;
>> +
>>       ret = omap_modeset_init(ddev);
>>       if (ret) {
>>           dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
>> @@ -624,7 +704,10 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
>>       omap_modeset_fini(ddev);
>>   err_free_overlays:
>>       omap_hwoverlays_destroy(priv);
>> +err_free_priv_obj:
>> +    omap_global_obj_fini(priv);
>>   err_gem_deinit:
>> +    drm_mode_config_cleanup(ddev);
>>       omap_gem_deinit(ddev);
>>       destroy_workqueue(priv->wq);
>>       omap_disconnect_pipelines(ddev);
>> @@ -649,6 +732,8 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
>>         omap_modeset_fini(ddev);
>>       omap_hwoverlays_destroy(priv);
>> +    omap_global_obj_fini(priv);
>> +    drm_mode_config_cleanup(ddev);
>>       omap_gem_deinit(ddev);
>>         destroy_workqueue(priv->wq);
>> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
>> index b4d9c2062723..280cdd27bc8e 100644
>> --- a/drivers/gpu/drm/omapdrm/omap_drv.h
>> +++ b/drivers/gpu/drm/omapdrm/omap_drv.h
>> @@ -14,6 +14,7 @@
>>   #include "dss/omapdss.h"
>>   #include "dss/dss.h"
>>   +#include <drm/drm_atomic.h>
>>   #include <drm/drm_gem.h>
>>   #include <drm/omap_drm.h>
>>   @@ -41,6 +42,15 @@ struct omap_drm_pipeline {
>>       unsigned int alias_id;
>>   };
>>   +/*
>> + * Global private object state for tracking resources that are shared across
>> + * multiple kms objects (planes/crtcs/etc).
>> + */
>> +#define to_omap_global_state(x) container_of(x, struct omap_global_state, base)
> 
> Add empty line here.

Ack

> 
>> +struct omap_global_state {
>> +    struct drm_private_state base;
>> +};
>> +
>>   struct omap_drm_private {
>>       struct drm_device *ddev;
>>       struct device *dev;
>> @@ -61,6 +71,13 @@ struct omap_drm_private {
>>       unsigned int num_ovls;
>>       struct omap_hw_overlay *overlays[8];
>>   +    /*
>> +     * Global private object state, Do not access directly, use
>> +     * omap_global_get_state()
>> +     */
>> +    struct drm_modeset_lock glob_obj_lock;
> 
> This is not used... What am I missing?

It's a leftover from v4, now the lock has been moved into drm_atomic_get_private_obj_state()

> 
>> +    struct drm_private_obj glob_obj;
>> +
>>       struct drm_fb_helper *fbdev;
>>         struct workqueue_struct *wq;
>> @@ -88,5 +105,9 @@ struct omap_drm_private {
>>       void omap_debugfs_init(struct drm_minor *minor);
>> +struct omap_global_state *__must_check
>> +omap_get_global_state(struct drm_atomic_state *s);
>> +struct omap_global_state *
>> +omap_get_existing_global_state(struct omap_drm_private *priv);
> 
> These could also be separated by empty lines. At least to my eyes it gets confusing if those declarations are not separated.

Atomic states can be extremely confusing, and hard to track.
I checked and they do what they are documented for...

The omap_get_existing_global_state() is the most confusing since the result depends if
we are in an atomic transaction of not.

Neil

> 
>  Tomi
Tomi Valkeinen Oct. 12, 2021, 1:38 p.m. UTC | #3
On 12/10/2021 16:23, Neil Armstrong wrote:

>>> +    struct drm_private_obj glob_obj;
>>> +
>>>        struct drm_fb_helper *fbdev;
>>>          struct workqueue_struct *wq;
>>> @@ -88,5 +105,9 @@ struct omap_drm_private {
>>>        void omap_debugfs_init(struct drm_minor *minor);
>>> +struct omap_global_state *__must_check
>>> +omap_get_global_state(struct drm_atomic_state *s);
>>> +struct omap_global_state *
>>> +omap_get_existing_global_state(struct omap_drm_private *priv);
>>
>> These could also be separated by empty lines. At least to my eyes it gets confusing if those declarations are not separated.
> 
> Atomic states can be extremely confusing, and hard to track.
> I checked and they do what they are documented for...
> 
> The omap_get_existing_global_state() is the most confusing since the result depends if
> we are in an atomic transaction of not.

So here I was just talking about the cosmetics, how the lines above look 
like. I have trouble seeing where the function declaration starts and 
where it ends without looking closely, as both lines of the declaration 
start at the first column, and there are no empty lines between the 
declarations.

But now that you mention, yes, the states are confusing =). And this 
series is somewhat difficult. I think it's important for future 
maintainability to include explanations and comments in this series for 
the confusing parts (plane-overlay mapping and state handling, mostly).

  Tomi
Neil Armstrong Oct. 12, 2021, 3:41 p.m. UTC | #4
On 12/10/2021 15:38, Tomi Valkeinen wrote:
> On 12/10/2021 16:23, Neil Armstrong wrote:
> 
>>>> +    struct drm_private_obj glob_obj;
>>>> +
>>>>        struct drm_fb_helper *fbdev;
>>>>          struct workqueue_struct *wq;
>>>> @@ -88,5 +105,9 @@ struct omap_drm_private {
>>>>        void omap_debugfs_init(struct drm_minor *minor);
>>>> +struct omap_global_state *__must_check
>>>> +omap_get_global_state(struct drm_atomic_state *s);
>>>> +struct omap_global_state *
>>>> +omap_get_existing_global_state(struct omap_drm_private *priv);
>>>
>>> These could also be separated by empty lines. At least to my eyes it gets confusing if those declarations are not separated.
>>
>> Atomic states can be extremely confusing, and hard to track.
>> I checked and they do what they are documented for...
>>
>> The omap_get_existing_global_state() is the most confusing since the result depends if
>> we are in an atomic transaction of not.
> 
> So here I was just talking about the cosmetics, how the lines above look like. I have trouble seeing where the function declaration starts and where it ends without looking closely, as both lines of the declaration start at the first column, and there are no empty lines between the declarations.

Ok, it's a legacy of the 80chars max, will reformat.

> 
> But now that you mention, yes, the states are confusing =). And this series is somewhat difficult. I think it's important for future maintainability to include explanations and comments in this series for the confusing parts (plane-overlay mapping and state handling, mostly).

Yep I added some hopefully useful comments explaining that.

Neil

> 
>  Tomi
diff mbox series

Patch

diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index b994014b22e8..c7912374d393 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -128,6 +128,82 @@  static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
+/* Global/shared object state funcs */
+
+/*
+ * This is a helper that returns the private state currently in operation.
+ * Note that this would return the "old_state" if called in the atomic check
+ * path, and the "new_state" after the atomic swap has been done.
+ */
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv)
+{
+	return to_omap_global_state(priv->glob_obj.state);
+}
+
+/*
+ * This acquires the modeset lock set aside for global state, creates
+ * a new duplicated private object state.
+ */
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s)
+{
+	struct omap_drm_private *priv = s->dev->dev_private;
+	struct drm_private_state *priv_state;
+
+	priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_obj);
+	if (IS_ERR(priv_state))
+		return ERR_CAST(priv_state);
+
+	return to_omap_global_state(priv_state);
+}
+
+static struct drm_private_state *
+omap_global_duplicate_state(struct drm_private_obj *obj)
+{
+	struct omap_global_state *state;
+
+	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+
+	return &state->base;
+}
+
+static void omap_global_destroy_state(struct drm_private_obj *obj,
+				      struct drm_private_state *state)
+{
+	struct omap_global_state *omap_state = to_omap_global_state(state);
+
+	kfree(omap_state);
+}
+
+static const struct drm_private_state_funcs omap_global_state_funcs = {
+	.atomic_duplicate_state = omap_global_duplicate_state,
+	.atomic_destroy_state = omap_global_destroy_state,
+};
+
+static int omap_global_obj_init(struct drm_device *dev)
+{
+	struct omap_drm_private *priv = dev->dev_private;
+	struct omap_global_state *state;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	drm_atomic_private_obj_init(dev, &priv->glob_obj, &state->base,
+				    &omap_global_state_funcs);
+	return 0;
+}
+
+static void omap_global_obj_fini(struct omap_drm_private *priv)
+{
+	drm_atomic_private_obj_fini(&priv->glob_obj);
+}
+
 static void omap_disconnect_pipelines(struct drm_device *ddev)
 {
 	struct omap_drm_private *priv = ddev->dev_private;
@@ -231,8 +307,6 @@  static int omap_modeset_init(struct drm_device *dev)
 	if (!omapdss_stack_is_ready())
 		return -EPROBE_DEFER;
 
-	drm_mode_config_init(dev);
-
 	ret = omap_modeset_init_properties(dev);
 	if (ret < 0)
 		return ret;
@@ -583,10 +657,16 @@  static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 
 	omap_gem_init(ddev);
 
-	ret = omap_hwoverlays_init(priv);
+	drm_mode_config_init(ddev);
+
+	ret = omap_global_obj_init(ddev);
 	if (ret)
 		goto err_gem_deinit;
 
+	ret = omap_hwoverlays_init(priv);
+	if (ret)
+		goto err_free_priv_obj;
+
 	ret = omap_modeset_init(ddev);
 	if (ret) {
 		dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
@@ -624,7 +704,10 @@  static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 	omap_modeset_fini(ddev);
 err_free_overlays:
 	omap_hwoverlays_destroy(priv);
+err_free_priv_obj:
+	omap_global_obj_fini(priv);
 err_gem_deinit:
+	drm_mode_config_cleanup(ddev);
 	omap_gem_deinit(ddev);
 	destroy_workqueue(priv->wq);
 	omap_disconnect_pipelines(ddev);
@@ -649,6 +732,8 @@  static void omapdrm_cleanup(struct omap_drm_private *priv)
 
 	omap_modeset_fini(ddev);
 	omap_hwoverlays_destroy(priv);
+	omap_global_obj_fini(priv);
+	drm_mode_config_cleanup(ddev);
 	omap_gem_deinit(ddev);
 
 	destroy_workqueue(priv->wq);
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index b4d9c2062723..280cdd27bc8e 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -14,6 +14,7 @@ 
 #include "dss/omapdss.h"
 #include "dss/dss.h"
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_gem.h>
 #include <drm/omap_drm.h>
 
@@ -41,6 +42,15 @@  struct omap_drm_pipeline {
 	unsigned int alias_id;
 };
 
+/*
+ * Global private object state for tracking resources that are shared across
+ * multiple kms objects (planes/crtcs/etc).
+ */
+#define to_omap_global_state(x) container_of(x, struct omap_global_state, base)
+struct omap_global_state {
+	struct drm_private_state base;
+};
+
 struct omap_drm_private {
 	struct drm_device *ddev;
 	struct device *dev;
@@ -61,6 +71,13 @@  struct omap_drm_private {
 	unsigned int num_ovls;
 	struct omap_hw_overlay *overlays[8];
 
+	/*
+	 * Global private object state, Do not access directly, use
+	 * omap_global_get_state()
+	 */
+	struct drm_modeset_lock glob_obj_lock;
+	struct drm_private_obj glob_obj;
+
 	struct drm_fb_helper *fbdev;
 
 	struct workqueue_struct *wq;
@@ -88,5 +105,9 @@  struct omap_drm_private {
 
 
 void omap_debugfs_init(struct drm_minor *minor);
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s);
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv);
 
 #endif /* __OMAPDRM_DRV_H__ */