From: Ville Syrjälä <ville.syrj...@linux.intel.com>

Just a quick prototype to test the atomic modeset API. Implemented
via already existing non-atomic mechanisms internally.
---
 drivers/gpu/drm/i915/Makefile        |    1 +
 drivers/gpu/drm/i915/intel_atomic.c  |  788 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c |    7 +
 3 files changed, 796 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_atomic.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 2e9268d..f97e7a4 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -15,6 +15,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
          i915_gem_tiling.o \
          i915_sysfs.o \
          i915_trace_points.o \
+         intel_atomic.o \
          intel_display.o \
          intel_crt.o \
          intel_lvds.o \
diff --git a/drivers/gpu/drm/i915/intel_atomic.c 
b/drivers/gpu/drm/i915/intel_atomic.c
new file mode 100644
index 0000000..a6643fd
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -0,0 +1,788 @@
+/*
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+
+static struct drm_property *prop_src_x;
+static struct drm_property *prop_src_y;
+static struct drm_property *prop_src_w;
+static struct drm_property *prop_src_h;
+static struct drm_property *prop_crtc_x;
+static struct drm_property *prop_crtc_y;
+static struct drm_property *prop_crtc_w;
+static struct drm_property *prop_crtc_h;
+static struct drm_property *prop_fb_id;
+static struct drm_property *prop_crtc_id;
+static struct drm_property *prop_mode_id;
+static struct drm_property *prop_connector_ids;
+/* FIXME must be per-CRTC */
+static struct drm_property_blob *blob_connector_ids;
+
+static uint32_t *connector_ids;
+
+struct intel_plane_state {
+       struct drm_plane *plane;
+       int32_t crtc_x, crtc_y;
+       uint32_t crtc_w, crtc_h;
+       uint32_t src_x, src_y, src_w, src_h;
+       struct drm_framebuffer *fb;
+       struct drm_crtc *crtc;
+       uint32_t fb_id;
+       uint32_t crtc_id;
+       bool dirty;
+};
+
+struct intel_crtc_state {
+       struct drm_crtc *crtc;
+       struct drm_display_mode *mode;
+       int x, y;
+       struct drm_framebuffer *fb;
+       uint32_t fb_id;
+       bool mode_dirty;
+       bool fb_dirty;
+       bool active_dirty;
+       unsigned int count_connectors;
+       struct drm_connector **connectors;
+};
+
+struct intel_atomic_state {
+       struct intel_plane_state plane[3];
+       struct intel_crtc_state crtc[3];
+       bool fbs_pinned;
+       bool dirty;
+};
+
+static int populate_connectors(const struct drm_crtc *crtc,
+                              struct drm_connector **connector_list)
+{
+       struct drm_connector *connector;
+
+       int i = 0;
+
+       list_for_each_entry(connector, &crtc->dev->mode_config.connector_list, 
head) {
+               if (!connector->encoder || connector->encoder->crtc != crtc)
+                       continue;
+
+               connector_list[i++] = connector;
+       }
+
+       return i;
+}
+
+static void *intel_atomic_begin(struct drm_device *dev, uint32_t flags)
+{
+       struct intel_atomic_state *state;
+       struct drm_plane *plane;
+       struct drm_crtc *crtc;
+       struct drm_connector **connector_ptr;
+       int i;
+
+       state = kzalloc(sizeof *state + dev->mode_config.num_connector *
+                       sizeof(struct drm_connector *) * 
ARRAY_SIZE(state->crtc), GFP_KERNEL);
+       if (!state)
+               return ERR_PTR(-ENOMEM);
+
+       connector_ptr = (struct drm_connector **)(state + 1);
+
+       i = 0;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (i >= ARRAY_SIZE(state->crtc))
+                       break;
+
+               state->crtc[i].crtc = crtc;
+               state->crtc[i].mode = &crtc->mode;
+               state->crtc[i].x = crtc->x;
+               state->crtc[i].y = crtc->y;
+               state->crtc[i].fb = crtc->fb;
+               state->crtc[i].fb_id = crtc->fb ? crtc->fb->base.id : 0;
+
+               state->crtc[i].count_connectors = populate_connectors(crtc, 
connector_ptr);
+               state->crtc[i].connectors = connector_ptr;
+               connector_ptr += dev->mode_config.num_connector;
+
+               i++;
+       }
+
+       i = 0;
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               if (i >= ARRAY_SIZE(state->plane))
+                       break;
+
+               state->plane[i].plane = plane;
+               state->plane[i].crtc_x = plane->crtc_x;
+               state->plane[i].crtc_y = plane->crtc_y;
+               state->plane[i].crtc_w = plane->crtc_w;
+               state->plane[i].crtc_h = plane->crtc_h;
+               state->plane[i].src_x = plane->src_x;
+               state->plane[i].src_y = plane->src_y;
+               state->plane[i].src_w = plane->src_w;
+               state->plane[i].src_h = plane->src_h;
+               state->plane[i].fb = plane->fb;
+               state->plane[i].fb_id = plane->fb ? plane->fb->base.id : 0;
+               state->plane[i].crtc = plane->crtc;
+               state->plane[i].crtc_id = plane->crtc ? plane->crtc->base.id : 
0;
+
+               i++;
+       }
+
+       return state;
+}
+
+static int plane_set(struct intel_plane_state *state,
+                    struct drm_property *prop,
+                    uint64_t value)
+{
+       struct drm_plane *plane = state->plane;
+       struct drm_mode_object *obj;
+
+       if (!state)
+               return -ENOENT;
+
+       if (prop == prop_src_x) {
+               if (state->src_x == value)
+                       return 0;
+               state->src_x = value;
+       } else if (prop == prop_src_y) {
+               if (state->src_y == value)
+                       return 0;
+               state->src_y = value;
+       } else if (prop == prop_src_w) {
+               if (state->src_w == value)
+                       return 0;
+               state->src_w = value;
+       } else if (prop == prop_src_h) {
+               if (state->src_h == value)
+                       return 0;
+               state->src_h = value;
+       } else if (prop == prop_crtc_x) {
+               if (state->crtc_x == value)
+                       return 0;
+               state->crtc_x = value;
+       } else if (prop == prop_crtc_y) {
+               if (state->crtc_y == value)
+                       return 0;
+               state->crtc_y = value;
+       } else if (prop == prop_crtc_w) {
+               if (state->crtc_w == value)
+                       return 0;
+               state->crtc_w = value;
+       } else if (prop == prop_crtc_h) {
+               if (state->crtc_h == value)
+                       return 0;
+               state->crtc_h = value;
+       } else if (prop == prop_crtc_id) {
+               struct drm_crtc *crtc = NULL;
+
+               if (state->crtc_id == value)
+                       return 0;
+
+               if (value) {
+                       obj = drm_mode_object_find(plane->dev, value, 
DRM_MODE_OBJECT_CRTC);
+                       if (!obj) {
+                               printk("Unknown CRTC ID %llu\n", value);
+                               return -ENOENT;
+                       }
+                       crtc = obj_to_crtc(obj);
+               }
+
+               state->crtc = crtc;
+               state->crtc_id = value;
+       } else if (prop == prop_fb_id) {
+               struct drm_framebuffer *fb = NULL;
+
+               if (state->fb_id == value)
+                       return 0;
+
+               if (value) {
+                       obj = drm_mode_object_find(plane->dev, value, 
DRM_MODE_OBJECT_FB);
+                       if (!obj) {
+                               printk("Unknown framebuffer ID %llu\n", value);
+                               return -ENOENT;
+                       }
+                       fb = obj_to_fb(obj);
+               }
+
+               state->fb = fb;
+               state->fb_id = value;
+       } else
+               return -ENOENT;
+
+       state->dirty = true;
+
+       return 0;
+}
+
+static int crtc_set(struct intel_crtc_state *state,
+                   struct drm_property *prop,
+                   uint64_t value, void *blob_data)
+{
+       struct drm_crtc *crtc = state->crtc;
+       struct drm_mode_object *obj;
+
+       if (!state)
+               return -ENOENT;
+
+       if (prop == prop_src_x) {
+               if (state->x == value)
+                       return 0;
+               state->x = value;
+               state->mode_dirty = true;
+       } else if (prop == prop_src_y) {
+               if (state->y == value)
+                       return 0;
+               state->y = value;
+               state->mode_dirty = true;
+       } else if (prop == prop_mode_id) {
+               struct drm_display_mode *mode = NULL;
+
+               if (value) {
+                       obj = drm_mode_object_find(crtc->dev, value, 
DRM_MODE_OBJECT_MODE);
+                       if (!obj) {
+                               printk("Unknown mode ID %llu\n", value);
+                               return -ENOENT;
+                       }
+                       mode = obj_to_mode(obj);
+               }
+
+               if (!state->mode && !mode)
+                       return 0;
+
+               if (state->mode && mode && !memcmp(state->mode, mode, sizeof 
*mode))
+                       return 0;
+
+               if (!state->mode || !mode ||
+                   state->mode->hdisplay != mode->hdisplay ||
+                   state->mode->vdisplay != mode->vdisplay)
+                       state->active_dirty = true;
+
+               state->mode = mode;
+               state->mode_dirty = true;
+       } else if (prop == prop_fb_id) {
+               struct drm_framebuffer *fb = NULL;
+
+               if (state->fb_id == value)
+                       return 0;
+
+               if (value) {
+                       obj = drm_mode_object_find(crtc->dev, value, 
DRM_MODE_OBJECT_FB);
+                       if (!obj) {
+                               printk("Unknown framebuffer ID %llu\n", value);
+                               return -ENOENT;
+                       }
+                       fb = obj_to_fb(obj);
+               }
+
+               if (state->fb && fb) {
+                       /* can we page flip? */
+                       if (state->fb->pixel_format == fb->pixel_format &&
+                           state->fb->offsets[0] == fb->offsets[0] &&
+                           state->fb->pitches[0] == fb->pitches[0]) {
+                               state->fb_id = value;
+                               state->fb = obj_to_fb(obj);
+                               state->fb_dirty = true;
+                               return 0;
+                       }
+               }
+
+               state->fb_id = value;
+               state->fb = fb;
+               state->mode_dirty = true;
+       } else if (prop == prop_connector_ids) {
+               const uint32_t *new_conn = blob_data;
+               uint32_t count_new_conn = value / sizeof(uint32_t);
+               unsigned int i;
+
+               if (value & 3)
+                       return -EINVAL;
+
+               if (count_new_conn > crtc->dev->mode_config.num_connector)
+                       return -ERANGE;
+
+               if (count_new_conn == state->count_connectors) {
+                       for (i = 0; i < count_new_conn; i++) {
+                               if (state->connectors[i]->base.id != 
new_conn[i])
+                                       break;
+                       }
+                       /* no change */
+                       if (i == count_new_conn)
+                               return 0;
+               }
+
+               if (!count_new_conn) {
+                       state->count_connectors = 0;
+                       state->mode_dirty = true;
+                       return 0;
+               }
+
+               for (i = 0; i < count_new_conn; i++) {
+                       obj = drm_mode_object_find(crtc->dev, new_conn[i], 
DRM_MODE_OBJECT_CONNECTOR);
+                       if (!obj) {
+                               printk("Unknown connector ID %u\n", 
new_conn[i]);
+                               return -ENOENT;
+                       }
+
+                       state->connectors[i] = obj_to_connector(obj);
+               }
+               state->count_connectors = count_new_conn;
+               state->mode_dirty = true;
+       } else
+               return -ENOENT;
+
+       return 0;
+}
+
+static struct intel_plane_state *get_plane_state(struct intel_atomic_state 
*state,
+                                                struct drm_plane *plane)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(state->plane); i++)
+               if (plane == state->plane[i].plane)
+                       return &state->plane[i];
+
+       return NULL;
+}
+
+static struct intel_crtc_state *get_crtc_state(struct intel_atomic_state 
*state,
+                                              struct drm_crtc *crtc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(state->crtc); i++)
+               if (crtc == state->crtc[i].crtc)
+                       return &state->crtc[i];
+
+       return NULL;
+}
+
+static int intel_atomic_set(struct drm_device *dev,
+                           void *state,
+                           struct drm_mode_object *obj,
+                           struct drm_property *prop,
+                           uint64_t value, void *blob_data)
+{
+       struct intel_atomic_state *s = state;
+       int ret = -EINVAL;
+
+       switch (obj->type) {
+       case DRM_MODE_OBJECT_PLANE:
+               ret = plane_set(get_plane_state(s, obj_to_plane(obj)), prop, 
value);
+               break;
+       case DRM_MODE_OBJECT_CRTC:
+               ret = crtc_set(get_crtc_state(s, obj_to_crtc(obj)), prop, 
value, blob_data);
+               break;
+       default:
+               break;
+       }
+
+       kfree(blob_data);
+
+       if (ret)
+               return ret;
+
+       s->dirty = true;
+
+       return 0;
+}
+
+static int check_plane(struct intel_plane_state *state)
+{
+       /* FIXME check everything */
+
+       return 0;
+}
+
+static void dirty_planes(struct intel_atomic_state *state,
+                        struct drm_crtc *crtc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(state->plane); i++) {
+               if (state->plane[i].crtc == crtc)
+                       state->plane[i].dirty = true;
+       }
+}
+
+static int check_crtc(struct intel_atomic_state *state,
+                     struct intel_crtc_state *s)
+{
+       /*
+        * Mark all planes on this CRTC as dirty if the active video
+        * area changed so that the planes will get reclipped correctly.
+        */
+       if (s->active_dirty)
+               dirty_planes(state, s->crtc);
+
+       /* FIXME check mode and fb if dirty */
+
+       return 0;
+}
+
+static int intel_atomic_check(struct drm_device *dev, void *state)
+{
+       struct intel_atomic_state *s = state;
+       int i;
+
+       if (!s->dirty)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(s->crtc); i++) {
+               if (!s->crtc[i].fb_dirty && !s->crtc[i].mode_dirty)
+                       continue;
+
+               check_crtc(s, &s->crtc[i]);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(s->plane); i++) {
+               if (!s->plane[i].dirty)
+                       continue;
+
+               check_plane(&s->plane[i]);
+       }
+
+       return 0;
+}
+
+static void update_plane_props(struct intel_plane_state *state)
+{
+       struct drm_mode_object *obj = &state->plane->base;
+
+       if (prop_src_x)
+       drm_object_property_set_value(obj, prop_src_x, state->src_x);
+       if (prop_src_y)
+       drm_object_property_set_value(obj, prop_src_y, state->src_y);
+       if (prop_src_w)
+       drm_object_property_set_value(obj, prop_src_w, state->src_w);
+       if (prop_src_h)
+       drm_object_property_set_value(obj, prop_src_h, state->src_h);
+
+       if (prop_crtc_x)
+       drm_object_property_set_value(obj, prop_crtc_x, state->crtc_x);
+       if (prop_crtc_y)
+       drm_object_property_set_value(obj, prop_crtc_y, state->crtc_y);
+       if (prop_crtc_w)
+       drm_object_property_set_value(obj, prop_crtc_w, state->crtc_w);
+       if (prop_crtc_h)
+       drm_object_property_set_value(obj, prop_crtc_h, state->crtc_h);
+
+       if (prop_fb_id)
+       drm_object_property_set_value(obj, prop_fb_id, state->fb_id);
+
+       if (prop_crtc_id)
+       drm_object_property_set_value(obj, prop_crtc_id, state->crtc_id);
+}
+
+static void update_crtc_props(struct intel_crtc_state *state)
+{
+       struct drm_mode_object *obj = &state->crtc->base;
+       struct drm_device *dev = state->crtc->dev;
+       unsigned int i;
+
+       if (prop_src_x)
+       drm_object_property_set_value(obj, prop_src_x, state->x);
+       if (prop_src_y)
+       drm_object_property_set_value(obj, prop_src_y, state->y);
+
+       if (prop_fb_id)
+       drm_object_property_set_value(obj, prop_fb_id, state->fb_id);
+
+       /* FIXME if mode is user specifiec via old setcrtc ioctl prop value 
should be -1 */
+       if (prop_mode_id)
+       drm_object_property_set_value(obj, prop_mode_id,
+                                     state->mode ? state->mode->base.id : 0);
+
+       if (!prop_connector_ids || !connector_ids)
+               return;
+
+       if (blob_connector_ids)
+               drm_property_destroy_blob(dev, blob_connector_ids);
+
+       for (i = 0; i < state->count_connectors; i++)
+               connector_ids[i] = state->connectors[i]->base.id;
+
+       blob_connector_ids = drm_property_create_blob(dev,
+                                                     state->count_connectors * 
sizeof connector_ids[0],
+                                                     connector_ids);
+       if (!blob_connector_ids)
+               drm_object_property_set_value(obj, prop_connector_ids,
+                                             blob_connector_ids->base.id);
+       else
+               drm_object_property_set_value(obj, prop_connector_ids, 0);
+}
+
+static void update_props(struct intel_atomic_state *s)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(s->crtc); i++) {
+               if (!s->crtc[i].fb_dirty && !s->crtc[i].mode_dirty)
+                       continue;
+
+               update_crtc_props(&s->crtc[i]);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(s->plane); i++) {
+               if (!s->plane[i].dirty)
+                       continue;
+
+               update_plane_props(&s->plane[i]);
+       }
+}
+
+static int update_crtc(struct intel_crtc_state *state)
+{
+       struct drm_crtc *crtc = state->crtc;
+       struct drm_mode_set set;
+       int i;
+
+       if (!state->mode_dirty)
+               return crtc->funcs->page_flip(crtc, state->fb, NULL);
+
+       set.crtc = state->crtc;
+       set.x = state->x;
+       set.y = state->y;
+       set.mode = state->mode;
+       set.connectors = state->connectors;
+       set.num_connectors = state->count_connectors;
+       set.fb = state->fb;
+
+#if 0
+       printk("CRTC %u\n"
+              " x = %d\n"
+              " y = %d\n",
+              crtc->base.id,
+              set.x,
+              set.y);
+
+       if (set.mode) {
+               printk(" mode %u\n"
+                      "  hdisplay = %d\n"
+                      "  hsync_start = %d\n"
+                      "  hsync_end = %d\n"
+                      "  htotal = %d\n"
+                      "  hdisplay = %d\n"
+                      "  hsync_start = %d\n"
+                      "  hsync_end = %d\n"
+                      "  htotal = %d\n"
+                      "  clock = %d\n"
+                      "  vrefresh = %d\n",
+                      set.mode->base.id,
+                      set.mode->hdisplay,
+                      set.mode->hsync_start,
+                      set.mode->hsync_end,
+                      set.mode->htotal,
+                      set.mode->vdisplay,
+                      set.mode->vsync_start,
+                      set.mode->vsync_end,
+                      set.mode->vtotal,
+                      set.mode->clock,
+                      set.mode->vrefresh);
+       } else
+               printk(" no mode\n");
+
+       if (set.num_connectors) {
+               printk(" connectors:");
+               for (i = 0; i < set.num_connectors; i++)
+                       printk(" %u", set.connectors[i]->base.id);
+               printk("\n");
+       } else
+               printk(" no connectors\n");
+#endif
+
+       return crtc->funcs->set_config(&set);
+}
+
+static int update_plane(struct intel_plane_state *state)
+{
+       struct drm_plane *plane = state->plane;
+       int ret;
+
+       if (state->fb && state->crtc)
+               ret = plane->funcs->update_plane(plane,
+                                                state->crtc,
+                                                state->fb,
+                                                state->crtc_x,
+                                                state->crtc_y,
+                                                state->crtc_w,
+                                                state->crtc_h,
+                                                state->src_x,
+                                                state->src_y,
+                                                state->src_w,
+                                                state->src_h);
+       else
+               ret = plane->funcs->disable_plane(plane);
+
+       if (ret)
+               return ret;
+
+       plane->fb = state->fb;
+       plane->crtc = state->crtc;
+       plane->crtc_x = state->crtc_x;
+       plane->crtc_y = state->crtc_y;
+       plane->crtc_w = state->crtc_w;
+       plane->crtc_h = state->crtc_h;
+       plane->src_x = state->src_x;
+       plane->src_y = state->src_y;
+       plane->src_w = state->src_w;
+       plane->src_h = state->src_h;
+
+       return 0;
+}
+
+static int intel_atomic_commit(struct drm_device *dev, void *state)
+{
+       struct intel_atomic_state *s = state;
+       int i;
+       int ret = 0;
+
+       if (!s->dirty)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(s->crtc); i++) {
+               if (!s->crtc[i].mode_dirty)
+                       continue;
+
+               //intel_disable_crtc();
+       }
+
+       for (i = 0; i < ARRAY_SIZE(s->plane); i++) {
+               if (!s->plane[i].dirty)
+                       continue;
+
+               ret = update_plane(&s->plane[i]);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(s->crtc); i++) {
+               if (!s->crtc[i].mode_dirty && !s->crtc[i].fb_dirty)
+                       continue;
+
+               ret = update_crtc(&s->crtc[i]);
+               if (ret)
+                       return ret;
+       }
+
+       update_props(s);
+
+       return ret;
+}
+
+static void intel_atomic_end(struct drm_device *dev, void *state)
+{
+       kfree(state);
+}
+
+static const struct drm_atomic_funcs intel_atomic_funcs = {
+       .begin = intel_atomic_begin,
+       .set = intel_atomic_set,
+       .check = intel_atomic_check,
+       .commit = intel_atomic_commit,
+       .end = intel_atomic_end,
+};
+
+int intel_atomic_init(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_plane *plane;
+       void *state;
+
+       connector_ids = kcalloc(dev->mode_config.num_connector, sizeof 
connector_ids[0], GFP_KERNEL);
+       if (!connector_ids)
+               return -ENOMEM;
+
+       prop_src_x = drm_property_create_range(dev, 0, "SRC_X", 0, UINT_MAX);
+       prop_src_y = drm_property_create_range(dev, 0, "SRC_Y", 0, UINT_MAX);
+       prop_src_w = drm_property_create_range(dev, 0, "SRC_W", 0, UINT_MAX);
+       prop_src_h = drm_property_create_range(dev, 0, "SRC_H", 0, UINT_MAX);
+
+       // fixme signed values needed
+       prop_crtc_x = drm_property_create_range(dev, 0, "CRTC_X", INT_MIN, 
INT_MAX);
+       prop_crtc_y = drm_property_create_range(dev, 0, "CRTC_Y", INT_MIN, 
INT_MAX);
+       prop_crtc_w = drm_property_create_range(dev, 0, "CRTC_W", 0, INT_MAX);
+       prop_crtc_h = drm_property_create_range(dev, 0, "CRTC_H", 0, INT_MAX);
+
+       prop_fb_id = drm_property_create_range(dev, 0, "FB_ID", 0, UINT_MAX);
+       prop_crtc_id = drm_property_create_range(dev, 0, "CRTC_ID", 0, 
UINT_MAX);
+       prop_mode_id = drm_property_create_range(dev, 0, "MODE_ID", 0, 
UINT_MAX);
+
+       prop_connector_ids = drm_property_create(dev, DRM_MODE_PROP_BLOB, 
"CONNECTOR_IDS", 0);
+
+       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+               struct drm_mode_object *obj = &plane->base;
+
+               if (prop_src_x)
+               drm_object_attach_property(obj, prop_src_x, 0);
+               if (prop_src_y)
+               drm_object_attach_property(obj, prop_src_y, 0);
+               if (prop_src_w)
+               drm_object_attach_property(obj, prop_src_w, 0);
+               if (prop_src_h)
+               drm_object_attach_property(obj, prop_src_h, 0);
+
+               if (prop_crtc_x)
+               drm_object_attach_property(obj, prop_crtc_x, 0);
+               if (prop_crtc_y)
+               drm_object_attach_property(obj, prop_crtc_y, 0);
+               if (prop_crtc_w)
+               drm_object_attach_property(obj, prop_crtc_w, 0);
+               if (prop_crtc_h)
+               drm_object_attach_property(obj, prop_crtc_h, 0);
+
+               if (prop_fb_id)
+               drm_object_attach_property(obj, prop_fb_id, 0);
+               if (prop_crtc_id)
+               drm_object_attach_property(obj, prop_crtc_id, 0);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct drm_mode_object *obj = &crtc->base;
+
+               if (prop_src_x)
+               drm_object_attach_property(obj, prop_src_x, 0);
+               if (prop_src_y)
+               drm_object_attach_property(obj, prop_src_y, 0);
+
+               if (prop_fb_id)
+               drm_object_attach_property(obj, prop_fb_id, 0);
+               if (prop_mode_id)
+               drm_object_attach_property(obj, prop_mode_id, 0);
+               if (prop_connector_ids)
+               drm_object_attach_property(obj, prop_connector_ids, 0);
+       }
+
+       dev->driver->atomic_funcs = &intel_atomic_funcs;
+
+       /* quick way to pre-populate the properties... */
+       state = intel_atomic_begin(dev, 0);
+       if (state) {
+               update_props(state);
+               intel_atomic_end(dev, state);
+       }
+
+       return 0;
+}
+
+void intel_atomic_fini(struct drm_device *dev)
+{
+       kfree(connector_ids);
+
+       if (blob_connector_ids)
+               drm_property_destroy_blob(dev, blob_connector_ids);
+
+       drm_property_destroy(dev, prop_src_x);
+       drm_property_destroy(dev, prop_src_y);
+       drm_property_destroy(dev, prop_src_w);
+       drm_property_destroy(dev, prop_src_h);
+
+       drm_property_destroy(dev, prop_crtc_x);
+       drm_property_destroy(dev, prop_crtc_y);
+       drm_property_destroy(dev, prop_crtc_w);
+       drm_property_destroy(dev, prop_crtc_h);
+
+       drm_property_destroy(dev, prop_fb_id);
+       drm_property_destroy(dev, prop_crtc_id);
+       drm_property_destroy(dev, prop_mode_id);
+       drm_property_destroy(dev, prop_connector_ids);
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index aec6cac..3ff6ae9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7049,6 +7049,9 @@ void intel_modeset_init_hw(struct drm_device *dev)
                ivb_pch_pwm_override(dev);
 }
 
+void intel_atomic_init(struct drm_device *dev);
+void intel_atomic_fini(struct drm_device *dev);
+
 void intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7103,6 +7106,8 @@ void intel_modeset_init(struct drm_device *dev)
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
+
+       intel_atomic_init(dev);
 }
 
 void intel_modeset_gem_init(struct drm_device *dev)
@@ -7118,6 +7123,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
        struct drm_crtc *crtc;
        struct intel_crtc *intel_crtc;
 
+       intel_atomic_fini(dev);
+
        drm_kms_helper_poll_fini(dev);
        mutex_lock(&dev->struct_mutex);
 
-- 
1.7.3.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to