dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [RFC 00/11] atomic pageflip v3
@ 2012-10-13  0:49 Rob Clark
  2012-10-13  0:49 ` [RFC 01/11] drm: add atomic fxns Rob Clark
                   ` (11 more replies)
  0 siblings, 12 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

This is following a bit the approach that Ville is taking for atomic-
modeset, in that it is switching over to using properties for everything.
The advantage of this approach is that it makes it easier to add new
attributes to set as part of a page-flip (and even opens the option to
add new object types).

The basic principles are:
 a) split out object state (in this case, plane and crtc, although I
    expect more to be added as atomic-modeset is added) into separate
    structures that can be atomically committed or rolled back.  The
    property values array is also split out into the state structs,
    so that the property values visible to userspace automatically
    reflect the current state (ie. property changes are either
    committed or discarded depending on whether the state changes
    are committed or discarded).
 b) expand the object property API (set_property()) to take a state
    object.  The obj->set_property() simply updates the state object
    without actually applying the changes to the hw.
 c) after all the property updates are done, the updated state can
    be checked for correctness and against the hw capabilities, and
    then either discarded or committed atomically.

Since we need to include properties in the atomic-pageflip scheme,
doing everything via properties avoids updating a bunch of additional
driver provided callbacks.

For drivers that have been atomic-ified, they no longer need to
implement .page_flip(), .set_plane(), .disable_plane().  Instead they
should implement the atomic fxns, and their various .set_property()
functions would not actually touch the hw, but instead update state
objects.  State objects should hold all the state which could
potentially be applied to the hw.  The .set_property() functions
should not actually update the hw, because it might be the users
intention to only test a new configuration.

In drm_crtc / drm_plane, the userspace visible attributes are split
out into separate drm_crtc_state / drm_plane_state structs.  (Note
that this is only partially done for crtc, only the page-flip related
attributes are split out.  I wanted to do this first, and then add the
modeset related attributes in a later patch to split things up into
smaller pieces.)  The intention is that drivers can wrap the state
structs, and add whatever other information they need.  For example:

    struct omap_plane_state {
           struct drm_plane_state base;
           uint8_t rotation;
           uint8_t zorder;
           uint8_t enabled;
    };

It doesn't strictly need to be just property values.  If driver needs
to calculate some clock settings, fifo thresholds, or other internal
state, based the external state set from userspace, it could stuff
that stuff into it's state structs as well if it wanted.  But at a
minimum the state objects should encapsulate the userspace visible
state.

For atomic-ified drivers, all updates, whether it be userspace
setproperty ioctl updating a single property, or legacy setplane or
pageflip ioctls, or new atomic ioctl(s), all go through the same path
from the driver's perspective:

    state = dev->atomic_begin();
    for (... one or more ...)
       obj->set_property(obj, state, prop, value);
    if (dev->atomic_check(state))
       dev->atomic_commit(state, event);
    dev->atomic_end(state);

The global driver state token/object returned from .atomic_begin() is
opaque from drm core perspective.  It somehow encapsulates the state
of all crtc/plane/etc.  Inside the driver's different .set_property()
fxns, this global state object gets mapped to per crtc/plane state
objects.  Core drm helpers for dealing with common attributes (fb_id,
crtc_x/y/w/h, etc) are provided.  (ie. drm_plane_set_property(),
drm_plane_check_state(), etc.)   This is to avoid forcing each driver
to duplicate code for setting common properties and sanity checking.

After all the property updates have been passed to the driver via
.set_property() calls, .atomic_check() is called.  This should check
all the modified crtc/plane's (using drm_{plane,crtc}_check_state()
for common check), and do any needed global sanity checks for the hw
(ie. can this combination of planes meet hw bandwidth limitations,
etc).

For ioctls with a 'test' flag, the .atomic_commit() step might be
skipped if userspace is only testing the new configuration.  In either
case, .atomic_commit() is only called if .atomic_check() succeeds, so
at this point it is already known that the new configuration is
"good", so .atomic_commit() should really only fail for catastrophic
things (unable to allocate memory, hardware is on fire, etc).

The .atomic_end() is called at the end if the driver needs to do some
cleanup.

------

The intention is for this to also simplify atomic-modeset, by
providing some of the necessary infrastructure (object property types,
signed property values, and property's whose usespace visible values
automatically tracks the object state which is either committed or
discarded depending on whether the state change was committed to hw
or not) which will also be needed for atomic-modeset.

So far, I've only updated omapdrm to the new APIs, as a proof of
concept.  Only a few drivers support drm plane, so I expect the
updates to convert drm-plane to properties should not be so hard.
Possibly for crtc/pageflip we might need to have a transition period
where we still support crtc->page_flip() code path until all drivers
are updated.

My complete branch is here:

  https://github.com/robclark/kernel-omap4/commits/drm_nuclear-2
  git://github.com/robclark/kernel-omap4.git drm_nuclear-2

v1: original RFC
v2: I don't remember
v3: don't remove .page_flip(), .update_plane(), etc.  These are still
    used for drivers that don't implement the atomic functions, to
    allow for a transition period

Note that I haven't changed the format of the atomic-pageflip ioctl
itself since the last patchset.  At this point I'm more interested in
feedback on the first nine patches.

Rob Clark (11):
  drm: add atomic fxns
  drm: add object property type
  drm: add DRM_MODE_PROP_DYNAMIC property flag
  drm: add DRM_MODE_PROP_SIGNED property flag
  drm: split property values out
  drm: convert plane to properties
  drm: add drm_plane_state
  drm: convert page_flip to properties
  drm: add drm_crtc_state
  drm: atomic pageflip
  drm/omap: update for atomic age

 drivers/gpu/drm/drm_crtc.c            |  916 ++++++++++++++++++++++++++++-----
 drivers/gpu/drm/drm_crtc_helper.c     |   51 +-
 drivers/gpu/drm/drm_drv.c             |    1 +
 drivers/gpu/drm/drm_fb_helper.c       |   12 +-
 drivers/staging/omapdrm/Makefile      |    1 +
 drivers/staging/omapdrm/omap_atomic.c |  347 +++++++++++++
 drivers/staging/omapdrm/omap_atomic.h |   52 ++
 drivers/staging/omapdrm/omap_crtc.c   |  237 +++++----
 drivers/staging/omapdrm/omap_drv.c    |   26 +-
 drivers/staging/omapdrm/omap_drv.h    |   45 +-
 drivers/staging/omapdrm/omap_fb.c     |   44 +-
 drivers/staging/omapdrm/omap_plane.c  |  295 ++++++-----
 include/drm/drm.h                     |    2 +
 include/drm/drmP.h                    |   52 ++
 include/drm/drm_crtc.h                |  161 +++++-
 include/drm/drm_mode.h                |   50 ++
 16 files changed, 1818 insertions(+), 474 deletions(-)
 create mode 100644 drivers/staging/omapdrm/omap_atomic.c
 create mode 100644 drivers/staging/omapdrm/omap_atomic.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [RFC 01/11] drm: add atomic fxns
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 02/11] drm: add object property type Rob Clark
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

The 'atomic' mechanism allows for multiple properties to be updated,
checked, and commited atomically.  This will be the basis of atomic-
modeset and nuclear-pageflip.

The basic flow is:

   state = dev->atomic_begin();
   for (... one or more ...)
      obj->set_property(obj, state, prop, value);
   if (dev->atomic_check(state))
      dev->atomic_commit(state, event);
   dev->atomic_end(state);

The split of check and commit steps is to allow for ioctls with a
test-only flag (which would skip the commit step).

The atomic functions are mandatory, as they will end up getting
called from enough places that it is easier not to have to bother
with if-null checks everywhere.
---
 drivers/gpu/drm/drm_crtc.c           |  126 +++++++++++++++++++++-------------
 drivers/staging/omapdrm/omap_crtc.c  |    4 +-
 drivers/staging/omapdrm/omap_drv.h   |    2 +-
 drivers/staging/omapdrm/omap_plane.c |    2 +-
 include/drm/drmP.h                   |   52 ++++++++++++++
 include/drm/drm_crtc.h               |    8 +--
 6 files changed, 139 insertions(+), 55 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index cee96f4..a236acf 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3208,12 +3208,11 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
 	return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
 }
 
-static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
-					   struct drm_property *property,
+static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+					   void *state, struct drm_property *property,
 					   uint64_t value)
 {
 	int ret = -EINVAL;
-	struct drm_connector *connector = obj_to_connector(obj);
 
 	/* Do DPMS ourselves */
 	if (property == connector->dev->mode_config.dpms_property) {
@@ -3221,7 +3220,7 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
 			(*connector->funcs->dpms)(connector, (int)value);
 		ret = 0;
 	} else if (connector->funcs->set_property)
-		ret = connector->funcs->set_property(connector, property, value);
+		ret = connector->funcs->set_property(connector, state, property, value);
 
 	/* store the property value if successful */
 	if (!ret)
@@ -3229,36 +3228,87 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
 	return ret;
 }
 
-static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
-				      struct drm_property *property,
+static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+				      void *state, struct drm_property *property,
 				      uint64_t value)
 {
 	int ret = -EINVAL;
-	struct drm_crtc *crtc = obj_to_crtc(obj);
 
 	if (crtc->funcs->set_property)
-		ret = crtc->funcs->set_property(crtc, property, value);
+		ret = crtc->funcs->set_property(crtc, state, property, value);
 	if (!ret)
-		drm_object_property_set_value(obj, property, value);
+		drm_object_property_set_value(&crtc->base, property, value);
 
 	return ret;
 }
 
-static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
-				      struct drm_property *property,
+static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+				      void *state, struct drm_property *property,
 				      uint64_t value)
 {
 	int ret = -EINVAL;
-	struct drm_plane *plane = obj_to_plane(obj);
 
 	if (plane->funcs->set_property)
-		ret = plane->funcs->set_property(plane, property, value);
+		ret = plane->funcs->set_property(plane, state, property, value);
 	if (!ret)
-		drm_object_property_set_value(obj, property, value);
+		drm_object_property_set_value(&plane->base, property, value);
 
 	return ret;
 }
 
+static int drm_mode_set_obj_prop(struct drm_device *dev,
+		struct drm_mode_object *obj, void *state,
+		struct drm_property *property, uint64_t value)
+{
+	if (drm_property_change_is_valid(property, value)) {
+		switch (obj->type) {
+		case DRM_MODE_OBJECT_CONNECTOR:
+			return drm_mode_connector_set_obj_prop(obj_to_connector(obj),
+					state, property, value);
+		case DRM_MODE_OBJECT_CRTC:
+			return drm_mode_crtc_set_obj_prop(obj_to_crtc(obj),
+					state, property, value);
+		case DRM_MODE_OBJECT_PLANE:
+			return drm_mode_plane_set_obj_prop(obj_to_plane(obj),
+					state, property, value);
+		}
+	}
+
+	return -EINVAL;
+}
+
+/* call with mode_config mutex held */
+static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
+		uint32_t obj_id, uint32_t obj_type,
+		uint32_t prop_id, uint64_t value)
+{
+	struct drm_mode_object *arg_obj;
+	struct drm_mode_object *prop_obj;
+	struct drm_property *property;
+	int i;
+
+	arg_obj = drm_mode_object_find(dev, obj_id, obj_type);
+	if (!arg_obj)
+		return -EINVAL;
+	if (!arg_obj->properties)
+		return -EINVAL;
+
+	for (i = 0; i < arg_obj->properties->count; i++)
+		if (arg_obj->properties->ids[i] == prop_id)
+			break;
+
+	if (i == arg_obj->properties->count)
+		return -EINVAL;
+
+	prop_obj = drm_mode_object_find(dev, prop_id,
+					DRM_MODE_OBJECT_PROPERTY);
+	if (!prop_obj)
+		return -EINVAL;
+	property = obj_to_property(prop_obj);
+
+	return drm_mode_set_obj_prop(dev, arg_obj, state, property, value);
+}
+
 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 				      struct drm_file *file_priv)
 {
@@ -3319,53 +3369,35 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 				    struct drm_file *file_priv)
 {
 	struct drm_mode_obj_set_property *arg = data;
-	struct drm_mode_object *arg_obj;
-	struct drm_mode_object *prop_obj;
-	struct drm_property *property;
+	void *state = NULL;
 	int ret = -EINVAL;
-	int i;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
 	mutex_lock(&dev->mode_config.mutex);
 
-	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
-	if (!arg_obj)
-		goto out;
-	if (!arg_obj->properties)
-		goto out;
-
-	for (i = 0; i < arg_obj->properties->count; i++)
-		if (arg_obj->properties->ids[i] == arg->prop_id)
-			break;
+	state = dev->driver->atomic_begin(dev, NULL);
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto out_unlock;
+	}
 
-	if (i == arg_obj->properties->count)
+	ret = drm_mode_set_obj_prop_id(dev, state,
+			arg->obj_id, arg->obj_type,
+			arg->prop_id, arg->value);
+	if (ret)
 		goto out;
 
-	prop_obj = drm_mode_object_find(dev, arg->prop_id,
-					DRM_MODE_OBJECT_PROPERTY);
-	if (!prop_obj)
-		goto out;
-	property = obj_to_property(prop_obj);
-
-	if (!drm_property_change_is_valid(property, arg->value))
+	ret = dev->driver->atomic_check(dev, state);
+	if (ret)
 		goto out;
 
-	switch (arg_obj->type) {
-	case DRM_MODE_OBJECT_CONNECTOR:
-		ret = drm_mode_connector_set_obj_prop(arg_obj, property,
-						      arg->value);
-		break;
-	case DRM_MODE_OBJECT_CRTC:
-		ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
-		break;
-	case DRM_MODE_OBJECT_PLANE:
-		ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
-		break;
-	}
+	ret = dev->driver->atomic_commit(dev, state, NULL);
 
 out:
+	dev->driver->atomic_end(dev, state);
+out_unlock:
 	mutex_unlock(&dev->mode_config.mutex);
 	return ret;
 }
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index e430559..eddbb2f 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -327,7 +327,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 	return 0;
 }
 
-static int omap_crtc_set_property(struct drm_crtc *crtc,
+static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
 		struct drm_property *property, uint64_t val)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -338,7 +338,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
 				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
 	}
 
