Merge branch 'topic/core-stuff' into topic/atomic-core
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 17 Dec 2014 19:24:02 +0000 (20:24 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 17 Dec 2014 19:24:02 +0000 (20:24 +0100)
Backmerge my drm-misc branch because of conflicts. Just simple stuff
but better to clear this out before I merge the other atomic patches.

Conflicts:
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_edid.c

Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
1  2 
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_plane_helper.c
drivers/gpu/drm/sti/sti_drm_crtc.c
drivers/gpu/drm/tegra/dc.c

index 481bb2598b62ffb32a62fb3dd087a0a5d87b010f,6700ebafef1677ab15d3db66d6c42b5b8ee25e71..303c9918a2d5783c13519a49cfb819a394b6aaac
@@@ -61,8 -61,8 +61,8 @@@ static struct drm_framebuffer *add_fram
  /*
   * Global properties
   */
- static const struct drm_prop_enum_list drm_dpms_enum_list[] =
{     { DRM_MODE_DPMS_ON, "On" },
+ static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
      { DRM_MODE_DPMS_ON, "On" },
        { DRM_MODE_DPMS_STANDBY, "Standby" },
        { DRM_MODE_DPMS_SUSPEND, "Suspend" },
        { DRM_MODE_DPMS_OFF, "Off" }
@@@ -70,8 -70,7 +70,7 @@@
  
  DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
  
- static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
- {
+ static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
        { DRM_PLANE_TYPE_OVERLAY, "Overlay" },
        { DRM_PLANE_TYPE_PRIMARY, "Primary" },
        { DRM_PLANE_TYPE_CURSOR, "Cursor" },
@@@ -80,8 -79,7 +79,7 @@@
  /*
   * Optional properties
   */
- static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
- {
+ static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
        { DRM_MODE_SCALE_NONE, "None" },
        { DRM_MODE_SCALE_FULLSCREEN, "Full" },
        { DRM_MODE_SCALE_CENTER, "Center" },
@@@ -97,8 -95,7 +95,7 @@@ static const struct drm_prop_enum_list 
  /*
   * Non-global properties, but "required" for certain connectors.
   */
- static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
- {
+ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
        { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
  
  DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
  
- static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
- {
+ static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
        { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
  DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
                 drm_dvi_i_subconnector_enum_list)
  
- static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
- {
+ static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
  
  DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
  
- static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
- {
+ static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
@@@ -154,8 -148,8 +148,8 @@@ struct drm_conn_prop_enum_list 
  /*
   * Connector and encoder types.
   */
- static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
{     { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
+ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
      { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
        { DRM_MODE_CONNECTOR_VGA, "VGA" },
        { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
        { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
        { DRM_MODE_CONNECTOR_DSI, "DSI" },
  };
  
- static const struct drm_prop_enum_list drm_encoder_enum_list[] =
{     { DRM_MODE_ENCODER_NONE, "None" },
+ static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
      { DRM_MODE_ENCODER_NONE, "None" },
        { DRM_MODE_ENCODER_DAC, "DAC" },
        { DRM_MODE_ENCODER_TMDS, "TMDS" },
        { DRM_MODE_ENCODER_LVDS, "LVDS" },
        { DRM_MODE_ENCODER_DPMST, "DP MST" },
  };
  
- static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
- {
+ static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
        { SubPixelUnknown, "Unknown" },
        { SubPixelHorizontalRGB, "Horizontal RGB" },
        { SubPixelHorizontalBGR, "Horizontal BGR" },
@@@ -910,11 -903,6 +903,11 @@@ void drm_connector_cleanup(struct drm_c
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode, *t;
  
 +      if (connector->tile_group) {
 +              drm_mode_put_tile_group(dev, connector->tile_group);
 +              connector->tile_group = NULL;
 +      }
 +
        list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
                drm_mode_remove(connector, mode);
  
@@@ -1142,6 -1130,7 +1135,7 @@@ EXPORT_SYMBOL(drm_encoder_init)
  void drm_encoder_cleanup(struct drm_encoder *encoder)
  {
        struct drm_device *dev = encoder->dev;
        drm_modeset_lock_all(dev);
        drm_mode_object_put(dev, &encoder->base);
        kfree(encoder->name);
@@@ -1185,8 -1174,8 +1179,8 @@@ int drm_universal_plane_init(struct drm
        plane->base.properties = &plane->properties;
        plane->dev = dev;
        plane->funcs = funcs;
-       plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
-                                     GFP_KERNEL);
+       plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
+                                           GFP_KERNEL);
        if (!plane->format_types) {
                DRM_DEBUG_KMS("out of memory when allocating plane\n");
                drm_mode_object_put(dev, &plane->base);
@@@ -1353,11 -1342,6 +1347,11 @@@ static int drm_mode_create_standard_con
                                       "PATH", 0);
        dev->mode_config.path_property = dev_path;
  
 +      dev->mode_config.tile_property = drm_property_create(dev,
 +                                                           DRM_MODE_PROP_BLOB |
 +                                                           DRM_MODE_PROP_IMMUTABLE,
 +                                                           "TILE", 0);
 +
        return 0;
  }
  
@@@ -1599,7 -1583,7 +1593,7 @@@ static int drm_mode_group_init(struct d
        total_objects += dev->mode_config.num_encoder;
        total_objects += dev->mode_config.num_bridge;
  
-       group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
+       group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL);
        if (!group->id_list)
                return -ENOMEM;
  
@@@ -1629,7 -1613,8 +1623,8 @@@ int drm_mode_group_init_legacy_group(st
        struct drm_bridge *bridge;
        int ret;
  
-       if ((ret = drm_mode_group_init(dev, group)))
+       ret = drm_mode_group_init(dev, group);
+       if (ret)
                return ret;
  
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
@@@ -2045,11 -2030,9 +2040,9 @@@ int drm_mode_getconnector(struct drm_de
  
        props_count = connector->properties.count;
  
-       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               if (connector->encoder_ids[i] != 0) {
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
+               if (connector->encoder_ids[i] != 0)
                        encoders_count++;
-               }
-       }
  
        if (out_resp->count_modes == 0) {
                connector->funcs->fill_modes(connector,
                prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
                prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
                for (i = 0; i < connector->properties.count; i++) {
 -                      if (put_user(connector->properties.ids[i],
 -                                   prop_ptr + copied)) {
 +                      struct drm_property *prop = connector->properties.properties[i];
 +                      uint64_t val;
 +
 +                      ret = drm_object_property_get_value(&connector->base, prop, &val);
 +                      if (ret)
 +                              goto out;
 +
 +                      if (put_user(prop->base.id, prop_ptr + copied)) {
                                ret = -EFAULT;
                                goto out;
                        }
 -
 -                      if (put_user(connector->properties.values[i],
 -                                   prop_values + copied)) {
 +                      if (put_user(val, prop_values + copied)) {
                                ret = -EFAULT;
                                goto out;
                        }
@@@ -2533,7 -2512,7 +2526,7 @@@ int drm_mode_setplane(struct drm_devic
   *
   * This is a little helper to wrap internal calls to the ->set_config driver
   * interface. The only thing it adds is correct refcounting dance.
-  * 
+  *
   * Returns:
   * Zero on success, negative errno on failure.
   */
@@@ -2725,9 -2704,9 +2718,9 @@@ int drm_mode_setcrtc(struct drm_device 
                        goto out;
                }
  
-               connector_set = kmalloc(crtc_req->count_connectors *
-                                       sizeof(struct drm_connector *),
-                                       GFP_KERNEL);
+               connector_set = kmalloc_array(crtc_req->count_connectors,
+                                             sizeof(struct drm_connector *),
+                                             GFP_KERNEL);
                if (!connector_set) {
                        ret = -ENOMEM;
                        goto out;
@@@ -2972,6 -2951,7 +2965,7 @@@ int drm_mode_cursor2_ioctl(struct drm_d
                           void *data, struct drm_file *file_priv)
  {
        struct drm_mode_cursor2 *req = data;
        return drm_mode_cursor_common(dev, req, file_priv);
  }
  
@@@ -3419,7 -3399,7 +3413,7 @@@ int drm_mode_dirtyfb_ioctl(struct drm_d
                        ret = -EINVAL;
                        goto out_err1;
                }
-               clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
+               clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
                if (!clips) {
                        ret = -ENOMEM;
                        goto out_err1;
@@@ -3520,7 -3500,8 +3514,8 @@@ struct drm_property *drm_property_creat
        property->dev = dev;
  
        if (num_values) {
-               property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
+               property->values = kcalloc(num_values, sizeof(uint64_t),
+                                          GFP_KERNEL);
                if (!property->values)
                        goto fail;
        }
@@@ -3826,7 -3807,7 +3821,7 @@@ void drm_object_attach_property(struct 
                return;
        }
  
 -      obj->properties->ids[count] = property->base.id;
 +      obj->properties->properties[count] = property;
        obj->properties->values[count] = init_val;
        obj->properties->count++;
  }
@@@ -3851,7 -3832,7 +3846,7 @@@ int drm_object_property_set_value(struc
        int i;
  
        for (i = 0; i < obj->properties->count; i++) {
 -              if (obj->properties->ids[i] == property->base.id) {
 +              if (obj->properties->properties[i] == property) {
                        obj->properties->values[i] = val;
                        return 0;
                }
@@@ -3881,7 -3862,7 +3876,7 @@@ int drm_object_property_get_value(struc
        int i;
  
        for (i = 0; i < obj->properties->count; i++) {
 -              if (obj->properties->ids[i] == property->base.id) {
 +              if (obj->properties->properties[i] == property) {
                        *val = obj->properties->values[i];
                        return 0;
                }
@@@ -4061,7 -4042,7 +4056,7 @@@ int drm_mode_getblob_ioctl(struct drm_d
  
        if (out_resp->length == blob->length) {
                blob_ptr = (void __user *)(unsigned long)out_resp->data;
-               if (copy_to_user(blob_ptr, blob->data, blob->length)){
+               if (copy_to_user(blob_ptr, blob->data, blob->length)) {
                        ret = -EFAULT;
                        goto done;
                }
@@@ -4105,52 -4086,6 +4100,52 @@@ int drm_mode_connector_set_path_propert
  }
  EXPORT_SYMBOL(drm_mode_connector_set_path_property);
  
 +/**
 + * drm_mode_connector_set_tile_property - set tile property on connector
 + * @connector: connector to set property on.
 + *
 + * This looks up the tile information for a connector, and creates a
 + * property for userspace to parse if it exists. The property is of
 + * the form of 8 integers using ':' as a separator.
 + *
 + * Returns:
 + * Zero on success, errno on failure.
 + */
 +int drm_mode_connector_set_tile_property(struct drm_connector *connector)
 +{
 +      struct drm_device *dev = connector->dev;
 +      int ret, size;
 +      char tile[256];
 +
 +      if (connector->tile_blob_ptr)
 +              drm_property_destroy_blob(dev, connector->tile_blob_ptr);
 +
 +      if (!connector->has_tile) {
 +              connector->tile_blob_ptr = NULL;
 +              ret = drm_object_property_set_value(&connector->base,
 +                                                  dev->mode_config.tile_property, 0);
 +              return ret;
 +      }
 +
 +      snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
 +               connector->tile_group->id, connector->tile_is_single_monitor,
 +               connector->num_h_tile, connector->num_v_tile,
 +               connector->tile_h_loc, connector->tile_v_loc,
 +               connector->tile_h_size, connector->tile_v_size);
 +      size = strlen(tile) + 1;
 +
 +      connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
 +                                                          size, tile);
 +      if (!connector->tile_blob_ptr)
 +              return -EINVAL;
 +
 +      ret = drm_object_property_set_value(&connector->base,
 +                                          dev->mode_config.tile_property,
 +                                          connector->tile_blob_ptr->base.id);
 +      return ret;
 +}
 +EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
 +
  /**
   * drm_mode_connector_update_edid_property - update the edid property of a connector
   * @connector: drm connector
@@@ -4197,35 -4132,28 +4192,38 @@@ int drm_mode_connector_update_edid_prop
  }
  EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
  
 -static bool drm_property_change_is_valid(struct drm_property *property,
 -                                       uint64_t value)
 +/* Some properties could refer to dynamic refcnt'd objects, or things that
 + * need special locking to handle lifetime issues (ie. to ensure the prop
 + * value doesn't become invalid part way through the property update due to
 + * race).  The value returned by reference via 'obj' should be passed back
 + * to drm_property_change_valid_put() after the property is set (and the
 + * object to which the property is attached has a chance to take it's own
 + * reference).
 + */
 +static bool drm_property_change_valid_get(struct drm_property *property,
 +                                       uint64_t value, struct drm_mode_object **ref)
  {
+       int i;
        if (property->flags & DRM_MODE_PROP_IMMUTABLE)
                return false;
  
 +      *ref = NULL;
 +
        if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
                if (value < property->values[0] || value > property->values[1])
                        return false;
                return true;
        } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
                int64_t svalue = U642I64(value);
                if (svalue < U642I64(property->values[0]) ||
                                svalue > U642I64(property->values[1]))
                        return false;
                return true;
        } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
-               int i;
                uint64_t valid_mask = 0;
                for (i = 0; i < property->num_values; i++)
                        valid_mask |= (1ULL << property->values[i]);
                return !(value & ~valid_mask);
                /* Only the driver knows */
                return true;
        } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
 -              struct drm_mode_object *obj;
 -
                /* a zero value for an object property translates to null: */
                if (value == 0)
                        return true;
 -              /*
 -               * NOTE: use _object_find() directly to bypass restriction on
 -               * looking up refcnt'd objects (ie. fb's).  For a refcnt'd
 -               * object this could race against object finalization, so it
 -               * simply tells us that the object *was* valid.  Which is good
 -               * enough.
 -               */
 -              obj = _object_find(property->dev, value, property->values[0]);
 -              return obj != NULL;
 +
 +              /* handle refcnt'd objects specially: */
 +              if (property->values[0] == DRM_MODE_OBJECT_FB) {
 +                      struct drm_framebuffer *fb;
 +                      fb = drm_framebuffer_lookup(property->dev, value);
 +                      if (fb) {
 +                              *ref = &fb->base;
 +                              return true;
 +                      } else {
 +                              return false;
 +                      }
 +              } else {
 +                      return _object_find(property->dev, value, property->values[0]) != NULL;
 +              }
 +      } else {
 +              int i;
 +              for (i = 0; i < property->num_values; i++)
 +                      if (property->values[i] == value)
 +                              return true;
 +              return false;
        }
+       for (i = 0; i < property->num_values; i++)
+               if (property->values[i] == value)
+                       return true;
+       return false;
  }
  
 +static void drm_property_change_valid_put(struct drm_property *property,
 +              struct drm_mode_object *ref)
 +{
 +      if (!ref)
 +              return;
 +
 +      if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
 +              if (property->values[0] == DRM_MODE_OBJECT_FB)
 +                      drm_framebuffer_unreference(obj_to_fb(ref));
 +      }
 +}
 +
  /**
   * drm_mode_connector_property_set_ioctl - set the current value of a connector property
   * @dev: DRM device
@@@ -4417,19 -4329,13 +4420,19 @@@ int drm_mode_obj_get_properties_ioctl(s
                prop_values_ptr = (uint64_t __user *)(unsigned long)
                                  (arg->prop_values_ptr);
                for (i = 0; i < props_count; i++) {
 -                      if (put_user(obj->properties->ids[i],
 -                                   props_ptr + copied)) {
 +                      struct drm_property *prop = obj->properties->properties[i];
 +                      uint64_t val;
 +
 +                      ret = drm_object_property_get_value(obj, prop, &val);
 +                      if (ret)
 +                              goto out;
 +
 +                      if (put_user(prop->base.id, props_ptr + copied)) {
                                ret = -EFAULT;
                                goto out;
                        }
 -                      if (put_user(obj->properties->values[i],
 -                                   prop_values_ptr + copied)) {
 +
 +                      if (put_user(val, prop_values_ptr + copied)) {
                                ret = -EFAULT;
                                goto out;
                        }
@@@ -4465,8 -4371,8 +4468,8 @@@ int drm_mode_obj_set_property_ioctl(str
        struct drm_mode_object *arg_obj;
        struct drm_mode_object *prop_obj;
        struct drm_property *property;
 -      int ret = -EINVAL;
 -      int i;
 +      int i, ret = -EINVAL;
 +      struct drm_mode_object *ref;
  
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
                goto out;
  
        for (i = 0; i < arg_obj->properties->count; i++)
 -              if (arg_obj->properties->ids[i] == arg->prop_id)
 +              if (arg_obj->properties->properties[i]->base.id == arg->prop_id)
                        break;
  
        if (i == arg_obj->properties->count)
        }
        property = obj_to_property(prop_obj);
  
 -      if (!drm_property_change_is_valid(property, arg->value))
 +      if (!drm_property_change_valid_get(property, arg->value, &ref))
                goto out;
  
        switch (arg_obj->type) {
                break;
        }
  
 +      drm_property_change_valid_put(property, ref);
 +
  out:
        drm_modeset_unlock_all(dev);
        return ret;
@@@ -4564,7 -4468,8 +4567,8 @@@ int drm_mode_crtc_set_gamma_size(struc
  {
        crtc->gamma_size = gamma_size;
  
-       crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
+       crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
+                                   GFP_KERNEL);
        if (!crtc->gamma_store) {
                crtc->gamma_size = 0;
                return -ENOMEM;
@@@ -4779,23 -4684,23 +4783,23 @@@ int drm_mode_page_flip_ioctl(struct drm
        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) {
+               if (file_priv->event_space < sizeof(e->event)) {
                        spin_unlock_irqrestore(&dev->event_lock, flags);
                        goto out;
                }
-               file_priv->event_space -= sizeof e->event;
+               file_priv->event_space -= sizeof(e->event);
                spin_unlock_irqrestore(&dev->event_lock, flags);
  
-               e = kzalloc(sizeof *e, GFP_KERNEL);
+               e = kzalloc(sizeof(*e), GFP_KERNEL);
                if (e == NULL) {
                        spin_lock_irqsave(&dev->event_lock, flags);
-                       file_priv->event_space += sizeof e->event;
+                       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.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;
        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;
+                       file_priv->event_space += sizeof(e->event);
                        spin_unlock_irqrestore(&dev->event_lock, flags);
                        kfree(e);
                }
@@@ -5255,7 -5160,6 +5259,7 @@@ void drm_mode_config_init(struct drm_de
        INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
        INIT_LIST_HEAD(&dev->mode_config.plane_list);
        idr_init(&dev->mode_config.crtc_idr);
 +      idr_init(&dev->mode_config.tile_idr);
  
        drm_modeset_lock_all(dev);
        drm_mode_create_standard_connector_properties(dev);
@@@ -5343,7 -5247,6 +5347,7 @@@ void drm_mode_config_cleanup(struct drm
                crtc->funcs->destroy(crtc);
        }
  
 +      idr_destroy(&dev->mode_config.tile_idr);
        idr_destroy(&dev->mode_config.crtc_idr);
        drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
  }
@@@ -5366,100 -5269,3 +5370,100 @@@ struct drm_property *drm_mode_create_ro
                                           supported_rotations);
  }
  EXPORT_SYMBOL(drm_mode_create_rotation_property);
 +
 +/**
 + * DOC: Tile group
 + *
 + * Tile groups are used to represent tiled monitors with a unique
 + * integer identifier. Tiled monitors using DisplayID v1.3 have
 + * a unique 8-byte handle, we store this in a tile group, so we
 + * have a common identifier for all tiles in a monitor group.
 + */
 +static void drm_tile_group_free(struct kref *kref)
 +{
 +      struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
 +      struct drm_device *dev = tg->dev;
 +      mutex_lock(&dev->mode_config.idr_mutex);
 +      idr_remove(&dev->mode_config.tile_idr, tg->id);
 +      mutex_unlock(&dev->mode_config.idr_mutex);
 +      kfree(tg);
 +}
 +
 +/**
 + * drm_mode_put_tile_group - drop a reference to a tile group.
 + * @dev: DRM device
 + * @tg: tile group to drop reference to.
 + *
 + * drop reference to tile group and free if 0.
 + */
 +void drm_mode_put_tile_group(struct drm_device *dev,
 +                           struct drm_tile_group *tg)
 +{
 +      kref_put(&tg->refcount, drm_tile_group_free);
 +}
 +
 +/**
 + * drm_mode_get_tile_group - get a reference to an existing tile group
 + * @dev: DRM device
 + * @topology: 8-bytes unique per monitor.
 + *
 + * Use the unique bytes to get a reference to an existing tile group.
 + *
 + * RETURNS:
 + * tile group or NULL if not found.
 + */
 +struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
 +                                             char topology[8])
 +{
 +      struct drm_tile_group *tg;
 +      int id;
 +      mutex_lock(&dev->mode_config.idr_mutex);
 +      idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
 +              if (!memcmp(tg->group_data, topology, 8)) {
 +                      if (!kref_get_unless_zero(&tg->refcount))
 +                              tg = NULL;
 +                      mutex_unlock(&dev->mode_config.idr_mutex);
 +                      return tg;
 +              }
 +      }
 +      mutex_unlock(&dev->mode_config.idr_mutex);
 +      return NULL;
 +}
 +
 +/**
 + * drm_mode_create_tile_group - create a tile group from a displayid description
 + * @dev: DRM device
 + * @topology: 8-bytes unique per monitor.
 + *
 + * Create a tile group for the unique monitor, and get a unique
 + * identifier for the tile group.
 + *
 + * RETURNS:
 + * new tile group or error.
 + */
 +struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
 +                                                char topology[8])
 +{
 +      struct drm_tile_group *tg;
 +      int ret;
 +
 +      tg = kzalloc(sizeof(*tg), GFP_KERNEL);
 +      if (!tg)
 +              return ERR_PTR(-ENOMEM);
 +
 +      kref_init(&tg->refcount);
 +      memcpy(tg->group_data, topology, 8);
 +      tg->dev = dev;
 +
 +      mutex_lock(&dev->mode_config.idr_mutex);
 +      ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
 +      if (ret >= 0) {
 +              tg->id = ret;
 +      } else {
 +              kfree(tg);
 +              tg = ERR_PTR(ret);
 +      }
 +
 +      mutex_unlock(&dev->mode_config.idr_mutex);
 +      return tg;
 +}
index ae61fb21ea864de0155c2c8418143bd84b39b1f7,391dfb7d1086e808c01d21d4f67db56285613d43..f24c4cfe674b9e0d75a36f0ab017afef7bcddb5f
@@@ -142,6 -142,17 +142,17 @@@ int drm_plane_helper_check_update(struc
  {
        int hscale, vscale;
  
+       if (!fb) {
+               *visible = false;
+               return 0;
+       }
+       /* crtc should only be NULL when disabling (i.e., !fb) */
+       if (WARN_ON(!crtc)) {
+               *visible = false;
+               return 0;
+       }
        if (!crtc->enabled && !can_update_disabled) {
                DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
                return -EINVAL;
                return -ERANGE;
        }
  
-       if (!fb) {
-               *visible = false;
-               return 0;
-       }
        *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
        if (!*visible)
                /*
@@@ -517,7 -523,6 +523,7 @@@ int drm_plane_helper_update(struct drm_
                plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
        if (!plane_state)
                return -ENOMEM;
 +      plane_state->plane = plane;
  
        plane_state->crtc = crtc;
        drm_atomic_set_fb_for_plane(plane_state, fb);
@@@ -564,7 -569,6 +570,7 @@@ int drm_plane_helper_disable(struct drm
                plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
        if (!plane_state)
                return -ENOMEM;
 +      plane_state->plane = plane;
  
        plane_state->crtc = NULL;
        drm_atomic_set_fb_for_plane(plane_state, NULL);
index 4c651c200f205693f9e166963803992008255ea5,70e6e97a850ee15cfd697de44ba67d8ca7569b4b..e6f6ef7c4866ad94eb7bd503eabc9aee7e2b8181
@@@ -28,7 -28,7 +28,7 @@@ static void sti_drm_crtc_prepare(struc
        struct device *dev = mixer->dev;
        struct sti_compositor *compo = dev_get_drvdata(dev);
  
 -      compo->enable = true;
 +      mixer->enabled = true;
  
        /* Prepare and enable the compo IP clock */
        if (mixer->id == STI_MIXER_MAIN) {
@@@ -38,8 -38,6 +38,8 @@@
                if (clk_prepare_enable(compo->clk_compo_aux))
                        DRM_INFO("Failed to prepare/enable compo_aux clk\n");
        }
 +
 +      sti_mixer_clear_all_layers(mixer);
  }
  
  static void sti_drm_crtc_commit(struct drm_crtc *crtc)
@@@ -64,8 -62,6 +64,8 @@@
        /* Enable layer on mixer */
        if (sti_mixer_set_layer_status(mixer, layer, true))
                DRM_ERROR("Can not enable layer at mixer\n");
 +
 +      drm_crtc_vblank_on(crtc);
  }
  
  static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
@@@ -148,8 -144,7 +148,8 @@@ sti_drm_crtc_mode_set(struct drm_crtc *
        w = crtc->primary->fb->width - x;
        h = crtc->primary->fb->height - y;
  
 -      return sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode,
 +      return sti_layer_prepare(layer, crtc,
 +                      crtc->primary->fb, &crtc->mode,
                        mixer->id, 0, 0, w, h, x, y, w, h);
  }
  
@@@ -176,8 -171,7 +176,8 @@@ static int sti_drm_crtc_mode_set_base(s
        w = crtc->primary->fb->width - crtc->x;
        h = crtc->primary->fb->height - crtc->y;
  
 -      ret = sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode,
 +      ret = sti_layer_prepare(layer, crtc,
 +                              crtc->primary->fb, &crtc->mode,
                                mixer->id, 0, 0, w, h,
                                crtc->x, crtc->y, w, h);
        if (ret) {
@@@ -190,11 -184,6 +190,6 @@@ out
        return ret;
  }
  
- static void sti_drm_crtc_load_lut(struct drm_crtc *crtc)
- {
-       /* do nothing */
- }
  static void sti_drm_crtc_disable(struct drm_crtc *crtc)
  {
        struct sti_mixer *mixer = to_sti_mixer(crtc);
        struct sti_compositor *compo = dev_get_drvdata(dev);
        struct sti_layer *layer;
  
 -      if (!compo->enable)
 +      if (!mixer->enabled)
                return;
  
        DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
        /* Then disable layer itself */
        sti_layer_disable(layer);
  
 -      drm_vblank_off(crtc->dev, mixer->id);
 +      drm_crtc_vblank_off(crtc);
  
        /* Disable pixel clock and compo IP clocks */
        if (mixer->id == STI_MIXER_MAIN) {
                clk_disable_unprepare(compo->clk_compo_aux);
        }
  
 -      compo->enable = false;
 +      mixer->enabled = false;
  }
  
  static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
        .mode_fixup = sti_drm_crtc_mode_fixup,
        .mode_set = sti_drm_crtc_mode_set,
        .mode_set_base = sti_drm_crtc_mode_set_base,
-       .load_lut = sti_drm_crtc_load_lut,
        .disable = sti_drm_crtc_disable,
  };
  
@@@ -370,6 -358,7 +364,6 @@@ void sti_drm_crtc_disable_vblank(struc
        struct sti_drm_private *priv = dev->dev_private;
        struct sti_compositor *compo = priv->compo;
        struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
 -      unsigned long flags;
  
        DRM_DEBUG_DRIVER("\n");
  
                DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
  
        /* free the resources of the pending requests */
 -      spin_lock_irqsave(&dev->event_lock, flags);
        if (compo->mixer[crtc]->pending_event) {
                drm_vblank_put(dev, crtc);
                compo->mixer[crtc]->pending_event = NULL;
        }
 -      spin_unlock_irqrestore(&dev->event_lock, flags);
 -
  }
  EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
  
@@@ -401,7 -393,6 +395,7 @@@ bool sti_drm_crtc_is_main(struct drm_cr
  
        return false;
  }
 +EXPORT_SYMBOL(sti_drm_crtc_is_main);
  
  int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
                struct drm_plane *primary, struct drm_plane *cursor)
index 3367960286a6f162455e0363a54dace2c6882883,d9076a10cb75bb4b73aa6c99bbee2eb360baeacb..7fe7bb1227cf2f5c4c17ffaa1de551c45622fa1a
@@@ -906,7 -906,7 +906,7 @@@ static void tegra_crtc_disable(struct d
                }
        }
  
 -      drm_vblank_off(drm, dc->pipe);
 +      drm_crtc_vblank_off(crtc);
        tegra_dc_commit(dc);
  }
  
@@@ -996,6 -996,8 +996,6 @@@ static int tegra_crtc_mode_set(struct d
        u32 value;
        int err;
  
 -      drm_vblank_pre_modeset(crtc->dev, dc->pipe);
 -
        err = tegra_crtc_setup_clk(crtc, mode);
        if (err) {
                dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err);
@@@ -1049,8 -1051,6 +1049,8 @@@ static void tegra_crtc_prepare(struct d
        unsigned int syncpt;
        unsigned long value;
  
 +      drm_crtc_vblank_off(crtc);
 +
        /* hardware initialization */
        reset_control_deassert(dc->rst);
        usleep_range(10000, 20000);
@@@ -1091,14 -1091,10 +1091,10 @@@ static void tegra_crtc_commit(struct dr
  {
        struct tegra_dc *dc = to_tegra_dc(crtc);
  
 -      drm_vblank_post_modeset(crtc->dev, dc->pipe);
 +      drm_crtc_vblank_on(crtc);
        tegra_dc_commit(dc);
  }
  
- static void tegra_crtc_load_lut(struct drm_crtc *crtc)
- {
- }
  static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
        .disable = tegra_crtc_disable,
        .mode_fixup = tegra_crtc_mode_fixup,
        .mode_set_base = tegra_crtc_mode_set_base,
        .prepare = tegra_crtc_prepare,
        .commit = tegra_crtc_commit,
-       .load_lut = tegra_crtc_load_lut,
  };
  
  static irqreturn_t tegra_dc_irq(int irq, void *data)