xref: /openbsd-src/sys/dev/pci/drm/drm_mode_object.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
17f4dd379Sjsg /*
27f4dd379Sjsg  * Copyright (c) 2016 Intel Corporation
37f4dd379Sjsg  *
47f4dd379Sjsg  * Permission to use, copy, modify, distribute, and sell this software and its
57f4dd379Sjsg  * documentation for any purpose is hereby granted without fee, provided that
67f4dd379Sjsg  * the above copyright notice appear in all copies and that both that copyright
77f4dd379Sjsg  * notice and this permission notice appear in supporting documentation, and
87f4dd379Sjsg  * that the name of the copyright holders not be used in advertising or
97f4dd379Sjsg  * publicity pertaining to distribution of the software without specific,
107f4dd379Sjsg  * written prior permission.  The copyright holders make no representations
117f4dd379Sjsg  * about the suitability of this software for any purpose.  It is provided "as
127f4dd379Sjsg  * is" without express or implied warranty.
137f4dd379Sjsg  *
147f4dd379Sjsg  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
157f4dd379Sjsg  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
167f4dd379Sjsg  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
177f4dd379Sjsg  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
187f4dd379Sjsg  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
197f4dd379Sjsg  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
207f4dd379Sjsg  * OF THIS SOFTWARE.
217f4dd379Sjsg  */
227f4dd379Sjsg 
237f4dd379Sjsg #include <linux/export.h>
24c349dbc7Sjsg #include <linux/uaccess.h>
251bb76ff1Sjsg #include <linux/backlight.h>
26c349dbc7Sjsg 
277f4dd379Sjsg #include <drm/drm_atomic.h>
28c349dbc7Sjsg #include <drm/drm_drv.h>
29c349dbc7Sjsg #include <drm/drm_device.h>
30c349dbc7Sjsg #include <drm/drm_file.h>
31c349dbc7Sjsg #include <drm/drm_mode_object.h>
32c349dbc7Sjsg #include <drm/drm_print.h>
337f4dd379Sjsg 
347f4dd379Sjsg #include "drm_crtc_internal.h"
357f4dd379Sjsg 
367f4dd379Sjsg /*
377f4dd379Sjsg  * Internal function to assign a slot in the object idr and optionally
387f4dd379Sjsg  * register the object into the idr.
397f4dd379Sjsg  */
__drm_mode_object_add(struct drm_device * dev,struct drm_mode_object * obj,uint32_t obj_type,bool register_obj,void (* obj_free_cb)(struct kref * kref))407f4dd379Sjsg int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
417f4dd379Sjsg 			  uint32_t obj_type, bool register_obj,
427f4dd379Sjsg 			  void (*obj_free_cb)(struct kref *kref))
437f4dd379Sjsg {
447f4dd379Sjsg 	int ret;
457f4dd379Sjsg 
46c349dbc7Sjsg 	WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb);
47c349dbc7Sjsg 
487f4dd379Sjsg 	mutex_lock(&dev->mode_config.idr_mutex);
49c349dbc7Sjsg 	ret = idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL,
50c349dbc7Sjsg 			1, 0, GFP_KERNEL);
517f4dd379Sjsg 	if (ret >= 0) {
527f4dd379Sjsg 		/*
537f4dd379Sjsg 		 * Set up the object linking under the protection of the idr
547f4dd379Sjsg 		 * lock so that other users can't see inconsistent state.
557f4dd379Sjsg 		 */
567f4dd379Sjsg 		obj->id = ret;
577f4dd379Sjsg 		obj->type = obj_type;
587f4dd379Sjsg 		if (obj_free_cb) {
597f4dd379Sjsg 			obj->free_cb = obj_free_cb;
607f4dd379Sjsg 			kref_init(&obj->refcount);
617f4dd379Sjsg 		}
627f4dd379Sjsg 	}
637f4dd379Sjsg 	mutex_unlock(&dev->mode_config.idr_mutex);
647f4dd379Sjsg 
657f4dd379Sjsg 	return ret < 0 ? ret : 0;
667f4dd379Sjsg }
677f4dd379Sjsg 
687f4dd379Sjsg /**
697f4dd379Sjsg  * drm_mode_object_add - allocate a new modeset identifier
707f4dd379Sjsg  * @dev: DRM device
717f4dd379Sjsg  * @obj: object pointer, used to generate unique ID
727f4dd379Sjsg  * @obj_type: object type
737f4dd379Sjsg  *
747f4dd379Sjsg  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
757f4dd379Sjsg  * for tracking modes, CRTCs and connectors.
767f4dd379Sjsg  *
777f4dd379Sjsg  * Returns:
787f4dd379Sjsg  * Zero on success, error code on failure.
797f4dd379Sjsg  */
drm_mode_object_add(struct drm_device * dev,struct drm_mode_object * obj,uint32_t obj_type)807f4dd379Sjsg int drm_mode_object_add(struct drm_device *dev,
817f4dd379Sjsg 			struct drm_mode_object *obj, uint32_t obj_type)
827f4dd379Sjsg {
837f4dd379Sjsg 	return __drm_mode_object_add(dev, obj, obj_type, true, NULL);
847f4dd379Sjsg }
857f4dd379Sjsg 
drm_mode_object_register(struct drm_device * dev,struct drm_mode_object * obj)867f4dd379Sjsg void drm_mode_object_register(struct drm_device *dev,
877f4dd379Sjsg 			      struct drm_mode_object *obj)
887f4dd379Sjsg {
897f4dd379Sjsg 	mutex_lock(&dev->mode_config.idr_mutex);
90c349dbc7Sjsg 	idr_replace(&dev->mode_config.object_idr, obj, obj->id);
917f4dd379Sjsg 	mutex_unlock(&dev->mode_config.idr_mutex);
927f4dd379Sjsg }
937f4dd379Sjsg 
947f4dd379Sjsg /**
955ca02815Sjsg  * drm_mode_object_unregister - free a modeset identifier
967f4dd379Sjsg  * @dev: DRM device
977f4dd379Sjsg  * @object: object to free
987f4dd379Sjsg  *
997f4dd379Sjsg  * Free @id from @dev's unique identifier pool.
1007f4dd379Sjsg  * This function can be called multiple times, and guards against
1017f4dd379Sjsg  * multiple removals.
1027f4dd379Sjsg  * These modeset identifiers are _not_ reference counted. Hence don't use this
1037f4dd379Sjsg  * for reference counted modeset objects like framebuffers.
1047f4dd379Sjsg  */
drm_mode_object_unregister(struct drm_device * dev,struct drm_mode_object * object)1057f4dd379Sjsg void drm_mode_object_unregister(struct drm_device *dev,
1067f4dd379Sjsg 				struct drm_mode_object *object)
1077f4dd379Sjsg {
108c349dbc7Sjsg 	WARN_ON(!dev->driver->load && dev->registered && !object->free_cb);
109c349dbc7Sjsg 
1107f4dd379Sjsg 	mutex_lock(&dev->mode_config.idr_mutex);
1117f4dd379Sjsg 	if (object->id) {
112c349dbc7Sjsg 		idr_remove(&dev->mode_config.object_idr, object->id);
1137f4dd379Sjsg 		object->id = 0;
1147f4dd379Sjsg 	}
1157f4dd379Sjsg 	mutex_unlock(&dev->mode_config.idr_mutex);
1167f4dd379Sjsg }
1177f4dd379Sjsg 
1187f4dd379Sjsg /**
1195ca02815Sjsg  * drm_mode_object_lease_required - check types which must be leased to be used
1207f4dd379Sjsg  * @type: type of object
1217f4dd379Sjsg  *
1227f4dd379Sjsg  * Returns whether the provided type of drm_mode_object must
1237f4dd379Sjsg  * be owned or leased to be used by a process.
1247f4dd379Sjsg  */
drm_mode_object_lease_required(uint32_t type)1257f4dd379Sjsg bool drm_mode_object_lease_required(uint32_t type)
1267f4dd379Sjsg {
1277f4dd379Sjsg 	switch(type) {
1287f4dd379Sjsg 	case DRM_MODE_OBJECT_CRTC:
1297f4dd379Sjsg 	case DRM_MODE_OBJECT_CONNECTOR:
1307f4dd379Sjsg 	case DRM_MODE_OBJECT_PLANE:
1317f4dd379Sjsg 		return true;
1327f4dd379Sjsg 	default:
1337f4dd379Sjsg 		return false;
1347f4dd379Sjsg 	}
1357f4dd379Sjsg }
1367f4dd379Sjsg 
__drm_mode_object_find(struct drm_device * dev,struct drm_file * file_priv,uint32_t id,uint32_t type)1377f4dd379Sjsg struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
1387f4dd379Sjsg 					       struct drm_file *file_priv,
1397f4dd379Sjsg 					       uint32_t id, uint32_t type)
1407f4dd379Sjsg {
1417f4dd379Sjsg 	struct drm_mode_object *obj = NULL;
1427f4dd379Sjsg 
1437f4dd379Sjsg 	mutex_lock(&dev->mode_config.idr_mutex);
144c349dbc7Sjsg 	obj = idr_find(&dev->mode_config.object_idr, id);
1457f4dd379Sjsg 	if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type)
1467f4dd379Sjsg 		obj = NULL;
1477f4dd379Sjsg 	if (obj && obj->id != id)
1487f4dd379Sjsg 		obj = NULL;
1497f4dd379Sjsg 
1507f4dd379Sjsg #ifdef notyet
1517f4dd379Sjsg 	if (obj && drm_mode_object_lease_required(obj->type) &&
152*f005ef32Sjsg 	    !_drm_lease_held(file_priv, obj->id)) {
153*f005ef32Sjsg 		drm_dbg_kms(dev, "[OBJECT:%d] not included in lease", id);
1547f4dd379Sjsg 		obj = NULL;
155*f005ef32Sjsg 	}
1567f4dd379Sjsg #endif
1577f4dd379Sjsg 
1587f4dd379Sjsg 	if (obj && obj->free_cb) {
1597f4dd379Sjsg 		if (!kref_get_unless_zero(&obj->refcount))
1607f4dd379Sjsg 			obj = NULL;
1617f4dd379Sjsg 	}
1627f4dd379Sjsg 	mutex_unlock(&dev->mode_config.idr_mutex);
1637f4dd379Sjsg 
1647f4dd379Sjsg 	return obj;
1657f4dd379Sjsg }
1667f4dd379Sjsg 
1677f4dd379Sjsg /**
1687f4dd379Sjsg  * drm_mode_object_find - look up a drm object with static lifetime
1697f4dd379Sjsg  * @dev: drm device
1707f4dd379Sjsg  * @file_priv: drm file
1717f4dd379Sjsg  * @id: id of the mode object
1727f4dd379Sjsg  * @type: type of the mode object
1737f4dd379Sjsg  *
1747f4dd379Sjsg  * This function is used to look up a modeset object. It will acquire a
1757f4dd379Sjsg  * reference for reference counted objects. This reference must be dropped again
1767f4dd379Sjsg  * by callind drm_mode_object_put().
1777f4dd379Sjsg  */
drm_mode_object_find(struct drm_device * dev,struct drm_file * file_priv,uint32_t id,uint32_t type)1787f4dd379Sjsg struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
1797f4dd379Sjsg 		struct drm_file *file_priv,
1807f4dd379Sjsg 		uint32_t id, uint32_t type)
1817f4dd379Sjsg {
1827f4dd379Sjsg 	struct drm_mode_object *obj = NULL;
1837f4dd379Sjsg 
1847f4dd379Sjsg 	obj = __drm_mode_object_find(dev, file_priv, id, type);
1857f4dd379Sjsg 	return obj;
1867f4dd379Sjsg }
1877f4dd379Sjsg EXPORT_SYMBOL(drm_mode_object_find);
1887f4dd379Sjsg 
1897f4dd379Sjsg /**
1907f4dd379Sjsg  * drm_mode_object_put - release a mode object reference
1917f4dd379Sjsg  * @obj: DRM mode object
1927f4dd379Sjsg  *
1937f4dd379Sjsg  * This function decrements the object's refcount if it is a refcounted modeset
1947f4dd379Sjsg  * object. It is a no-op on any other object. This is used to drop references
1957f4dd379Sjsg  * acquired with drm_mode_object_get().
1967f4dd379Sjsg  */
drm_mode_object_put(struct drm_mode_object * obj)1977f4dd379Sjsg void drm_mode_object_put(struct drm_mode_object *obj)
1987f4dd379Sjsg {
1997f4dd379Sjsg 	if (obj->free_cb) {
2007f4dd379Sjsg 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
2017f4dd379Sjsg 		kref_put(&obj->refcount, obj->free_cb);
2027f4dd379Sjsg 	}
2037f4dd379Sjsg }
2047f4dd379Sjsg EXPORT_SYMBOL(drm_mode_object_put);
2057f4dd379Sjsg 
2067f4dd379Sjsg /**
2077f4dd379Sjsg  * drm_mode_object_get - acquire a mode object reference
2087f4dd379Sjsg  * @obj: DRM mode object
2097f4dd379Sjsg  *
2107f4dd379Sjsg  * This function increments the object's refcount if it is a refcounted modeset
2117f4dd379Sjsg  * object. It is a no-op on any other object. References should be dropped again
2127f4dd379Sjsg  * by calling drm_mode_object_put().
2137f4dd379Sjsg  */
drm_mode_object_get(struct drm_mode_object * obj)2147f4dd379Sjsg void drm_mode_object_get(struct drm_mode_object *obj)
2157f4dd379Sjsg {
2167f4dd379Sjsg 	if (obj->free_cb) {
2177f4dd379Sjsg 		DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
2187f4dd379Sjsg 		kref_get(&obj->refcount);
2197f4dd379Sjsg 	}
2207f4dd379Sjsg }
2217f4dd379Sjsg EXPORT_SYMBOL(drm_mode_object_get);
2227f4dd379Sjsg 
2237f4dd379Sjsg /**
2247f4dd379Sjsg  * drm_object_attach_property - attach a property to a modeset object
2257f4dd379Sjsg  * @obj: drm modeset object
2267f4dd379Sjsg  * @property: property to attach
2277f4dd379Sjsg  * @init_val: initial value of the property
2287f4dd379Sjsg  *
2297f4dd379Sjsg  * This attaches the given property to the modeset object with the given initial
2307f4dd379Sjsg  * value. Currently this function cannot fail since the properties are stored in
2317f4dd379Sjsg  * a statically sized array.
232c349dbc7Sjsg  *
233c349dbc7Sjsg  * Note that all properties must be attached before the object itself is
234c349dbc7Sjsg  * registered and accessible from userspace.
2357f4dd379Sjsg  */
drm_object_attach_property(struct drm_mode_object * obj,struct drm_property * property,uint64_t init_val)2367f4dd379Sjsg void drm_object_attach_property(struct drm_mode_object *obj,
2377f4dd379Sjsg 				struct drm_property *property,
2387f4dd379Sjsg 				uint64_t init_val)
2397f4dd379Sjsg {
2407f4dd379Sjsg 	int count = obj->properties->count;
241c349dbc7Sjsg 	struct drm_device *dev = property->dev;
242c349dbc7Sjsg 
243c349dbc7Sjsg 
244c349dbc7Sjsg 	if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
245c349dbc7Sjsg 		struct drm_connector *connector = obj_to_connector(obj);
246c349dbc7Sjsg 
247c349dbc7Sjsg 		WARN_ON(!dev->driver->load &&
248c349dbc7Sjsg 			connector->registration_state == DRM_CONNECTOR_REGISTERED);
249c349dbc7Sjsg 	} else {
250c349dbc7Sjsg 		WARN_ON(!dev->driver->load && dev->registered);
251c349dbc7Sjsg 	}
2527f4dd379Sjsg 
2537f4dd379Sjsg 	if (count == DRM_OBJECT_MAX_PROPERTY) {
2547f4dd379Sjsg 		WARN(1, "Failed to attach object property (type: 0x%x). Please "
2557f4dd379Sjsg 			"increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
2567f4dd379Sjsg 			"you see this message on the same object type.\n",
2577f4dd379Sjsg 			obj->type);
2587f4dd379Sjsg 		return;
2597f4dd379Sjsg 	}
2607f4dd379Sjsg 
2617f4dd379Sjsg 	obj->properties->properties[count] = property;
2627f4dd379Sjsg 	obj->properties->values[count] = init_val;
2637f4dd379Sjsg 	obj->properties->count++;
2647f4dd379Sjsg }
2657f4dd379Sjsg EXPORT_SYMBOL(drm_object_attach_property);
2667f4dd379Sjsg 
2677f4dd379Sjsg /**
2687f4dd379Sjsg  * drm_object_property_set_value - set the value of a property
2697f4dd379Sjsg  * @obj: drm mode object to set property value for
2707f4dd379Sjsg  * @property: property to set
2717f4dd379Sjsg  * @val: value the property should be set to
2727f4dd379Sjsg  *
2737f4dd379Sjsg  * This function sets a given property on a given object. This function only
2747f4dd379Sjsg  * changes the software state of the property, it does not call into the
2757f4dd379Sjsg  * driver's ->set_property callback.
2767f4dd379Sjsg  *
2777f4dd379Sjsg  * Note that atomic drivers should not have any need to call this, the core will
2787f4dd379Sjsg  * ensure consistency of values reported back to userspace through the
2797f4dd379Sjsg  * appropriate ->atomic_get_property callback. Only legacy drivers should call
2807f4dd379Sjsg  * this function to update the tracked value (after clamping and other
2817f4dd379Sjsg  * restrictions have been applied).
2827f4dd379Sjsg  *
2837f4dd379Sjsg  * Returns:
2847f4dd379Sjsg  * Zero on success, error code on failure.
2857f4dd379Sjsg  */
drm_object_property_set_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t val)2867f4dd379Sjsg int drm_object_property_set_value(struct drm_mode_object *obj,
2877f4dd379Sjsg 				  struct drm_property *property, uint64_t val)
2887f4dd379Sjsg {
2897f4dd379Sjsg 	int i;
2907f4dd379Sjsg 
2917f4dd379Sjsg 	WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
2927f4dd379Sjsg 		!(property->flags & DRM_MODE_PROP_IMMUTABLE));
2937f4dd379Sjsg 
2947f4dd379Sjsg 	for (i = 0; i < obj->properties->count; i++) {
2957f4dd379Sjsg 		if (obj->properties->properties[i] == property) {
2967f4dd379Sjsg 			obj->properties->values[i] = val;
2977f4dd379Sjsg 			return 0;
2987f4dd379Sjsg 		}
2997f4dd379Sjsg 	}
3007f4dd379Sjsg 
3017f4dd379Sjsg 	return -EINVAL;
3027f4dd379Sjsg }
3037f4dd379Sjsg EXPORT_SYMBOL(drm_object_property_set_value);
3047f4dd379Sjsg 
__drm_object_property_get_prop_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3051bb76ff1Sjsg static int __drm_object_property_get_prop_value(struct drm_mode_object *obj,
3067f4dd379Sjsg 						struct drm_property *property,
3077f4dd379Sjsg 						uint64_t *val)
3087f4dd379Sjsg {
3097f4dd379Sjsg 	int i;
3107f4dd379Sjsg 
3111bb76ff1Sjsg 	for (i = 0; i < obj->properties->count; i++) {
3121bb76ff1Sjsg 		if (obj->properties->properties[i] == property) {
3131bb76ff1Sjsg 			*val = obj->properties->values[i];
3141bb76ff1Sjsg 			return 0;
3151bb76ff1Sjsg 		}
3161bb76ff1Sjsg 	}
3171bb76ff1Sjsg 
3181bb76ff1Sjsg 	return -EINVAL;
3191bb76ff1Sjsg }
3201bb76ff1Sjsg 
__drm_object_property_get_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3211bb76ff1Sjsg static int __drm_object_property_get_value(struct drm_mode_object *obj,
3221bb76ff1Sjsg 					   struct drm_property *property,
3231bb76ff1Sjsg 					   uint64_t *val)
3241bb76ff1Sjsg {
3251bb76ff1Sjsg 
3267f4dd379Sjsg #ifdef __OpenBSD__
3277f4dd379Sjsg 	if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
3287f4dd379Sjsg 		struct drm_connector *connector = obj_to_connector(obj);
3297f4dd379Sjsg 
3307f4dd379Sjsg 		if (property == connector->backlight_property) {
3317f4dd379Sjsg 			struct backlight_device *bd =
3327f4dd379Sjsg 				connector->backlight_device;
3337f4dd379Sjsg 
3347f4dd379Sjsg 			if (bd->props.type == BACKLIGHT_FIRMWARE)
3357f4dd379Sjsg 				*val = bd->ops->get_brightness(bd);
3367f4dd379Sjsg 			else
3377f4dd379Sjsg 				*val = bd->props.brightness;
3387f4dd379Sjsg 			return 0;
3397f4dd379Sjsg 		}
3407f4dd379Sjsg 	}
3417f4dd379Sjsg #endif
3427f4dd379Sjsg 
3437f4dd379Sjsg 	/* read-only properties bypass atomic mechanism and still store
3447f4dd379Sjsg 	 * their value in obj->properties->values[].. mostly to avoid
3457f4dd379Sjsg 	 * having to deal w/ EDID and similar props in atomic paths:
3467f4dd379Sjsg 	 */
3477f4dd379Sjsg 	if (drm_drv_uses_atomic_modeset(property->dev) &&
3487f4dd379Sjsg 			!(property->flags & DRM_MODE_PROP_IMMUTABLE))
3497f4dd379Sjsg 		return drm_atomic_get_property(obj, property, val);
3507f4dd379Sjsg 
3511bb76ff1Sjsg 	return __drm_object_property_get_prop_value(obj, property, val);
3527f4dd379Sjsg }
3537f4dd379Sjsg 
3547f4dd379Sjsg /**
3557f4dd379Sjsg  * drm_object_property_get_value - retrieve the value of a property
3567f4dd379Sjsg  * @obj: drm mode object to get property value from
3577f4dd379Sjsg  * @property: property to retrieve
3587f4dd379Sjsg  * @val: storage for the property value
3597f4dd379Sjsg  *
3607f4dd379Sjsg  * This function retrieves the softare state of the given property for the given
3617f4dd379Sjsg  * property. Since there is no driver callback to retrieve the current property
3627f4dd379Sjsg  * value this might be out of sync with the hardware, depending upon the driver
3637f4dd379Sjsg  * and property.
3647f4dd379Sjsg  *
3657f4dd379Sjsg  * Atomic drivers should never call this function directly, the core will read
3667f4dd379Sjsg  * out property values through the various ->atomic_get_property callbacks.
3677f4dd379Sjsg  *
3687f4dd379Sjsg  * Returns:
3697f4dd379Sjsg  * Zero on success, error code on failure.
3707f4dd379Sjsg  */
drm_object_property_get_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3717f4dd379Sjsg int drm_object_property_get_value(struct drm_mode_object *obj,
3727f4dd379Sjsg 				  struct drm_property *property, uint64_t *val)
3737f4dd379Sjsg {
3747f4dd379Sjsg 	WARN_ON(drm_drv_uses_atomic_modeset(property->dev));
3757f4dd379Sjsg 
3767f4dd379Sjsg 	return __drm_object_property_get_value(obj, property, val);
3777f4dd379Sjsg }
3787f4dd379Sjsg EXPORT_SYMBOL(drm_object_property_get_value);
3797f4dd379Sjsg 
3801bb76ff1Sjsg /**
3811bb76ff1Sjsg  * drm_object_property_get_default_value - retrieve the default value of a
3821bb76ff1Sjsg  * property when in atomic mode.
3831bb76ff1Sjsg  * @obj: drm mode object to get property value from
3841bb76ff1Sjsg  * @property: property to retrieve
3851bb76ff1Sjsg  * @val: storage for the property value
3861bb76ff1Sjsg  *
3871bb76ff1Sjsg  * This function retrieves the default state of the given property as passed in
3881bb76ff1Sjsg  * to drm_object_attach_property
3891bb76ff1Sjsg  *
3901bb76ff1Sjsg  * Only atomic drivers should call this function directly, as for non-atomic
3911bb76ff1Sjsg  * drivers it will return the current value.
3921bb76ff1Sjsg  *
3931bb76ff1Sjsg  * Returns:
3941bb76ff1Sjsg  * Zero on success, error code on failure.
3951bb76ff1Sjsg  */
drm_object_property_get_default_value(struct drm_mode_object * obj,struct drm_property * property,uint64_t * val)3961bb76ff1Sjsg int drm_object_property_get_default_value(struct drm_mode_object *obj,
3971bb76ff1Sjsg 					  struct drm_property *property,
3981bb76ff1Sjsg 					  uint64_t *val)
3991bb76ff1Sjsg {
4001bb76ff1Sjsg 	WARN_ON(!drm_drv_uses_atomic_modeset(property->dev));
4011bb76ff1Sjsg 
4021bb76ff1Sjsg 	return __drm_object_property_get_prop_value(obj, property, val);
4031bb76ff1Sjsg }
4041bb76ff1Sjsg EXPORT_SYMBOL(drm_object_property_get_default_value);
4051bb76ff1Sjsg 
4067f4dd379Sjsg /* helper for getconnector and getproperties ioctls */
drm_mode_object_get_properties(struct drm_mode_object * obj,bool atomic,uint32_t __user * prop_ptr,uint64_t __user * prop_values,uint32_t * arg_count_props)4077f4dd379Sjsg int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic,
4087f4dd379Sjsg 				   uint32_t __user *prop_ptr,
4097f4dd379Sjsg 				   uint64_t __user *prop_values,
4107f4dd379Sjsg 				   uint32_t *arg_count_props)
4117f4dd379Sjsg {
4127f4dd379Sjsg 	int i, ret, count;
4137f4dd379Sjsg 
4147f4dd379Sjsg 	for (i = 0, count = 0; i < obj->properties->count; i++) {
4157f4dd379Sjsg 		struct drm_property *prop = obj->properties->properties[i];
4167f4dd379Sjsg 		uint64_t val;
4177f4dd379Sjsg 
4187f4dd379Sjsg 		if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
4197f4dd379Sjsg 			continue;
4207f4dd379Sjsg 
4217f4dd379Sjsg 		if (*arg_count_props > count) {
4227f4dd379Sjsg 			ret = __drm_object_property_get_value(obj, prop, &val);
4237f4dd379Sjsg 			if (ret)
4247f4dd379Sjsg 				return ret;
4257f4dd379Sjsg 
4267f4dd379Sjsg 			if (put_user(prop->base.id, prop_ptr + count))
4277f4dd379Sjsg 				return -EFAULT;
4287f4dd379Sjsg 
4297f4dd379Sjsg 			if (put_user(val, prop_values + count))
4307f4dd379Sjsg 				return -EFAULT;
4317f4dd379Sjsg 		}
4327f4dd379Sjsg 
4337f4dd379Sjsg 		count++;
4347f4dd379Sjsg 	}
4357f4dd379Sjsg 	*arg_count_props = count;
4367f4dd379Sjsg 
4377f4dd379Sjsg 	return 0;
4387f4dd379Sjsg }
4397f4dd379Sjsg 
4407f4dd379Sjsg /**
4417f4dd379Sjsg  * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
4427f4dd379Sjsg  * @dev: DRM device
4437f4dd379Sjsg  * @data: ioctl data
4447f4dd379Sjsg  * @file_priv: DRM file info
4457f4dd379Sjsg  *
4467f4dd379Sjsg  * This function retrieves the current value for an object's property. Compared
4477f4dd379Sjsg  * to the connector specific ioctl this one is extended to also work on crtc and
4487f4dd379Sjsg  * plane objects.
4497f4dd379Sjsg  *
4507f4dd379Sjsg  * Called by the user via ioctl.
4517f4dd379Sjsg  *
4527f4dd379Sjsg  * Returns:
4537f4dd379Sjsg  * Zero on success, negative errno on failure.
4547f4dd379Sjsg  */
drm_mode_obj_get_properties_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)4557f4dd379Sjsg int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
4567f4dd379Sjsg 				      struct drm_file *file_priv)
4577f4dd379Sjsg {
4587f4dd379Sjsg 	struct drm_mode_obj_get_properties *arg = data;
4597f4dd379Sjsg 	struct drm_mode_object *obj;
460ad8b1aafSjsg 	struct drm_modeset_acquire_ctx ctx;
4617f4dd379Sjsg 	int ret = 0;
4627f4dd379Sjsg 
4637f4dd379Sjsg 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
464c349dbc7Sjsg 		return -EOPNOTSUPP;
4657f4dd379Sjsg 
466ad8b1aafSjsg 	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
4677f4dd379Sjsg 
4687f4dd379Sjsg 	obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
4697f4dd379Sjsg 	if (!obj) {
4707f4dd379Sjsg 		ret = -ENOENT;
4717f4dd379Sjsg 		goto out;
4727f4dd379Sjsg 	}
4737f4dd379Sjsg 	if (!obj->properties) {
4747f4dd379Sjsg 		ret = -EINVAL;
4757f4dd379Sjsg 		goto out_unref;
4767f4dd379Sjsg 	}
4777f4dd379Sjsg 
4787f4dd379Sjsg 	ret = drm_mode_object_get_properties(obj, file_priv->atomic,
4797f4dd379Sjsg 			(uint32_t __user *)(unsigned long)(arg->props_ptr),
4807f4dd379Sjsg 			(uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
4817f4dd379Sjsg 			&arg->count_props);
4827f4dd379Sjsg 
4837f4dd379Sjsg out_unref:
4847f4dd379Sjsg 	drm_mode_object_put(obj);
4857f4dd379Sjsg out:
486ad8b1aafSjsg 	DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
4877f4dd379Sjsg 	return ret;
4887f4dd379Sjsg }
4897f4dd379Sjsg 
drm_mode_obj_find_prop_id(struct drm_mode_object * obj,uint32_t prop_id)4907f4dd379Sjsg struct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj,
4917f4dd379Sjsg 					       uint32_t prop_id)
4927f4dd379Sjsg {
4937f4dd379Sjsg 	int i;
4947f4dd379Sjsg 
4957f4dd379Sjsg 	for (i = 0; i < obj->properties->count; i++)
4967f4dd379Sjsg 		if (obj->properties->properties[i]->base.id == prop_id)
4977f4dd379Sjsg 			return obj->properties->properties[i];
4987f4dd379Sjsg 
4997f4dd379Sjsg 	return NULL;
5007f4dd379Sjsg }
5017f4dd379Sjsg 
set_property_legacy(struct drm_mode_object * obj,struct drm_property * prop,uint64_t prop_value)5027f4dd379Sjsg static int set_property_legacy(struct drm_mode_object *obj,
5037f4dd379Sjsg 			       struct drm_property *prop,
5047f4dd379Sjsg 			       uint64_t prop_value)
5057f4dd379Sjsg {
5067f4dd379Sjsg 	struct drm_device *dev = prop->dev;
5077f4dd379Sjsg 	struct drm_mode_object *ref;
508ad8b1aafSjsg 	struct drm_modeset_acquire_ctx ctx;
5097f4dd379Sjsg 	int ret = -EINVAL;
5107f4dd379Sjsg 
5117f4dd379Sjsg 	if (!drm_property_change_valid_get(prop, prop_value, &ref))
5127f4dd379Sjsg 		return -EINVAL;
5137f4dd379Sjsg 
514ad8b1aafSjsg 	DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
5157f4dd379Sjsg 	switch (obj->type) {
5167f4dd379Sjsg 	case DRM_MODE_OBJECT_CONNECTOR:
5177f4dd379Sjsg 		ret = drm_connector_set_obj_prop(obj, prop, prop_value);
5187f4dd379Sjsg 		break;
5197f4dd379Sjsg 	case DRM_MODE_OBJECT_CRTC:
5207f4dd379Sjsg 		ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value);
5217f4dd379Sjsg 		break;
5227f4dd379Sjsg 	case DRM_MODE_OBJECT_PLANE:
5237f4dd379Sjsg 		ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj),
5247f4dd379Sjsg 						  prop, prop_value);
5257f4dd379Sjsg 		break;
5267f4dd379Sjsg 	}
5277f4dd379Sjsg 	drm_property_change_valid_put(prop, ref);
528ad8b1aafSjsg 	DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
5297f4dd379Sjsg 
5307f4dd379Sjsg 	return ret;
5317f4dd379Sjsg }
5327f4dd379Sjsg 
set_property_atomic(struct drm_mode_object * obj,struct drm_file * file_priv,struct drm_property * prop,uint64_t prop_value)5337f4dd379Sjsg static int set_property_atomic(struct drm_mode_object *obj,
534c349dbc7Sjsg 			       struct drm_file *file_priv,
5357f4dd379Sjsg 			       struct drm_property *prop,
5367f4dd379Sjsg 			       uint64_t prop_value)
5377f4dd379Sjsg {
5387f4dd379Sjsg 	struct drm_device *dev = prop->dev;
5397f4dd379Sjsg 	struct drm_atomic_state *state;
5407f4dd379Sjsg 	struct drm_modeset_acquire_ctx ctx;
5417f4dd379Sjsg 	int ret;
5427f4dd379Sjsg 
5437f4dd379Sjsg 	state = drm_atomic_state_alloc(dev);
5447f4dd379Sjsg 	if (!state)
5457f4dd379Sjsg 		return -ENOMEM;
5467f4dd379Sjsg 
5477f4dd379Sjsg 	drm_modeset_acquire_init(&ctx, 0);
5487f4dd379Sjsg 	state->acquire_ctx = &ctx;
5497f4dd379Sjsg 
5507f4dd379Sjsg retry:
5517f4dd379Sjsg 	if (prop == state->dev->mode_config.dpms_property) {
5527f4dd379Sjsg 		if (obj->type != DRM_MODE_OBJECT_CONNECTOR) {
5537f4dd379Sjsg 			ret = -EINVAL;
5547f4dd379Sjsg 			goto out;
5557f4dd379Sjsg 		}
5567f4dd379Sjsg 
5577f4dd379Sjsg 		ret = drm_atomic_connector_commit_dpms(state,
5587f4dd379Sjsg 						       obj_to_connector(obj),
5597f4dd379Sjsg 						       prop_value);
5607f4dd379Sjsg #ifdef __OpenBSD__
5617f4dd379Sjsg 	} else if (obj->type == DRM_MODE_OBJECT_CONNECTOR &&
5627f4dd379Sjsg 	    prop == (obj_to_connector(obj))->backlight_property) {
5637f4dd379Sjsg 		struct drm_connector *connector = obj_to_connector(obj);
5647f4dd379Sjsg 		connector->backlight_device->props.brightness = prop_value;
5657f4dd379Sjsg 		backlight_schedule_update_status(connector->backlight_device);
566c78098b6Svisa 		knote_locked(&connector->dev->note, NOTE_CHANGE);
5677f4dd379Sjsg 		ret = 0;
5687f4dd379Sjsg #endif
5697f4dd379Sjsg 	} else {
570c349dbc7Sjsg 		ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value);
5717f4dd379Sjsg 		if (ret)
5727f4dd379Sjsg 			goto out;
5737f4dd379Sjsg 		ret = drm_atomic_commit(state);
5747f4dd379Sjsg 	}
5757f4dd379Sjsg out:
5767f4dd379Sjsg 	if (ret == -EDEADLK) {
5777f4dd379Sjsg 		drm_atomic_state_clear(state);
5787f4dd379Sjsg 		drm_modeset_backoff(&ctx);
5797f4dd379Sjsg 		goto retry;
5807f4dd379Sjsg 	}
5817f4dd379Sjsg 
5827f4dd379Sjsg 	drm_atomic_state_put(state);
5837f4dd379Sjsg 
5847f4dd379Sjsg 	drm_modeset_drop_locks(&ctx);
5857f4dd379Sjsg 	drm_modeset_acquire_fini(&ctx);
5867f4dd379Sjsg 
5877f4dd379Sjsg 	return ret;
5887f4dd379Sjsg }
5897f4dd379Sjsg 
drm_mode_obj_set_property_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)5907f4dd379Sjsg int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
5917f4dd379Sjsg 				    struct drm_file *file_priv)
5927f4dd379Sjsg {
5937f4dd379Sjsg 	struct drm_mode_obj_set_property *arg = data;
5947f4dd379Sjsg 	struct drm_mode_object *arg_obj;
5957f4dd379Sjsg 	struct drm_property *property;
5967f4dd379Sjsg 	int ret = -EINVAL;
5977f4dd379Sjsg 
5987f4dd379Sjsg 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
599c349dbc7Sjsg 		return -EOPNOTSUPP;
6007f4dd379Sjsg 
6017f4dd379Sjsg 	arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
6027f4dd379Sjsg 	if (!arg_obj)
6037f4dd379Sjsg 		return -ENOENT;
6047f4dd379Sjsg 
6057f4dd379Sjsg 	if (!arg_obj->properties)
6067f4dd379Sjsg 		goto out_unref;
6077f4dd379Sjsg 
6087f4dd379Sjsg 	property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id);
6097f4dd379Sjsg 	if (!property)
6107f4dd379Sjsg 		goto out_unref;
6117f4dd379Sjsg 
6127f4dd379Sjsg 	if (drm_drv_uses_atomic_modeset(property->dev))
613c349dbc7Sjsg 		ret = set_property_atomic(arg_obj, file_priv, property, arg->value);
6147f4dd379Sjsg 	else
6157f4dd379Sjsg 		ret = set_property_legacy(arg_obj, property, arg->value);
6167f4dd379Sjsg 
6177f4dd379Sjsg out_unref:
6187f4dd379Sjsg 	drm_mode_object_put(arg_obj);
6197f4dd379Sjsg 	return ret;
6207f4dd379Sjsg }
621