18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2016 Intel Corporation 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, distribute, and sell this software and its 58c2ecf20Sopenharmony_ci * documentation for any purpose is hereby granted without fee, provided that 68c2ecf20Sopenharmony_ci * the above copyright notice appear in all copies and that both that copyright 78c2ecf20Sopenharmony_ci * notice and this permission notice appear in supporting documentation, and 88c2ecf20Sopenharmony_ci * that the name of the copyright holders not be used in advertising or 98c2ecf20Sopenharmony_ci * publicity pertaining to distribution of the software without specific, 108c2ecf20Sopenharmony_ci * written prior permission. The copyright holders make no representations 118c2ecf20Sopenharmony_ci * about the suitability of this software for any purpose. It is provided "as 128c2ecf20Sopenharmony_ci * is" without express or implied warranty. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 158c2ecf20Sopenharmony_ci * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 168c2ecf20Sopenharmony_ci * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 178c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 188c2ecf20Sopenharmony_ci * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 198c2ecf20Sopenharmony_ci * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 208c2ecf20Sopenharmony_ci * OF THIS SOFTWARE. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/export.h> 248c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 278c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 288c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 298c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 308c2ecf20Sopenharmony_ci#include <drm/drm_mode_object.h> 318c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "drm_crtc_internal.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Internal function to assign a slot in the object idr and optionally 378c2ecf20Sopenharmony_ci * register the object into the idr. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ciint __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj, 408c2ecf20Sopenharmony_ci uint32_t obj_type, bool register_obj, 418c2ecf20Sopenharmony_ci void (*obj_free_cb)(struct kref *kref)) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int ret; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci mutex_lock(&dev->mode_config.idr_mutex); 488c2ecf20Sopenharmony_ci ret = idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL, 498c2ecf20Sopenharmony_ci 1, 0, GFP_KERNEL); 508c2ecf20Sopenharmony_ci if (ret >= 0) { 518c2ecf20Sopenharmony_ci /* 528c2ecf20Sopenharmony_ci * Set up the object linking under the protection of the idr 538c2ecf20Sopenharmony_ci * lock so that other users can't see inconsistent state. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci obj->id = ret; 568c2ecf20Sopenharmony_ci obj->type = obj_type; 578c2ecf20Sopenharmony_ci if (obj_free_cb) { 588c2ecf20Sopenharmony_ci obj->free_cb = obj_free_cb; 598c2ecf20Sopenharmony_ci kref_init(&obj->refcount); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci mutex_unlock(&dev->mode_config.idr_mutex); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/** 688c2ecf20Sopenharmony_ci * drm_mode_object_add - allocate a new modeset identifier 698c2ecf20Sopenharmony_ci * @dev: DRM device 708c2ecf20Sopenharmony_ci * @obj: object pointer, used to generate unique ID 718c2ecf20Sopenharmony_ci * @obj_type: object type 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * Create a unique identifier based on @ptr in @dev's identifier space. Used 748c2ecf20Sopenharmony_ci * for tracking modes, CRTCs and connectors. 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * Returns: 778c2ecf20Sopenharmony_ci * Zero on success, error code on failure. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ciint drm_mode_object_add(struct drm_device *dev, 808c2ecf20Sopenharmony_ci struct drm_mode_object *obj, uint32_t obj_type) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return __drm_mode_object_add(dev, obj, obj_type, true, NULL); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_civoid drm_mode_object_register(struct drm_device *dev, 868c2ecf20Sopenharmony_ci struct drm_mode_object *obj) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci mutex_lock(&dev->mode_config.idr_mutex); 898c2ecf20Sopenharmony_ci idr_replace(&dev->mode_config.object_idr, obj, obj->id); 908c2ecf20Sopenharmony_ci mutex_unlock(&dev->mode_config.idr_mutex); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/** 948c2ecf20Sopenharmony_ci * drm_mode_object_unregister - free a modeset identifer 958c2ecf20Sopenharmony_ci * @dev: DRM device 968c2ecf20Sopenharmony_ci * @object: object to free 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * Free @id from @dev's unique identifier pool. 998c2ecf20Sopenharmony_ci * This function can be called multiple times, and guards against 1008c2ecf20Sopenharmony_ci * multiple removals. 1018c2ecf20Sopenharmony_ci * These modeset identifiers are _not_ reference counted. Hence don't use this 1028c2ecf20Sopenharmony_ci * for reference counted modeset objects like framebuffers. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_civoid drm_mode_object_unregister(struct drm_device *dev, 1058c2ecf20Sopenharmony_ci struct drm_mode_object *object) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci WARN_ON(!dev->driver->load && dev->registered && !object->free_cb); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci mutex_lock(&dev->mode_config.idr_mutex); 1108c2ecf20Sopenharmony_ci if (object->id) { 1118c2ecf20Sopenharmony_ci idr_remove(&dev->mode_config.object_idr, object->id); 1128c2ecf20Sopenharmony_ci object->id = 0; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci mutex_unlock(&dev->mode_config.idr_mutex); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/** 1188c2ecf20Sopenharmony_ci * drm_lease_required - check types which must be leased to be used 1198c2ecf20Sopenharmony_ci * @type: type of object 1208c2ecf20Sopenharmony_ci * 1218c2ecf20Sopenharmony_ci * Returns whether the provided type of drm_mode_object must 1228c2ecf20Sopenharmony_ci * be owned or leased to be used by a process. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cibool drm_mode_object_lease_required(uint32_t type) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci switch(type) { 1278c2ecf20Sopenharmony_ci case DRM_MODE_OBJECT_CRTC: 1288c2ecf20Sopenharmony_ci case DRM_MODE_OBJECT_CONNECTOR: 1298c2ecf20Sopenharmony_ci case DRM_MODE_OBJECT_PLANE: 1308c2ecf20Sopenharmony_ci return true; 1318c2ecf20Sopenharmony_ci default: 1328c2ecf20Sopenharmony_ci return false; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistruct drm_mode_object *__drm_mode_object_find(struct drm_device *dev, 1378c2ecf20Sopenharmony_ci struct drm_file *file_priv, 1388c2ecf20Sopenharmony_ci uint32_t id, uint32_t type) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct drm_mode_object *obj = NULL; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci mutex_lock(&dev->mode_config.idr_mutex); 1438c2ecf20Sopenharmony_ci obj = idr_find(&dev->mode_config.object_idr, id); 1448c2ecf20Sopenharmony_ci if (obj && type != DRM_MODE_OBJECT_ANY && obj->type != type) 1458c2ecf20Sopenharmony_ci obj = NULL; 1468c2ecf20Sopenharmony_ci if (obj && obj->id != id) 1478c2ecf20Sopenharmony_ci obj = NULL; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (obj && drm_mode_object_lease_required(obj->type) && 1508c2ecf20Sopenharmony_ci !_drm_lease_held(file_priv, obj->id)) 1518c2ecf20Sopenharmony_ci obj = NULL; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (obj && obj->free_cb) { 1548c2ecf20Sopenharmony_ci if (!kref_get_unless_zero(&obj->refcount)) 1558c2ecf20Sopenharmony_ci obj = NULL; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci mutex_unlock(&dev->mode_config.idr_mutex); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return obj; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/** 1638c2ecf20Sopenharmony_ci * drm_mode_object_find - look up a drm object with static lifetime 1648c2ecf20Sopenharmony_ci * @dev: drm device 1658c2ecf20Sopenharmony_ci * @file_priv: drm file 1668c2ecf20Sopenharmony_ci * @id: id of the mode object 1678c2ecf20Sopenharmony_ci * @type: type of the mode object 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * This function is used to look up a modeset object. It will acquire a 1708c2ecf20Sopenharmony_ci * reference for reference counted objects. This reference must be dropped again 1718c2ecf20Sopenharmony_ci * by callind drm_mode_object_put(). 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_cistruct drm_mode_object *drm_mode_object_find(struct drm_device *dev, 1748c2ecf20Sopenharmony_ci struct drm_file *file_priv, 1758c2ecf20Sopenharmony_ci uint32_t id, uint32_t type) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct drm_mode_object *obj = NULL; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci obj = __drm_mode_object_find(dev, file_priv, id, type); 1808c2ecf20Sopenharmony_ci return obj; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_mode_object_find); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/** 1858c2ecf20Sopenharmony_ci * drm_mode_object_put - release a mode object reference 1868c2ecf20Sopenharmony_ci * @obj: DRM mode object 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * This function decrements the object's refcount if it is a refcounted modeset 1898c2ecf20Sopenharmony_ci * object. It is a no-op on any other object. This is used to drop references 1908c2ecf20Sopenharmony_ci * acquired with drm_mode_object_get(). 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_civoid drm_mode_object_put(struct drm_mode_object *obj) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci if (obj->free_cb) { 1958c2ecf20Sopenharmony_ci DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); 1968c2ecf20Sopenharmony_ci kref_put(&obj->refcount, obj->free_cb); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_mode_object_put); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * drm_mode_object_get - acquire a mode object reference 2038c2ecf20Sopenharmony_ci * @obj: DRM mode object 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * This function increments the object's refcount if it is a refcounted modeset 2068c2ecf20Sopenharmony_ci * object. It is a no-op on any other object. References should be dropped again 2078c2ecf20Sopenharmony_ci * by calling drm_mode_object_put(). 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_civoid drm_mode_object_get(struct drm_mode_object *obj) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci if (obj->free_cb) { 2128c2ecf20Sopenharmony_ci DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); 2138c2ecf20Sopenharmony_ci kref_get(&obj->refcount); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_mode_object_get); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/** 2198c2ecf20Sopenharmony_ci * drm_object_attach_property - attach a property to a modeset object 2208c2ecf20Sopenharmony_ci * @obj: drm modeset object 2218c2ecf20Sopenharmony_ci * @property: property to attach 2228c2ecf20Sopenharmony_ci * @init_val: initial value of the property 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * This attaches the given property to the modeset object with the given initial 2258c2ecf20Sopenharmony_ci * value. Currently this function cannot fail since the properties are stored in 2268c2ecf20Sopenharmony_ci * a statically sized array. 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Note that all properties must be attached before the object itself is 2298c2ecf20Sopenharmony_ci * registered and accessible from userspace. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_civoid drm_object_attach_property(struct drm_mode_object *obj, 2328c2ecf20Sopenharmony_ci struct drm_property *property, 2338c2ecf20Sopenharmony_ci uint64_t init_val) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int count = obj->properties->count; 2368c2ecf20Sopenharmony_ci struct drm_device *dev = property->dev; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (obj->type == DRM_MODE_OBJECT_CONNECTOR) { 2408c2ecf20Sopenharmony_ci struct drm_connector *connector = obj_to_connector(obj); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci WARN_ON(!dev->driver->load && 2438c2ecf20Sopenharmony_ci connector->registration_state == DRM_CONNECTOR_REGISTERED); 2448c2ecf20Sopenharmony_ci } else { 2458c2ecf20Sopenharmony_ci WARN_ON(!dev->driver->load && dev->registered); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (count == DRM_OBJECT_MAX_PROPERTY) { 2498c2ecf20Sopenharmony_ci WARN(1, "Failed to attach object property (type: 0x%x). Please " 2508c2ecf20Sopenharmony_ci "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " 2518c2ecf20Sopenharmony_ci "you see this message on the same object type.\n", 2528c2ecf20Sopenharmony_ci obj->type); 2538c2ecf20Sopenharmony_ci return; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci obj->properties->properties[count] = property; 2578c2ecf20Sopenharmony_ci obj->properties->values[count] = init_val; 2588c2ecf20Sopenharmony_ci obj->properties->count++; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_object_attach_property); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/** 2638c2ecf20Sopenharmony_ci * drm_object_property_set_value - set the value of a property 2648c2ecf20Sopenharmony_ci * @obj: drm mode object to set property value for 2658c2ecf20Sopenharmony_ci * @property: property to set 2668c2ecf20Sopenharmony_ci * @val: value the property should be set to 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * This function sets a given property on a given object. This function only 2698c2ecf20Sopenharmony_ci * changes the software state of the property, it does not call into the 2708c2ecf20Sopenharmony_ci * driver's ->set_property callback. 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci * Note that atomic drivers should not have any need to call this, the core will 2738c2ecf20Sopenharmony_ci * ensure consistency of values reported back to userspace through the 2748c2ecf20Sopenharmony_ci * appropriate ->atomic_get_property callback. Only legacy drivers should call 2758c2ecf20Sopenharmony_ci * this function to update the tracked value (after clamping and other 2768c2ecf20Sopenharmony_ci * restrictions have been applied). 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * Returns: 2798c2ecf20Sopenharmony_ci * Zero on success, error code on failure. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ciint drm_object_property_set_value(struct drm_mode_object *obj, 2828c2ecf20Sopenharmony_ci struct drm_property *property, uint64_t val) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci int i; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci WARN_ON(drm_drv_uses_atomic_modeset(property->dev) && 2878c2ecf20Sopenharmony_ci !(property->flags & DRM_MODE_PROP_IMMUTABLE)); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci for (i = 0; i < obj->properties->count; i++) { 2908c2ecf20Sopenharmony_ci if (obj->properties->properties[i] == property) { 2918c2ecf20Sopenharmony_ci obj->properties->values[i] = val; 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_object_property_set_value); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic int __drm_object_property_get_value(struct drm_mode_object *obj, 3018c2ecf20Sopenharmony_ci struct drm_property *property, 3028c2ecf20Sopenharmony_ci uint64_t *val) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci int i; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* read-only properties bypass atomic mechanism and still store 3078c2ecf20Sopenharmony_ci * their value in obj->properties->values[].. mostly to avoid 3088c2ecf20Sopenharmony_ci * having to deal w/ EDID and similar props in atomic paths: 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci if (drm_drv_uses_atomic_modeset(property->dev) && 3118c2ecf20Sopenharmony_ci !(property->flags & DRM_MODE_PROP_IMMUTABLE)) 3128c2ecf20Sopenharmony_ci return drm_atomic_get_property(obj, property, val); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci for (i = 0; i < obj->properties->count; i++) { 3158c2ecf20Sopenharmony_ci if (obj->properties->properties[i] == property) { 3168c2ecf20Sopenharmony_ci *val = obj->properties->values[i]; 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return -EINVAL; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci/** 3268c2ecf20Sopenharmony_ci * drm_object_property_get_value - retrieve the value of a property 3278c2ecf20Sopenharmony_ci * @obj: drm mode object to get property value from 3288c2ecf20Sopenharmony_ci * @property: property to retrieve 3298c2ecf20Sopenharmony_ci * @val: storage for the property value 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * This function retrieves the softare state of the given property for the given 3328c2ecf20Sopenharmony_ci * property. Since there is no driver callback to retrieve the current property 3338c2ecf20Sopenharmony_ci * value this might be out of sync with the hardware, depending upon the driver 3348c2ecf20Sopenharmony_ci * and property. 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * Atomic drivers should never call this function directly, the core will read 3378c2ecf20Sopenharmony_ci * out property values through the various ->atomic_get_property callbacks. 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci * Returns: 3408c2ecf20Sopenharmony_ci * Zero on success, error code on failure. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ciint drm_object_property_get_value(struct drm_mode_object *obj, 3438c2ecf20Sopenharmony_ci struct drm_property *property, uint64_t *val) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci WARN_ON(drm_drv_uses_atomic_modeset(property->dev)); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return __drm_object_property_get_value(obj, property, val); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_object_property_get_value); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/* helper for getconnector and getproperties ioctls */ 3528c2ecf20Sopenharmony_ciint drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, 3538c2ecf20Sopenharmony_ci uint32_t __user *prop_ptr, 3548c2ecf20Sopenharmony_ci uint64_t __user *prop_values, 3558c2ecf20Sopenharmony_ci uint32_t *arg_count_props) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int i, ret, count; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci for (i = 0, count = 0; i < obj->properties->count; i++) { 3608c2ecf20Sopenharmony_ci struct drm_property *prop = obj->properties->properties[i]; 3618c2ecf20Sopenharmony_ci uint64_t val; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic) 3648c2ecf20Sopenharmony_ci continue; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (*arg_count_props > count) { 3678c2ecf20Sopenharmony_ci ret = __drm_object_property_get_value(obj, prop, &val); 3688c2ecf20Sopenharmony_ci if (ret) 3698c2ecf20Sopenharmony_ci return ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (put_user(prop->base.id, prop_ptr + count)) 3728c2ecf20Sopenharmony_ci return -EFAULT; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (put_user(val, prop_values + count)) 3758c2ecf20Sopenharmony_ci return -EFAULT; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci count++; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci *arg_count_props = count; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/** 3868c2ecf20Sopenharmony_ci * drm_mode_obj_get_properties_ioctl - get the current value of a object's property 3878c2ecf20Sopenharmony_ci * @dev: DRM device 3888c2ecf20Sopenharmony_ci * @data: ioctl data 3898c2ecf20Sopenharmony_ci * @file_priv: DRM file info 3908c2ecf20Sopenharmony_ci * 3918c2ecf20Sopenharmony_ci * This function retrieves the current value for an object's property. Compared 3928c2ecf20Sopenharmony_ci * to the connector specific ioctl this one is extended to also work on crtc and 3938c2ecf20Sopenharmony_ci * plane objects. 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * Called by the user via ioctl. 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci * Returns: 3988c2ecf20Sopenharmony_ci * Zero on success, negative errno on failure. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ciint drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 4018c2ecf20Sopenharmony_ci struct drm_file *file_priv) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct drm_mode_obj_get_properties *arg = data; 4048c2ecf20Sopenharmony_ci struct drm_mode_object *obj; 4058c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx ctx; 4068c2ecf20Sopenharmony_ci int ret = 0; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); 4148c2ecf20Sopenharmony_ci if (!obj) { 4158c2ecf20Sopenharmony_ci ret = -ENOENT; 4168c2ecf20Sopenharmony_ci goto out; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci if (!obj->properties) { 4198c2ecf20Sopenharmony_ci ret = -EINVAL; 4208c2ecf20Sopenharmony_ci goto out_unref; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci ret = drm_mode_object_get_properties(obj, file_priv->atomic, 4248c2ecf20Sopenharmony_ci (uint32_t __user *)(unsigned long)(arg->props_ptr), 4258c2ecf20Sopenharmony_ci (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), 4268c2ecf20Sopenharmony_ci &arg->count_props); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ciout_unref: 4298c2ecf20Sopenharmony_ci drm_mode_object_put(obj); 4308c2ecf20Sopenharmony_ciout: 4318c2ecf20Sopenharmony_ci DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistruct drm_property *drm_mode_obj_find_prop_id(struct drm_mode_object *obj, 4368c2ecf20Sopenharmony_ci uint32_t prop_id) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci int i; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci for (i = 0; i < obj->properties->count; i++) 4418c2ecf20Sopenharmony_ci if (obj->properties->properties[i]->base.id == prop_id) 4428c2ecf20Sopenharmony_ci return obj->properties->properties[i]; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return NULL; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int set_property_legacy(struct drm_mode_object *obj, 4488c2ecf20Sopenharmony_ci struct drm_property *prop, 4498c2ecf20Sopenharmony_ci uint64_t prop_value) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct drm_device *dev = prop->dev; 4528c2ecf20Sopenharmony_ci struct drm_mode_object *ref; 4538c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx ctx; 4548c2ecf20Sopenharmony_ci int ret = -EINVAL; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (!drm_property_change_valid_get(prop, prop_value, &ref)) 4578c2ecf20Sopenharmony_ci return -EINVAL; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); 4608c2ecf20Sopenharmony_ci switch (obj->type) { 4618c2ecf20Sopenharmony_ci case DRM_MODE_OBJECT_CONNECTOR: 4628c2ecf20Sopenharmony_ci ret = drm_connector_set_obj_prop(obj, prop, prop_value); 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci case DRM_MODE_OBJECT_CRTC: 4658c2ecf20Sopenharmony_ci ret = drm_mode_crtc_set_obj_prop(obj, prop, prop_value); 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case DRM_MODE_OBJECT_PLANE: 4688c2ecf20Sopenharmony_ci ret = drm_mode_plane_set_obj_prop(obj_to_plane(obj), 4698c2ecf20Sopenharmony_ci prop, prop_value); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci drm_property_change_valid_put(prop, ref); 4738c2ecf20Sopenharmony_ci DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return ret; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int set_property_atomic(struct drm_mode_object *obj, 4798c2ecf20Sopenharmony_ci struct drm_file *file_priv, 4808c2ecf20Sopenharmony_ci struct drm_property *prop, 4818c2ecf20Sopenharmony_ci uint64_t prop_value) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct drm_device *dev = prop->dev; 4848c2ecf20Sopenharmony_ci struct drm_atomic_state *state; 4858c2ecf20Sopenharmony_ci struct drm_modeset_acquire_ctx ctx; 4868c2ecf20Sopenharmony_ci int ret; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci state = drm_atomic_state_alloc(dev); 4898c2ecf20Sopenharmony_ci if (!state) 4908c2ecf20Sopenharmony_ci return -ENOMEM; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci drm_modeset_acquire_init(&ctx, 0); 4938c2ecf20Sopenharmony_ci state->acquire_ctx = &ctx; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ciretry: 4968c2ecf20Sopenharmony_ci if (prop == state->dev->mode_config.dpms_property) { 4978c2ecf20Sopenharmony_ci if (obj->type != DRM_MODE_OBJECT_CONNECTOR) { 4988c2ecf20Sopenharmony_ci ret = -EINVAL; 4998c2ecf20Sopenharmony_ci goto out; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci ret = drm_atomic_connector_commit_dpms(state, 5038c2ecf20Sopenharmony_ci obj_to_connector(obj), 5048c2ecf20Sopenharmony_ci prop_value); 5058c2ecf20Sopenharmony_ci } else { 5068c2ecf20Sopenharmony_ci ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value); 5078c2ecf20Sopenharmony_ci if (ret) 5088c2ecf20Sopenharmony_ci goto out; 5098c2ecf20Sopenharmony_ci ret = drm_atomic_commit(state); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ciout: 5128c2ecf20Sopenharmony_ci if (ret == -EDEADLK) { 5138c2ecf20Sopenharmony_ci drm_atomic_state_clear(state); 5148c2ecf20Sopenharmony_ci drm_modeset_backoff(&ctx); 5158c2ecf20Sopenharmony_ci goto retry; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci drm_atomic_state_put(state); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci drm_modeset_drop_locks(&ctx); 5218c2ecf20Sopenharmony_ci drm_modeset_acquire_fini(&ctx); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return ret; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ciint drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 5278c2ecf20Sopenharmony_ci struct drm_file *file_priv) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct drm_mode_obj_set_property *arg = data; 5308c2ecf20Sopenharmony_ci struct drm_mode_object *arg_obj; 5318c2ecf20Sopenharmony_ci struct drm_property *property; 5328c2ecf20Sopenharmony_ci int ret = -EINVAL; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 5358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type); 5388c2ecf20Sopenharmony_ci if (!arg_obj) 5398c2ecf20Sopenharmony_ci return -ENOENT; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (!arg_obj->properties) 5428c2ecf20Sopenharmony_ci goto out_unref; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci property = drm_mode_obj_find_prop_id(arg_obj, arg->prop_id); 5458c2ecf20Sopenharmony_ci if (!property) 5468c2ecf20Sopenharmony_ci goto out_unref; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (drm_drv_uses_atomic_modeset(property->dev)) 5498c2ecf20Sopenharmony_ci ret = set_property_atomic(arg_obj, file_priv, property, arg->value); 5508c2ecf20Sopenharmony_ci else 5518c2ecf20Sopenharmony_ci ret = set_property_legacy(arg_obj, property, arg->value); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ciout_unref: 5548c2ecf20Sopenharmony_ci drm_mode_object_put(arg_obj); 5558c2ecf20Sopenharmony_ci return ret; 5568c2ecf20Sopenharmony_ci} 557