@@ -13,7 +13,8 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
drm_trace_points.o drm_global.o drm_prime.o \
- drm_rect.o drm_vma_manager.o drm_flip_work.o
+ drm_rect.o drm_vma_manager.o drm_flip_work.o \
+ drm_atomic_helper.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
@@ -216,6 +216,12 @@ static struct drm_driver driver = {
.dumb_map_offset = ast_dumb_mmap_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
};
static int __init ast_init(void)
@@ -29,6 +29,7 @@
#define __AST_DRV_H__
#include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
@@ -101,6 +101,12 @@ static struct drm_driver driver = {
.dumb_create = cirrus_dumb_create,
.dumb_map_offset = cirrus_dumb_mmap_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
};
static struct pci_driver cirrus_pci_driver = {
@@ -14,6 +14,7 @@
#include <video/vga.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
new file mode 100644
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * 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 <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+
+/**
+ * drm_atomic_helper_begin - start a sequence of atomic updates
+ * @dev: DRM device
+ * @flags: the modifier flags that userspace has requested
+ *
+ * Begin a sequence of atomic property sets. Returns a driver
+ * private state object that is passed back into the various
+ * object's set_property() fxns, and into the remainder of the
+ * atomic funcs. The state object should accumulate the changes
+ * from one o more set_property()'s. At the end, the state can
+ * be checked, and optionally committed.
+ *
+ * RETURNS
+ * a driver private state object, which is passed back in to
+ * the various other atomic fxns, or error (such as -EBUSY if
+ * there is still a pending async update)
+ */
+void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
+{
+ struct drm_atomic_helper_state *state;
+ int sz;
+ void *ptr;
+
+ sz = sizeof(*state);
+
+ ptr = kzalloc(sz, GFP_KERNEL);
+
+ state = ptr;
+ ptr = &state[1];
+
+ kref_init(&state->refcount);
+ state->dev = dev;
+ state->flags = flags;
+ return state;
+}
+EXPORT_SYMBOL(drm_atomic_helper_begin);
+
+/**
+ * drm_atomic_helper_set_event - set a pending event on mode object
+ * @dev: DRM device
+ * @state: the driver private state object
+ * @obj: the object to set the event on
+ * @event: the event to send back
+ *
+ * Set pending event for an update on the specified object. The
+ * event is to be sent back to userspace after the update completes.
+ */
+int drm_atomic_helper_set_event(struct drm_device *dev,
+ void *state, struct drm_mode_object *obj,
+ struct drm_pending_vblank_event *event)
+{
+ return -EINVAL; /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_helper_set_event);
+
+/**
+ * drm_atomic_helper_check - validate state object
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Check the state object to see if the requested state is
+ * physically possible.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_check(struct drm_device *dev, void *state)
+{
+ return 0; /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_helper_check);
+
+/**
+ * drm_atomic_helper_commit - commit state
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Commit the state. This will only be called if atomic_check()
+ * succeeds.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_commit(struct drm_device *dev, void *state)
+{
+ return 0; /* for now */
+}
+EXPORT_SYMBOL(drm_atomic_helper_commit);
+
+/**
+ * drm_atomic_helper_end - conclude the atomic update
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Release resources associated with the state object.
+ */
+void drm_atomic_helper_end(struct drm_device *dev, void *state)
+{
+ drm_atomic_helper_state_unreference(state);
+}
+EXPORT_SYMBOL(drm_atomic_helper_end);
+
+void _drm_atomic_helper_state_free(struct kref *kref)
+{
+ struct drm_atomic_helper_state *state =
+ container_of(kref, struct drm_atomic_helper_state, refcount);
+ kfree(state);
+}
+EXPORT_SYMBOL(_drm_atomic_helper_state_free);
+
+
+const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
+};
+EXPORT_SYMBOL(drm_atomic_helper_funcs);
@@ -3281,20 +3281,21 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
}
-static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
- struct drm_property *property,
- uint64_t value)
+static int drm_mode_connector_set_obj_prop(struct drm_connector *connector,
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data)
{
int ret = -EINVAL;
- struct drm_connector *connector = obj_to_connector(obj);
/* Do DPMS ourselves */
if (property == connector->dev->mode_config.dpms_property) {
if (connector->funcs->dpms)
(*connector->funcs->dpms)(connector, (int)value);
ret = 0;
- } else if (connector->funcs->set_property)
- ret = connector->funcs->set_property(connector, property, value);
+ } else if (connector->funcs->set_property) {
+ ret = connector->funcs->set_property(connector, state,
+ property, value, blob_data);
+ }
/* store the property value if successful */
if (!ret)
@@ -3302,36 +3303,90 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
return ret;
}
-static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
- struct drm_property *property,
- uint64_t value)
+static int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data)
{
int ret = -EINVAL;
- struct drm_crtc *crtc = obj_to_crtc(obj);
if (crtc->funcs->set_property)
- ret = crtc->funcs->set_property(crtc, property, value);
+ ret = crtc->funcs->set_property(crtc, state, property,
+ value, blob_data);
if (!ret)
- drm_object_property_set_value(obj, property, value);
+ drm_object_property_set_value(&crtc->base, property, value);
return ret;
}
-static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
- struct drm_property *property,
- uint64_t value)
+static int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data)
{
int ret = -EINVAL;
- struct drm_plane *plane = obj_to_plane(obj);
if (plane->funcs->set_property)
- ret = plane->funcs->set_property(plane, property, value);
+ ret = plane->funcs->set_property(plane, state, property,
+ value, blob_data);
if (!ret)
- drm_object_property_set_value(obj, property, value);
+ drm_object_property_set_value(&plane->base, property, value);
return ret;
}
+static int drm_mode_set_obj_prop(struct drm_device *dev,
+ struct drm_mode_object *obj, void *state,
+ struct drm_property *property, uint64_t value, void *blob_data)
+{
+ if (drm_property_change_is_valid(property, value)) {
+ switch (obj->type) {
+ case DRM_MODE_OBJECT_CONNECTOR:
+ return drm_mode_connector_set_obj_prop(obj_to_connector(obj),
+ state, property, value, blob_data);
+ case DRM_MODE_OBJECT_CRTC:
+ return drm_mode_crtc_set_obj_prop(obj_to_crtc(obj),
+ state, property, value, blob_data);
+ case DRM_MODE_OBJECT_PLANE:
+ return drm_mode_plane_set_obj_prop(obj_to_plane(obj),
+ state, property, value, blob_data);
+ }
+ }
+
+ return -EINVAL;
+}
+
+/* call with mode_config mutex held */
+static int drm_mode_set_obj_prop_id(struct drm_device *dev, void *state,
+ uint32_t obj_id, uint32_t obj_type,
+ uint32_t prop_id, uint64_t value, void *blob_data)
+{
+ struct drm_mode_object *arg_obj;
+ struct drm_mode_object *prop_obj;
+ struct drm_property *property;
+ int i;
+
+ arg_obj = drm_mode_object_find(dev, obj_id, obj_type);
+ if (!arg_obj)
+ return -ENOENT;
+ if (!arg_obj->properties)
+ return -EINVAL;
+
+ for (i = 0; i < arg_obj->properties->count; i++)
+ if (arg_obj->properties->ids[i] == prop_id)
+ break;
+
+ if (i == arg_obj->properties->count)
+ return -EINVAL;
+
+ prop_obj = drm_mode_object_find(dev, prop_id,
+ DRM_MODE_OBJECT_PROPERTY);
+ if (!prop_obj)
+ return -ENOENT;
+ property = obj_to_property(prop_obj);
+
+ return drm_mode_set_obj_prop(dev, arg_obj, state, property,
+ value, blob_data);
+}
+
int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -3392,57 +3447,35 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_mode_obj_set_property *arg = data;
- struct drm_mode_object *arg_obj;
- struct drm_mode_object *prop_obj;
- struct drm_property *property;
+ void *state;
int ret = -EINVAL;
- int i;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
drm_modeset_lock_all(dev);
- arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
- if (!arg_obj) {
- ret = -ENOENT;
- goto out;
+ state = dev->driver->atomic_begin(dev, 0);
+ if (IS_ERR(state)) {
+ ret = PTR_ERR(state);
+ goto out_unlock;
}
- if (!arg_obj->properties)
- goto out;
-
- for (i = 0; i < arg_obj->properties->count; i++)
- if (arg_obj->properties->ids[i] == arg->prop_id)
- break;
- if (i == arg_obj->properties->count)
+ ret = drm_mode_set_obj_prop_id(dev, state,
+ arg->obj_id, arg->obj_type,
+ arg->prop_id, arg->value, NULL);
+ if (ret)
goto out;
- prop_obj = drm_mode_object_find(dev, arg->prop_id,
- DRM_MODE_OBJECT_PROPERTY);
- if (!prop_obj) {
- ret = -ENOENT;
- goto out;
- }
- property = obj_to_property(prop_obj);
-
- if (!drm_property_change_is_valid(property, arg->value))
+ ret = dev->driver->atomic_check(dev, state);
+ if (ret)
goto out;
- switch (arg_obj->type) {
- case DRM_MODE_OBJECT_CONNECTOR:
- ret = drm_mode_connector_set_obj_prop(arg_obj, property,
- arg->value);
- break;
- case DRM_MODE_OBJECT_CRTC:
- ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
- break;
- case DRM_MODE_OBJECT_PLANE:
- ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
- break;
- }
+ ret = dev->driver->atomic_commit(dev, state);
out:
+ dev->driver->atomic_end(dev, state);
+out_unlock:
drm_modeset_unlock_all(dev);
return ret;
}
@@ -254,8 +254,10 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
}
static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
struct drm_device *dev = crtc->dev;
struct exynos_drm_private *dev_priv = dev->dev_private;
@@ -13,6 +13,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/exynos_drm.h>
@@ -269,6 +270,12 @@ static struct drm_driver exynos_drm_driver = {
.dumb_create = exynos_drm_gem_dumb_create,
.dumb_map_offset = exynos_drm_gem_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = exynos_dmabuf_prime_export,
@@ -217,8 +217,10 @@ static void exynos_plane_destroy(struct drm_plane *plane)
}
static int exynos_plane_set_property(struct drm_plane *plane,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
struct drm_device *dev = plane->dev;
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
@@ -212,8 +212,10 @@ static int cdv_intel_crt_get_modes(struct drm_connector *connector)
}
static int cdv_intel_crt_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
return 0;
}
@@ -1644,8 +1644,10 @@ cdv_intel_dp_detect_audio(struct drm_connector *connector)
static int
cdv_intel_dp_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
struct drm_psb_private *dev_priv = connector->dev->dev_private;
struct gma_encoder *encoder = gma_attached_encoder(connector);
@@ -157,8 +157,10 @@ static enum drm_connector_status cdv_hdmi_detect(
}
static int cdv_hdmi_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
struct drm_encoder *encoder = connector->encoder;
@@ -452,8 +452,10 @@ static void cdv_intel_lvds_destroy(struct drm_connector *connector)
}
static int cdv_intel_lvds_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
struct drm_encoder *encoder = connector->encoder;
@@ -243,8 +243,10 @@ mdfld_dsi_connector_detect(struct drm_connector *connector, bool force)
}
static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
struct drm_encoder *encoder = connector->encoder;
@@ -676,6 +676,13 @@ static struct drm_driver driver = {
.preclose = psb_driver_preclose,
.postclose = psb_driver_close,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
+
.gem_free_object = psb_gem_free_object,
.gem_vm_ops = &psb_gem_vm_ops,
.dumb_create = psb_gem_dumb_create,
@@ -25,6 +25,7 @@
#include <drm/drmP.h>
#include <drm/drm_global.h>
#include <drm/gma_drm.h>
+#include <drm/drm_atomic_helper.h>
#include "psb_reg.h"
#include "psb_intel_drv.h"
#include "gma_display.h"
@@ -261,8 +261,10 @@ extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
extern int psb_intel_lvds_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode);
extern int psb_intel_lvds_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value);
+ uint64_t value,
+ void *blob_data);
extern void psb_intel_lvds_destroy(struct drm_connector *connector);
extern const struct drm_encoder_funcs psb_intel_lvds_enc_funcs;
@@ -569,8 +569,10 @@ void psb_intel_lvds_destroy(struct drm_connector *connector)
}
int psb_intel_lvds_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
struct drm_encoder *encoder = connector->encoder;
@@ -1705,8 +1705,10 @@ static bool psb_intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
static int
psb_intel_sdvo_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
struct psb_intel_sdvo_connector *psb_intel_sdvo_connector = to_psb_intel_sdvo_connector(connector);
@@ -978,6 +978,14 @@ static struct drm_driver driver = {
.dumb_create = i915_gem_dumb_create,
.dumb_map_offset = i915_gem_mmap_gtt,
.dumb_destroy = drm_gem_dumb_destroy,
+
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
+
.ioctls = i915_ioctls,
.fops = &i915_driver_fops,
.name = DRIVER_NAME,
@@ -699,8 +699,10 @@ static int intel_crt_get_modes(struct drm_connector *connector)
}
static int intel_crt_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
return 0;
}
@@ -3160,8 +3160,10 @@ intel_dp_detect_audio(struct drm_connector *connector)
static int
intel_dp_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -31,6 +31,7 @@
#include "i915_drv.h"
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_dp_helper.h>
@@ -1004,8 +1004,10 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
static int
intel_hdmi_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct intel_digital_port *intel_dig_port =
@@ -482,8 +482,10 @@ static void intel_lvds_destroy(struct drm_connector *connector)
}
static int intel_lvds_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_device *dev = connector->dev;
@@ -2032,8 +2032,10 @@ static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
static int
intel_sdvo_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
@@ -1439,8 +1439,9 @@ intel_tv_destroy(struct drm_connector *connector)
static int
-intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
- uint64_t val)
+intel_tv_set_property(struct drm_connector *connector, void *state,
+ struct drm_property *property,
+ uint64_t val, void *blob_data)
{
struct drm_device *dev = connector->dev;
struct intel_tv *intel_tv = intel_attached_tv(connector);
@@ -103,6 +103,13 @@ static struct drm_driver driver = {
.dumb_create = mgag200_dumb_create,
.dumb_map_offset = mgag200_dumb_mmap_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
};
static struct pci_driver mgag200_pci_driver = {
@@ -16,6 +16,7 @@
#include <video/vga.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
@@ -424,8 +424,8 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb);
}
-static int mdp4_crtc_set_property(struct drm_crtc *crtc,
- struct drm_property *property, uint64_t val)
+static int mdp4_crtc_set_property(struct drm_crtc *crtc, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data)
{
// XXX
return -EINVAL;
@@ -84,8 +84,8 @@ void mdp4_plane_install_properties(struct drm_plane *plane,
// XXX
}
-int mdp4_plane_set_property(struct drm_plane *plane,
- struct drm_property *property, uint64_t val)
+int mdp4_plane_set_property(struct drm_plane *plane, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data)
{
// XXX
return -EINVAL;
@@ -734,6 +734,12 @@ static struct drm_driver msm_driver = {
.gem_prime_import_sg_table = msm_gem_prime_import_sg_table,
.gem_prime_vmap = msm_gem_prime_vmap,
.gem_prime_vunmap = msm_gem_prime_vunmap,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = msm_debugfs_init,
.debugfs_cleanup = msm_debugfs_cleanup,
@@ -40,6 +40,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/msm_drm.h>
struct msm_kms;
@@ -208,9 +208,9 @@ nv10_set_params(struct nouveau_plane *plane)
}
static int
-nv10_set_property(struct drm_plane *plane,
+nv10_set_property(struct drm_plane *plane, void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value, void *blob_data)
{
struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
@@ -447,7 +447,8 @@ nouveau_connector_force(struct drm_connector *connector)
static int
nouveau_connector_set_property(struct drm_connector *connector,
- struct drm_property *property, uint64_t value)
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data)
{
struct nouveau_display *disp = nouveau_display(connector->dev);
struct nouveau_connector *nv_connector = nouveau_connector(connector);
@@ -822,6 +822,13 @@ driver = {
.dumb_map_offset = nouveau_display_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
+
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
#ifdef GIT_REVISION
@@ -29,6 +29,7 @@
#include <subdev/vm.h>
#include <drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/nouveau_drm.h>
#include <drm/ttm/ttm_bo_api.h>
@@ -362,8 +362,8 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
return 0;
}
-static int omap_crtc_set_property(struct drm_crtc *crtc,
- struct drm_property *property, uint64_t val)
+static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_drm_private *priv = crtc->dev->dev_private;
@@ -373,7 +373,8 @@ static int omap_crtc_set_property(struct drm_crtc *crtc,
!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
}
- return omap_plane_set_property(omap_crtc->plane, property, val);
+ return omap_plane_set_property(omap_crtc->plane, state,
+ property, val, blob_data);
}
static const struct drm_crtc_funcs omap_crtc_funcs = {
@@ -625,6 +625,12 @@ static struct drm_driver omap_drm_driver = {
.dumb_create = omap_gem_dumb_create,
.dumb_map_offset = omap_gem_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
.ioctls = ioctls,
.num_ioctls = DRM_OMAP_NUM_IOCTLS,
.fops = &omapdriver_fops,
@@ -25,6 +25,7 @@
#include <linux/types.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/omap_drm.h>
#include <linux/platform_data/omap_drm.h>
@@ -173,8 +174,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
void (*fxn)(void *), void *arg);
void omap_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj);
-int omap_plane_set_property(struct drm_plane *plane,
- struct drm_property *property, uint64_t val);
+int omap_plane_set_property(struct drm_plane *plane, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data);
struct drm_encoder *omap_encoder_init(struct drm_device *dev,
struct omap_dss_device *dssdev);
@@ -327,8 +327,8 @@ 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,
- struct drm_property *property, uint64_t val)
+int omap_plane_set_property(struct drm_plane *plane, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data)
{
struct omap_plane *omap_plane = to_omap_plane(plane);
struct omap_drm_private *priv = plane->dev->dev_private;
@@ -812,8 +812,10 @@ static enum drm_connector_status qxl_conn_detect(
}
static int qxl_conn_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
DRM_DEBUG("\n");
return 0;
@@ -34,6 +34,7 @@
#include "drmP.h"
#include "drm/drm.h"
#include "drm_crtc_helper.h"
+#include "drm_atomic_helper.h"
#include "qxl_drv.h"
#include "qxl_object.h"
@@ -221,6 +222,14 @@ static struct drm_driver qxl_driver = {
.dumb_create = qxl_mode_dumb_create,
.dumb_map_offset = qxl_mode_dumb_mmap,
.dumb_destroy = drm_gem_dumb_destroy,
+
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
+
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = qxl_debugfs_init,
.debugfs_cleanup = qxl_debugfs_takedown,
@@ -368,8 +368,9 @@ static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_conn
}
}
-static int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
- uint64_t val)
+static int radeon_connector_set_property(struct drm_connector *connector,
+ void *state, struct drm_property *property,
+ uint64_t val, void *blob_data)
{
struct drm_device *dev = connector->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -691,8 +692,10 @@ static void radeon_connector_destroy(struct drm_connector *connector)
}
static int radeon_lvds_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
struct drm_device *dev = connector->dev;
struct radeon_encoder *radeon_encoder;
@@ -34,6 +34,7 @@
#include "radeon_drv.h"
#include <drm/drm_pciids.h>
+#include <drm/drm_atomic_helper.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
@@ -548,6 +549,14 @@ static struct drm_driver kms_driver = {
.dumb_create = radeon_mode_dumb_create,
.dumb_map_offset = radeon_mode_dumb_mmap,
.dumb_destroy = drm_gem_dumb_destroy,
+
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
+
.fops = &radeon_driver_kms_fops,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
@@ -21,6 +21,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
@@ -175,6 +176,12 @@ static struct drm_driver rcar_du_driver = {
.dumb_create = rcar_du_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
.fops = &rcar_du_fops,
.name = "rcar-du",
.desc = "Renesas R-Car Display Unit",
@@ -396,8 +396,10 @@ done:
}
static int rcar_du_plane_set_property(struct drm_plane *plane,
+ void *state,
struct drm_property *property,
- uint64_t value)
+ uint64_t value,
+ void *blob_data)
{
struct rcar_du_plane *rplane = to_rcar_plane(plane);
struct rcar_du_group *rgrp = rplane->group;
@@ -21,6 +21,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include "shmob_drm_crtc.h"
@@ -285,6 +286,12 @@ static struct drm_driver shmob_drm_driver = {
.dumb_create = drm_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
.fops = &shmob_drm_fops,
.name = "shmob-drm",
.desc = "Renesas SH Mobile DRM",
@@ -519,6 +519,12 @@ static struct drm_driver tilcdc_driver = {
.dumb_create = drm_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = tilcdc_debugfs_init,
.debugfs_cleanup = tilcdc_debugfs_cleanup,
@@ -31,6 +31,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
@@ -206,7 +206,8 @@ static struct drm_encoder *slave_connector_best_encoder(
}
static int slave_connector_set_property(struct drm_connector *connector,
- struct drm_property *property, uint64_t value)
+ void *state, struct drm_property *property,
+ uint64_t value, void *blob_data)
{
struct drm_encoder *encoder = to_slave_connector(connector)->encoder;
return get_slave_funcs(encoder)->set_property(encoder,
@@ -115,9 +115,9 @@ udl_best_single_encoder(struct drm_connector *connector)
return encoder;
}
-static int udl_connector_set_property(struct drm_connector *connector,
- struct drm_property *property,
- uint64_t val)
+static int udl_connector_set_property(struct drm_connector *connector,
+ void *state, struct drm_property *property,
+ uint64_t val, void *blob_data)
{
return 0;
}
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <drm/drm_usb.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include "udl_drv.h"
static struct drm_driver driver;
@@ -88,6 +89,13 @@ static struct drm_driver driver = {
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_import = udl_gem_prime_import,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
+
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
@@ -1235,6 +1235,13 @@ static struct drm_driver driver = {
.dumb_map_offset = vmw_dumb_map_offset,
.dumb_destroy = vmw_dumb_destroy,
+ .atomic_begin = drm_atomic_helper_begin,
+ .atomic_set_event = drm_atomic_helper_set_event,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .atomic_end = drm_atomic_helper_end,
+ .atomic_helpers = &drm_atomic_helper_funcs,
+
.fops = &vmwgfx_driver_fops,
.name = VMWGFX_DRIVER_NAME,
.desc = VMWGFX_DRIVER_DESC,
@@ -30,6 +30,7 @@
#include "vmwgfx_reg.h"
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/vmwgfx_drm.h>
#include <drm/drm_hashtab.h>
#include <linux/suspend.h>
@@ -1994,8 +1994,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
}
int vmw_du_connector_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t val)
+ uint64_t val,
+ void *blob_data)
{
return 0;
}
@@ -141,8 +141,10 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force);
int vmw_du_connector_fill_modes(struct drm_connector *connector,
uint32_t max_width, uint32_t max_height);
int vmw_du_connector_set_property(struct drm_connector *connector,
+ void *state,
struct drm_property *property,
- uint64_t val);
+ uint64_t val,
+ void *blob_data);
/*
@@ -973,6 +973,83 @@ struct drm_driver {
struct drm_device *dev,
uint32_t handle);
+ /*
+ * Atomic functions:
+ */
+
+ /**
+ * atomic_begin - start a sequence of atomic updates
+ * @dev: DRM device
+ * @flags: the modifier flags that userspace has requested
+ *
+ * Begin a sequence of atomic property sets. Returns a driver
+ * private state object that is passed back into the various
+ * object's set_property() fxns, and into the remainder of the
+ * atomic funcs. The state object should accumulate the changes
+ * from one o more set_property()'s. At the end, the state can
+ * be checked, and optionally committed.
+ *
+ * RETURNS
+ * a driver private state object, which is passed back in to
+ * the various other atomic fxns, or error (such as -EBUSY if
+ * there is still a pending async update)
+ */
+ void *(*atomic_begin)(struct drm_device *dev, uint32_t flags);
+
+ /**
+ * atomic_set_event - set a pending event on mode object
+ * @dev: DRM device
+ * @state: the driver private state object
+ * @obj: the object to set the event on
+ * @event: the event to send back
+ *
+ * Set pending event for an update on the specified object. The
+ * event is to be sent back to userspace after the update completes.
+ */
+ int (*atomic_set_event)(struct drm_device *dev,
+ void *state, struct drm_mode_object *obj,
+ struct drm_pending_vblank_event *event);
+
+ /**
+ * atomic_check - validate state object
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Check the state object to see if the requested state is
+ * physically possible.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+ int (*atomic_check)(struct drm_device *dev, void *state);
+
+ /**
+ * atomic_commit - commit state
+ * @dev: DRM device
+ * @state: the driver private state object
+ *
+ * Commit the state. This will only be called if atomic_check()
+ * succeeds.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+ int (*atomic_commit)(struct drm_device *dev, void *state);
+
+ /**
+ * atomic_end - conclude the atomic update
+ * @dev: DRM device
+ * @state: the driver private state object
+
+ * Release resources associated with the state object.
+ */
+ void (*atomic_end)(struct drm_device *dev, void *state);
+
+ /**
+ * Helpers used by drm-atomic-helpers
+ */
+ const void *atomic_helpers;
+
/* Driver private ops for this object */
const struct vm_operations_struct *gem_vm_ops;
new file mode 100644
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * 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 DRM_ATOMIC_HELPER_H_
+#define DRM_ATOMIC_HELPER_H_
+
+/**
+ * DOC: atomic state helpers
+ *
+ * Base helper atomic state and functions. Drivers are free to either
+ * use these as-is, extend them, or completely replace them, in order
+ * to implement the atomic KMS API.
+ *
+ * A naive driver, with no special constraints or hw support for atomic
+ * updates may simply add the following to their driver struct:
+ *
+ * .atomic_begin = drm_atomic_helper_begin,
+ * .atomic_set_event = drm_atomic_helper_set_event,
+ * .atomic_check = drm_atomic_helper_check,
+ * .atomic_commit = drm_atomic_helper_commit,
+ * .atomic_end = drm_atomic_helper_end,
+ * .atomic_helpers = &drm_atomic_helper_funcs,
+ *
+ * In addition, if you're plane/crtc doesn't already have it's own custom
+ * properties, then add to your plane/crtc_funcs:
+ *
+ * .set_property = drm_atomic_helper_{plane,crtc}_set_property,
+ *
+ * Unlike the crtc helpers, it is intended that the atomic helpers can be
+ * used piecemeal by the drivers, either using all or overriding parts as
+ * needed.
+ *
+ * A driver which can have (for example) conflicting modes across multiple
+ * crtcs (for example, bandwidth limitations or clock/pll configuration
+ * restrictions), can simply wrap drm_atomic_helper_check() with their own
+ * driver specific .atomic_check() function.
+ *
+ * A driver which can support true atomic updates can wrap
+ * drm_atomic_helper_commit().
+ *
+ * A driver with custom properties should override the appropriate get_state(),
+ * check_state(), and commit_state() functions in .atomic_helpers if it uses
+ * the drm-atomic-helpers. Otherwise it is free to use &drm_atomic_helper_funcs
+ * as-is.
+ */
+
+/**
+ * struct drm_atomic_helper_funcs - helper funcs used by the atomic helpers
+ */
+struct drm_atomic_helper_funcs {
+ int dummy; /* for now */
+};
+
+const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
+
+void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags);
+int drm_atomic_helper_set_event(struct drm_device *dev,
+ void *state, struct drm_mode_object *obj,
+ struct drm_pending_vblank_event *event);
+int drm_atomic_helper_check(struct drm_device *dev, void *state);
+int drm_atomic_helper_commit(struct drm_device *dev, void *state);
+void drm_atomic_helper_end(struct drm_device *dev, void *state);
+
+/**
+ * struct drm_atomic_helper_state - the state object used by atomic helpers
+ */
+struct drm_atomic_helper_state {
+ struct kref refcount;
+ struct drm_device *dev;
+ uint32_t flags;
+};
+
+static inline void
+drm_atomic_helper_state_reference(struct drm_atomic_helper_state *state)
+{
+ kref_get(&state->refcount);
+}
+
+static inline void
+drm_atomic_helper_state_unreference(struct drm_atomic_helper_state *state)
+{
+ void _drm_atomic_helper_state_free(struct kref *kref);
+ kref_put(&state->refcount, _drm_atomic_helper_state_free);
+}
+
+#endif /* DRM_ATOMIC_HELPER_H_ */
@@ -376,8 +376,9 @@ struct drm_crtc_funcs {
struct drm_pending_vblank_event *event,
uint32_t flags);
- int (*set_property)(struct drm_crtc *crtc,
- struct drm_property *property, uint64_t val);
+ int (*set_property)(struct drm_crtc *crtc, void *state,
+ struct drm_property *property, uint64_t val,
+ void *blob_data);
};
/**
@@ -487,8 +488,8 @@ struct drm_connector_funcs {
enum drm_connector_status (*detect)(struct drm_connector *connector,
bool force);
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
- int (*set_property)(struct drm_connector *connector, struct drm_property *property,
- uint64_t val);
+ int (*set_property)(struct drm_connector *connector, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data);
void (*destroy)(struct drm_connector *connector);
void (*force)(struct drm_connector *connector);
};
@@ -659,8 +660,9 @@ struct drm_plane_funcs {
int (*disable_plane)(struct drm_plane *plane);
void (*destroy)(struct drm_plane *plane);
- int (*set_property)(struct drm_plane *plane,
- struct drm_property *property, uint64_t val);
+ int (*set_property)(struct drm_plane *plane, void *state,
+ struct drm_property *property, uint64_t val,
+ void *blob_data);
};
/**