-	return omap_plane_set_property(omap_crtc->plane, property, val);
+	return omap_plane_set_property(omap_crtc->plane, state, property, val);
 }
 
 static const struct drm_crtc_funcs omap_crtc_funcs = {
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index fec3c75..c20ed7e 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -171,7 +171,7 @@ int omap_plane_mode_set(struct drm_plane *plane,
 		void (*fxn)(void *), void *arg);
 void omap_plane_install_properties(struct drm_plane *plane,
 		struct drm_mode_object *obj);
-int omap_plane_set_property(struct drm_plane *plane,
+int omap_plane_set_property(struct drm_plane *plane, void *state,
 		struct drm_property *property, uint64_t val);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev);
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index c9098fc..854fdce 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -327,7 +327,7 @@ void omap_plane_install_properties(struct drm_plane *plane,
 	drm_object_attach_property(obj, prop, 0);
 }
 
-int omap_plane_set_property(struct drm_plane *plane,
+int omap_plane_set_property(struct drm_plane *plane, void *state,
 		struct drm_property *property, uint64_t val)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index ee8f927..9c41d36 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -940,6 +940,58 @@ struct drm_driver {
 			    struct drm_device *dev,
 			    uint32_t handle);
 
+	/*
+	 * Atomic functions:
+	 */
+
+	/**
+	 * Begin a sequence of atomic property sets.  Returns a driver
+	 * private state object that is passed back into the various
+	 * object's set_property() fxns, and into the remainder of the
+	 * atomic funcs.  The state object should accumulate the changes
+	 * from one o more set_property()'s.  At the end, the state can
+	 * be checked, and optionally committed.
+	 *
+	 * \param dev dev DRM device handle.
+	 * \param crtc for asynchronous page-flip operations, the crtc
+	 *   that is being updated.  (The driver should return -EBUSY if
+	 *   a page-flip is still pending.)  Otherwise, NULL.
+	 * \returns a driver private state object, which is passed
+	 *   back in to the various other atomic fxns
+	 */
+	void *(*atomic_begin)(struct drm_device *dev, struct drm_crtc *crtc);
+
+	/**
+	 * Check the state object to see if the requested state is
+	 * physically possible.
+	 *
+	 * \param dev dev DRM device handle.
+	 * \param state the driver private state object
+	 */
+	int (*atomic_check)(struct drm_device *dev, void *state);
+
+	/**
+	 * Commit the state.  This will only be called if atomic_check()
+	 * succeeds.
+	 *
+	 * \param dev dev DRM device handle.
+	 * \param state the driver private state object
+	 * \param event for asynchronous page-flip operations, the
+	 *   userspace has requested an event to be sent when the
+	 *   page-flip completes, or NULL.  Will always be NULL for
+	 *   non-page-flip operations
+	 */
+	int (*atomic_commit)(struct drm_device *dev, void *state,
+			struct drm_pending_vblank_event *event);
+
+	/**
+	 * Release resources associated with the state object.
+	 *
+	 * \param dev dev DRM device handle.
+	 * \param state the driver private state object
+	 */
+	void (*atomic_end)(struct drm_device *dev, void *state);
+
 	/* Driver private ops for this object */
 	const struct vm_operations_struct *gem_vm_ops;
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index a45cdc2..4ae5295 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -356,7 +356,7 @@ struct drm_crtc_funcs {
 			 struct drm_framebuffer *fb,
 			 struct drm_pending_vblank_event *event);
 
-	int (*set_property)(struct drm_crtc *crtc,
+	int (*set_property)(struct drm_crtc *crtc, void *state,
 			    struct drm_property *property, uint64_t val);
 };
 
@@ -454,8 +454,8 @@ struct drm_connector_funcs {
 	enum drm_connector_status (*detect)(struct drm_connector *connector,
 					    bool force);
 	int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
-	int (*set_property)(struct drm_connector *connector, struct drm_property *property,
-			     uint64_t val);
+	int (*set_property)(struct drm_connector *connector, void *state,
+			struct drm_property *property, uint64_t val);
 	void (*destroy)(struct drm_connector *connector);
 	void (*force)(struct drm_connector *connector);
 };
@@ -627,7 +627,7 @@ struct drm_plane_funcs {
 	int (*disable_plane)(struct drm_plane *plane);
 	void (*destroy)(struct drm_plane *plane);
 
-	int (*set_property)(struct drm_plane *plane,
+	int (*set_property)(struct drm_plane *plane, void *state,
 			    struct drm_property *property, uint64_t val);
 };
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 02/11] drm: add object property type
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
  2012-10-13  0:49 ` [RFC 01/11] drm: add atomic fxns Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 03/11] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

An object property is an id (idr) for a drm mode object.  This
will allow a property to be used set/get a framebuffer, CRTC, etc.
---
 drivers/gpu/drm/drm_crtc.c |   33 +++++++++++++++++++++++++++++----
 include/drm/drm_crtc.h     |   10 ++++++++++
 include/drm/drm_mode.h     |    1 +
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index a236acf..e25903d 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2758,6 +2758,8 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
 	if (!property)
 		return NULL;
 
+	property->dev = dev;
+
 	if (num_values) {
 		property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
 		if (!property->values)
@@ -2861,6 +2863,23 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
 }
 EXPORT_SYMBOL(drm_property_create_range);
 
+struct drm_property *drm_property_create_object(struct drm_device *dev,
+					 int flags, const char *name, uint32_t type)
+{
+	struct drm_property *property;
+
+	flags |= DRM_MODE_PROP_OBJECT;
+
+	property = drm_property_create(dev, flags, name, 1);
+	if (!property)
+		return NULL;
+
+	property->values[0] = type;
+
+	return property;
+}
+EXPORT_SYMBOL(drm_property_create_object);
+
 int drm_property_add_enum(struct drm_property *property, int index,
 			  uint64_t value, const char *name)
 {
@@ -3184,6 +3203,11 @@ static bool drm_property_change_is_valid(struct drm_property *property,
 		for (i = 0; i < property->num_values; i++)
 			valid_mask |= (1ULL << property->values[i]);
 		return !(value & ~valid_mask);
+	} else if (property->flags & DRM_MODE_PROP_OBJECT) {
+		/* a zero value for an object property translates to null: */
+		if (value)
+			return true;
+		return drm_property_get_obj(property, value) != NULL;
 	} else {
 		int i;
 		for (i = 0; i < property->num_values; i++)
@@ -3256,9 +3280,8 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 	return ret;
 }
 
-static int drm_mode_set_obj_prop(struct drm_device *dev,
-		struct drm_mode_object *obj, void *state,
-		struct drm_property *property, uint64_t value)
+static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
+		void *state, struct drm_property *property, uint64_t value)
 {
 	if (drm_property_change_is_valid(property, value)) {
 		switch (obj->type) {
@@ -3272,6 +3295,8 @@ static int drm_mode_set_obj_prop(struct drm_device *dev,
 			return drm_mode_plane_set_obj_prop(obj_to_plane(obj),
 					state, property, value);
 		}
+	} else {
+		DRM_DEBUG("invalid value: %s = %llx\n", property->name, value);
 	}
 
 	return -EINVAL;
@@ -3306,7 +3331,7 @@ static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
 		return -EINVAL;
 	property = obj_to_property(prop_obj);
 
-	return drm_mode_set_obj_prop(dev, arg_obj, state, property, value);
+	return drm_mode_set_obj_prop(arg_obj, state, property, value);
 }
 
 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 4ae5295..f319127 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -290,6 +290,7 @@ struct drm_property {
 	char name[DRM_PROP_NAME_LEN];
 	uint32_t num_values;
 	uint64_t *values;
+	struct drm_device *dev;
 
 	struct list_head enum_blob_list;
 };
@@ -947,6 +948,8 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
 struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
 					 const char *name,
 					 uint64_t min, uint64_t max);
+struct drm_property *drm_property_create_object(struct drm_device *dev,
+					 int flags, const char *name, uint32_t type);
 extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
 extern int drm_property_add_enum(struct drm_property *property, int index,
 				 uint64_t value, const char *name);
@@ -966,6 +969,13 @@ extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
 					 int gamma_size);
 extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 		uint32_t id, uint32_t type);
+
+static inline struct drm_mode_object *
+drm_property_get_obj(struct drm_property *property, uint64_t value)
+{
+	return drm_mode_object_find(property->dev, value, property->values[0]);
+}
+
 /* IOCTLs */
 extern int drm_mode_getresources(struct drm_device *dev,
 				 void *data, struct drm_file *file_priv);
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 3d6301b..dff792f 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -231,6 +231,7 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_ENUM	(1<<3) /* enumerated type with text strings */
 #define DRM_MODE_PROP_BLOB	(1<<4)
 #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
+#define DRM_MODE_PROP_OBJECT	(1<<6) /* drm mode object */
 
 struct drm_mode_property_enum {
 	__u64 value;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 03/11] drm: add DRM_MODE_PROP_DYNAMIC property flag
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
  2012-10-13  0:49 ` [RFC 01/11] drm: add atomic fxns Rob Clark
  2012-10-13  0:49 ` [RFC 02/11] drm: add object property type Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 04/11] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

This indicates to userspace that the property is something that can
be set dynamically without requiring a "test" step to check if the
hw is capable.  This allows a userspace compositor, such as weston,
to avoid an extra ioctl to check whether it needs to fall-back to
GPU to composite some surface prior to submission of GPU render
commands.
---
 include/drm/drm_mode.h |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index dff792f..e03ece6 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -232,6 +232,15 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_BLOB	(1<<4)
 #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
 #define DRM_MODE_PROP_OBJECT	(1<<6) /* drm mode object */
+/* Properties that are not dynamic cannot safely be changed without a
+ * atomic-modeset / atomic-pageflip test step.  But if userspace is
+ * only changing dynamic properties, it is guaranteed that the change
+ * will not exceed hw limits, so no test step is required.
+ *
+ * Note that fb_id properties are a bit ambiguous.. they of course can
+ * be changed dynamically, assuming the pixel format does not change.
+ */
+#define DRM_MODE_PROP_DYNAMIC	(1<<24)
 
 struct drm_mode_property_enum {
 	__u64 value;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 04/11] drm: add DRM_MODE_PROP_SIGNED property flag
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (2 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 03/11] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 05/11] drm: split property values out Rob Clark
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

Flag for range property types indicating that the value is a signed
integer rather than unsigned.  For range properties, the signed flag
will trigger use of signed integer comparisions, to handle negative
values properly.
---
 drivers/gpu/drm/drm_crtc.c |   10 ++++++++--
 include/drm/drm_crtc.h     |    9 +++++++++
 include/drm/drm_mode.h     |    2 ++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e25903d..5308a34 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3191,9 +3191,15 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
 static bool drm_property_change_is_valid(struct drm_property *property,
 					 uint64_t value)
 {
-	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+	if (property->flags & DRM_MODE_PROP_IMMUTABLE) {
 		return false;
-	if (property->flags & DRM_MODE_PROP_RANGE) {
+	} else if (property->flags & (DRM_MODE_PROP_RANGE|DRM_MODE_PROP_SIGNED)) {
+		int64_t svalue = U642I64(value);
+		if (svalue < U642I64(property->values[0]) ||
+				svalue > U642I64(property->values[1]))
+			return false;
+		return true;
+	} else if (property->flags & DRM_MODE_PROP_RANGE) {
 		if (value < property->values[0] || value > property->values[1])
 			return false;
 		return true;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index f319127..219d35a 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -61,6 +61,15 @@ struct drm_object_properties {
 	uint64_t values[DRM_OBJECT_MAX_PROPERTY];
 };
 
+static inline int64_t U642I64(uint64_t val)
+{
+	return (int64_t)*((int64_t *)&val);
+}
+static inline uint64_t I642U64(int64_t val)
+{
+	return (uint64_t)*((uint64_t *)&val);
+}
+
 /*
  * Note on terminology:  here, for brevity and convenience, we refer to connector
  * control chips as 'CRTCs'.  They can control any type of connector, VGA, LVDS,
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index e03ece6..f9232e4 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -241,6 +241,8 @@ struct drm_mode_get_connector {
  * be changed dynamically, assuming the pixel format does not change.
  */
 #define DRM_MODE_PROP_DYNAMIC	(1<<24)
+/* Indicates that numeric property values are signed rather than unsigned: */
+#define DRM_MODE_PROP_SIGNED   (1<<25)
 
 struct drm_mode_property_enum {
 	__u64 value;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 05/11] drm: split property values out
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (3 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 04/11] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 06/11] drm: convert plane to properties Rob Clark
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

Split property values out into a different struct, so we can later
move property values into state structs.  This will allow the
property values to stay in sync w/ the state updates which are
either discarded or atomically committed.
---
 drivers/gpu/drm/drm_crtc.c         |   29 ++++++++++++++++++++---------
 drivers/gpu/drm/drm_fb_helper.c    |    1 +
 drivers/staging/omapdrm/omap_drv.c |    5 +++--
 include/drm/drm_crtc.h             |   10 +++++++++-
 4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5308a34..b1ccfea 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -446,6 +446,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 		goto out;
 
 	crtc->base.properties = &crtc->properties;
+	crtc->base.propvals = &crtc->propvals;
 
 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
 	dev->mode_config.num_crtc++;
@@ -547,6 +548,7 @@ int drm_connector_init(struct drm_device *dev,
 		goto out;
 
 	connector->base.properties = &connector->properties;
+	connector->base.propvals = &connector->propvals;
 	connector->dev = dev;
 	connector->funcs = funcs;
 	connector->connector_type = connector_type;
@@ -670,6 +672,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		goto out;
 
 	plane->base.properties = &plane->properties;
+	plane->base.propvals = &plane->propvals;
 	plane->dev = dev;
 	plane->funcs = funcs;
 	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
@@ -1549,7 +1552,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 				goto out;
 			}
 
-			if (put_user(connector->properties.values[i],
+			if (put_user(connector->propvals.values[i],
 				     prop_values + copied)) {
 				ret = -EFAULT;
 				goto out;
@@ -2951,19 +2954,20 @@ void drm_object_attach_property(struct drm_mode_object *obj,
 	}
 
 	obj->properties->ids[count] = property->base.id;
-	obj->properties->values[count] = init_val;
+	obj->propvals->values[count] = init_val;
 	obj->properties->count++;
 }
 EXPORT_SYMBOL(drm_object_attach_property);
 
 int drm_object_property_set_value(struct drm_mode_object *obj,
+				  struct drm_object_property_values *propvals,
 				  struct drm_property *property, uint64_t val)
 {
 	int i;
 
 	for (i = 0; i < obj->properties->count; i++) {
 		if (obj->properties->ids[i] == property->base.id) {
-			obj->properties->values[i] = val;
+			propvals->values[i] = val;
 			return 0;
 		}
 	}
@@ -2979,7 +2983,7 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
 
 	for (i = 0; i < obj->properties->count; i++) {
 		if (obj->properties->ids[i] == property->base.id) {
-			*val = obj->properties->values[i];
+			*val = obj->propvals->values[i];
 			return 0;
 		}
 	}
@@ -3172,7 +3176,9 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 	/* Delete edid, when there is none. */
 	if (!edid) {
 		connector->edid_blob_ptr = NULL;
-		ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0);
+		ret = drm_object_property_set_value(&connector->base,
+				&connector->propvals,
+				dev->mode_config.edid_property, 0);
 		return ret;
 	}
 
@@ -3181,6 +3187,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 							    size, edid);
 
 	ret = drm_object_property_set_value(&connector->base,
+					       &connector->propvals,
 					       dev->mode_config.edid_property,
 					       connector->edid_blob_ptr->base.id);
 
@@ -3254,7 +3261,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 
 	/* store the property value if successful */
 	if (!ret)
-		drm_object_property_set_value(&connector->base, property, value);
+		drm_object_property_set_value(&connector->base,
+				&connector->propvals, property, value);
+
 	return ret;
 }
 
@@ -3267,7 +3276,8 @@ static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 	if (crtc->funcs->set_property)
 		ret = crtc->funcs->set_property(crtc, state, property, value);
 	if (!ret)
-		drm_object_property_set_value(&crtc->base, property, value);
+		drm_object_property_set_value(&crtc->base, &crtc->propvals,
+				property, value);
 
 	return ret;
 }
@@ -3281,7 +3291,8 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 	if (plane->funcs->set_property)
 		ret = plane->funcs->set_property(plane, state, property, value);
 	if (!ret)
-		drm_object_property_set_value(&plane->base, property, value);
+		drm_object_property_set_value(&plane->base, &plane->propvals,
+				property, value);
 
 	return ret;
 }
@@ -3382,7 +3393,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 				ret = -EFAULT;
 				goto out;
 			}
-			if (put_user(obj->properties->values[i],
+			if (put_user(obj->propvals->values[i],
 				     prop_values_ptr + copied)) {
 				ret = -EFAULT;
 				goto out;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 712b3e88..80bdb59 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -332,6 +332,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 			connector = fb_helper->connector_info[j]->connector;
 			connector->funcs->dpms(connector, dpms_mode);
 			drm_object_property_set_value(&connector->base,
+				&connector->propvals,
 				dev->mode_config.dpms_property, dpms_mode);
 		}
 	}
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index bdb98d5..5f5ee84 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -526,8 +526,9 @@ static void dev_lastclose(struct drm_device *dev)
 	 * default state on lastclose?
 	 */
 	for (i = 0; i < priv->num_planes; i++) {
-		drm_object_property_set_value(&priv->planes[i]->base,
-				priv->rotation_prop, 0);
+		struct drm_plane *plane = priv->planes[i];
+		drm_object_property_set_value(&plane->base,
+				&plane->propvals, priv->rotation_prop, 0);
 	}
 
 	mutex_lock(&dev->mode_config.mutex);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 219d35a..cb438bf 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -37,7 +37,7 @@ struct drm_device;
 struct drm_mode_set;
 struct drm_framebuffer;
 struct drm_object_properties;
-
+struct drm_object_property_values;
 
 #define DRM_MODE_OBJECT_CRTC 0xcccccccc
 #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
@@ -52,12 +52,16 @@ struct drm_mode_object {
 	uint32_t id;
 	uint32_t type;
 	struct drm_object_properties *properties;
+	struct drm_object_property_values *propvals;
 };
 
 #define DRM_OBJECT_MAX_PROPERTY 24
 struct drm_object_properties {
 	int count;
 	uint32_t ids[DRM_OBJECT_MAX_PROPERTY];
+};
+
+struct drm_object_property_values {
 	uint64_t values[DRM_OBJECT_MAX_PROPERTY];
 };
 
@@ -430,6 +434,7 @@ struct drm_crtc {
 	void *helper_private;
 
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 };
 
 
@@ -596,6 +601,7 @@ struct drm_connector {
 	struct list_head user_modes;
 	struct drm_property_blob *edid_blob_ptr;
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 
 	uint8_t polled; /* DRM_CONNECTOR_POLL_* */
 
@@ -681,6 +687,7 @@ struct drm_plane {
 	void *helper_private;
 
 	struct drm_object_properties properties;
+	struct drm_object_property_values propvals;
 };
 
 /**
@@ -928,6 +935,7 @@ extern void drm_mode_connector_list_update(struct drm_connector *connector);
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 						struct edid *edid);
 extern int drm_object_property_set_value(struct drm_mode_object *obj,
+					 struct drm_object_property_values *propvals,
 					 struct drm_property *property,
 					 uint64_t val);
 extern int drm_object_property_get_value(struct drm_mode_object *obj,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 06/11] drm: convert plane to properties
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (4 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 05/11] drm: split property values out Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 07/11] drm: add drm_plane_state Rob Clark
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

Use atomic properties mechanism to set plane attributes.  This by
itself doesn't accomplish anything, but it avoids having multiple
code paths to do the same thing when nuclear-pageflip and atomic-
modeset are introduced.
---
 drivers/gpu/drm/drm_crtc.c |  278 +++++++++++++++++++++++++++++++++++++++++---
 include/drm/drm_crtc.h     |   25 +++-
 2 files changed, 289 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index b1ccfea..da29732 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -38,6 +38,14 @@
 #include "drm_edid.h"
 #include "drm_fourcc.h"
 
+static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
+		void *state, struct drm_property *property, uint64_t value);
+
+static inline bool dev_supports_atomic(struct drm_device *dev)
+{
+	return !!dev->driver->atomic_begin;
+}
+
 /* Avoid boilerplate.  I'm tired of typing. */
 #define DRM_ENUM_NAME_FN(fnname, list)				\
 	char *fnname(int val)					\
@@ -376,8 +384,10 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
  *
  * Scans all the CRTCs and planes in @dev's mode_config.  If they're
  * using @fb, removes it, setting it to NULL.
+ *
+ * Legacy version.. remove when all drivers converted to 'atomic' API
  */
-void drm_framebuffer_remove(struct drm_framebuffer *fb)
+static void drm_framebuffer_remove_legacy(struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = fb->dev;
 	struct drm_crtc *crtc;
@@ -414,6 +424,71 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 
 	drm_framebuffer_unreference(fb);
 }
+
+/**
+ * drm_framebuffer_remove - remove and unreference a framebuffer object
+ * @fb: framebuffer to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Scans all the CRTCs and planes in @dev's mode_config.  If they're
+ * using @fb, removes it, setting it to NULL.
+ */
+void drm_framebuffer_remove(struct drm_framebuffer *fb)
+{
+	struct drm_device *dev = fb->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_crtc *crtc;
+	struct drm_plane *plane;
+	struct drm_mode_set set;
+	void *state;
+	int ret;
+
+	if (!dev_supports_atomic(dev)) {
+		drm_framebuffer_remove_legacy(fb);
+		return;
+	}
+
+	state = dev->driver->atomic_begin(dev, NULL);
+	if (IS_ERR(state)) {
+		DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+		return;
+	}
+
+	/* remove from any CRTC */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		if (crtc->fb == fb) {
+			/* should turn off the crtc */
+			memset(&set, 0, sizeof(struct drm_mode_set));
+			set.crtc = crtc;
+			set.fb = NULL;
+			ret = crtc->funcs->set_config(&set);
+			if (ret)
+				DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+		}
+	}
+
+	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+		if (plane->fb == fb) {
+			/* should turn off the crtc */
+			drm_mode_plane_set_obj_prop(plane, state, config->prop_crtc_id, 0);
+			drm_mode_plane_set_obj_prop(plane, state, config->prop_fb_id, 0);
+		}
+	}
+
+	/* just disabling stuff shouldn't fail, hopefully: */
+	if(dev->driver->atomic_check(dev, state))
+		DRM_ERROR("failed to disable crtc and/or plane when fb was deleted\n");
+	else
+		dev->driver->atomic_commit(dev, state, NULL);
+
+	dev->driver->atomic_end(dev, state);
+
+	list_del(&fb->filp_head);
+
+	drm_framebuffer_unreference(fb);
+}
 EXPORT_SYMBOL(drm_framebuffer_remove);
 
 /**
@@ -663,6 +738,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		   const uint32_t *formats, uint32_t format_count,
 		   bool priv)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
 	mutex_lock(&dev->mode_config.mutex);
@@ -699,6 +775,20 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 		INIT_LIST_HEAD(&plane->head);
 	}
 
+	if (!dev_supports_atomic(dev))
+		goto out;
+
+	drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+	drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+	drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+
  out:
 	mutex_unlock(&dev->mode_config.mutex);
 
@@ -772,23 +862,91 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
 }
 EXPORT_SYMBOL(drm_mode_destroy);
 
-static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
+static int drm_mode_create_standard_properties(struct drm_device *dev)
 {
-	struct drm_property *edid;
-	struct drm_property *dpms;
+	struct drm_property *prop;
 
 	/*
 	 * Standard properties (apply to all connectors)
 	 */
-	edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+	prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
 				   DRM_MODE_PROP_IMMUTABLE,
 				   "EDID", 0);
-	dev->mode_config.edid_property = edid;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.edid_property = prop;
 
-	dpms = drm_property_create_enum(dev, 0,
+	prop = drm_property_create_enum(dev, 0,
 				   "DPMS", drm_dpms_enum_list,
 				   ARRAY_SIZE(drm_dpms_enum_list));
-	dev->mode_config.dpms_property = dpms;
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.dpms_property = prop;
+
+
+	/* TODO we need the driver to control which of these are dynamic
+	 * and which are not..  or maybe we should just set all to zero
+	 * and let the individual drivers frob the prop->flags for the
+	 * properties they can support dynamic changes on..
+	 */
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_DYNAMIC,
+			"src_x", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_x = prop;
+
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_DYNAMIC,
+			"src_y", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_y = prop;
+
+	prop = drm_property_create_range(dev, 0, "src_w", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_w = prop;
+
+	prop = drm_property_create_range(dev, 0, "src_h", 0, UINT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_src_h = prop;
+
+	prop = drm_property_create_range(dev,
+			DRM_MODE_PROP_DYNAMIC | DRM_MODE_PROP_SIGNED,
+			"crtc_x", I642U64(INT_MIN), I642U64(INT_MAX));
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_x = prop;
+
+	prop = drm_property_create_range(dev,
+			DRM_MODE_PROP_DYNAMIC | DRM_MODE_PROP_SIGNED,
+			"crtc_y", I642U64(INT_MIN), I642U64(INT_MAX));
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_y = prop;
+
+	prop = drm_property_create_range(dev, 0, "crtc_w", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_w = prop;
+
+	prop = drm_property_create_range(dev, 0, "crtc_h", 0, INT_MAX);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_h = prop;
+
+	prop = drm_property_create_object(dev, DRM_MODE_PROP_DYNAMIC,
+			"fb", DRM_MODE_OBJECT_FB);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_fb_id = prop;
+
+	prop = drm_property_create_object(dev, 0,
+			"crtc", DRM_MODE_OBJECT_CRTC);
+	if (!prop)
+		return -ENOMEM;
+	dev->mode_config.prop_crtc_id = prop;
 
 	return 0;
 }
@@ -1003,7 +1161,7 @@ void drm_mode_config_init(struct drm_device *dev)
 	idr_init(&dev->mode_config.crtc_idr);
 
 	mutex_lock(&dev->mode_config.mutex);
-	drm_mode_create_standard_connector_properties(dev);
+	drm_mode_create_standard_properties(dev);
 	mutex_unlock(&dev->mode_config.mutex);
 
 	/* Just to be sure */
@@ -1745,8 +1903,10 @@ out:
  *
  * Set plane info, including placement, fb, scaling, and other factors.
  * Or pass a NULL fb to disable.
+ *
+ * Legacy version.. remove when all drivers converted to 'atomic' API
  */
-int drm_mode_setplane(struct drm_device *dev, void *data,
+static int drm_mode_setplane_legacy(struct drm_device *dev, void *data,
 			struct drm_file *file_priv)
 {
 	struct drm_mode_set_plane *plane_req = data;
@@ -1866,6 +2026,95 @@ out:
 }
 
 /**
+ * drm_mode_setplane - set up or tear down an plane
+ * @dev: DRM device
+ * @data: ioctl data*
+ * @file_prive: DRM file info
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Set plane info, including placement, fb, scaling, and other factors.
+ * Or pass a NULL fb to disable.
+ */
+int drm_mode_setplane(struct drm_device *dev, void *data,
+			struct drm_file *file_priv)
+{
+	struct drm_mode_set_plane *plane_req = data;
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_mode_object *obj;
+	void *state;
+	int ret = 0;
+
+	if (!dev_supports_atomic(dev))
+		return drm_mode_setplane_legacy(dev, data, file_priv);
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return -EINVAL;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	obj = drm_mode_object_find(dev, plane_req->crtc_id,
+				   DRM_MODE_OBJECT_CRTC);
+	if (!obj) {
+		DRM_DEBUG_KMS("Unknown CRTC ID %d\n",
+			      plane_req->crtc_id);
+		ret = -ENOENT;
+		goto out_unlock;
+	}
+
+	state = dev->driver->atomic_begin(dev, obj_to_crtc(obj));
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto out_unlock;
+	}
+
+	obj = drm_mode_object_find(dev, plane_req->plane_id,
+				   DRM_MODE_OBJECT_PLANE);
+	if (!obj) {
+		DRM_DEBUG_KMS("Unknown plane ID %d\n",
+			      plane_req->plane_id);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	ret =
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_crtc_id, plane_req->crtc_id) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_fb_id, plane_req->fb_id) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_crtc_x, I642U64(plane_req->crtc_x)) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_crtc_y, I642U64(plane_req->crtc_y)) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_crtc_w, plane_req->crtc_w) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_crtc_h, plane_req->crtc_h) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_src_w, plane_req->src_w) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_src_h, plane_req->src_h) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_src_x, plane_req->src_x) ||
+		drm_mode_set_obj_prop(obj, state,
+				config->prop_src_y, plane_req->src_y) ||
+		dev->driver->atomic_check(dev, state);
+
+	if (ret)
+		goto out;
+
+	ret = dev->driver->atomic_commit(dev, state, NULL);
+
+out:
+	dev->driver->atomic_end(dev, state);
+out_unlock:
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
+}
+
+/**
  * drm_mode_setcrtc - set CRTC configuration
  * @inode: inode from the ioctl
  * @filp: file * from the ioctl
@@ -3245,7 +3494,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
 	return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
 }
 
-static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 					   void *state, struct drm_property *property,
 					   uint64_t value)
 {
@@ -3266,8 +3515,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_connector_set_obj_prop);
 
-static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 				      void *state, struct drm_property *property,
 				      uint64_t value)
 {
@@ -3281,8 +3531,9 @@ static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_crtc_set_obj_prop);
 
-static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 				      void *state, struct drm_property *property,
 				      uint64_t value)
 {
@@ -3296,6 +3547,7 @@ static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 
 	return ret;
 }
+EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
 static int drm_mode_set_obj_prop(struct drm_mode_object *obj,
 		void *state, struct drm_property *property, uint64_t value)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index cb438bf..514b3f4 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -810,8 +810,20 @@ struct drm_mode_config {
 	bool poll_enabled;
 	struct delayed_work output_poll_work;
 
-	/* pointers to standard properties */
+	/* just so blob properties can always be in a list: */
 	struct list_head property_blob_list;
+
+	/* pointers to standard properties */
+	struct drm_property *prop_src_x;
+	struct drm_property *prop_src_y;
+	struct drm_property *prop_src_w;
+	struct drm_property *prop_src_h;
+	struct drm_property *prop_crtc_x;
+	struct drm_property *prop_crtc_y;
+	struct drm_property *prop_crtc_w;
+	struct drm_property *prop_crtc_h;
+	struct drm_property *prop_fb_id;
+	struct drm_property *prop_crtc_id;
 	struct drm_property *edid_property;
 	struct drm_property *dpms_property;
 
@@ -941,6 +953,17 @@ extern int drm_object_property_set_value(struct drm_mode_object *obj,
 extern int drm_object_property_get_value(struct drm_mode_object *obj,
 					 struct drm_property *property,
 					 uint64_t *value);
+
+int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+					   void *state, struct drm_property *property,
+					   uint64_t value);
+int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+				      void *state, struct drm_property *property,
+				      uint64_t value);
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+				      void *state, struct drm_property *property,
+				      uint64_t value);
+
 extern int drm_framebuffer_init(struct drm_device *dev,
 				struct drm_framebuffer *fb,
 				const struct drm_framebuffer_funcs *funcs);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 07/11] drm: add drm_plane_state
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (5 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 06/11] drm: convert plane to properties Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 08/11] drm: convert page_flip to properties Rob Clark
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

Break the mutable state of a plane out into a separate structure.
This makes it easier to have some helpers for plane->set_property()
and for checking for invalid params.  The idea is that individual
drivers can wrap the state struct in their own struct which adds
driver specific parameters, for easy build-up of state across
multiple set_property() calls and for easy atomic commit or roll-
back.

The same should be done for CRTC, encoder, and connector, but this
patch only includes the first part (plane).
---
 drivers/gpu/drm/drm_crtc.c           |  142 ++++++++++++++++++++++++++++++----
 drivers/staging/omapdrm/omap_crtc.c  |    4 +-
 drivers/staging/omapdrm/omap_drv.c   |    2 +-
 drivers/staging/omapdrm/omap_plane.c |   16 ++--
 include/drm/drm_crtc.h               |   52 +++++++++++--
 5 files changed, 181 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index da29732..63365f0 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -409,14 +409,14 @@ static void drm_framebuffer_remove_legacy(struct drm_framebuffer *fb)
 	}
 
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->fb == fb) {
+		if (plane->state->fb == fb) {
 			/* should turn off the crtc */
 			ret = plane->funcs->disable_plane(plane);
 			if (ret)
 				DRM_ERROR("failed to disable plane with busy fb\n");
 			/* disconnect the plane from the fb and crtc: */
-			plane->fb = NULL;
-			plane->crtc = NULL;
+			plane->state->fb = NULL;
+			plane->state->crtc = NULL;
 		}
 	}
 
@@ -470,7 +470,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	}
 
 	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->fb == fb) {
+		if (plane->state->fb == fb) {
 			/* should turn off the crtc */
 			drm_mode_plane_set_obj_prop(plane, state, config->prop_crtc_id, 0);
 			drm_mode_plane_set_obj_prop(plane, state, config->prop_fb_id, 0);
@@ -743,12 +743,21 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 
 	mutex_lock(&dev->mode_config.mutex);
 
+	if (!dev_supports_atomic(dev)) {
+		plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+		if (!plane->state) {
+			DRM_DEBUG_KMS("out of memory when allocating state\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
 	if (ret)
 		goto out;
 
 	plane->base.properties = &plane->properties;
-	plane->base.propvals = &plane->propvals;
+	plane->base.propvals = &plane->state->propvals;
 	plane->dev = dev;
 	plane->funcs = funcs;
 	plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
@@ -812,6 +821,110 @@ void drm_plane_cleanup(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
+int drm_plane_check_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	unsigned int fb_width, fb_height;
+	struct drm_framebuffer *fb = state->fb;
+	int i;
+
+	/* disabling the plane is allowed: */
+	if (!fb)
+		return 0;
+
+	fb_width = fb->width << 16;
+	fb_height = fb->height << 16;
+
+	/* Check whether this plane supports the fb pixel format. */
+	for (i = 0; i < plane->format_count; i++)
+		if (fb->pixel_format == plane->format_types[i])
+			break;
+	if (i == plane->format_count) {
+		DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
+		return -EINVAL;
+	}
+
+	/* Make sure source coordinates are inside the fb. */
+	if (state->src_w > fb_width ||
+			state->src_x > fb_width - state->src_w ||
+			state->src_h > fb_height ||
+			state->src_y > fb_height - state->src_h) {
+		DRM_DEBUG_KMS("Invalid source coordinates "
+			      "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+			      state->src_w >> 16,
+			      ((state->src_w & 0xffff) * 15625) >> 10,
+			      state->src_h >> 16,
+			      ((state->src_h & 0xffff) * 15625) >> 10,
+			      state->src_x >> 16,
+			      ((state->src_x & 0xffff) * 15625) >> 10,
+			      state->src_y >> 16,
+			      ((state->src_y & 0xffff) * 15625) >> 10);
+		return -ENOSPC;
+	}
+
+	/* Give drivers some help against integer overflows */
+	if (state->crtc_w > INT_MAX ||
+			state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
+			state->crtc_h > INT_MAX ||
+			state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
+		DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+			      state->crtc_w, state->crtc_h,
+			      state->crtc_x, state->crtc_y);
+		return -ERANGE;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_check_state);
+
+void drm_plane_commit_state(struct drm_plane *plane,
+		struct drm_plane_state *state)
+{
+	plane->state = state;
+	plane->base.propvals = &state->propvals;
+}
+EXPORT_SYMBOL(drm_plane_commit_state);
+
+int drm_plane_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state,
+		struct drm_property *property, uint64_t value)
+{
+	struct drm_device *dev = plane->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	drm_object_property_set_value(&plane->base,
+			&state->propvals, property, value);
+
+	if (property == config->prop_fb_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		state->fb = obj ? obj_to_fb(obj) : NULL;
+	} else if (property == config->prop_crtc_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		state->crtc = obj ? obj_to_crtc(obj) : NULL;
+	} else if (property == config->prop_crtc_x) {
+		state->crtc_x = U642I64(value);
+	} else if (property == config->prop_crtc_y) {
+		state->crtc_y = U642I64(value);
+	} else if (property == config->prop_crtc_w) {
+		state->crtc_w = value;
+	} else if (property == config->prop_crtc_h) {
+		state->crtc_h = value;
+	} else if (property == config->prop_src_x) {
+		state->src_x = value;
+	} else if (property == config->prop_src_y) {
+		state->src_y = value;
+	} else if (property == config->prop_src_w) {
+		state->src_w = value;
+	} else if (property == config->prop_src_h) {
+		state->src_h = value;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_plane_set_property);
+
 /**
  * drm_mode_create - create a new display mode
  * @dev: DRM device
@@ -1857,13 +1970,13 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	}
 	plane = obj_to_plane(obj);
 
-	if (plane->crtc)
-		plane_resp->crtc_id = plane->crtc->base.id;
+	if (plane->state->crtc)
+		plane_resp->crtc_id = plane->state->crtc->base.id;
 	else
 		plane_resp->crtc_id = 0;
 
-	if (plane->fb)
-		plane_resp->fb_id = plane->fb->base.id;
+	if (plane->state->fb)
+		plane_resp->fb_id = plane->state->fb->base.id;
 	else
 		plane_resp->fb_id = 0;
 
@@ -1940,8 +2053,8 @@ static int drm_mode_setplane_legacy(struct drm_device *dev, void *data,
 	/* No fb means shut it down */
 	if (!plane_req->fb_id) {
 		plane->funcs->disable_plane(plane);
-		plane->crtc = NULL;
-		plane->fb = NULL;
+		plane->state->crtc = NULL;
+		plane->state->fb = NULL;
 		goto out;
 	}
 
@@ -2015,8 +2128,8 @@ static int drm_mode_setplane_legacy(struct drm_device *dev, void *data,
 					 plane_req->src_x, plane_req->src_y,
 					 plane_req->src_w, plane_req->src_h);
 	if (!ret) {
-		plane->crtc = crtc;
-		plane->fb = fb;
+		plane->state->crtc = crtc;
+		plane->state->fb = fb;
 	}
 
 out:
@@ -3541,9 +3654,6 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 
 	if (plane->funcs->set_property)
 		ret = plane->funcs->set_property(plane, state, property, value);
-	if (!ret)
-		drm_object_property_set_value(&plane->base, &plane->propvals,
-				property, value);
 
 	return ret;
 }
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index eddbb2f..1236d21 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -168,7 +168,7 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 		/* and any attached overlay planes: */
 		for (i = 0; i < priv->num_planes; i++) {
 			struct drm_plane *plane = priv->planes[i];
-			if (plane->crtc == crtc)
+			if (plane->state->crtc == crtc)
 				WARN_ON(omap_plane_dpms(plane, mode));
 		}
 	}
@@ -605,7 +605,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
 	omap_crtc->channel = channel;
 	omap_crtc->plane = plane;
-	omap_crtc->plane->crtc = crtc;
+	omap_crtc->plane->state->crtc = crtc;
 	omap_crtc->name = channel_names[channel];
 	omap_crtc->pipe = id;
 
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 5f5ee84..7321510 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -528,7 +528,7 @@ static void dev_lastclose(struct drm_device *dev)
 	for (i = 0; i < priv->num_planes; i++) {
 		struct drm_plane *plane = priv->planes[i];
 		drm_object_property_set_value(&plane->base,
-				&plane->propvals, priv->rotation_prop, 0);
+				&plane->state->propvals, priv->rotation_prop, 0);
 	}
 
 	mutex_lock(&dev->mode_config.mutex);
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index 854fdce..cb5d427 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -122,7 +122,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	struct drm_plane *plane = &omap_plane->base;
 	struct drm_device *dev = plane->dev;
 	struct omap_overlay_info *info = &omap_plane->info;
-	struct drm_crtc *crtc = plane->crtc;
+	struct drm_crtc *crtc = plane->state->crtc;
 	enum omap_channel channel;
 	bool enabled = omap_plane->enabled && crtc;
 	bool ilace, replication;
@@ -131,7 +131,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	DBG("%s, enabled=%d", omap_plane->name, enabled);
 
 	/* if fb has changed, pin new fb: */
-	update_pin(plane, enabled ? plane->fb : NULL);
+	update_pin(plane, enabled ? plane->state->fb : NULL);
 
 	if (!enabled) {
 		dispc_ovl_enable(omap_plane->id, false);
@@ -141,7 +141,7 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	channel = omap_crtc_channel(crtc);
 
 	/* update scanout: */
-	omap_framebuffer_update_scanout(plane->fb, win, info);
+	omap_framebuffer_update_scanout(plane->state->fb, win, info);
 
 	DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
 			info->out_width, info->out_height,
@@ -186,16 +186,16 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
 		cb.fxn(cb.arg);
 
 	if (omap_plane->enabled) {
-		omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
+		omap_framebuffer_flush(plane->state->fb, info->pos_x, info->pos_y,
 				info->out_width, info->out_height);
 	}
 }
 
 static int apply(struct drm_plane *plane)
 {
-	if (plane->crtc) {
+	if (plane->state->crtc) {
 		struct omap_plane *omap_plane = to_omap_plane(plane);
-		return omap_crtc_apply(plane->crtc, &omap_plane->apply);
+		return omap_crtc_apply(plane->state->crtc, &omap_plane->apply);
 	}
 	return 0;
 }
@@ -232,8 +232,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
 		omap_plane->apply_done_cb.arg = arg;
 	}
 
-	plane->fb = fb;
-	plane->crtc = crtc;
+	plane->state->fb = fb;
+	plane->state->crtc = crtc;
 
 	return apply(plane);
 }
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 514b3f4..ef558dd 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -648,6 +648,37 @@ struct drm_plane_funcs {
 };
 
 /**
+ * drm_plane_state - mutable plane state
+ * @crtc: currently bound CRTC
+ * @fb: currently bound fb
+ * @crtc_x: left position of visible portion of plane on crtc
+ * @crtc_y: upper position of visible portion of plane on crtc
+ * @crtc_w: width of visible portion of plane on crtc
+ * @crtc_h: height of visible portion of plane on crtc
+ * @src_x: left position of visible portion of plane within
+ *   plane (in 16.16)
+ * @src_y: upper position of visible portion of plane within
+ *   plane (in 16.16)
+ * @src_w: width of visible portion of plane (in 16.16)
+ * @src_h: height of visible portion of plane (in 16.16)
+ * @propvals: property values
+ */
+struct drm_plane_state {
+	struct drm_crtc *crtc;
+	struct drm_framebuffer *fb;
+
+	/* Signed dest location allows it to be partially off screen */
+	int32_t crtc_x, crtc_y;
+	uint32_t crtc_w, crtc_h;
+
+	/* Source values are 16.16 fixed point */
+	uint32_t src_x, src_y;
+	uint32_t src_h, src_w;
+
+	struct drm_object_property_values propvals;
+};
+
+/**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
  * @head: for list management
@@ -655,11 +686,9 @@ struct drm_plane_funcs {
  * @possible_crtcs: pipes this plane can be bound to
  * @format_types: array of formats supported by this plane
  * @format_count: number of formats supported
- * @crtc: currently bound CRTC
- * @fb: currently bound fb
+ * @state: the mutable state
  * @gamma_size: size of gamma table
  * @gamma_store: gamma correction table
- * @enabled: enabled flag
  * @funcs: helper functions
  * @helper_private: storage for drver layer
  * @properties: property tracking for this plane
@@ -674,20 +703,20 @@ struct drm_plane {
 	uint32_t *format_types;
 	uint32_t format_count;
 
-	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb;
+	/*
+	 * State that can be updated from userspace, and atomically
+	 * commited or rolled back:
+	 */
+	struct drm_plane_state *state;
 
 	/* CRTC gamma size for reporting to userspace */
 	uint32_t gamma_size;
 	uint16_t *gamma_store;
 
-	bool enabled;
-
 	const struct drm_plane_funcs *funcs;
 	void *helper_private;
 
 	struct drm_object_properties properties;
-	struct drm_object_property_values propvals;
 };
 
 /**
@@ -895,6 +924,13 @@ extern int drm_plane_init(struct drm_device *dev,
 			  const uint32_t *formats, uint32_t format_count,
 			  bool priv);
 extern void drm_plane_cleanup(struct drm_plane *plane);
+extern int drm_plane_check_state(struct drm_plane *plane,
+		struct drm_plane_state *state);
+extern void drm_plane_commit_state(struct drm_plane *plane,
+		struct drm_plane_state *state);
+extern int drm_plane_set_property(struct drm_plane *plane,
+		struct drm_plane_state *state,
+		struct drm_property *property, uint64_t value);
 
 extern void drm_encoder_cleanup(struct drm_encoder *encoder);
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 08/11] drm: convert page_flip to properties
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (6 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 07/11] drm: add drm_plane_state Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 09/11] drm: add drm_crtc_state Rob Clark
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

Use atomic properties mechanism for CRTC page_flip.  This by itself
doesn't accomplish anything, but it avoids having multiple code
paths to do the same thing when nuclear-pageflip and atomic-modeset
are introduced.
---
 drivers/gpu/drm/drm_crtc.c |  167 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 130 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 63365f0..bcdd6be 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -441,9 +441,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_crtc *crtc;
 	struct drm_plane *plane;
-	struct drm_mode_set set;
 	void *state;
-	int ret;
 
 	if (!dev_supports_atomic(dev)) {
 		drm_framebuffer_remove_legacy(fb);
@@ -460,12 +458,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (crtc->fb == fb) {
 			/* should turn off the crtc */
-			memset(&set, 0, sizeof(struct drm_mode_set));
-			set.crtc = crtc;
-			set.fb = NULL;
-			ret = crtc->funcs->set_config(&set);
-			if (ret)
-				DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+			drm_mode_crtc_set_obj_prop(crtc, state, config->prop_fb_id, 0);
 		}
 	}
 
@@ -508,6 +501,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
 int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 		   const struct drm_crtc_funcs *funcs)
 {
+	struct drm_mode_config *config = &dev->mode_config;
 	int ret;
 
 	crtc->dev = dev;
@@ -526,6 +520,13 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
 	dev->mode_config.num_crtc++;
 
+	if (!dev_supports_atomic(dev))
+		goto out;
+
+	drm_object_attach_property(&crtc->base, config->prop_fb_id, 0);
+	drm_object_attach_property(&crtc->base, config->prop_crtc_x, 0);
+	drm_object_attach_property(&crtc->base, config->prop_crtc_y, 0);
+
  out:
 	mutex_unlock(&dev->mode_config.mutex);
 
@@ -3960,7 +3961,53 @@ out:
 	return ret;
 }
 
-int drm_mode_page_flip_ioctl(struct drm_device *dev,
+static struct drm_pending_vblank_event *create_vblank_event(
+		struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
+{
+	struct drm_pending_vblank_event *e = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (file_priv->event_space < sizeof e->event) {
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		goto out;
+	}
+	file_priv->event_space -= sizeof e->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	e = kzalloc(sizeof *e, GFP_KERNEL);
+	if (e == NULL) {
+		spin_lock_irqsave(&dev->event_lock, flags);
+		file_priv->event_space += sizeof e->event;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+		goto out;
+	}
+
+	e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+	e->event.base.length = sizeof e->event;
+	e->event.user_data = user_data;
+	e->base.event = &e->event.base;
+	e->base.file_priv = file_priv;
+	e->base.destroy =
+		(void (*) (struct drm_pending_event *)) kfree;
+
+out:
+	return e;
+}
+
+static void destroy_vblank_event(struct drm_device *dev,
+		struct drm_file *file_priv, struct drm_pending_vblank_event *e)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	file_priv->event_space += sizeof e->event;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+	kfree(e);
+}
+
+/* Legacy version.. remove when all drivers converted to 'atomic' API */
+static int drm_mode_page_flip_ioctl_legacy(struct drm_device *dev,
 			     void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_crtc_page_flip *page_flip = data;
@@ -3968,7 +4015,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	struct drm_crtc *crtc;
 	struct drm_framebuffer *fb;
 	struct drm_pending_vblank_event *e = NULL;
-	unsigned long flags;
 	int hdisplay, vdisplay;
 	int ret = -EINVAL;
 
@@ -4017,43 +4063,90 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	}
 
 	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
-		ret = -ENOMEM;
-		spin_lock_irqsave(&dev->event_lock, flags);
-		if (file_priv->event_space < sizeof e->event) {
-			spin_unlock_irqrestore(&dev->event_lock, flags);
+		e = create_vblank_event(dev, file_priv, page_flip->user_data);
+		if (!e) {
+			ret = -ENOMEM;
 			goto out;
 		}
-		file_priv->event_space -= sizeof e->event;
-		spin_unlock_irqrestore(&dev->event_lock, flags);
+	}
 
-		e = kzalloc(sizeof *e, GFP_KERNEL);
-		if (e == NULL) {
-			spin_lock_irqsave(&dev->event_lock, flags);
-			file_priv->event_space += sizeof e->event;
-			spin_unlock_irqrestore(&dev->event_lock, flags);
-			goto out;
-		}
+	ret = crtc->funcs->page_flip(crtc, fb, e);
+	if (ret && e)
+		destroy_vblank_event(dev, file_priv, e);
+
+out:
+	mutex_unlock(&dev->mode_config.mutex);
+	return ret;
+}
+
+int drm_mode_page_flip_ioctl(struct drm_device *dev,
+			     void *data, struct drm_file *file_priv)
+{
+	struct drm_mode_crtc_page_flip *page_flip = data;
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_mode_object *obj;
+	struct drm_crtc *crtc;
+	struct drm_pending_vblank_event *e = NULL;
+	void *state;
+	int ret = -EINVAL;
+
+	if (!dev_supports_atomic(dev))
+		return drm_mode_page_flip_ioctl_legacy(dev, data, file_priv);
+
+	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
+	    page_flip->reserved != 0)
+		return -EINVAL;
 
-		e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
-		e->event.base.length = sizeof e->event;
-		e->event.user_data = page_flip->user_data;
-		e->base.event = &e->event.base;
-		e->base.file_priv = file_priv;
-		e->base.destroy =
-			(void (*) (struct drm_pending_event *)) kfree;
+	mutex_lock(&dev->mode_config.mutex);
+
+	obj = drm_mode_object_find(dev, page_flip->crtc_id,
+			DRM_MODE_OBJECT_CRTC);
+	if (!obj) {
+		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", page_flip->crtc_id);
+		ret = -ENOENT;
+		goto out_unlock;
 	}
+	crtc = obj_to_crtc(obj);
 
-	ret = crtc->funcs->page_flip(crtc, fb, e);
-	if (ret) {
-		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
-			spin_lock_irqsave(&dev->event_lock, flags);
-			file_priv->event_space += sizeof e->event;
-			spin_unlock_irqrestore(&dev->event_lock, flags);
-			kfree(e);
+	state = dev->driver->atomic_begin(dev, crtc);
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto out_unlock;
+	}
+
+	if (crtc->fb == NULL) {
+		/* The framebuffer is currently unbound, presumably
+		 * due to a hotplug event, that userspace has not
+		 * yet discovered.
+		 */
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+		e = create_vblank_event(dev, file_priv, page_flip->user_data);
+		if (!e) {
+			ret = -ENOMEM;
+			goto out;
 		}
 	}
 
+	ret = drm_mode_set_obj_prop(obj, state,
+			config->prop_fb_id, page_flip->fb_id);
+	if (ret)
+		goto out;
+
+	ret = dev->driver->atomic_check(dev, state);
+	if (ret)
+		goto out;
+
+	ret = dev->driver->atomic_commit(dev, state, e);
+	if (ret && e)
+		destroy_vblank_event(dev, file_priv, e);
+
 out:
+	dev->driver->atomic_end(dev, state);
+out_unlock:
 	mutex_unlock(&dev->mode_config.mutex);
 	return ret;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 09/11] drm: add drm_crtc_state
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (7 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 08/11] drm: convert page_flip to properties Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 10/11] drm: atomic pageflip Rob Clark
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

Start breaking out the mutable state of the CRTC into it's own
structure.  Plus add _check_state() and _set_property() helpers.
This only moves the state that is related to scanout fb, which
is needed for nuclear-pageflip.  The rest of the mutable state
should be moved from drm_crtc to drm_crtc_state as part of the
atomic-modeset implementation.
---
 drivers/gpu/drm/drm_crtc.c          |  112 ++++++++++++++++++++++++++++-------
 drivers/gpu/drm/drm_crtc_helper.c   |   51 ++++++++--------
 drivers/gpu/drm/drm_fb_helper.c     |   11 ++--
 drivers/staging/omapdrm/omap_crtc.c |   16 ++---
 drivers/staging/omapdrm/omap_fb.c   |   10 ++--
 include/drm/drm_crtc.h              |   49 +++++++++++----
 6 files changed, 173 insertions(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index bcdd6be..7337fd8 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -397,7 +397,7 @@ static void drm_framebuffer_remove_legacy(struct drm_framebuffer *fb)
 
 	/* remove from any CRTC */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (crtc->fb == fb) {
+		if (crtc->state->fb == fb) {
 			/* should turn off the crtc */
 			memset(&set, 0, sizeof(struct drm_mode_set));
 			set.crtc = crtc;
@@ -456,7 +456,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 
 	/* remove from any CRTC */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (crtc->fb == fb) {
+		if (crtc->state->fb == fb) {
 			/* should turn off the crtc */
 			drm_mode_crtc_set_obj_prop(crtc, state, config->prop_fb_id, 0);
 		}
@@ -506,16 +506,25 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 
 	crtc->dev = dev;
 	crtc->funcs = funcs;
-	crtc->invert_dimensions = false;
+	crtc->state->invert_dimensions = false;
 
 	mutex_lock(&dev->mode_config.mutex);
 
+	if (!dev_supports_atomic(dev)) {
+		crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+		if (!crtc->state) {
+			DRM_DEBUG_KMS("out of memory when allocating state\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
 	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
 	if (ret)
 		goto out;
 
 	crtc->base.properties = &crtc->properties;
-	crtc->base.propvals = &crtc->propvals;
+	crtc->base.propvals = &crtc->state->propvals;
 
 	list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
 	dev->mode_config.num_crtc++;
@@ -559,6 +568,67 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
+int drm_crtc_check_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	int hdisplay, vdisplay;
+
+	/* disabling the crtc is allowed: */
+	if (!fb)
+		return 0;
+
+	hdisplay = crtc->mode.hdisplay;
+	vdisplay = crtc->mode.vdisplay;
+
+	if (state->invert_dimensions)
+		swap(hdisplay, vdisplay);
+
+	if (hdisplay > fb->width ||
+	    vdisplay > fb->height ||
+	    state->x > fb->width - hdisplay ||
+	    state->y > fb->height - vdisplay) {
+		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
+			      fb->width, fb->height, hdisplay, vdisplay,
+			      state->x, state->y,
+			      state->invert_dimensions ? " (inverted)" : "");
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_crtc_check_state);
+
+void drm_crtc_commit_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	crtc->state = state;
+	crtc->base.propvals = &state->propvals;
+}
+EXPORT_SYMBOL(drm_crtc_commit_state);
+
+int drm_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_crtc_state *state,
+		struct drm_property *property, uint64_t value)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *config = &dev->mode_config;
+
+	if (property == config->prop_fb_id) {
+		struct drm_mode_object *obj = drm_property_get_obj(property, value);
+		state->fb = obj ? obj_to_fb(obj) : NULL;
+	} else if (property == config->prop_crtc_x) {
+		state->x = *(int *)&value;
+	} else if (property == config->prop_crtc_y) {
+		state->y = *(int32_t *)&value;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_crtc_set_property);
+
 /**
  * drm_mode_probed_add - add a mode to a connector's probed mode list
  * @connector: connector the new mode
@@ -1689,11 +1759,11 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	}
 	crtc = obj_to_crtc(obj);
 
-	crtc_resp->x = crtc->x;
-	crtc_resp->y = crtc->y;
+	crtc_resp->x = crtc->state->x;
+	crtc_resp->y = crtc->state->y;
 	crtc_resp->gamma_size = crtc->gamma_size;
-	if (crtc->fb)
-		crtc_resp->fb_id = crtc->fb->base.id;
+	if (crtc->state->fb)
+		crtc_resp->fb_id = crtc->state->fb->base.id;
 	else
 		crtc_resp->fb_id = 0;
 
@@ -2283,12 +2353,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 		/* If we have a mode we need a framebuffer. */
 		/* If we pass -1, set the mode with the currently bound fb */
 		if (crtc_req->fb_id == -1) {
-			if (!crtc->fb) {
+			if (!crtc->state->fb) {
 				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
 				ret = -EINVAL;
 				goto out;
 			}
-			fb = crtc->fb;
+			fb = crtc->state->fb;
 		} else {
 			obj = drm_mode_object_find(dev, crtc_req->fb_id,
 						   DRM_MODE_OBJECT_FB);
@@ -2318,7 +2388,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 		hdisplay = mode->hdisplay;
 		vdisplay = mode->vdisplay;
 
-		if (crtc->invert_dimensions)
+		if (crtc->state->invert_dimensions)
 			swap(hdisplay, vdisplay);
 
 		if (hdisplay > fb->width ||
@@ -2328,7 +2398,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 			DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
 				      fb->width, fb->height,
 				      hdisplay, vdisplay, crtc_req->x, crtc_req->y,
-				      crtc->invert_dimensions ? " (inverted)" : "");
+				      crtc->state->invert_dimensions ? " (inverted)" : "");
 			ret = -ENOSPC;
 			goto out;
 		}
@@ -3639,9 +3709,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
 
 	if (crtc->funcs->set_property)
 		ret = crtc->funcs->set_property(crtc, state, property, value);
-	if (!ret)
-		drm_object_property_set_value(&crtc->base, &crtc->propvals,
-				property, value);
 
 	return ret;
 }
@@ -4028,7 +4095,7 @@ static int drm_mode_page_flip_ioctl_legacy(struct drm_device *dev,
 		goto out;
 	crtc = obj_to_crtc(obj);
 
-	if (crtc->fb == NULL) {
+	if (crtc->state->fb == NULL) {
 		/* The framebuffer is currently unbound, presumably
 		 * due to a hotplug event, that userspace has not
 		 * yet discovered.
@@ -4048,16 +4115,17 @@ static int drm_mode_page_flip_ioctl_legacy(struct drm_device *dev,
 	hdisplay = crtc->mode.hdisplay;
 	vdisplay = crtc->mode.vdisplay;
 
-	if (crtc->invert_dimensions)
+	if (crtc->state->invert_dimensions)
 		swap(hdisplay, vdisplay);
 
 	if (hdisplay > fb->width ||
 	    vdisplay > fb->height ||
-	    crtc->x > fb->width - hdisplay ||
-	    crtc->y > fb->height - vdisplay) {
+	    crtc->state->x > fb->width - hdisplay ||
+	    crtc->state->y > fb->height - vdisplay) {
 		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
-			      fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
-			      crtc->invert_dimensions ? " (inverted)" : "");
+			      fb->width, fb->height, hdisplay, vdisplay,
+			      crtc->state->x, crtc->state->y,
+			      crtc->state->invert_dimensions ? " (inverted)" : "");
 		ret = -ENOSPC;
 		goto out;
 	}
@@ -4114,7 +4182,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 		goto out_unlock;
 	}
 
-	if (crtc->fb == NULL) {
+	if (crtc->state->fb == NULL) {
 		/* The framebuffer is currently unbound, presumably
 		 * due to a hotplug event, that userspace has not
 		 * yet discovered.
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 3252e70..65ed229 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -266,7 +266,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
 				(*crtc_funcs->disable)(crtc);
 			else
 				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
-			crtc->fb = NULL;
+			crtc->state->fb = NULL;
 		}
 	}
 }
@@ -363,15 +363,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 
 	saved_hwmode = crtc->hwmode;
 	saved_mode = crtc->mode;
-	saved_x = crtc->x;
-	saved_y = crtc->y;
+	saved_x = crtc->state->x;
+	saved_y = crtc->state->y;
 
 	/* Update crtc values up front so the driver can rely on them for mode
 	 * setting.
 	 */
 	crtc->mode = *mode;
-	crtc->x = x;
-	crtc->y = y;
+	crtc->state->x = x;
+	crtc->state->y = y;
 
 	/* Pass our mode to the connectors and the CRTC to give them a chance to
 	 * adjust it according to limitations or connector properties, and also
@@ -456,8 +456,8 @@ done:
 	if (!ret) {
 		crtc->hwmode = saved_hwmode;
 		crtc->mode = saved_mode;
-		crtc->x = saved_x;
-		crtc->y = saved_y;
+		crtc->state->x = saved_x;
+		crtc->state->y = saved_y;
 	}
 
 	return ret;
@@ -591,29 +591,29 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
 	save_set.crtc = set->crtc;
 	save_set.mode = &set->crtc->mode;
-	save_set.x = set->crtc->x;
-	save_set.y = set->crtc->y;
-	save_set.fb = set->crtc->fb;
+	save_set.x = set->crtc->state->x;
+	save_set.y = set->crtc->state->y;
+	save_set.fb = set->crtc->state->fb;
 
 	/* We should be able to check here if the fb has the same properties
 	 * and then just flip_or_move it */
-	if (set->crtc->fb != set->fb) {
+	if (set->crtc->state->fb != set->fb) {
 		/* If we have no fb then treat it as a full mode set */
-		if (set->crtc->fb == NULL) {
+		if (set->crtc->state->fb == NULL) {
 			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
 			mode_changed = true;
 		} else if (set->fb == NULL) {
 			mode_changed = true;
-		} else if (set->fb->depth != set->crtc->fb->depth) {
+		} else if (set->fb->depth != set->crtc->state->fb->depth) {
 			mode_changed = true;
 		} else if (set->fb->bits_per_pixel !=
-			   set->crtc->fb->bits_per_pixel) {
+			   set->crtc->state->fb->bits_per_pixel) {
 			mode_changed = true;
 		} else
 			fb_changed = true;
 	}
 
-	if (set->x != set->crtc->x || set->y != set->crtc->y)
+	if (set->x != set->crtc->state->x || set->y != set->crtc->state->y)
 		fb_changed = true;
 
 	if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
@@ -704,14 +704,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 			DRM_DEBUG_KMS("attempting to set mode from"
 					" userspace\n");
 			drm_mode_debug_printmodeline(set->mode);
-			old_fb = set->crtc->fb;
-			set->crtc->fb = set->fb;
+			old_fb = set->crtc->state->fb;
+			set->crtc->state->fb = set->fb;
 			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
 						      set->x, set->y,
 						      old_fb)) {
 				DRM_ERROR("failed to set mode on [CRTC:%d]\n",
 					  set->crtc->base.id);
-				set->crtc->fb = old_fb;
+				set->crtc->state->fb = old_fb;
 				ret = -EINVAL;
 				goto fail;
 			}
@@ -724,16 +724,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 		}
 		drm_helper_disable_unused_functions(dev);
 	} else if (fb_changed) {
-		set->crtc->x = set->x;
-		set->crtc->y = set->y;
+		set->crtc->state->x = set->x;
+		set->crtc->state->y = set->y;
 
-		old_fb = set->crtc->fb;
-		if (set->crtc->fb != set->fb)
-			set->crtc->fb = set->fb;
+		old_fb = set->crtc->state->fb;
+		if (set->crtc->state->fb != set->fb)
+			set->crtc->state->fb = set->fb;
 		ret = crtc_funcs->mode_set_base(set->crtc,
 						set->x, set->y, old_fb);
 		if (ret != 0) {
-			set->crtc->fb = old_fb;
+			set->crtc->state->fb = old_fb;
 			goto fail;
 		}
 	}
@@ -888,7 +888,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
 			continue;
 
 		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
-					       crtc->x, crtc->y, crtc->fb);
+					       crtc->state->x, crtc->state->y,
+					       crtc->state->fb);
 
 		if (ret == false)
 			DRM_ERROR("failed to set mode on crtc %p\n", crtc);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 80bdb59..725ae08 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -185,7 +185,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
 
 	list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
 		if (crtc->base.id == c->base.id)
-			return c->fb;
+			return c->state->fb;
 	}
 
 	return NULL;
@@ -214,8 +214,9 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 		}
 
 		drm_fb_helper_restore_lut_atomic(mode_set->crtc);
-		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
-					    crtc->y, LEAVE_ATOMIC_MODE_SET);
+		funcs->mode_set_base_atomic(mode_set->crtc, fb,
+				crtc->state->x, crtc->state->y,
+				LEAVE_ATOMIC_MODE_SET);
 	}
 
 	return 0;
@@ -1356,9 +1357,9 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 
 	mutex_lock(&dev->mode_config.mutex);
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (crtc->fb)
+		if (crtc->state->fb)
 			crtcs_bound++;
-		if (crtc->fb == fb_helper->fb)
+		if (crtc->state->fb == fb_helper->fb)
 			bound++;
 	}
 
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index 1236d21..b903c63 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -206,7 +206,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
 		}
 	}
 
-	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
+	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->state->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16,
@@ -234,7 +234,7 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 	struct drm_plane *plane = omap_crtc->plane;
 	struct drm_display_mode *mode = &crtc->mode;
 
-	return omap_plane_mode_set(plane, crtc, crtc->fb,
+	return omap_plane_mode_set(plane, crtc, crtc->state->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
 			x << 16, y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16,
@@ -274,14 +274,14 @@ static void page_flip_worker(struct work_struct *work)
 	struct drm_gem_object *bo;
 
 	mutex_lock(&dev->mode_config.mutex);
-	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
+	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->state->fb,
 			0, 0, mode->hdisplay, mode->vdisplay,
-			crtc->x << 16, crtc->y << 16,
+			crtc->state->x << 16, crtc->state->y << 16,
 			mode->hdisplay << 16, mode->vdisplay << 16,
 			vblank_cb, crtc);
 	mutex_unlock(&dev->mode_config.mutex);
 
-	bo = omap_framebuffer_bo(crtc->fb, 0);
+	bo = omap_framebuffer_bo(crtc->state->fb, 0);
 	drm_gem_object_unreference_unlocked(bo);
 }
 
@@ -303,7 +303,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct drm_gem_object *bo;
 
-	DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1,
+	DBG("%d -> %d (event=%p)", crtc->state->fb ? crtc->state->fb->base.id : -1,
 			fb->base.id, event);
 
 	if (omap_crtc->old_fb) {
@@ -312,7 +312,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 	}
 
 	omap_crtc->event = event;
-	crtc->fb = fb;
+	crtc->state->fb = fb;
 
 	/*
 	 * Hold a reference temporarily until the crtc is updated
@@ -334,7 +334,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
 	struct omap_drm_private *priv = crtc->dev->dev_private;
 
 	if (property == priv->rotation_prop) {
-		crtc->invert_dimensions =
+		crtc->state->invert_dimensions =
 				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
 	}
 
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 7fe0345..66c11f9 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -316,7 +316,7 @@ struct drm_connector *omap_framebuffer_get_next_connector(
 		if (connector != from) {
 			struct drm_encoder *encoder = connector->encoder;
 			struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
-			if (crtc && crtc->fb == fb) {
+			if (crtc && crtc->state->fb == fb) {
 				return connector;
 			}
 		}
@@ -342,10 +342,10 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb,
 			 * could do the coordinate translation..
 			 */
 			struct drm_crtc *crtc = connector->encoder->crtc;
-			int cx = max(0, x - crtc->x);
-			int cy = max(0, y - crtc->y);
-			int cw = w + (x - crtc->x) - cx;
-			int ch = h + (y - crtc->y) - cy;
+			int cx = max(0, x - crtc->state->x);
+			int cy = max(0, y - crtc->state->y);
+			int cw = w + (x - crtc->state->x) - cx;
+			int ch = h + (y - crtc->state->y) - cy;
 
 			omap_connector_flush(connector, cx, cy, cw, ch);
 		}
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index ef558dd..f445135 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -375,18 +375,43 @@ struct drm_crtc_funcs {
 };
 
 /**
+ * drm_crtc_state - mutable crtc state
+ * @fb: the framebuffer that the CRTC is currently bound to
+ * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
+ *    invert the width/height of the crtc.  This is used if the driver
+ *    is performing 90 or 270 degree rotated scanout
+ * @x: x position on screen
+ * @y: y position on screen
+ * @propvals: property values
+ */
+struct drm_crtc_state {
+	/*
+	 * NOTE: more should move from 'struct drm_crtc' into here as
+	 * part of the atomic-modeset support:
+	 *   + enabled
+	 *   + mode
+	 *   + hwmode
+	 *   + framedur_ns
+	 *   + linedur_ns
+	 *   + pixeldur_ns
+	 *
+	 * For now, I'm just moving what is needed for atomic-pageflip
+	 */
+	struct drm_framebuffer *fb;
+	bool invert_dimensions;
+	int x, y;
+	struct drm_object_property_values propvals;
+};
+
+/**
  * drm_crtc - central CRTC control structure
  * @dev: parent DRM device
  * @head: list management
  * @base: base KMS object for ID tracking etc.
+ * @state: the mutable state
  * @enabled: is this CRTC enabled?
  * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
- * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
- *    invert the width/height of the crtc.  This is used if the driver
- *    is performing 90 or 270 degree rotated scanout
- * @x: x position on screen
- * @y: y position on screen
  * @funcs: CRTC control functions
  * @gamma_size: size of gamma ramp
  * @gamma_store: gamma ramp values
@@ -405,8 +430,7 @@ struct drm_crtc {
 
 	struct drm_mode_object base;
 
-	/* framebuffer the connector is currently bound to */
-	struct drm_framebuffer *fb;
+	struct drm_crtc_state *state;
 
 	bool enabled;
 
@@ -418,9 +442,6 @@ struct drm_crtc {
 	 */
 	struct drm_display_mode hwmode;
 
-	bool invert_dimensions;
-
-	int x, y;
 	const struct drm_crtc_funcs *funcs;
 
 	/* CRTC gamma size for reporting to userspace */
@@ -434,7 +455,6 @@ struct drm_crtc {
 	void *helper_private;
 
 	struct drm_object_properties properties;
-	struct drm_object_property_values propvals;
 };
 
 
@@ -902,6 +922,13 @@ extern int drm_crtc_init(struct drm_device *dev,
 			 struct drm_crtc *crtc,
 			 const struct drm_crtc_funcs *funcs);
 extern void drm_crtc_cleanup(struct drm_crtc *crtc);
+extern int drm_crtc_check_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state);
+extern void drm_crtc_commit_state(struct drm_crtc *crtc,
+		struct drm_crtc_state *state);
+extern int drm_crtc_set_property(struct drm_crtc *crtc,
+		struct drm_crtc_state *state,
+		struct drm_property *property, uint64_t value);
 
 extern int drm_connector_init(struct drm_device *dev,
 			      struct drm_connector *connector,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 10/11] drm: atomic pageflip
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (8 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 09/11] drm: add drm_crtc_state Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:49 ` [RFC 11/11] drm/omap: update for atomic age Rob Clark
  2012-10-13  0:58 ` [RFC 00/11] atomic pageflip v3 Rob Clark
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

---
 drivers/gpu/drm/drm_crtc.c |   75 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_drv.c  |    1 +
 include/drm/drm.h          |    2 ++
 include/drm/drm_crtc.h     |    2 ++
 include/drm/drm_mode.h     |   38 ++++++++++++++++++++++
 5 files changed, 118 insertions(+)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 7337fd8..baca5ba 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -4219,6 +4219,81 @@ out_unlock:
 	return ret;
 }
 
+int drm_mode_atomic_page_flip_ioctl(struct drm_device *dev,
+			     void *data, struct drm_file *file_priv)
+{
+	struct drm_mode_crtc_atomic_page_flip *page_flip = data;
+	struct drm_mode_obj_set_property __user *props =
+			(struct drm_mode_obj_set_property __user *)
+			(unsigned long)page_flip->props_ptr;
+	struct drm_pending_vblank_event *e = NULL;
+	struct drm_mode_object *obj;
+	void *state;
+	int i, ret;
+
+	if (page_flip->flags & ~DRM_MODE_ATOMIC_PAGE_FLIP_FLAGS ||
+	    page_flip->reserved != 0)
+		return -EINVAL;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
+			!dev_supports_atomic(dev))
+		return -EINVAL;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	obj = drm_mode_object_find(dev, page_flip->crtc_id,
+			DRM_MODE_OBJECT_CRTC);
+	if (!obj) {
+		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", page_flip->crtc_id);
+		ret = -ENOENT;
+		goto out_unlock;
+	}
+
+	state = dev->driver->atomic_begin(dev, obj_to_crtc(obj));
+	if (IS_ERR(state)) {
+		ret = PTR_ERR(state);
+		goto out_unlock;
+	}
+
+	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+		e = create_vblank_event(dev, file_priv, page_flip->user_data);
+		if (!e) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
+	for (i = 0; i < page_flip->count_props; i++) {
+		struct drm_mode_obj_set_property prop;
+		if (copy_from_user(&prop, &props[i], sizeof(prop))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		ret = drm_mode_set_obj_prop_id(dev, state,
+				prop.obj_id, prop.obj_type,
+				prop.prop_id, prop.value);
+		if (ret)
+			goto out;
+	}
+
+	ret = dev->driver->atomic_check(dev, state);
+	if (ret)
+		goto out;
+
+	if (!(page_flip->flags & DRM_MODE_TEST_ONLY))
+		ret = dev->driver->atomic_commit(dev, state, e);
+
+	if (ret && e)
+		destroy_vblank_event(dev, file_priv, e);
+
+out:
+	dev->driver->atomic_end(dev, state);
+out_unlock:
+	mutex_unlock(&dev->mode_config.mutex);
+	return ret;
+}
+
 void drm_mode_config_reset(struct drm_device *dev)
 {
 	struct drm_crtc *crtc;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 52717ef2..b7bb78a 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -166,6 +166,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC_PAGE_FLIP, drm_mode_atomic_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 };
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
diff --git a/include/drm/drm.h b/include/drm/drm.h
index e51035a..0908741 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -732,6 +732,8 @@ struct drm_prime_handle {
 #define DRM_IOCTL_MODE_ADDFB2		DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
 #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES	DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
 #define DRM_IOCTL_MODE_OBJ_SETPROPERTY	DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
+/* placeholder for DRM_IOCTL_ATOMIC_MODE_SET */
+#define DRM_IOCTL_MODE_ATOMIC_PAGE_FLIP	DRM_IOWR(0xBC, struct drm_mode_crtc_atomic_page_flip)
 
 /**
  * Device specific ioctls should only be in their respective headers
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index f445135..47c043f 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -1129,6 +1129,8 @@ extern bool drm_detect_hdmi_monitor(struct edid *edid);
 extern bool drm_detect_monitor_audio(struct edid *edid);
 extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
 				    void *data, struct drm_file *file_priv);
+extern int drm_mode_atomic_page_flip_ioctl(struct drm_device *dev,
+			     void *data, struct drm_file *file_priv);
 extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
 				int hdisplay, int vdisplay, int vrefresh,
 				bool reduced, bool interlaced, bool margins);
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index f9232e4..7da6741 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -411,7 +411,10 @@ struct drm_mode_crtc_lut {
 };
 
 #define DRM_MODE_PAGE_FLIP_EVENT 0x01
+#define DRM_MODE_TEST_ONLY       0x02
 #define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT
+#define DRM_MODE_ATOMIC_PAGE_FLIP_FLAGS \
+	(DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_TEST_ONLY)
 
 /*
  * Request a page flip on the specified crtc.
@@ -443,6 +446,41 @@ struct drm_mode_crtc_page_flip {
 	__u64 user_data;
 };
 
+/*
+ * Request a page flip on the crtc specified by 'crtc_id' plus zero or
+ * more planes attached to this crtc.
+ *
+ * This ioctl will ask KMS to schedule a page flip for the specified
+ * crtc.  Once any pending rendering targeting the specified fb(s) (as
+ * of ioctl time) has completed, the crtc and zero or more planes will
+ * be reprogrammed to display the new fb(s) after the next vertical
+ * refresh.  The ioctl returns immediately, but subsequent rendering
+ * to the current fb will block in the execbuffer ioctl until the page
+ * flip happens.  If a page flip is already pending as the ioctl is
+ * called, EBUSY will be returned.
+ *
+ * The ioctl supports the following flags:
+ *  + DRM_MODE_PAGE_FLIP_EVENT, which will request that drm sends back
+ *    a vblank event (see drm.h: struct drm_event_vblank) when the page
+ *    flip is done.  The user_data field passed in with this ioctl will
+ *    be returned as the user_data field in the vblank event struct.
+ *  + DRM_MODE_TEST_ONLY, don't actually apply the changes (or generate
+ *    a vblank event) but just test the configuration to see if it is
+ *    possible.
+ *
+ * The reserved field must be zero until we figure out something clever
+ * to use it for.
+ */
+
+struct drm_mode_crtc_atomic_page_flip {
+	uint32_t crtc_id;
+	uint32_t flags;
+	uint64_t user_data;
+	uint32_t reserved;
+	uint32_t count_props;
+	uint64_t props_ptr;  /* ptr to array of drm_mode_obj_set_property */
+};
+
 /* create a dumb scanout buffer */
 struct drm_mode_create_dumb {
 	uint32_t height;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC 11/11] drm/omap: update for atomic age
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (9 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 10/11] drm: atomic pageflip Rob Clark
@ 2012-10-13  0:49 ` Rob Clark
  2012-10-13  0:58 ` [RFC 00/11] atomic pageflip v3 Rob Clark
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:49 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

From: Rob Clark <rob@ti.com>

---
 drivers/staging/omapdrm/Makefile      |    1 +
 drivers/staging/omapdrm/omap_atomic.c |  347 +++++++++++++++++++++++++++++++++
 drivers/staging/omapdrm/omap_atomic.h |   52 +++++
 drivers/staging/omapdrm/omap_crtc.c   |  231 +++++++++++-----------
 drivers/staging/omapdrm/omap_drv.c    |   27 ++-
 drivers/staging/omapdrm/omap_drv.h    |   43 ++--
 drivers/staging/omapdrm/omap_fb.c     |   34 ++--
 drivers/staging/omapdrm/omap_plane.c  |  291 ++++++++++++++-------------
 8 files changed, 737 insertions(+), 289 deletions(-)
 create mode 100644 drivers/staging/omapdrm/omap_atomic.c
 create mode 100644 drivers/staging/omapdrm/omap_atomic.h

diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile
index d85e058..7d45e4d 100644
--- a/drivers/staging/omapdrm/Makefile
+++ b/drivers/staging/omapdrm/Makefile
@@ -13,6 +13,7 @@ omapdrm-y := omap_drv.o \
 	omap_connector.o \
 	omap_fb.o \
 	omap_fbdev.o \
+	omap_atomic.o \
 	omap_gem.o \
 	omap_gem_dmabuf.o \
 	omap_dmm_tiler.o \
diff --git a/drivers/staging/omapdrm/omap_atomic.c b/drivers/staging/omapdrm/omap_atomic.c
new file mode 100644
index 0000000..fbf03f1
--- /dev/null
+++ b/drivers/staging/omapdrm/omap_atomic.c
@@ -0,0 +1,347 @@
+/*
+ * drivers/staging/omapdrm/omap_atomic.c
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Rob Clark <rob.clark@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "omap_drv.h"
+#include "omap_atomic.h"
+
+struct omap_atomic_state {
+	struct drm_device *dev;
+
+	/* for page-flips, this is the CRTC involved: */
+	struct drm_crtc *crtc;
+	int pipe;
+
+	int num_dirty_planes, num_dirty_crtcs;
+	struct omap_plane_state *plane_state[8];
+	struct omap_crtc_state  *crtc_state[8];
+
+	int num_pending_fbs;
+	atomic_t num_ready_fbs;
+	struct drm_framebuffer  *pending_fbs[8];
+
+	/* for handling page flips without caring about what
+	 * the callback is called from.  Possibly we should just
+	 * make omap_gem always call the cb from the worker so
+	 * we don't have to care about this..
+	 */
+	struct work_struct commit_work;
+};
+
+static void commit_worker(struct work_struct *work);
+
+static int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc)
+{
+	struct omap_drm_private *priv = dev->dev_private;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++)
+		if (priv->crtcs[i] == crtc)
+			return i;
+
+	BUG();  /* bogus CRTC ptr */
+	return -1;
+}
+
+static void set_atomic(struct omap_atomic_state *omap_state, bool atomic)
+{
+	struct omap_drm_private *priv = omap_state->dev->dev_private;
+	if (omap_state->crtc) {
+		int pipe = omap_state->pipe;
+		priv->crtc_atomic[pipe] = atomic;
+	} else {
+		priv->global_atomic = atomic;
+	}
+}
+
+void *omap_atomic_begin(struct drm_device *dev, struct drm_crtc *crtc)
+{
+	struct omap_drm_private *priv = dev->dev_private;
+	struct omap_atomic_state *omap_state;
+	int pipe = 0;
+
+	if (crtc) {
+		pipe = crtc2pipe(dev, crtc);
+		if (priv->event[pipe]) {
+			dev_err(dev->dev, "pending page-flip!\n");
+			return ERR_PTR(-EBUSY);
+		}
+		WARN_ON(priv->crtc_atomic[pipe]);
+	} else {
+		WARN_ON(priv->global_atomic);
+	}
+
+	omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
+	if (!omap_state) {
+		dev_err(dev->dev, "failed to allocate state\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	omap_state->dev = dev;
+	omap_state->crtc = crtc;
+	omap_state->pipe = pipe;
+
+	INIT_WORK(&omap_state->commit_work, commit_worker);
+
+	set_atomic(omap_state, true);
+
+	DBG("state=%p, crtc=%p", omap_state, crtc);
+
+	return omap_state;
+}
+
+static void release_state(struct omap_atomic_state *omap_state)
+{
+	int i;
+
+	DBG("state=%p", omap_state);
+
+	for (i = 0; i < omap_state->num_pending_fbs; i++)
+		drm_framebuffer_unreference(omap_state->pending_fbs[i]);
+
+	/*
+	 * omap_plane_commit()/omap_crtc_commit() have taken ownership
+	 * of their respective state objects, so don't need to kfree()
+	 * 'em here
+	 */
+
+	kfree(omap_state);
+}
+
+int omap_atomic_check(struct drm_device *dev, void *state)
+{
+	struct omap_atomic_state *omap_state = state;
+	struct omap_drm_private *priv = dev->dev_private;
+	int i, ret = 0;
+
+	for (i = 0; (i < ARRAY_SIZE(omap_state->plane_state)) && !ret; i++)
+		if (omap_state->plane_state[i])
+			ret = omap_plane_check_state(priv->planes[i],
+					omap_state->plane_state[i]);
+
+	for (i = 0; (i < ARRAY_SIZE(omap_state->crtc_state)) && !ret; i++)
+		if (omap_state->crtc_state[i])
+			ret = omap_crtc_check_state(priv->crtcs[i],
+					omap_state->crtc_state[i]);
+
+	DBG("state=%p, ret=%d", omap_state, ret);
+
+	if (ret) {
+		set_atomic(omap_state, false);
+		release_state(omap_state);
+	}
+
+	return ret;
+}
+
+static void commit_state(struct omap_atomic_state *omap_state)
+{
+	struct drm_device *dev = omap_state->dev;
+	struct omap_drm_private *priv = dev->dev_private;
+	int i;
+
+	DBG("state=%p", omap_state);
+
+	for (i = 0; i < ARRAY_SIZE(omap_state->plane_state); i++) {
+		struct omap_plane_state *plane_state =
+				omap_state->plane_state[i];
+		if (plane_state)
+			omap_plane_commit_state(priv->planes[i], plane_state);
+	}
+
+	set_atomic(omap_state, false);
+
+	for (i = 0; i < ARRAY_SIZE(omap_state->crtc_state); i++) {
+		struct omap_crtc_state *crtc_state =
+				omap_state->crtc_state[i];
+		if (crtc_state)
+			omap_crtc_commit_state(priv->crtcs[i], crtc_state);
+	}
+
+	release_state(omap_state);
+}
+
+static void commit_worker(struct work_struct *work)
+{
+	struct omap_atomic_state *omap_state =
+			container_of(work, struct omap_atomic_state, commit_work);
+	struct drm_device *dev = omap_state->dev;
+
+	mutex_lock(&dev->mode_config.mutex);
+	DBG("state=%p", omap_state);
+	commit_state(omap_state);
+	mutex_unlock(&dev->mode_config.mutex);
+}
+
+static void commit_cb(void *state)
+{
+	struct omap_atomic_state *omap_state = state;
+	struct omap_drm_private *priv = omap_state->dev->dev_private;
+	int num_ready_fbs = atomic_inc_return(&omap_state->num_ready_fbs);
+
+	if (num_ready_fbs == omap_state->num_pending_fbs)
+		queue_work(priv->wq, &omap_state->commit_work);
+}
+
+static void commit_async(struct drm_device *dev, void *state,
+		struct drm_pending_vblank_event *event)
+{
+	struct omap_atomic_state *omap_state = state;
+	struct omap_drm_private *priv = omap_state->dev->dev_private;
+	int i;
+
+	if (event) {
+		int pipe = omap_state->pipe;
+		WARN_ON(priv->event[pipe]);
+		priv->event[pipe] = event;
+	}
+
+	if (!omap_state->num_pending_fbs) {
+		commit_state(omap_state);
+		return;
+	}
+
+	for (i = 0; i < omap_state->num_pending_fbs; i++) {
+		struct drm_gem_object *bo;
+		bo = omap_framebuffer_bo(omap_state->pending_fbs[i], 0);
+		omap_gem_op_async(bo, OMAP_GEM_READ, commit_cb, omap_state);
+	}
+}
+
+int omap_atomic_commit(struct drm_device *dev, void *state,
+		struct drm_pending_vblank_event *event)
+{
+	struct omap_atomic_state *omap_state = state;
+
+	DBG("state=%p, event=%p", omap_state, event);
+
+	if (omap_state->crtc) {
+		/* async page-flip */
+		commit_async(dev, state, event);
+	} else {
+		/* sync mode-set, etc */
+		WARN_ON(event);  /* this should not happen */
+		commit_state(omap_state);
+	}
+
+	return 0;
+}
+
+void omap_atomic_end(struct drm_device *dev, void *state)
+{
+	/*
+	 * State is freed either if atomic_check() fails or
+	 * when async pageflip completes, so we don't need
+	 * to do anything here.
+	 */
+}
+
+struct omap_plane_state *omap_atomic_plane_state(void *state, int id)
+{
+	struct omap_atomic_state *omap_state = state;
+	struct omap_drm_private *priv = omap_state->dev->dev_private;
+	struct omap_plane_state *plane_state = omap_state->plane_state[id];
+	int i;
+
+	if (!plane_state) {
+		struct drm_plane *plane = priv->planes[id];
+
+		plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+
+		/* snapshot current state: */
+		*plane_state = *to_omap_plane_state(plane->state);
+
+		omap_state->plane_state[id] = plane_state;
+	}
+
+	/* updating a plane implicitly dirties the crtc: */
+	for (i = 0; i < priv->num_crtcs; i++) {
+		if (priv->crtcs[i] == plane_state->base.crtc) {
+			omap_atomic_crtc_state(state, i);
+			break;
+		}
+	}
+
+	return plane_state;
+}
+
+struct omap_crtc_state *omap_atomic_crtc_state(void *state, int id)
+{
+	struct omap_atomic_state *omap_state = state;
+	struct omap_drm_private *priv = omap_state->dev->dev_private;
+	struct omap_crtc_state *crtc_state = omap_state->crtc_state[id];
+
+	if (!crtc_state) {
+		struct drm_crtc *crtc = priv->crtcs[id];
+
+		crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
+
+		/* snapshot current state: */
+		*crtc_state = *to_omap_crtc_state(crtc->state);
+
+		omap_state->crtc_state[id] = crtc_state;
+	}
+
+	return crtc_state;
+}
+
+/* when fb is changed, that gets recorded in the state, so that pageflips
+ * can defer until all fb's are ready
+ */
+void omap_atomic_add_fb(void *state, struct drm_framebuffer *fb)
+{
+	struct omap_atomic_state *omap_state = state;
+	drm_framebuffer_reference(fb);
+	omap_state->pending_fbs[omap_state->num_pending_fbs++] = fb;
+}
+
+/* possibly this could be in drm core? */
+static void send_page_flip_event(struct drm_device *dev, int crtc,
+		struct drm_pending_vblank_event *event)
+{
+	unsigned long flags;
+	struct timeval now;
+
+	DBG("%p", event);
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	event->event.sequence = drm_vblank_count_and_time(dev, crtc, &now);
+	event->event.tv_sec = now.tv_sec;
+	event->event.tv_usec = now.tv_usec;
+	list_add_tail(&event->base.link,
+			&event->base.file_priv->event_list);
+	wake_up_interruptible(&event->base.file_priv->event_wait);
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+/* called when plane is updated.. so we can keep track of when to send
+ * page-flip events
+ */
+void omap_atomic_plane_update(struct drm_device *dev, int id)
+{
+	struct omap_drm_private *priv = dev->dev_private;
+	int pipe = crtc2pipe(dev, priv->planes[id]->state->crtc);
+
+	DBG("id=%d", id);
+
+	if (priv->event[pipe]) {
+		/* wakeup userspace */
+		send_page_flip_event(dev, pipe, priv->event[pipe]);
+		priv->event[pipe] = NULL;
+	}
+}
diff --git a/drivers/staging/omapdrm/omap_atomic.h b/drivers/staging/omapdrm/omap_atomic.h
new file mode 100644
index 0000000..6ba596a
--- /dev/null
+++ b/drivers/staging/omapdrm/omap_atomic.h
@@ -0,0 +1,52 @@
+/*
+ * drivers/staging/omapdrm/omap_atomic.h
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Rob Clark <rob.clark@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP_ATOMIC_H__
+#define __OMAP_ATOMIC_H__
+
+#include "drm_mode.h"
+#include "drm_crtc.h"
+
+struct omap_plane_state {
+	struct drm_plane_state base;
+	uint8_t rotation;
+	uint8_t zorder;
+	uint8_t enabled;
+};
+#define to_omap_plane_state(x) container_of(x, struct omap_plane_state, base)
+
+struct omap_crtc_state {
+	struct drm_crtc_state base;
+};
+#define to_omap_crtc_state(x) container_of(x, struct omap_crtc_state, base)
+
+void *omap_atomic_begin(struct drm_device *dev, struct drm_crtc *crtc);
+int omap_atomic_check(struct drm_device *dev, void *state);
+int omap_atomic_commit(struct drm_device *dev, void *state,
+		struct drm_pending_vblank_event *event);
+void omap_atomic_end(struct drm_device *dev, void *state);
+
+struct omap_plane_state *omap_atomic_plane_state(void *state, int id);
+struct omap_crtc_state *omap_atomic_crtc_state(void *state, int id);
+
+void omap_atomic_add_fb(void *state, struct drm_framebuffer *fb);
+
+void omap_atomic_plane_update(struct drm_device *dev, int id);
+
+#endif /* __OMAP_ATOMIC_H__ */
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index b903c63..f9af31e 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -32,7 +32,6 @@ struct omap_crtc {
 	const char *name;
 	int pipe;
 	enum omap_channel channel;
-	struct omap_overlay_manager_info info;
 
 	struct dss_lcd_mgr_config lcd_config;
 
@@ -50,21 +49,10 @@ struct omap_crtc {
 	/* list of queued apply's: */
 	struct list_head queued_applies;
 
+	bool in_apply;       /* for debug */
+
 	/* for handling queued and in-progress applies: */
 	struct work_struct apply_work;
-
-	/* if there is a pending flip, these will be non-null: */
-	struct drm_pending_vblank_event *event;
-	struct drm_framebuffer *old_fb;
-
-	/* for handling page flips without caring about what
-	 * the callback is called from.  Possibly we should just
-	 * make omap_gem always call the cb from the worker so
-	 * we don't have to care about this..
-	 *
-	 * XXX maybe fold into apply_work??
-	 */
-	struct work_struct page_flip_work;
 };
 
 /*
@@ -132,6 +120,9 @@ static const struct dss_mgr_ops mgr_ops = {
  * CRTC funcs:
  */
 
+static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+		struct drm_framebuffer *old_fb);
+
 static void omap_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -146,6 +137,7 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
 
 	channel2crtc[omap_crtc->channel] = NULL;
 
+	kfree(crtc->state);
 	kfree(omap_crtc);
 }
 
@@ -206,11 +198,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
 		}
 	}
 
-	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->state->fb,
-			0, 0, mode->hdisplay, mode->vdisplay,
-			x << 16, y << 16,
-			mode->hdisplay << 16, mode->vdisplay << 16,
-			NULL, NULL);
+	return omap_crtc_mode_set_base(crtc, x, y, old_fb);
 }
 
 static void omap_crtc_prepare(struct drm_crtc *crtc)
@@ -232,99 +220,61 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct drm_plane *plane = omap_crtc->plane;
-	struct drm_display_mode *mode = &crtc->mode;
-
-	return omap_plane_mode_set(plane, crtc, crtc->state->fb,
-			0, 0, mode->hdisplay, mode->vdisplay,
-			x << 16, y << 16,
-			mode->hdisplay << 16, mode->vdisplay << 16,
-			NULL, NULL);
-}
-
-static void omap_crtc_load_lut(struct drm_crtc *crtc)
-{
-}
-
-static void vblank_cb(void *arg)
-{
-	struct drm_crtc *crtc = arg;
-	struct drm_device *dev = crtc->dev;
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-
-	/* wakeup userspace */
-	if (omap_crtc->event)
-		drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
-
-	omap_crtc->event = NULL;
-	omap_crtc->old_fb = NULL;
-
-	spin_unlock_irqrestore(&dev->event_lock, flags);
-}
-
-static void page_flip_worker(struct work_struct *work)
-{
-	struct omap_crtc *omap_crtc =
-			container_of(work, struct omap_crtc, page_flip_work);
-	struct drm_crtc *crtc = &omap_crtc->base;
 	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_display_mode *mode = &crtc->mode;
-	struct drm_gem_object *bo;
+	void *state;
+	int w, h, ret;
 
-	mutex_lock(&dev->mode_config.mutex);
-	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->state->fb,
-			0, 0, mode->hdisplay, mode->vdisplay,
-			crtc->state->x << 16, crtc->state->y << 16,
-			mode->hdisplay << 16, mode->vdisplay << 16,
-			vblank_cb, crtc);
-	mutex_unlock(&dev->mode_config.mutex);
+	if (WARN_ON(!crtc->state->fb))
+		return -EINVAL;
 
-	bo = omap_framebuffer_bo(crtc->state->fb, 0);
-	drm_gem_object_unreference_unlocked(bo);
-}
+	w = mode->hdisplay;
+	h = mode->vdisplay;
 
-static void page_flip_cb(void *arg)
-{
-	struct drm_crtc *crtc = arg;
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	struct omap_drm_private *priv = crtc->dev->dev_private;
+	if (crtc->state->invert_dimensions) {
+		swap(w, h);
+		swap(x, y);
+	}
 
-	/* avoid assumptions about what ctxt we are called from: */
-	queue_work(priv->wq, &omap_crtc->page_flip_work);
+	/* for now, until property based atomic mode-set: */
+	state = omap_atomic_begin(dev, NULL);
+	if (IS_ERR(state))
+		return PTR_ERR(state);
+
+	ret =
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_crtc_id, crtc->base.id) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_fb_id, crtc->state->fb->base.id) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_crtc_x, 0) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_crtc_y, 0) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_crtc_w, mode->hdisplay) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_crtc_h, mode->vdisplay) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_src_w, w << 16) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_src_h, h << 16) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_src_x, x << 16) ||
+		drm_mode_plane_set_obj_prop(plane, state,
+				config->prop_src_y, y << 16) ||
+		dev->driver->atomic_check(dev, state);
+
+	if (!ret)
+		ret = omap_atomic_commit(dev, state, NULL);
+
+	omap_atomic_end(dev, state);
+
+	return ret;
 }
 
-static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
-		 struct drm_framebuffer *fb,
-		 struct drm_pending_vblank_event *event)
+static void omap_crtc_load_lut(struct drm_crtc *crtc)
 {
-	struct drm_device *dev = crtc->dev;
-	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-	struct drm_gem_object *bo;
-
-	DBG("%d -> %d (event=%p)", crtc->state->fb ? crtc->state->fb->base.id : -1,
-			fb->base.id, event);
-
-	if (omap_crtc->old_fb) {
-		dev_err(dev->dev, "already a pending flip\n");
-		return -EINVAL;
-	}
-
-	omap_crtc->event = event;
-	crtc->state->fb = fb;
-
-	/*
-	 * Hold a reference temporarily until the crtc is updated
-	 * and takes the reference to the bo.  This avoids it
-	 * getting freed from under us:
-	 */
-	bo = omap_framebuffer_bo(fb, 0);
-	drm_gem_object_reference(bo);
-
-	omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
-
-	return 0;
 }
 
 static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
@@ -332,9 +282,23 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
 {
 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 	struct omap_drm_private *priv = crtc->dev->dev_private;
+	struct omap_crtc_state *crtc_state =
+			omap_atomic_crtc_state(state, omap_crtc->pipe);
+	int ret;
+
+	DBG("%s: %s = %llx", omap_crtc->name, property->name, val);
+
+	ret = drm_crtc_set_property(crtc, &crtc_state->base, property, val);
+	if (!ret) {
+		/* we need to set fb property on our private plane too:
+		 */
+		struct drm_mode_config *config = &crtc->dev->mode_config;
+		if (property != config->prop_fb_id)
+			return ret;
+	}
 
 	if (property == priv->rotation_prop) {
-		crtc->state->invert_dimensions =
+		crtc_state->base.invert_dimensions =
 				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
 	}
 
@@ -344,7 +308,6 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
 static const struct drm_crtc_funcs omap_crtc_funcs = {
 	.set_config = drm_crtc_helper_set_config,
 	.destroy = omap_crtc_destroy,
-	.page_flip = omap_crtc_page_flip_locked,
 	.set_property = omap_crtc_set_property,
 };
 
@@ -370,6 +333,24 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
 	return omap_crtc->channel;
 }
 
+int omap_crtc_check_state(struct drm_crtc *crtc,
+		struct omap_crtc_state *crtc_state)
+{
+	return drm_crtc_check_state(crtc, &crtc_state->base);
+}
+
+void omap_crtc_commit_state(struct drm_crtc *crtc,
+		struct omap_crtc_state *crtc_state)
+{
+
+	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+	struct omap_crtc_state *old_state = to_omap_crtc_state(crtc->state);
+	DBG("%s", omap_crtc->name);
+	drm_crtc_commit_state(crtc, &crtc_state->base);
+	kfree(old_state);
+	omap_crtc_apply(crtc, &omap_crtc->apply);
+}
+
 static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
 {
 	struct omap_crtc *omap_crtc =
@@ -407,6 +388,7 @@ static void apply_worker(struct work_struct *work)
 	 * with respect to modesetting ioctls from userspace.
 	 */
 	mutex_lock(&dev->mode_config.mutex);
+	omap_crtc->in_apply = true;
 	dispc_runtime_get();
 
 	/*
@@ -423,6 +405,9 @@ static void apply_worker(struct work_struct *work)
 		list_del(&apply->pending_node);
 	}
 
+	if (pipe_in_atomic(dev, omap_crtc->pipe))
+		goto out;
+
 	need_apply = !list_empty(&omap_crtc->queued_applies);
 
 	/* then handle the next round of of queued apply's: */
@@ -449,6 +434,7 @@ static void apply_worker(struct work_struct *work)
 
 out:
 	dispc_runtime_put();
+	omap_crtc->in_apply = false;
 	mutex_unlock(&dev->mode_config.mutex);
 }
 
@@ -459,13 +445,17 @@ int omap_crtc_apply(struct drm_crtc *crtc,
 	struct drm_device *dev = crtc->dev;
 
 	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+	WARN_ON(omap_crtc->in_apply);
 
 	/* no need to queue it again if it is already queued: */
-	if (apply->queued)
-		return 0;
+	if (! apply->queued) {
+		apply->queued = true;
+		list_add_tail(&apply->queued_node,
+				&omap_crtc->queued_applies);
+	}
 
-	apply->queued = true;
-	list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
+	if (pipe_in_atomic(dev, omap_crtc->pipe))
+		return 0;
 
 	/*
 	 * If there are no currently pending updates, then go ahead and
@@ -539,6 +529,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
 	struct omap_crtc *omap_crtc =
 			container_of(apply, struct omap_crtc, apply);
 	enum omap_channel channel = omap_crtc->channel;
+	struct omap_overlay_manager_info info = {0};
 
 	DBG("%s: enabled=%d, timings_valid=%d", omap_crtc->name,
 			omap_crtc->enabled,
@@ -549,9 +540,14 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
 		return;
 	}
 
+	info.default_color = 0x00000000;
+	info.trans_key = 0x00000000;
+	info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+	info.trans_enabled = false;
+
 	if (dss_mgr_is_lcd(channel))
 		dispc_mgr_set_lcd_config(channel, &omap_crtc->lcd_config);
-	dispc_mgr_setup(channel, &omap_crtc->info);
+	dispc_mgr_setup(channel, &info);
 	dispc_mgr_set_timings(channel, &omap_crtc->timings);
 	set_enabled(&omap_crtc->base, true);
 }
@@ -573,7 +569,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 {
 	struct drm_crtc *crtc = NULL;
 	struct omap_crtc *omap_crtc;
-	struct omap_overlay_manager_info *info;
 
 	DBG("%s", channel_names[channel]);
 
@@ -586,7 +581,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
 	crtc = &omap_crtc->base;
 
-	INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker);
+	crtc->state = kzalloc(sizeof(struct omap_crtc_state), GFP_KERNEL);
+
+	if (!crtc->state) {
+		dev_err(dev->dev, "could not allocate CRTC state\n");
+		goto fail;
+	}
+
 	INIT_WORK(&omap_crtc->apply_work, apply_worker);
 
 	INIT_LIST_HEAD(&omap_crtc->pending_applies);
@@ -612,12 +613,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 	channel2crtc[omap_crtc->channel] = crtc;
 	dss_install_mgr_ops(&mgr_ops);
 
-	/* TODO: fix hard-coded setup.. add properties! */
-	info->default_color = 0x00000000;
-	info->trans_key = 0x00000000;
-	info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
-	info->trans_enabled = false;
-
 	drm_crtc_init(dev, crtc, &omap_crtc_funcs);
 	drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 7321510..0b180b7 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -18,6 +18,7 @@
  */
 
 #include "omap_drv.h"
+#include "omap_atomic.h"
 
 #include "drm_crtc_helper.h"
 #include "drm_fb_helper.h"
@@ -510,6 +511,7 @@ static int dev_firstopen(struct drm_device *dev)
  */
 static void dev_lastclose(struct drm_device *dev)
 {
+	void *state;
 	int i;
 
 	/* we don't support vga-switcheroo.. so just make sure the fbdev
@@ -525,11 +527,16 @@ static void dev_lastclose(struct drm_device *dev)
 	 * a flag that properties should automatically be restored to
 	 * default state on lastclose?
 	 */
+	state = dev->driver->atomic_begin(dev, NULL);
 	for (i = 0; i < priv->num_planes; i++) {
 		struct drm_plane *plane = priv->planes[i];
-		drm_object_property_set_value(&plane->base,
-				&plane->state->propvals, priv->rotation_prop, 0);
+		drm_mode_plane_set_obj_prop(plane, state,
+				priv->rotation_prop, 0);
 	}
+	/* disabling rotation won't ever fail: */
+	dev->driver->atomic_check(dev, state);
+	dev->driver->atomic_commit(dev, state, NULL);
+	dev->driver->atomic_end(dev, state);
 
 	mutex_lock(&dev->mode_config.mutex);
 	ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev);
@@ -540,7 +547,19 @@ static void dev_lastclose(struct drm_device *dev)
 
 static void dev_preclose(struct drm_device *dev, struct drm_file *file)
 {
+	struct omap_drm_private *priv = dev->dev_private;
+	int i;
+
 	DBG("preclose: dev=%p", dev);
+
+	/*
+	 * Clear out pending events before they get destroyed in
+	 * drm_events_release(), so that if we later get a vblank
+	 * we don't deref a bogus ptr
+	 */
+	for (i = 0; i < ARRAY_SIZE(priv->event); i++)
+		if (priv->event[i] && priv->event[i]->base.file_priv == file)
+			priv->event[i] = NULL;
 }
 
 static void dev_postclose(struct drm_device *dev, struct drm_file *file)
@@ -597,6 +616,10 @@ static struct drm_driver omap_drm_driver = {
 		.dumb_create = omap_gem_dumb_create,
 		.dumb_map_offset = omap_gem_dumb_map_offset,
 		.dumb_destroy = omap_gem_dumb_destroy,
+		.atomic_begin = omap_atomic_begin,
+		.atomic_check = omap_atomic_check,
+		.atomic_commit = omap_atomic_commit,
+		.atomic_end = omap_atomic_end,
 		.ioctls = ioctls,
 		.num_ioctls = DRM_OMAP_NUM_IOCTLS,
 		.fops = &omapdriver_fops,
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index c20ed7e..131f0a8 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -27,6 +27,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <linux/platform_data/omap_drm.h>
 #include "omap_drm.h"
+#include "omap_atomic.h"
 
 /* APIs we need from dispc.. TODO omapdss should export these */
 #include "../../video/omap2/dss/dss.h"
@@ -47,15 +48,6 @@ void hdmi_dump_regs(struct seq_file *s);
  */
 #define MAX_MAPPERS 2
 
-/* parameters which describe (unrotated) coordinates of scanout within a fb: */
-struct omap_drm_window {
-	uint32_t rotation;
-	int32_t  crtc_x, crtc_y;		/* signed because can be offscreen */
-	uint32_t crtc_w, crtc_h;
-	uint32_t src_x, src_y;
-	uint32_t src_w, src_h;
-};
-
 /* Once GO bit is set, we can't make further updates to shadowed registers
  * until the GO bit is cleared.  So various parts in the kms code that need
  * to update shadowed registers queue up a pair of callbacks, pre_apply
@@ -119,9 +111,16 @@ struct omap_drm_private {
 	struct drm_property *zorder_prop;
 
 	/* irq handling: */
-	struct list_head irq_list;    /* list of omap_drm_irq */
+	struct list_head irq_list;   /* list of omap_drm_irq */
 	uint32_t vblank_mask;         /* irq bits set for userspace vblank */
 	struct omap_drm_irq error_handler;
+
+	/* atomic: */
+	bool global_atomic;           /* in global atomic update (ie. modeset) */
+	bool crtc_atomic[8];          /* in per-crtc atomic update (ie. pageflip) */
+
+	/* pending vblank event per CRTC: */
+	struct drm_pending_vblank_event *event[8];
 };
 
 /* this should probably be in drm-core to standardize amongst drivers */
@@ -154,6 +153,10 @@ void omap_fbdev_free(struct drm_device *dev);
 
 const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
 enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
+int omap_crtc_check_state(struct drm_crtc *crtc,
+		struct omap_crtc_state *crtc_state);
+void omap_crtc_commit_state(struct drm_crtc *crtc,
+		struct omap_crtc_state *crtc_state);
 int omap_crtc_apply(struct drm_crtc *crtc,
 		struct omap_drm_apply *apply);
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
@@ -162,17 +165,14 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 struct drm_plane *omap_plane_init(struct drm_device *dev,
 		int plane_id, bool private_plane);
 int omap_plane_dpms(struct drm_plane *plane, int mode);
-int omap_plane_mode_set(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		int crtc_x, int crtc_y,
-		unsigned int crtc_w, unsigned int crtc_h,
-		uint32_t src_x, uint32_t src_y,
-		uint32_t src_w, uint32_t src_h,
-		void (*fxn)(void *), void *arg);
 void omap_plane_install_properties(struct drm_plane *plane,
 		struct drm_mode_object *obj);
 int omap_plane_set_property(struct drm_plane *plane, void *state,
 		struct drm_property *property, uint64_t val);
+int omap_plane_check_state(struct drm_plane *plane,
+		struct omap_plane_state *plane_state);
+void omap_plane_commit_state(struct drm_plane *plane,
+		struct omap_plane_state *plane_state);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev);
 struct drm_encoder *omap_connector_attached_encoder(
@@ -198,7 +198,7 @@ int omap_framebuffer_replace(struct drm_framebuffer *a,
 		struct drm_framebuffer *b, void *arg,
 		void (*unpin)(void *arg, struct drm_gem_object *bo));
 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
-		struct omap_drm_window *win, struct omap_overlay_info *info);
+		struct drm_plane_state *state, struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
 		struct drm_framebuffer *fb, struct drm_connector *from);
 void omap_framebuffer_flush(struct drm_framebuffer *fb,
@@ -284,6 +284,13 @@ static inline uint32_t pipe2vbl(int crtc)
 	return dispc_mgr_get_vsync_irq(channel);
 }
 
+/* is the specified pipe/crtc blocked for atomic update? */
+static inline bool pipe_in_atomic(struct drm_device *dev, int pipe)
+{
+	struct omap_drm_private *priv = dev->dev_private;
+	return priv->global_atomic || priv->crtc_atomic[pipe];
+}
+
 /* should these be made into common util helpers?
  */
 
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 66c11f9..3d6350d 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -154,33 +154,34 @@ static uint32_t get_linear_addr(struct plane *plane,
 /* update ovl info for scanout, handles cases of multi-planar fb's, etc.
  */
 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
-		struct omap_drm_window *win, struct omap_overlay_info *info)
+		struct drm_plane_state *state, struct omap_overlay_info *info)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
+	struct omap_plane_state *plane_state = to_omap_plane_state(state);
 	const struct format *format = omap_fb->format;
 	struct plane *plane = &omap_fb->planes[0];
 	uint32_t x, y, orient = 0;
 
 	info->color_mode = format->dss_format;
 
-	info->pos_x      = win->crtc_x;
-	info->pos_y      = win->crtc_y;
-	info->out_width  = win->crtc_w;
-	info->out_height = win->crtc_h;
-	info->width      = win->src_w;
-	info->height     = win->src_h;
+	info->pos_x      = state->crtc_x;
+	info->pos_y      = state->crtc_y;
+	info->out_width  = state->crtc_w;
+	info->out_height = state->crtc_h;
+	info->width      = state->src_w >> 16;
+	info->height     = state->src_h >> 16;
 
-	x = win->src_x;
-	y = win->src_y;
+	x = state->src_x >> 16;
+	y = state->src_y >> 16;
 
 	if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) {
-		uint32_t w = win->src_w;
-		uint32_t h = win->src_h;
+		uint32_t w = state->src_w >> 16;
+		uint32_t h = state->src_h >> 16;
 
-		switch (win->rotation & 0xf) {
+		switch (plane_state->rotation & 0xf) {
 		default:
 			dev_err(fb->dev->dev, "invalid rotation: %02x",
-					(uint32_t)win->rotation);
+					plane_state->rotation);
 			/* fallthru to default to no rotation */
 		case 0:
 		case BIT(DRM_ROTATE_0):
@@ -197,10 +198,10 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
 			break;
 		}
 
-		if (win->rotation & BIT(DRM_REFLECT_X))
+		if (plane_state->rotation & BIT(DRM_REFLECT_X))
 			orient ^= MASK_X_INVERT;
 
-		if (win->rotation & BIT(DRM_REFLECT_Y))
+		if (plane_state->rotation & BIT(DRM_REFLECT_Y))
 			orient ^= MASK_Y_INVERT;
 
 		/* adjust x,y offset for flip/invert: */
@@ -220,6 +221,9 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
 		info->screen_width  = plane->pitch;
 	}
 
+	/* always do the rotation in tiler (or none at all): */
+	info->rotation = OMAP_DSS_ROT_0;
+
 	/* convert to pixels: */
 	info->screen_width /= format->planes[0].stride_bpp;
 
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c
index cb5d427..6881532 100644
--- a/drivers/staging/omapdrm/omap_plane.c
+++ b/drivers/staging/omapdrm/omap_plane.c
@@ -32,24 +32,14 @@
  * plane funcs
  */
 
-struct callback {
-	void (*fxn)(void *);
-	void *arg;
-};
-
 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
 
 struct omap_plane {
 	struct drm_plane base;
 	int id;  /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
 	const char *name;
-	struct omap_overlay_info info;
 	struct omap_drm_apply apply;
 
-	/* position/orientation of scanout within the fb: */
-	struct omap_drm_window win;
-	bool enabled;
-
 	/* last fb that we pinned: */
 	struct drm_framebuffer *pinned_fb;
 
@@ -60,9 +50,6 @@ struct omap_plane {
 
 	/* set of bo's pending unpin until next post_apply() */
 	DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *);
-
-	// XXX maybe get rid of this and handle vblank in crtc too?
-	struct callback apply_done_cb;
 };
 
 static void unpin(void *arg, struct drm_gem_object *bo)
@@ -114,24 +101,53 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
 	return 0;
 }
 
+static inline bool is_enabled(struct drm_plane_state *state)
+{
+	return to_omap_plane_state(state)->enabled &&
+			state->crtc && state->fb;
+}
+
+/* TODO get rid of this and convert dispc code to use drm state
+ * structs directly..
+ */
+static void state2info(struct omap_plane_state *plane_state,
+		struct omap_overlay_info *info)
+{
+
+	memset(info, 0, sizeof(*info));
+
+	info->global_alpha = 0xff;
+	/* TODO: we should calculate valid zorder from all the planes: */
+	info->zorder = plane_state->zorder;
+
+	/* update scanout: */
+	omap_framebuffer_update_scanout(plane_state->base.fb,
+			&plane_state->base, info);
+
+	DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
+			info->out_width, info->out_height, info->screen_width);
+	DBG("%d,%d %08x %08x", info->pos_x, info->pos_y,
+			info->paddr, info->p_uv_addr);
+}
+
 static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 {
 	struct omap_plane *omap_plane =
 			container_of(apply, struct omap_plane, apply);
-	struct omap_drm_window *win = &omap_plane->win;
 	struct drm_plane *plane = &omap_plane->base;
 	struct drm_device *dev = plane->dev;
-	struct omap_overlay_info *info = &omap_plane->info;
+	struct omap_overlay_info info;
 	struct drm_crtc *crtc = plane->state->crtc;
+	struct drm_framebuffer *fb = plane->state->fb;
 	enum omap_channel channel;
-	bool enabled = omap_plane->enabled && crtc;
-	bool ilace, replication;
+	bool enabled = is_enabled(plane->state);
+	bool replication;
 	int ret;
 
 	DBG("%s, enabled=%d", omap_plane->name, enabled);
 
 	/* if fb has changed, pin new fb: */
-	update_pin(plane, enabled ? plane->state->fb : NULL);
+	update_pin(plane, enabled ? fb : NULL);
 
 	if (!enabled) {
 		dispc_ovl_enable(omap_plane->id, false);
@@ -140,21 +156,14 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 
 	channel = omap_crtc_channel(crtc);
 
-	/* update scanout: */
-	omap_framebuffer_update_scanout(plane->state->fb, win, info);
-
-	DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
-			info->out_width, info->out_height,
-			info->screen_width);
-	DBG("%d,%d %08x %08x", info->pos_x, info->pos_y,
-			info->paddr, info->p_uv_addr);
+	state2info(to_omap_plane_state(plane->state), &info);
 
 	/* TODO: */
-	ilace = false;
 	replication = false;
 
 	/* and finally, update omapdss: */
-	ret = dispc_ovl_setup(omap_plane->id, info,
+	dispc_ovl_set_channel_out(omap_plane->id, channel);
+	ret = dispc_ovl_setup(omap_plane->id, &info,
 			replication, omap_crtc_timings(crtc), false);
 	if (ret) {
 		dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
@@ -162,7 +171,6 @@ static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 	}
 
 	dispc_ovl_enable(omap_plane->id, true);
-	dispc_ovl_set_channel_out(omap_plane->id, channel);
 }
 
 static void omap_plane_post_apply(struct omap_drm_apply *apply)
@@ -170,94 +178,21 @@ static void omap_plane_post_apply(struct omap_drm_apply *apply)
 	struct omap_plane *omap_plane =
 			container_of(apply, struct omap_plane, apply);
 	struct drm_plane *plane = &omap_plane->base;
-	struct omap_overlay_info *info = &omap_plane->info;
 	struct drm_gem_object *bo = NULL;
-	struct callback cb;
-
-	cb = omap_plane->apply_done_cb;
-	omap_plane->apply_done_cb.fxn = NULL;
 
 	while (kfifo_get(&omap_plane->unpin_fifo, &bo)) {
 		omap_gem_put_paddr(bo);
 		drm_gem_object_unreference_unlocked(bo);
 	}
 
-	if (cb.fxn)
-		cb.fxn(cb.arg);
-
-	if (omap_plane->enabled) {
-		omap_framebuffer_flush(plane->state->fb, info->pos_x, info->pos_y,
-				info->out_width, info->out_height);
-	}
-}
-
-static int apply(struct drm_plane *plane)
-{
-	if (plane->state->crtc) {
-		struct omap_plane *omap_plane = to_omap_plane(plane);
-		return omap_crtc_apply(plane->state->crtc, &omap_plane->apply);
-	}
-	return 0;
-}
-
-int omap_plane_mode_set(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		int crtc_x, int crtc_y,
-		unsigned int crtc_w, unsigned int crtc_h,
-		uint32_t src_x, uint32_t src_y,
-		uint32_t src_w, uint32_t src_h,
-		void (*fxn)(void *), void *arg)
-{
-	struct omap_plane *omap_plane = to_omap_plane(plane);
-	struct omap_drm_window *win = &omap_plane->win;
-
-	win->crtc_x = crtc_x;
-	win->crtc_y = crtc_y;
-	win->crtc_w = crtc_w;
-	win->crtc_h = crtc_h;
-
-	/* src values are in Q16 fixed point, convert to integer: */
-	win->src_x = src_x >> 16;
-	win->src_y = src_y >> 16;
-	win->src_w = src_w >> 16;
-	win->src_h = src_h >> 16;
-
-	if (fxn) {
-		/* omap_crtc should ensure that a new page flip
-		 * isn't permitted while there is one pending:
-		 */
-		BUG_ON(omap_plane->apply_done_cb.fxn);
+	omap_atomic_plane_update(plane->dev, omap_plane->id);
 
-		omap_plane->apply_done_cb.fxn = fxn;
-		omap_plane->apply_done_cb.arg = arg;
+	if (is_enabled(plane->state)) {
+		struct drm_plane_state *state = plane->state;
+		omap_framebuffer_flush(plane->state->fb,
+				state->crtc_x, state->crtc_y,
+				state->crtc_w, state->crtc_h);
 	}
-
-	plane->state->fb = fb;
-	plane->state->crtc = crtc;
-
-	return apply(plane);
-}
-
-static int omap_plane_update(struct drm_plane *plane,
-		struct drm_crtc *crtc, struct drm_framebuffer *fb,
-		int crtc_x, int crtc_y,
-		unsigned int crtc_w, unsigned int crtc_h,
-		uint32_t src_x, uint32_t src_y,
-		uint32_t src_w, uint32_t src_h)
-{
-	struct omap_plane *omap_plane = to_omap_plane(plane);
-	omap_plane->enabled = true;
-	return omap_plane_mode_set(plane, crtc, fb,
-			crtc_x, crtc_y, crtc_w, crtc_h,
-			src_x, src_y, src_w, src_h,
-			NULL, NULL);
-}
-
-static int omap_plane_disable(struct drm_plane *plane)
-{
-	struct omap_plane *omap_plane = to_omap_plane(plane);
-	omap_plane->win.rotation = BIT(DRM_ROTATE_0);
-	return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
 }
 
 static void omap_plane_destroy(struct drm_plane *plane)
@@ -268,24 +203,29 @@ static void omap_plane_destroy(struct drm_plane *plane)
 
 	omap_irq_unregister(plane->dev, &omap_plane->error_irq);
 
-	omap_plane_disable(plane);
+	omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
 	drm_plane_cleanup(plane);
 
 	WARN_ON(!kfifo_is_empty(&omap_plane->unpin_fifo));
 	kfifo_free(&omap_plane->unpin_fifo);
 
+	kfree(plane->state);
 	kfree(omap_plane);
 }
 
 int omap_plane_dpms(struct drm_plane *plane, int mode)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct drm_plane_state *state = plane->state;
 	bool enabled = (mode == DRM_MODE_DPMS_ON);
 	int ret = 0;
 
-	if (enabled != omap_plane->enabled) {
-		omap_plane->enabled = enabled;
-		ret = apply(plane);
+	DBG("%s: mode=%d", omap_plane->name, mode);
+
+	if (enabled != is_enabled(state)) {
+		to_omap_plane_state(state)->enabled = enabled;
+		if (state->crtc)
+			ret = omap_crtc_apply(state->crtc, &omap_plane->apply);
 	}
 
 	return ret;
@@ -332,24 +272,106 @@ int omap_plane_set_property(struct drm_plane *plane, void *state,
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct omap_drm_private *priv = plane->dev->dev_private;
-	int ret = -EINVAL;
+	struct omap_plane_state *plane_state =
+			omap_atomic_plane_state(state, omap_plane->id);
+	int ret;
+
+	DBG("%s: %s = %llx", omap_plane->name, property->name, val);
+
+	ret = drm_plane_set_property(plane, &plane_state->base, property, val);
+	if (!ret) {
+		/* if this property is handled by base, we are nearly done..
+		 * we just need to register an fb property w/ atomic so that
+		 * commit can be deferred until the fb is ready
+		 */
+		struct drm_mode_config *config = &plane->dev->mode_config;
+		if ((property == config->prop_fb_id) && val) {
+			struct drm_mode_object *obj =
+					drm_property_get_obj(property, val);
+			omap_atomic_add_fb(state, obj_to_fb(obj));
+		}
+		return ret;
+	}
+
+	/* if it is not a base plane property, see if it is one of ours: */
 
 	if (property == priv->rotation_prop) {
 		DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
-		omap_plane->win.rotation = val;
-		ret = apply(plane);
+		plane_state->rotation = val;
 	} else if (property == priv->zorder_prop) {
 		DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
-		omap_plane->info.zorder = val;
-		ret = apply(plane);
+		plane_state->zorder = val;
+	} else {
+		return -EINVAL;
 	}
 
-	return ret;
+	return 0;
+}
+
+int omap_plane_check_state(struct drm_plane *plane,
+		struct omap_plane_state *plane_state)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct drm_crtc *crtc = plane_state->base.crtc;
+	struct omap_overlay_info info;
+	int ret, x_predecim = 0, y_predecim = 0;
+
+	if (!is_enabled(&plane_state->base))
+		return 0;
+
+	ret = drm_plane_check_state(plane, &plane_state->base);
+	if (ret)
+		return ret;
+
+	state2info(plane_state, &info);
+
+	ret = dispc_ovl_check(omap_plane->id,
+			omap_crtc_channel(crtc),
+			&info, omap_crtc_timings(crtc),
+			&x_predecim, &y_predecim);
+	if (ret) {
+		DBG("%s: dispc_ovl_check failed: %d", omap_plane->name, ret);
+		return ret;
+	}
+
+	/* TODO add some properties to set max pre-decimation.. but
+	 * until then, we'd rather fallback to GPU than decimate:
+	 */
+	if ((x_predecim > 1) || (y_predecim > 1)) {
+		DBG("%s: x_predecim=%d, y_predecim=%d", omap_plane->name,
+				x_predecim, y_predecim);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void omap_plane_commit_state(struct drm_plane *plane,
+		struct omap_plane_state *plane_state)
+{
+	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_plane_state *old_state = to_omap_plane_state(plane->state);
+	struct drm_crtc *crtc;
+
+	DBG("%s", omap_plane->name);
+
+	crtc = plane_state->base.crtc;
+
+	/* TODO we need to handle crtc switch.. we should reject that
+	 * at the check() stage if we are still waiting for GO to clear
+	 * on the outgoing crtc..
+	 */
+	if (!crtc)
+		crtc = plane->state->crtc;
+
+	drm_plane_commit_state(plane, &plane_state->base);
+	kfree(old_state);
+
+	if (crtc)
+		omap_crtc_apply(crtc, &omap_plane->apply);
 }
 
 static const struct drm_plane_funcs omap_plane_funcs = {
-		.update_plane = omap_plane_update,
-		.disable_plane = omap_plane_disable,
 		.destroy = omap_plane_destroy,
 		.set_property = omap_plane_set_property,
 };
@@ -382,7 +404,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 	struct omap_drm_private *priv = dev->dev_private;
 	struct drm_plane *plane = NULL;
 	struct omap_plane *omap_plane;
-	struct omap_overlay_info *info;
 	int ret;
 
 	DBG("%s: priv=%d", plane_names[id], private_plane);
@@ -407,6 +428,13 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 
 	plane = &omap_plane->base;
 
+	plane->state = kzalloc(sizeof(struct omap_plane_state), GFP_KERNEL);
+
+	if (!plane->state) {
+		dev_err(dev->dev, "could not allocate CRTC state\n");
+		goto fail;
+	}
+
 	omap_plane->apply.pre_apply  = omap_plane_pre_apply;
 	omap_plane->apply.post_apply = omap_plane_post_apply;
 
@@ -419,24 +447,15 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 
 	omap_plane_install_properties(plane, &plane->base);
 
-	/* get our starting configuration, set defaults for parameters
-	 * we don't currently use, etc:
-	 */
-	info = &omap_plane->info;
-	info->rotation_type = OMAP_DSS_ROT_DMA;
-	info->rotation = OMAP_DSS_ROT_0;
-	info->global_alpha = 0xff;
-	info->mirror = 0;
-
 	/* Set defaults depending on whether we are a CRTC or overlay
 	 * layer.
-	 * TODO add ioctl to give userspace an API to change this.. this
-	 * will come in a subsequent patch.
 	 */
-	if (private_plane)
-		omap_plane->info.zorder = 0;
-	else
-		omap_plane->info.zorder = id;
+	if (!private_plane) {
+		struct omap_plane_state *plane_state =
+				to_omap_plane_state(plane->state);
+		plane_state->zorder = id;
+		plane_state->enabled = true;
+	}
 
 	return plane;
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [RFC 00/11] atomic pageflip v3
  2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
                   ` (10 preceding siblings ...)
  2012-10-13  0:49 ` [RFC 11/11] drm/omap: update for atomic age Rob Clark
@ 2012-10-13  0:58 ` Rob Clark
  11 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-10-13  0:58 UTC (permalink / raw)
  To: dri-devel; +Cc: patches, daniel.vetter, Rob Clark

On Fri, Oct 12, 2012 at 7:49 PM, Rob Clark <rob.clark@linaro.org> wrote:
> From: Rob Clark <rob@ti.com>
>
> This is following a bit the approach that Ville is taking for atomic-
> modeset, in that it is switching over to using properties for everything.
> The advantage of this approach is that it makes it easier to add new
> attributes to set as part of a page-flip (and even opens the option to
> add new object types).
>
> The basic principles are:
>  a) split out object state (in this case, plane and crtc, although I
>     expect more to be added as atomic-modeset is added) into separate
>     structures that can be atomically committed or rolled back.  The
>     property values array is also split out into the state structs,
>     so that the property values visible to userspace automatically
>     reflect the current state (ie. property changes are either
>     committed or discarded depending on whether the state changes
>     are committed or discarded).
>  b) expand the object property API (set_property()) to take a state
>     object.  The obj->set_property() simply updates the state object
>     without actually applying the changes to the hw.
>  c) after all the property updates are done, the updated state can
>     be checked for correctness and against the hw capabilities, and
>     then either discarded or committed atomically.
>
> Since we need to include properties in the atomic-pageflip scheme,
> doing everything via properties avoids updating a bunch of additional
> driver provided callbacks.
>
> For drivers that have been atomic-ified, they no longer need to
> implement .page_flip(), .set_plane(), .disable_plane().  Instead they
> should implement the atomic fxns, and their various .set_property()
> functions would not actually touch the hw, but instead update state
> objects.  State objects should hold all the state which could
> potentially be applied to the hw.  The .set_property() functions
> should not actually update the hw, because it might be the users
> intention to only test a new configuration.
>
> In drm_crtc / drm_plane, the userspace visible attributes are split
> out into separate drm_crtc_state / drm_plane_state structs.  (Note
> that this is only partially done for crtc, only the page-flip related
> attributes are split out.  I wanted to do this first, and then add the
> modeset related attributes in a later patch to split things up into
> smaller pieces.)  The intention is that drivers can wrap the state
> structs, and add whatever other information they need.  For example:
>
>     struct omap_plane_state {
>            struct drm_plane_state base;
>            uint8_t rotation;
>            uint8_t zorder;
>            uint8_t enabled;
>     };
>
> It doesn't strictly need to be just property values.  If driver needs
> to calculate some clock settings, fifo thresholds, or other internal
> state, based the external state set from userspace, it could stuff
> that stuff into it's state structs as well if it wanted.  But at a
> minimum the state objects should encapsulate the userspace visible
> state.
>
> For atomic-ified drivers, all updates, whether it be userspace
> setproperty ioctl updating a single property, or legacy setplane or
> pageflip ioctls, or new atomic ioctl(s), all go through the same path
> from the driver's perspective:
>
>     state = dev->atomic_begin();
>     for (... one or more ...)
>        obj->set_property(obj, state, prop, value);
>     if (dev->atomic_check(state))
>        dev->atomic_commit(state, event);
>     dev->atomic_end(state);
>
> The global driver state token/object returned from .atomic_begin() is
> opaque from drm core perspective.  It somehow encapsulates the state
> of all crtc/plane/etc.  Inside the driver's different .set_property()
> fxns, this global state object gets mapped to per crtc/plane state
> objects.  Core drm helpers for dealing with common attributes (fb_id,
> crtc_x/y/w/h, etc) are provided.  (ie. drm_plane_set_property(),
> drm_plane_check_state(), etc.)   This is to avoid forcing each driver
> to duplicate code for setting common properties and sanity checking.
>
> After all the property updates have been passed to the driver via
> .set_property() calls, .atomic_check() is called.  This should check
> all the modified crtc/plane's (using drm_{plane,crtc}_check_state()
> for common check), and do any needed global sanity checks for the hw
> (ie. can this combination of planes meet hw bandwidth limitations,
> etc).
>
> For ioctls with a 'test' flag, the .atomic_commit() step might be
> skipped if userspace is only testing the new configuration.  In either
> case, .atomic_commit() is only called if .atomic_check() succeeds, so
> at this point it is already known that the new configuration is
> "good", so .atomic_commit() should really only fail for catastrophic
> things (unable to allocate memory, hardware is on fire, etc).
>
> The .atomic_end() is called at the end if the driver needs to do some
> cleanup.
>
> ------
>
> The intention is for this to also simplify atomic-modeset, by
> providing some of the necessary infrastructure (object property types,
> signed property values, and property's whose usespace visible values
> automatically tracks the object state which is either committed or
> discarded depending on whether the state change was committed to hw
> or not) which will also be needed for atomic-modeset.
>
> So far, I've only updated omapdrm to the new APIs, as a proof of
> concept.  Only a few drivers support drm plane, so I expect the
> updates to convert drm-plane to properties should not be so hard.
> Possibly for crtc/pageflip we might need to have a transition period
> where we still support crtc->page_flip() code path until all drivers
> are updated.
>
> My complete branch is here:
>
>   https://github.com/robclark/kernel-omap4/commits/drm_nuclear-2
>   git://github.com/robclark/kernel-omap4.git drm_nuclear-2
>
> v1: original RFC
> v2: I don't remember
> v3: don't remove .page_flip(), .update_plane(), etc.  These are still
>     used for drivers that don't implement the atomic functions, to
>     allow for a transition period
>
> Note that I haven't changed the format of the atomic-pageflip ioctl
> itself since the last patchset.  At this point I'm more interested in
> feedback on the first nine patches.
>

