@@ -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 \
new file mode 100644
@@ -0,0 +1,270 @@
+/*
+ * 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;
+
+ 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, 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);
+
+void *omap_atomic_begin(struct drm_device *dev)
+{
+ struct omap_drm_private *priv = dev->dev_private;
+ struct omap_atomic_state *omap_state;
+
+ // XXX for page_flip, we probably want to know the crtc/crtc_id here,
+ // so we can error out at this point if there is still a pending flip
+ // on this crtc..
+
+ // XXX we should track that we are in-atomic-update per-crtc, so
+ // that page-flips on multple crtc's don't step on each other's feet
+
+ WARN_ON(priv->in_atomic_update);
+ priv->in_atomic_update = true;
+
+ 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;
+ INIT_WORK(&omap_state->commit_work, commit_worker);
+
+ return 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]);
+
+ return ret;
+}
+
+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;
+ struct omap_drm_private *priv = dev->dev_private;
+ int i;
+
+ mutex_lock(&dev->mode_config.mutex);
+
+ for (i = 0; i < ARRAY_SIZE(omap_state->plane_state); i++)
+ if (omap_state->plane_state[i])
+ omap_plane_commit_state(priv->planes[i],
+ omap_state->plane_state[i]);
+
+ priv->in_atomic_update = false;
+
+ for (i = 0; i < ARRAY_SIZE(omap_state->crtc_state); i++)
+ if (omap_state->crtc_state[i])
+ omap_crtc_commit_state(priv->crtcs[i],
+ omap_state->crtc_state[i]);
+
+ for (i = 0; i < omap_state->num_pending_fbs; i++)
+ drm_framebuffer_unreference(omap_state->pending_fbs[i]);
+
+ mutex_unlock(&dev->mode_config.mutex);
+
+ /* 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);
+}
+
+static void commit_cb(void *state)
+{
+ struct omap_atomic_state *omap_state = state;
+ struct omap_drm_private *priv = omap_state->dev->dev_private;
+ if (++omap_state->num_ready_fbs == omap_state->num_pending_fbs)
+ queue_work(priv->wq, &omap_state->commit_work);
+}
+
+int omap_atomic_commit(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;
+
+ // XXX for synchronous modeset, we should block until fb's are ready,
+ // rather than complete asynchronously
+
+ if (event) {
+ /* Stash the event on the first plane that is pending update..
+ * it doesn't really matter which one, since they all get
+ * vblank at the same time.
+ */
+ for (i = 0; i < ARRAY_SIZE(omap_state->plane_state); i++) {
+ if (omap_state->plane_state[i]) {
+ priv->event[i] = event;
+ break;
+ }
+ }
+
+ /* I don't think there should be any way that this can happen: */
+ WARN_ON(i == ARRAY_SIZE(omap_state->plane_state));
+ }
+
+ if (!omap_state->num_pending_fbs) {
+ queue_work(priv->wq, &omap_state->commit_work);
+ return 0;
+ }
+
+ 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);
+ }
+
+ return 0;
+}
+
+void omap_atomic_end(struct drm_device *dev, void *state)
+{
+ // XXX maybe we need to refcnt the state for async updates..
+ // for now we just kfree() stuff after the (potentially async)
+ // commit completes rather than here, which means state could
+ // already be freed by now
+ // XXX but this means we leak if check fails! don't fail!
+}
+
+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;
+ if (priv->event[id]) {
+ /* wakeup userspace */
+ send_page_flip_event(dev, id, priv->event[id]);
+ priv->event[id] = NULL;
+ }
+}
new file mode 100644
@@ -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);
+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__ */
@@ -32,7 +32,6 @@ struct omap_crtc {
const char *name;
int pipe;
enum omap_channel channel;
- struct omap_overlay_manager_info info;
struct omap_video_timings timings;
bool enabled, timings_valid;
@@ -48,25 +47,17 @@ struct omap_crtc {
/* 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;
-
- /* 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;
};
+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);
omap_crtc->plane->funcs->destroy(omap_crtc->plane);
drm_crtc_cleanup(crtc);
+ kfree(crtc->state);
kfree(omap_crtc);
}
@@ -89,7 +80,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));
}
}
@@ -127,11 +118,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
}
}
- return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->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)
@@ -153,134 +140,83 @@ 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->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)
-{
-}
-
-/* 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);
-}
-
-static void vblank_cb(void *arg)
-{
- struct drm_crtc *crtc = arg;
- struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
- struct drm_pending_vblank_event *event = omap_crtc->event;
-
- WARN_ON(!event);
-
- omap_crtc->event = NULL;
-
- /* wakeup userspace */
- if (event)
- send_page_flip_event(crtc->dev, omap_crtc->pipe, event);
-}
-
-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;
-
- mutex_lock(&dev->mode_config.mutex);
- omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
- 0, 0, mode->hdisplay, mode->vdisplay,
- crtc->x << 16, crtc->y << 16,
- mode->hdisplay << 16, mode->vdisplay << 16,
- vblank_cb, crtc);
- mutex_unlock(&dev->mode_config.mutex);
-
- bo = omap_framebuffer_bo(crtc->fb, 0);
- drm_gem_object_unreference_unlocked(bo);
-}
-
-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;
-
- /* avoid assumptions about what ctxt we are called from: */
- queue_work(priv->wq, &omap_crtc->page_flip_work);
+ void *state;
+ int ret;
+
+ /* for now, until property based atomic mode-set: */
+ state = omap_atomic_begin(dev);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ ret =
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_crtc_id, VOID2U64(crtc)) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_fb_id, VOID2U64(crtc->state->fb)) ||
+ 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, mode->hdisplay << 16) ||
+ drm_mode_plane_set_obj_prop(plane, state,
+ config->prop_src_h, mode->vdisplay << 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->fb ? crtc->fb->base.id : -1,
- fb->base.id, event);
-
- if (omap_crtc->event) {
- dev_err(dev->dev, "already a pending flip\n");
- return -EINVAL;
- }
-
- omap_crtc->event = event;
- crtc->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,
+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);
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: set_property: %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->invert_dimensions =
+ crtc_state->base.invert_dimensions =
!!(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 = {
.set_config = drm_crtc_helper_set_config,
.destroy = omap_crtc_destroy,
- .page_flip = omap_crtc_page_flip_locked,
.set_property = omap_crtc_set_property,
};
@@ -306,6 +242,22 @@ 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);
+ crtc->state = &crtc_state->base;
+ kfree(old_state);
+ omap_crtc_apply(crtc, &omap_crtc->apply);
+}
+
static void omap_crtc_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
{
struct omap_crtc *omap_crtc =
@@ -327,6 +279,7 @@ static void apply_worker(struct work_struct *work)
container_of(work, struct omap_crtc, apply_work);
struct drm_crtc *crtc = &omap_crtc->base;
struct drm_device *dev = crtc->dev;
+ struct omap_drm_private *priv = dev->dev_private;
struct omap_drm_apply *apply, *n;
bool need_apply;
@@ -345,6 +298,9 @@ static void apply_worker(struct work_struct *work)
list_del(&apply->pending_node);
}
+ if (priv->in_atomic_update)
+ goto out;
+
need_apply = !list_empty(&omap_crtc->queued_applies);
/* then handle the next round of of queued apply's: */
@@ -368,6 +324,8 @@ static void apply_worker(struct work_struct *work)
omap_crtc_irq(&omap_crtc->irq, 0);
}
}
+
+out:
dispc_runtime_put();
mutex_unlock(&dev->mode_config.mutex);
}
@@ -377,15 +335,19 @@ int omap_crtc_apply(struct drm_crtc *crtc,
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_device *dev = crtc->dev;
+ struct omap_drm_private *priv = dev->dev_private;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
/* 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 (priv->in_atomic_update)
+ return 0;
/*
* If there are no currently pending updates, then go ahead and
@@ -404,6 +366,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
{
struct omap_crtc *omap_crtc =
container_of(apply, struct omap_crtc, apply);
+ struct omap_overlay_manager_info info = {0};
DBG("%s: enabled=%d, timings_valid=%d", omap_crtc->name,
omap_crtc->enabled,
@@ -414,7 +377,12 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
return;
}
- dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
+ info.default_color = 0x00000000;
+ info.trans_key = 0x00000000;
+ info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+ info.trans_enabled = false;
+
+ dispc_mgr_setup(omap_crtc->channel, &info);
dispc_mgr_set_timings(omap_crtc->channel,
&omap_crtc->timings);
dispc_mgr_enable(omap_crtc->channel, true);
@@ -437,7 +405,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]);
@@ -450,7 +417,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);
@@ -464,16 +437,10 @@ 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;
- /* 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);
@@ -18,6 +18,7 @@
*/
#include "omap_drv.h"
+#include "omap_atomic.h"
#include "drm_crtc_helper.h"
#include "drm_fb_helper.h"
@@ -511,6 +512,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,
@@ -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 */
void dispc_clear_irqs(u32 mask);
@@ -80,15 +81,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
@@ -147,6 +139,12 @@ struct omap_drm_private {
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 in_atomic_update;
+
+ /* pending vblank event per CRTC: */
+ struct drm_pending_vblank_event *event[8];
};
/* this should probably be in drm-core to standardize amongst drivers */
@@ -179,6 +177,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,
@@ -187,17 +189,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,
+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(
@@ -223,7 +222,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,
@@ -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;
@@ -316,7 +320,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 +346,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);
}
@@ -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;
@@ -58,9 +48,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)
@@ -112,24 +99,60 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
return 0;
}
+static inline bool is_enabled(struct drm_plane_state *state)
+{
+#if 0
+ // TODO dpms is immediate, so if it happens after state is snapshot
+ // as part of atomic update, it ends up getting overriden.. which
+ // shouldn't be a problem once we have atomic modeset..
+ return to_omap_plane_state(state)->enabled &&
+ state->crtc && state->fb;
+#else
+ return state->crtc && state->fb;
+#endif
+}
+
+/* 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 drm_crtc *crtc = plane->crtc;
+ 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->fb : NULL);
+ update_pin(plane, enabled ? fb : NULL);
if (!enabled) {
dispc_ovl_enable(omap_plane->id, false);
@@ -138,21 +161,13 @@ 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);
-
- 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, channel, info, ilace,
+ ret = dispc_ovl_setup(omap_plane->id, channel, &info,
replication, omap_crtc_timings(crtc));
if (ret) {
dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
@@ -168,115 +183,51 @@ 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);
+ omap_atomic_plane_update(plane->dev, omap_plane->id);
- if (omap_plane->enabled) {
- omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
- info->out_width, info->out_height);
+ 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);
}
}
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;
}
-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_plane->apply_done_cb.fxn = fxn;
- omap_plane->apply_done_cb.arg = arg;
- }
-
- plane->fb = fb;
- plane->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)
{
struct omap_plane *omap_plane = to_omap_plane(plane);
DBG("%s", omap_plane->name);
- 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);
bool enabled = (mode == DRM_MODE_DPMS_ON);
int ret = 0;
- if (enabled != omap_plane->enabled) {
- omap_plane->enabled = enabled;
+ if (enabled != is_enabled(plane->state)) {
+ to_omap_plane_state(plane->state)->enabled = enabled;
ret = apply(plane);
}
@@ -319,29 +270,95 @@ 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);
struct omap_drm_private *priv = plane->dev->dev_private;
- int ret = -EINVAL;
+ struct omap_plane_state *omap_state =
+ omap_atomic_plane_state(state, omap_plane->id);
+ int ret;
+
+DBG("*** %s: set_property: %s = %llx", omap_plane->name, property->name, val);
+
+ ret = drm_plane_set_property(plane, &omap_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)
+ omap_atomic_add_fb(state, U642VOID(val));
+ 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);
+ omap_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);
+ omap_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, y_predecim;
+ bool replication;
+
+ 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);
+
+ /* TODO: */
+ replication = false;
+
+ ret = dispc_ovl_check(omap_plane->id, omap_crtc_channel(crtc),
+ &info, replication, 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_state *old_state = to_omap_plane_state(plane->state);
+ plane->state = &plane_state->base;
+ kfree(old_state);
+ apply(plane);
}
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,
};
@@ -360,7 +377,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);
@@ -385,6 +401,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;
@@ -393,24 +416,11 @@ 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)
+ to_omap_plane_state(plane->state)->zorder = id;
return plane;
From: Rob Clark <rob@ti.com> --- drivers/staging/omapdrm/Makefile | 1 + drivers/staging/omapdrm/omap_atomic.c | 270 +++++++++++++++++++++++++++++++++ drivers/staging/omapdrm/omap_atomic.h | 52 +++++++ drivers/staging/omapdrm/omap_crtc.c | 247 +++++++++++++----------------- drivers/staging/omapdrm/omap_drv.c | 5 + drivers/staging/omapdrm/omap_drv.h | 35 +++-- drivers/staging/omapdrm/omap_fb.c | 44 +++--- drivers/staging/omapdrm/omap_plane.c | 270 +++++++++++++++++---------------- 8 files changed, 616 insertions(+), 308 deletions(-) create mode 100644 drivers/staging/omapdrm/omap_atomic.c create mode 100644 drivers/staging/omapdrm/omap_atomic.h