Note, for the next version of this series, I was planning to update
all the other drivers to compile again, so update for new property fxn
prototypes, and crtc->fb to crtc->state->fb, etc.  But that will touch
a lot of code.  So if anyone has some major KMS changes in progress in
their driver that I should base on top of to minimize conflicts later,
let me know.

BR,
-R


> Rob Clark (11):
>   drm: add atomic fxns
>   drm: add object property type
>   drm: add DRM_MODE_PROP_DYNAMIC property flag
>   drm: add DRM_MODE_PROP_SIGNED property flag
>   drm: split property values out
>   drm: convert plane to properties
>   drm: add drm_plane_state
>   drm: convert page_flip to properties
>   drm: add drm_crtc_state
>   drm: atomic pageflip
>   drm/omap: update for atomic age
>
>  drivers/gpu/drm/drm_crtc.c            |  916 ++++++++++++++++++++++++++++-----
>  drivers/gpu/drm/drm_crtc_helper.c     |   51 +-
>  drivers/gpu/drm/drm_drv.c             |    1 +
>  drivers/gpu/drm/drm_fb_helper.c       |   12 +-
>  drivers/staging/omapdrm/Makefile      |    1 +
>  drivers/staging/omapdrm/omap_atomic.c |  347 +++++++++++++
>  drivers/staging/omapdrm/omap_atomic.h |   52 ++
>  drivers/staging/omapdrm/omap_crtc.c   |  237 +++++----
>  drivers/staging/omapdrm/omap_drv.c    |   26 +-
>  drivers/staging/omapdrm/omap_drv.h    |   45 +-
>  drivers/staging/omapdrm/omap_fb.c     |   44 +-
>  drivers/staging/omapdrm/omap_plane.c  |  295 ++++++-----
>  include/drm/drm.h                     |    2 +
>  include/drm/drmP.h                    |   52 ++
>  include/drm/drm_crtc.h                |  161 +++++-
>  include/drm/drm_mode.h                |   50 ++
>  16 files changed, 1818 insertions(+), 474 deletions(-)
>  create mode 100644 drivers/staging/omapdrm/omap_atomic.c
>  create mode 100644 drivers/staging/omapdrm/omap_atomic.h
>
> --
> 1.7.9.5
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [RFC 03/11] drm: add DRM_MODE_PROP_DYNAMIC property flag
  2012-09-13  3:49 [RFC 00/11] atomic pageflip (v2) Rob Clark
@ 2012-09-13  3:49 ` Rob Clark
  0 siblings, 0 replies; 14+ messages in thread
From: Rob Clark @ 2012-09-13  3:49 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, Rob Clark, patches

From: Rob Clark <rob@ti.com>

This indicates to userspace that the property is something that can
be set dynamically without requiring a "test" step to check if the
hw is capable.  This allows a userspace compositor, such as weston,
to avoid an extra ioctl to check whether it needs to fall-back to
GPU to composite some surface prior to submission of GPU render
commands.
---
 include/drm/drm_mode.h |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index cee4c53..15689d4 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -232,6 +232,15 @@ struct drm_mode_get_connector {
 #define DRM_MODE_PROP_BLOB	(1<<4)
 #define DRM_MODE_PROP_BITMASK	(1<<5) /* bitmask of enumerated types */
 #define DRM_MODE_PROP_OBJECT	(1<<6) /* drm mode object */
+/* Properties that are not dynamic cannot safely be changed without a
+ * atomic-modeset / atomic-pageflip test step.  But if userspace is
+ * only changing dynamic properties, it is guaranteed that the change
+ * will not exceed hw limits, so no test step is required.
+ *
+ * Note that fb_id properties are a bit ambiguous.. they of course can
+ * be changed dynamically, assuming the pixel format does not change.
+ */
+#define DRM_MODE_PROP_DYNAMIC	(1<<24)
 
 struct drm_mode_property_enum {
 	__u64 value;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2012-10-13  0:58 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-13  0:49 [RFC 00/11] atomic pageflip v3 Rob Clark
2012-10-13  0:49 ` [RFC 01/11] drm: add atomic fxns Rob Clark
2012-10-13  0:49 ` [RFC 02/11] drm: add object property type Rob Clark
2012-10-13  0:49 ` [RFC 03/11] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
2012-10-13  0:49 ` [RFC 04/11] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
2012-10-13  0:49 ` [RFC 05/11] drm: split property values out Rob Clark
2012-10-13  0:49 ` [RFC 06/11] drm: convert plane to properties Rob Clark
2012-10-13  0:49 ` [RFC 07/11] drm: add drm_plane_state Rob Clark
2012-10-13  0:49 ` [RFC 08/11] drm: convert page_flip to properties Rob Clark
2012-10-13  0:49 ` [RFC 09/11] drm: add drm_crtc_state Rob Clark
2012-10-13  0:49 ` [RFC 10/11] drm: atomic pageflip Rob Clark
2012-10-13  0:49 ` [RFC 11/11] drm/omap: update for atomic age Rob Clark
2012-10-13  0:58 ` [RFC 00/11] atomic pageflip v3 Rob Clark
  -- strict thread matches above, loose matches on Subject: below --
2012-09-13  3:49 [RFC 00/11] atomic pageflip (v2) Rob Clark
2012-09-13  3:49 ` [RFC 03/11] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).