1c349dbc7Sjsg /* 2c349dbc7Sjsg * Copyright (C) 2014 Red Hat 3c349dbc7Sjsg * Copyright (C) 2014 Intel Corp. 4c349dbc7Sjsg * Copyright (C) 2018 Intel Corp. 55ca02815Sjsg * Copyright (c) 2020, The Linux Foundation. All rights reserved. 6c349dbc7Sjsg * 7c349dbc7Sjsg * Permission is hereby granted, free of charge, to any person obtaining a 8c349dbc7Sjsg * copy of this software and associated documentation files (the "Software"), 9c349dbc7Sjsg * to deal in the Software without restriction, including without limitation 10c349dbc7Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11c349dbc7Sjsg * and/or sell copies of the Software, and to permit persons to whom the 12c349dbc7Sjsg * Software is furnished to do so, subject to the following conditions: 13c349dbc7Sjsg * 14c349dbc7Sjsg * The above copyright notice and this permission notice shall be included in 15c349dbc7Sjsg * all copies or substantial portions of the Software. 16c349dbc7Sjsg * 17c349dbc7Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18c349dbc7Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19c349dbc7Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20c349dbc7Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 21c349dbc7Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22c349dbc7Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23c349dbc7Sjsg * OTHER DEALINGS IN THE SOFTWARE. 24c349dbc7Sjsg * 25c349dbc7Sjsg * Authors: 26c349dbc7Sjsg * Rob Clark <robdclark@gmail.com> 27c349dbc7Sjsg * Daniel Vetter <daniel.vetter@ffwll.ch> 28c349dbc7Sjsg */ 29c349dbc7Sjsg 30c349dbc7Sjsg #include <linux/compiler.h> 31c349dbc7Sjsg #include <drm/drm_atomic_uapi.h> 32c349dbc7Sjsg #include <drm/drm_atomic.h> 331bb76ff1Sjsg #include <drm/drm_framebuffer.h> 34c349dbc7Sjsg #include <drm/drm_print.h> 35c349dbc7Sjsg #include <drm/drm_drv.h> 36c349dbc7Sjsg #include <drm/drm_writeback.h> 37c349dbc7Sjsg #include <drm/drm_vblank.h> 38c349dbc7Sjsg 39c349dbc7Sjsg #include <linux/dma-fence.h> 40c349dbc7Sjsg #include <linux/uaccess.h> 41c349dbc7Sjsg #include <linux/sync_file.h> 42c349dbc7Sjsg #include <linux/file.h> 43c349dbc7Sjsg 44c349dbc7Sjsg #include "drm_crtc_internal.h" 45c349dbc7Sjsg 46c349dbc7Sjsg /** 47c349dbc7Sjsg * DOC: overview 48c349dbc7Sjsg * 49c349dbc7Sjsg * This file contains the marshalling and demarshalling glue for the atomic UAPI 50c349dbc7Sjsg * in all its forms: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and 51c349dbc7Sjsg * SET_PROPERTY IOCTLs. Plus interface functions for compatibility helpers and 52c349dbc7Sjsg * drivers which have special needs to construct their own atomic updates, e.g. 535ca02815Sjsg * for load detect or similar. 54c349dbc7Sjsg */ 55c349dbc7Sjsg 56c349dbc7Sjsg /** 57c349dbc7Sjsg * drm_atomic_set_mode_for_crtc - set mode for CRTC 58c349dbc7Sjsg * @state: the CRTC whose incoming state to update 59c349dbc7Sjsg * @mode: kernel-internal mode to use for the CRTC, or NULL to disable 60c349dbc7Sjsg * 61c349dbc7Sjsg * Set a mode (originating from the kernel) on the desired CRTC state and update 62c349dbc7Sjsg * the enable property. 63c349dbc7Sjsg * 64c349dbc7Sjsg * RETURNS: 65c349dbc7Sjsg * Zero on success, error code on failure. Cannot return -EDEADLK. 66c349dbc7Sjsg */ 67c349dbc7Sjsg int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, 68c349dbc7Sjsg const struct drm_display_mode *mode) 69c349dbc7Sjsg { 70c349dbc7Sjsg struct drm_crtc *crtc = state->crtc; 71c349dbc7Sjsg struct drm_mode_modeinfo umode; 72c349dbc7Sjsg 73c349dbc7Sjsg /* Early return for no change. */ 74c349dbc7Sjsg if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) 75c349dbc7Sjsg return 0; 76c349dbc7Sjsg 77c349dbc7Sjsg drm_property_blob_put(state->mode_blob); 78c349dbc7Sjsg state->mode_blob = NULL; 79c349dbc7Sjsg 80c349dbc7Sjsg if (mode) { 8148c7f30eSjsg struct drm_property_blob *blob; 8248c7f30eSjsg 83c349dbc7Sjsg drm_mode_convert_to_umode(&umode, mode); 8448c7f30eSjsg blob = drm_property_create_blob(crtc->dev, 8548c7f30eSjsg sizeof(umode), &umode); 8648c7f30eSjsg if (IS_ERR(blob)) 8748c7f30eSjsg return PTR_ERR(blob); 88c349dbc7Sjsg 89c349dbc7Sjsg drm_mode_copy(&state->mode, mode); 9048c7f30eSjsg 9148c7f30eSjsg state->mode_blob = blob; 92c349dbc7Sjsg state->enable = true; 935ca02815Sjsg drm_dbg_atomic(crtc->dev, 945ca02815Sjsg "Set [MODE:%s] for [CRTC:%d:%s] state %p\n", 95c349dbc7Sjsg mode->name, crtc->base.id, crtc->name, state); 96c349dbc7Sjsg } else { 97c349dbc7Sjsg memset(&state->mode, 0, sizeof(state->mode)); 98c349dbc7Sjsg state->enable = false; 995ca02815Sjsg drm_dbg_atomic(crtc->dev, 1005ca02815Sjsg "Set [NOMODE] for [CRTC:%d:%s] state %p\n", 101c349dbc7Sjsg crtc->base.id, crtc->name, state); 102c349dbc7Sjsg } 103c349dbc7Sjsg 104c349dbc7Sjsg return 0; 105c349dbc7Sjsg } 106c349dbc7Sjsg EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc); 107c349dbc7Sjsg 108c349dbc7Sjsg /** 109c349dbc7Sjsg * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC 110c349dbc7Sjsg * @state: the CRTC whose incoming state to update 111c349dbc7Sjsg * @blob: pointer to blob property to use for mode 112c349dbc7Sjsg * 113c349dbc7Sjsg * Set a mode (originating from a blob property) on the desired CRTC state. 114c349dbc7Sjsg * This function will take a reference on the blob property for the CRTC state, 115c349dbc7Sjsg * and release the reference held on the state's existing mode property, if any 116c349dbc7Sjsg * was set. 117c349dbc7Sjsg * 118c349dbc7Sjsg * RETURNS: 119c349dbc7Sjsg * Zero on success, error code on failure. Cannot return -EDEADLK. 120c349dbc7Sjsg */ 121c349dbc7Sjsg int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, 122c349dbc7Sjsg struct drm_property_blob *blob) 123c349dbc7Sjsg { 124c349dbc7Sjsg struct drm_crtc *crtc = state->crtc; 125c349dbc7Sjsg 126c349dbc7Sjsg if (blob == state->mode_blob) 127c349dbc7Sjsg return 0; 128c349dbc7Sjsg 129c349dbc7Sjsg drm_property_blob_put(state->mode_blob); 130c349dbc7Sjsg state->mode_blob = NULL; 131c349dbc7Sjsg 132c349dbc7Sjsg memset(&state->mode, 0, sizeof(state->mode)); 133c349dbc7Sjsg 134c349dbc7Sjsg if (blob) { 135c349dbc7Sjsg int ret; 136c349dbc7Sjsg 137c349dbc7Sjsg if (blob->length != sizeof(struct drm_mode_modeinfo)) { 1385ca02815Sjsg drm_dbg_atomic(crtc->dev, 1395ca02815Sjsg "[CRTC:%d:%s] bad mode blob length: %zu\n", 140c349dbc7Sjsg crtc->base.id, crtc->name, 141c349dbc7Sjsg blob->length); 142c349dbc7Sjsg return -EINVAL; 143c349dbc7Sjsg } 144c349dbc7Sjsg 145c349dbc7Sjsg ret = drm_mode_convert_umode(crtc->dev, 146c349dbc7Sjsg &state->mode, blob->data); 147c349dbc7Sjsg if (ret) { 1485ca02815Sjsg drm_dbg_atomic(crtc->dev, 1495ca02815Sjsg "[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n", 150c349dbc7Sjsg crtc->base.id, crtc->name, 151c349dbc7Sjsg ret, drm_get_mode_status_name(state->mode.status)); 152c349dbc7Sjsg drm_mode_debug_printmodeline(&state->mode); 153c349dbc7Sjsg return -EINVAL; 154c349dbc7Sjsg } 155c349dbc7Sjsg 156c349dbc7Sjsg state->mode_blob = drm_property_blob_get(blob); 157c349dbc7Sjsg state->enable = true; 1585ca02815Sjsg drm_dbg_atomic(crtc->dev, 1595ca02815Sjsg "Set [MODE:%s] for [CRTC:%d:%s] state %p\n", 160c349dbc7Sjsg state->mode.name, crtc->base.id, crtc->name, 161c349dbc7Sjsg state); 162c349dbc7Sjsg } else { 163c349dbc7Sjsg state->enable = false; 1645ca02815Sjsg drm_dbg_atomic(crtc->dev, 1655ca02815Sjsg "Set [NOMODE] for [CRTC:%d:%s] state %p\n", 166c349dbc7Sjsg crtc->base.id, crtc->name, state); 167c349dbc7Sjsg } 168c349dbc7Sjsg 169c349dbc7Sjsg return 0; 170c349dbc7Sjsg } 171c349dbc7Sjsg EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc); 172c349dbc7Sjsg 173c349dbc7Sjsg /** 174c349dbc7Sjsg * drm_atomic_set_crtc_for_plane - set CRTC for plane 175c349dbc7Sjsg * @plane_state: the plane whose incoming state to update 176c349dbc7Sjsg * @crtc: CRTC to use for the plane 177c349dbc7Sjsg * 178c349dbc7Sjsg * Changing the assigned CRTC for a plane requires us to grab the lock and state 179c349dbc7Sjsg * for the new CRTC, as needed. This function takes care of all these details 180c349dbc7Sjsg * besides updating the pointer in the state object itself. 181c349dbc7Sjsg * 182c349dbc7Sjsg * Returns: 183c349dbc7Sjsg * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 184c349dbc7Sjsg * then the w/w mutex code has detected a deadlock and the entire atomic 185c349dbc7Sjsg * sequence must be restarted. All other errors are fatal. 186c349dbc7Sjsg */ 187c349dbc7Sjsg int 188c349dbc7Sjsg drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, 189c349dbc7Sjsg struct drm_crtc *crtc) 190c349dbc7Sjsg { 191c349dbc7Sjsg struct drm_plane *plane = plane_state->plane; 192c349dbc7Sjsg struct drm_crtc_state *crtc_state; 193c349dbc7Sjsg /* Nothing to do for same crtc*/ 194c349dbc7Sjsg if (plane_state->crtc == crtc) 195c349dbc7Sjsg return 0; 196c349dbc7Sjsg if (plane_state->crtc) { 197c349dbc7Sjsg crtc_state = drm_atomic_get_crtc_state(plane_state->state, 198c349dbc7Sjsg plane_state->crtc); 199c349dbc7Sjsg if (WARN_ON(IS_ERR(crtc_state))) 200c349dbc7Sjsg return PTR_ERR(crtc_state); 201c349dbc7Sjsg 202c349dbc7Sjsg crtc_state->plane_mask &= ~drm_plane_mask(plane); 203c349dbc7Sjsg } 204c349dbc7Sjsg 205c349dbc7Sjsg plane_state->crtc = crtc; 206c349dbc7Sjsg 207c349dbc7Sjsg if (crtc) { 208c349dbc7Sjsg crtc_state = drm_atomic_get_crtc_state(plane_state->state, 209c349dbc7Sjsg crtc); 210c349dbc7Sjsg if (IS_ERR(crtc_state)) 211c349dbc7Sjsg return PTR_ERR(crtc_state); 212c349dbc7Sjsg crtc_state->plane_mask |= drm_plane_mask(plane); 213c349dbc7Sjsg } 214c349dbc7Sjsg 215c349dbc7Sjsg if (crtc) 2165ca02815Sjsg drm_dbg_atomic(plane->dev, 2175ca02815Sjsg "Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n", 218c349dbc7Sjsg plane->base.id, plane->name, plane_state, 219c349dbc7Sjsg crtc->base.id, crtc->name); 220c349dbc7Sjsg else 2215ca02815Sjsg drm_dbg_atomic(plane->dev, 2225ca02815Sjsg "Link [PLANE:%d:%s] state %p to [NOCRTC]\n", 223c349dbc7Sjsg plane->base.id, plane->name, plane_state); 224c349dbc7Sjsg 225c349dbc7Sjsg return 0; 226c349dbc7Sjsg } 227c349dbc7Sjsg EXPORT_SYMBOL(drm_atomic_set_crtc_for_plane); 228c349dbc7Sjsg 229c349dbc7Sjsg /** 230c349dbc7Sjsg * drm_atomic_set_fb_for_plane - set framebuffer for plane 231c349dbc7Sjsg * @plane_state: atomic state object for the plane 232c349dbc7Sjsg * @fb: fb to use for the plane 233c349dbc7Sjsg * 234c349dbc7Sjsg * Changing the assigned framebuffer for a plane requires us to grab a reference 235c349dbc7Sjsg * to the new fb and drop the reference to the old fb, if there is one. This 236c349dbc7Sjsg * function takes care of all these details besides updating the pointer in the 237c349dbc7Sjsg * state object itself. 238c349dbc7Sjsg */ 239c349dbc7Sjsg void 240c349dbc7Sjsg drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, 241c349dbc7Sjsg struct drm_framebuffer *fb) 242c349dbc7Sjsg { 243c349dbc7Sjsg struct drm_plane *plane = plane_state->plane; 244c349dbc7Sjsg 245c349dbc7Sjsg if (fb) 2465ca02815Sjsg drm_dbg_atomic(plane->dev, 2475ca02815Sjsg "Set [FB:%d] for [PLANE:%d:%s] state %p\n", 248c349dbc7Sjsg fb->base.id, plane->base.id, plane->name, 249c349dbc7Sjsg plane_state); 250c349dbc7Sjsg else 2515ca02815Sjsg drm_dbg_atomic(plane->dev, 2525ca02815Sjsg "Set [NOFB] for [PLANE:%d:%s] state %p\n", 253c349dbc7Sjsg plane->base.id, plane->name, plane_state); 254c349dbc7Sjsg 255c349dbc7Sjsg drm_framebuffer_assign(&plane_state->fb, fb); 256c349dbc7Sjsg } 257c349dbc7Sjsg EXPORT_SYMBOL(drm_atomic_set_fb_for_plane); 258c349dbc7Sjsg 259c349dbc7Sjsg /** 260c349dbc7Sjsg * drm_atomic_set_crtc_for_connector - set CRTC for connector 261c349dbc7Sjsg * @conn_state: atomic state object for the connector 262c349dbc7Sjsg * @crtc: CRTC to use for the connector 263c349dbc7Sjsg * 264c349dbc7Sjsg * Changing the assigned CRTC for a connector requires us to grab the lock and 265c349dbc7Sjsg * state for the new CRTC, as needed. This function takes care of all these 266c349dbc7Sjsg * details besides updating the pointer in the state object itself. 267c349dbc7Sjsg * 268c349dbc7Sjsg * Returns: 269c349dbc7Sjsg * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK 270c349dbc7Sjsg * then the w/w mutex code has detected a deadlock and the entire atomic 271c349dbc7Sjsg * sequence must be restarted. All other errors are fatal. 272c349dbc7Sjsg */ 273c349dbc7Sjsg int 274c349dbc7Sjsg drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, 275c349dbc7Sjsg struct drm_crtc *crtc) 276c349dbc7Sjsg { 277c349dbc7Sjsg struct drm_connector *connector = conn_state->connector; 278c349dbc7Sjsg struct drm_crtc_state *crtc_state; 279c349dbc7Sjsg 280c349dbc7Sjsg if (conn_state->crtc == crtc) 281c349dbc7Sjsg return 0; 282c349dbc7Sjsg 283c349dbc7Sjsg if (conn_state->crtc) { 284c349dbc7Sjsg crtc_state = drm_atomic_get_new_crtc_state(conn_state->state, 285c349dbc7Sjsg conn_state->crtc); 286c349dbc7Sjsg 287c349dbc7Sjsg crtc_state->connector_mask &= 288c349dbc7Sjsg ~drm_connector_mask(conn_state->connector); 289c349dbc7Sjsg 290c349dbc7Sjsg drm_connector_put(conn_state->connector); 291c349dbc7Sjsg conn_state->crtc = NULL; 292c349dbc7Sjsg } 293c349dbc7Sjsg 294c349dbc7Sjsg if (crtc) { 295c349dbc7Sjsg crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc); 296c349dbc7Sjsg if (IS_ERR(crtc_state)) 297c349dbc7Sjsg return PTR_ERR(crtc_state); 298c349dbc7Sjsg 299c349dbc7Sjsg crtc_state->connector_mask |= 300c349dbc7Sjsg drm_connector_mask(conn_state->connector); 301c349dbc7Sjsg 302c349dbc7Sjsg drm_connector_get(conn_state->connector); 303c349dbc7Sjsg conn_state->crtc = crtc; 304c349dbc7Sjsg 3055ca02815Sjsg drm_dbg_atomic(connector->dev, 3065ca02815Sjsg "Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n", 307c349dbc7Sjsg connector->base.id, connector->name, 308c349dbc7Sjsg conn_state, crtc->base.id, crtc->name); 309c349dbc7Sjsg } else { 3105ca02815Sjsg drm_dbg_atomic(connector->dev, 3115ca02815Sjsg "Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n", 312c349dbc7Sjsg connector->base.id, connector->name, 313c349dbc7Sjsg conn_state); 314c349dbc7Sjsg } 315c349dbc7Sjsg 316c349dbc7Sjsg return 0; 317c349dbc7Sjsg } 318c349dbc7Sjsg EXPORT_SYMBOL(drm_atomic_set_crtc_for_connector); 319c349dbc7Sjsg 320c349dbc7Sjsg static void set_out_fence_for_crtc(struct drm_atomic_state *state, 321c349dbc7Sjsg struct drm_crtc *crtc, s32 __user *fence_ptr) 322c349dbc7Sjsg { 323c349dbc7Sjsg state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr; 324c349dbc7Sjsg } 325c349dbc7Sjsg 326c349dbc7Sjsg static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, 327c349dbc7Sjsg struct drm_crtc *crtc) 328c349dbc7Sjsg { 329c349dbc7Sjsg s32 __user *fence_ptr; 330c349dbc7Sjsg 331c349dbc7Sjsg fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr; 332c349dbc7Sjsg state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL; 333c349dbc7Sjsg 334c349dbc7Sjsg return fence_ptr; 335c349dbc7Sjsg } 336c349dbc7Sjsg 337c349dbc7Sjsg static int set_out_fence_for_connector(struct drm_atomic_state *state, 338c349dbc7Sjsg struct drm_connector *connector, 339c349dbc7Sjsg s32 __user *fence_ptr) 340c349dbc7Sjsg { 341c349dbc7Sjsg unsigned int index = drm_connector_index(connector); 342c349dbc7Sjsg 343c349dbc7Sjsg if (!fence_ptr) 344c349dbc7Sjsg return 0; 345c349dbc7Sjsg 346c349dbc7Sjsg if (put_user(-1, fence_ptr)) 347c349dbc7Sjsg return -EFAULT; 348c349dbc7Sjsg 349c349dbc7Sjsg state->connectors[index].out_fence_ptr = fence_ptr; 350c349dbc7Sjsg 351c349dbc7Sjsg return 0; 352c349dbc7Sjsg } 353c349dbc7Sjsg 354c349dbc7Sjsg static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, 355c349dbc7Sjsg struct drm_connector *connector) 356c349dbc7Sjsg { 357c349dbc7Sjsg unsigned int index = drm_connector_index(connector); 358c349dbc7Sjsg s32 __user *fence_ptr; 359c349dbc7Sjsg 360c349dbc7Sjsg fence_ptr = state->connectors[index].out_fence_ptr; 361c349dbc7Sjsg state->connectors[index].out_fence_ptr = NULL; 362c349dbc7Sjsg 363c349dbc7Sjsg return fence_ptr; 364c349dbc7Sjsg } 365c349dbc7Sjsg 366c349dbc7Sjsg static int 367c349dbc7Sjsg drm_atomic_replace_property_blob_from_id(struct drm_device *dev, 368c349dbc7Sjsg struct drm_property_blob **blob, 369c349dbc7Sjsg uint64_t blob_id, 370c349dbc7Sjsg ssize_t expected_size, 371c349dbc7Sjsg ssize_t expected_elem_size, 372c349dbc7Sjsg bool *replaced) 373c349dbc7Sjsg { 374c349dbc7Sjsg struct drm_property_blob *new_blob = NULL; 375c349dbc7Sjsg 376c349dbc7Sjsg if (blob_id != 0) { 377c349dbc7Sjsg new_blob = drm_property_lookup_blob(dev, blob_id); 378f005ef32Sjsg if (new_blob == NULL) { 379f005ef32Sjsg drm_dbg_atomic(dev, 380f005ef32Sjsg "cannot find blob ID %llu\n", blob_id); 381c349dbc7Sjsg return -EINVAL; 382f005ef32Sjsg } 383c349dbc7Sjsg 384c349dbc7Sjsg if (expected_size > 0 && 385c349dbc7Sjsg new_blob->length != expected_size) { 386f005ef32Sjsg drm_dbg_atomic(dev, 387f005ef32Sjsg "[BLOB:%d] length %zu different from expected %zu\n", 388f005ef32Sjsg new_blob->base.id, new_blob->length, expected_size); 389c349dbc7Sjsg drm_property_blob_put(new_blob); 390c349dbc7Sjsg return -EINVAL; 391c349dbc7Sjsg } 392c349dbc7Sjsg if (expected_elem_size > 0 && 393c349dbc7Sjsg new_blob->length % expected_elem_size != 0) { 394f005ef32Sjsg drm_dbg_atomic(dev, 395f005ef32Sjsg "[BLOB:%d] length %zu not divisible by element size %zu\n", 396f005ef32Sjsg new_blob->base.id, new_blob->length, expected_elem_size); 397c349dbc7Sjsg drm_property_blob_put(new_blob); 398c349dbc7Sjsg return -EINVAL; 399c349dbc7Sjsg } 400c349dbc7Sjsg } 401c349dbc7Sjsg 402c349dbc7Sjsg *replaced |= drm_property_replace_blob(blob, new_blob); 403c349dbc7Sjsg drm_property_blob_put(new_blob); 404c349dbc7Sjsg 405c349dbc7Sjsg return 0; 406c349dbc7Sjsg } 407c349dbc7Sjsg 408c349dbc7Sjsg static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, 409c349dbc7Sjsg struct drm_crtc_state *state, struct drm_property *property, 410c349dbc7Sjsg uint64_t val) 411c349dbc7Sjsg { 412c349dbc7Sjsg struct drm_device *dev = crtc->dev; 413c349dbc7Sjsg struct drm_mode_config *config = &dev->mode_config; 414c349dbc7Sjsg bool replaced = false; 415c349dbc7Sjsg int ret; 416c349dbc7Sjsg 417c349dbc7Sjsg if (property == config->prop_active) 418c349dbc7Sjsg state->active = val; 419c349dbc7Sjsg else if (property == config->prop_mode_id) { 420c349dbc7Sjsg struct drm_property_blob *mode = 421c349dbc7Sjsg drm_property_lookup_blob(dev, val); 422c349dbc7Sjsg ret = drm_atomic_set_mode_prop_for_crtc(state, mode); 423c349dbc7Sjsg drm_property_blob_put(mode); 424c349dbc7Sjsg return ret; 425c349dbc7Sjsg } else if (property == config->prop_vrr_enabled) { 426c349dbc7Sjsg state->vrr_enabled = val; 427c349dbc7Sjsg } else if (property == config->degamma_lut_property) { 428c349dbc7Sjsg ret = drm_atomic_replace_property_blob_from_id(dev, 429c349dbc7Sjsg &state->degamma_lut, 430c349dbc7Sjsg val, 431c349dbc7Sjsg -1, sizeof(struct drm_color_lut), 432c349dbc7Sjsg &replaced); 433c349dbc7Sjsg state->color_mgmt_changed |= replaced; 434c349dbc7Sjsg return ret; 435c349dbc7Sjsg } else if (property == config->ctm_property) { 436c349dbc7Sjsg ret = drm_atomic_replace_property_blob_from_id(dev, 437c349dbc7Sjsg &state->ctm, 438c349dbc7Sjsg val, 439c349dbc7Sjsg sizeof(struct drm_color_ctm), -1, 440c349dbc7Sjsg &replaced); 441c349dbc7Sjsg state->color_mgmt_changed |= replaced; 442c349dbc7Sjsg return ret; 443c349dbc7Sjsg } else if (property == config->gamma_lut_property) { 444c349dbc7Sjsg ret = drm_atomic_replace_property_blob_from_id(dev, 445c349dbc7Sjsg &state->gamma_lut, 446c349dbc7Sjsg val, 447c349dbc7Sjsg -1, sizeof(struct drm_color_lut), 448c349dbc7Sjsg &replaced); 449c349dbc7Sjsg state->color_mgmt_changed |= replaced; 450c349dbc7Sjsg return ret; 451c349dbc7Sjsg } else if (property == config->prop_out_fence_ptr) { 452c349dbc7Sjsg s32 __user *fence_ptr = u64_to_user_ptr(val); 453c349dbc7Sjsg 454c349dbc7Sjsg if (!fence_ptr) 455c349dbc7Sjsg return 0; 456c349dbc7Sjsg 457c349dbc7Sjsg if (put_user(-1, fence_ptr)) 458c349dbc7Sjsg return -EFAULT; 459c349dbc7Sjsg 460c349dbc7Sjsg set_out_fence_for_crtc(state->state, crtc, fence_ptr); 4615ca02815Sjsg } else if (property == crtc->scaling_filter_property) { 4625ca02815Sjsg state->scaling_filter = val; 463c349dbc7Sjsg } else if (crtc->funcs->atomic_set_property) { 464c349dbc7Sjsg return crtc->funcs->atomic_set_property(crtc, state, property, val); 465c349dbc7Sjsg } else { 4665ca02815Sjsg drm_dbg_atomic(crtc->dev, 467f005ef32Sjsg "[CRTC:%d:%s] unknown property [PROP:%d:%s]\n", 468c349dbc7Sjsg crtc->base.id, crtc->name, 469c349dbc7Sjsg property->base.id, property->name); 470c349dbc7Sjsg return -EINVAL; 471c349dbc7Sjsg } 472c349dbc7Sjsg 473c349dbc7Sjsg return 0; 474c349dbc7Sjsg } 475c349dbc7Sjsg 476c349dbc7Sjsg static int 477c349dbc7Sjsg drm_atomic_crtc_get_property(struct drm_crtc *crtc, 478c349dbc7Sjsg const struct drm_crtc_state *state, 479c349dbc7Sjsg struct drm_property *property, uint64_t *val) 480c349dbc7Sjsg { 481c349dbc7Sjsg struct drm_device *dev = crtc->dev; 482c349dbc7Sjsg struct drm_mode_config *config = &dev->mode_config; 483c349dbc7Sjsg 484c349dbc7Sjsg if (property == config->prop_active) 485c349dbc7Sjsg *val = drm_atomic_crtc_effectively_active(state); 486c349dbc7Sjsg else if (property == config->prop_mode_id) 487c349dbc7Sjsg *val = (state->mode_blob) ? state->mode_blob->base.id : 0; 488c349dbc7Sjsg else if (property == config->prop_vrr_enabled) 489c349dbc7Sjsg *val = state->vrr_enabled; 490c349dbc7Sjsg else if (property == config->degamma_lut_property) 491c349dbc7Sjsg *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0; 492c349dbc7Sjsg else if (property == config->ctm_property) 493c349dbc7Sjsg *val = (state->ctm) ? state->ctm->base.id : 0; 494c349dbc7Sjsg else if (property == config->gamma_lut_property) 495c349dbc7Sjsg *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; 496c349dbc7Sjsg else if (property == config->prop_out_fence_ptr) 497c349dbc7Sjsg *val = 0; 4985ca02815Sjsg else if (property == crtc->scaling_filter_property) 4995ca02815Sjsg *val = state->scaling_filter; 500c349dbc7Sjsg else if (crtc->funcs->atomic_get_property) 501c349dbc7Sjsg return crtc->funcs->atomic_get_property(crtc, state, property, val); 502f005ef32Sjsg else { 503f005ef32Sjsg drm_dbg_atomic(dev, 504f005ef32Sjsg "[CRTC:%d:%s] unknown property [PROP:%d:%s]\n", 505f005ef32Sjsg crtc->base.id, crtc->name, 506f005ef32Sjsg property->base.id, property->name); 507c349dbc7Sjsg return -EINVAL; 508f005ef32Sjsg } 509c349dbc7Sjsg 510c349dbc7Sjsg return 0; 511c349dbc7Sjsg } 512c349dbc7Sjsg 513c349dbc7Sjsg static int drm_atomic_plane_set_property(struct drm_plane *plane, 514c349dbc7Sjsg struct drm_plane_state *state, struct drm_file *file_priv, 515c349dbc7Sjsg struct drm_property *property, uint64_t val) 516c349dbc7Sjsg { 517c349dbc7Sjsg struct drm_device *dev = plane->dev; 518c349dbc7Sjsg struct drm_mode_config *config = &dev->mode_config; 519c349dbc7Sjsg bool replaced = false; 520c349dbc7Sjsg int ret; 521c349dbc7Sjsg 522c349dbc7Sjsg if (property == config->prop_fb_id) { 523c349dbc7Sjsg struct drm_framebuffer *fb; 524ad8b1aafSjsg 525c349dbc7Sjsg fb = drm_framebuffer_lookup(dev, file_priv, val); 526c349dbc7Sjsg drm_atomic_set_fb_for_plane(state, fb); 527c349dbc7Sjsg if (fb) 528c349dbc7Sjsg drm_framebuffer_put(fb); 529c349dbc7Sjsg } else if (property == config->prop_in_fence_fd) { 530c349dbc7Sjsg if (state->fence) 531c349dbc7Sjsg return -EINVAL; 532c349dbc7Sjsg 533c349dbc7Sjsg if (U642I64(val) == -1) 534c349dbc7Sjsg return 0; 535c349dbc7Sjsg 536c349dbc7Sjsg state->fence = sync_file_get_fence(val); 537c349dbc7Sjsg if (!state->fence) 538c349dbc7Sjsg return -EINVAL; 539c349dbc7Sjsg 540c349dbc7Sjsg } else if (property == config->prop_crtc_id) { 541c349dbc7Sjsg struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val); 542ad8b1aafSjsg 543f005ef32Sjsg if (val && !crtc) { 544f005ef32Sjsg drm_dbg_atomic(dev, 545f005ef32Sjsg "[PROP:%d:%s] cannot find CRTC with ID %llu\n", 546f005ef32Sjsg property->base.id, property->name, val); 547c349dbc7Sjsg return -EACCES; 548f005ef32Sjsg } 549c349dbc7Sjsg return drm_atomic_set_crtc_for_plane(state, crtc); 550c349dbc7Sjsg } else if (property == config->prop_crtc_x) { 551c349dbc7Sjsg state->crtc_x = U642I64(val); 552c349dbc7Sjsg } else if (property == config->prop_crtc_y) { 553c349dbc7Sjsg state->crtc_y = U642I64(val); 554c349dbc7Sjsg } else if (property == config->prop_crtc_w) { 555c349dbc7Sjsg state->crtc_w = val; 556c349dbc7Sjsg } else if (property == config->prop_crtc_h) { 557c349dbc7Sjsg state->crtc_h = val; 558c349dbc7Sjsg } else if (property == config->prop_src_x) { 559c349dbc7Sjsg state->src_x = val; 560c349dbc7Sjsg } else if (property == config->prop_src_y) { 561c349dbc7Sjsg state->src_y = val; 562c349dbc7Sjsg } else if (property == config->prop_src_w) { 563c349dbc7Sjsg state->src_w = val; 564c349dbc7Sjsg } else if (property == config->prop_src_h) { 565c349dbc7Sjsg state->src_h = val; 566c349dbc7Sjsg } else if (property == plane->alpha_property) { 567c349dbc7Sjsg state->alpha = val; 568c349dbc7Sjsg } else if (property == plane->blend_mode_property) { 569c349dbc7Sjsg state->pixel_blend_mode = val; 570c349dbc7Sjsg } else if (property == plane->rotation_property) { 571c349dbc7Sjsg if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) { 5725ca02815Sjsg drm_dbg_atomic(plane->dev, 5735ca02815Sjsg "[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n", 574c349dbc7Sjsg plane->base.id, plane->name, val); 575c349dbc7Sjsg return -EINVAL; 576c349dbc7Sjsg } 577c349dbc7Sjsg state->rotation = val; 578c349dbc7Sjsg } else if (property == plane->zpos_property) { 579c349dbc7Sjsg state->zpos = val; 580c349dbc7Sjsg } else if (property == plane->color_encoding_property) { 581c349dbc7Sjsg state->color_encoding = val; 582c349dbc7Sjsg } else if (property == plane->color_range_property) { 583c349dbc7Sjsg state->color_range = val; 584c349dbc7Sjsg } else if (property == config->prop_fb_damage_clips) { 585c349dbc7Sjsg ret = drm_atomic_replace_property_blob_from_id(dev, 586c349dbc7Sjsg &state->fb_damage_clips, 587c349dbc7Sjsg val, 588c349dbc7Sjsg -1, 589*8a67236bSjsg sizeof(struct drm_mode_rect), 590c349dbc7Sjsg &replaced); 591c349dbc7Sjsg return ret; 5925ca02815Sjsg } else if (property == plane->scaling_filter_property) { 5935ca02815Sjsg state->scaling_filter = val; 594c349dbc7Sjsg } else if (plane->funcs->atomic_set_property) { 595c349dbc7Sjsg return plane->funcs->atomic_set_property(plane, state, 596c349dbc7Sjsg property, val); 597c349dbc7Sjsg } else { 5985ca02815Sjsg drm_dbg_atomic(plane->dev, 599f005ef32Sjsg "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n", 600c349dbc7Sjsg plane->base.id, plane->name, 601c349dbc7Sjsg property->base.id, property->name); 602c349dbc7Sjsg return -EINVAL; 603c349dbc7Sjsg } 604c349dbc7Sjsg 605c349dbc7Sjsg return 0; 606c349dbc7Sjsg } 607c349dbc7Sjsg 608c349dbc7Sjsg static int 609c349dbc7Sjsg drm_atomic_plane_get_property(struct drm_plane *plane, 610c349dbc7Sjsg const struct drm_plane_state *state, 611c349dbc7Sjsg struct drm_property *property, uint64_t *val) 612c349dbc7Sjsg { 613c349dbc7Sjsg struct drm_device *dev = plane->dev; 614c349dbc7Sjsg struct drm_mode_config *config = &dev->mode_config; 615c349dbc7Sjsg 616c349dbc7Sjsg if (property == config->prop_fb_id) { 617c349dbc7Sjsg *val = (state->fb) ? state->fb->base.id : 0; 618c349dbc7Sjsg } else if (property == config->prop_in_fence_fd) { 619c349dbc7Sjsg *val = -1; 620c349dbc7Sjsg } else if (property == config->prop_crtc_id) { 621c349dbc7Sjsg *val = (state->crtc) ? state->crtc->base.id : 0; 622c349dbc7Sjsg } else if (property == config->prop_crtc_x) { 623c349dbc7Sjsg *val = I642U64(state->crtc_x); 624c349dbc7Sjsg } else if (property == config->prop_crtc_y) { 625c349dbc7Sjsg *val = I642U64(state->crtc_y); 626c349dbc7Sjsg } else if (property == config->prop_crtc_w) { 627c349dbc7Sjsg *val = state->crtc_w; 628c349dbc7Sjsg } else if (property == config->prop_crtc_h) { 629c349dbc7Sjsg *val = state->crtc_h; 630c349dbc7Sjsg } else if (property == config->prop_src_x) { 631c349dbc7Sjsg *val = state->src_x; 632c349dbc7Sjsg } else if (property == config->prop_src_y) { 633c349dbc7Sjsg *val = state->src_y; 634c349dbc7Sjsg } else if (property == config->prop_src_w) { 635c349dbc7Sjsg *val = state->src_w; 636c349dbc7Sjsg } else if (property == config->prop_src_h) { 637c349dbc7Sjsg *val = state->src_h; 638c349dbc7Sjsg } else if (property == plane->alpha_property) { 639c349dbc7Sjsg *val = state->alpha; 640c349dbc7Sjsg } else if (property == plane->blend_mode_property) { 641c349dbc7Sjsg *val = state->pixel_blend_mode; 642c349dbc7Sjsg } else if (property == plane->rotation_property) { 643c349dbc7Sjsg *val = state->rotation; 644c349dbc7Sjsg } else if (property == plane->zpos_property) { 645c349dbc7Sjsg *val = state->zpos; 646c349dbc7Sjsg } else if (property == plane->color_encoding_property) { 647c349dbc7Sjsg *val = state->color_encoding; 648c349dbc7Sjsg } else if (property == plane->color_range_property) { 649c349dbc7Sjsg *val = state->color_range; 650c349dbc7Sjsg } else if (property == config->prop_fb_damage_clips) { 651c349dbc7Sjsg *val = (state->fb_damage_clips) ? 652c349dbc7Sjsg state->fb_damage_clips->base.id : 0; 6535ca02815Sjsg } else if (property == plane->scaling_filter_property) { 6545ca02815Sjsg *val = state->scaling_filter; 655c349dbc7Sjsg } else if (plane->funcs->atomic_get_property) { 656c349dbc7Sjsg return plane->funcs->atomic_get_property(plane, state, property, val); 657c349dbc7Sjsg } else { 658f005ef32Sjsg drm_dbg_atomic(dev, 659f005ef32Sjsg "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n", 660f005ef32Sjsg plane->base.id, plane->name, 661f005ef32Sjsg property->base.id, property->name); 662c349dbc7Sjsg return -EINVAL; 663c349dbc7Sjsg } 664c349dbc7Sjsg 665c349dbc7Sjsg return 0; 666c349dbc7Sjsg } 667c349dbc7Sjsg 668c349dbc7Sjsg static int drm_atomic_set_writeback_fb_for_connector( 669c349dbc7Sjsg struct drm_connector_state *conn_state, 670c349dbc7Sjsg struct drm_framebuffer *fb) 671c349dbc7Sjsg { 672c349dbc7Sjsg int ret; 6735ca02815Sjsg struct drm_connector *conn = conn_state->connector; 674c349dbc7Sjsg 675c349dbc7Sjsg ret = drm_writeback_set_fb(conn_state, fb); 676c349dbc7Sjsg if (ret < 0) 677c349dbc7Sjsg return ret; 678c349dbc7Sjsg 679c349dbc7Sjsg if (fb) 6805ca02815Sjsg drm_dbg_atomic(conn->dev, 6815ca02815Sjsg "Set [FB:%d] for connector state %p\n", 682c349dbc7Sjsg fb->base.id, conn_state); 683c349dbc7Sjsg else 6845ca02815Sjsg drm_dbg_atomic(conn->dev, 6855ca02815Sjsg "Set [NOFB] for connector state %p\n", 686c349dbc7Sjsg conn_state); 687c349dbc7Sjsg 688c349dbc7Sjsg return 0; 689c349dbc7Sjsg } 690c349dbc7Sjsg 691c349dbc7Sjsg static int drm_atomic_connector_set_property(struct drm_connector *connector, 692c349dbc7Sjsg struct drm_connector_state *state, struct drm_file *file_priv, 693c349dbc7Sjsg struct drm_property *property, uint64_t val) 694c349dbc7Sjsg { 695c349dbc7Sjsg struct drm_device *dev = connector->dev; 696c349dbc7Sjsg struct drm_mode_config *config = &dev->mode_config; 697c349dbc7Sjsg bool replaced = false; 698c349dbc7Sjsg int ret; 699c349dbc7Sjsg 700c349dbc7Sjsg if (property == config->prop_crtc_id) { 701c349dbc7Sjsg struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val); 702ad8b1aafSjsg 703f005ef32Sjsg if (val && !crtc) { 704f005ef32Sjsg drm_dbg_atomic(dev, 705f005ef32Sjsg "[PROP:%d:%s] cannot find CRTC with ID %llu\n", 706f005ef32Sjsg property->base.id, property->name, val); 707c349dbc7Sjsg return -EACCES; 708f005ef32Sjsg } 709c349dbc7Sjsg return drm_atomic_set_crtc_for_connector(state, crtc); 710c349dbc7Sjsg } else if (property == config->dpms_property) { 711c349dbc7Sjsg /* setting DPMS property requires special handling, which 712c349dbc7Sjsg * is done in legacy setprop path for us. Disallow (for 713c349dbc7Sjsg * now?) atomic writes to DPMS property: 714c349dbc7Sjsg */ 715f005ef32Sjsg drm_dbg_atomic(dev, 716f005ef32Sjsg "legacy [PROP:%d:%s] can only be set via legacy uAPI\n", 717f005ef32Sjsg property->base.id, property->name); 718c349dbc7Sjsg return -EINVAL; 719c349dbc7Sjsg } else if (property == config->tv_select_subconnector_property) { 720f005ef32Sjsg state->tv.select_subconnector = val; 721f005ef32Sjsg } else if (property == config->tv_subconnector_property) { 722c349dbc7Sjsg state->tv.subconnector = val; 723c349dbc7Sjsg } else if (property == config->tv_left_margin_property) { 724c349dbc7Sjsg state->tv.margins.left = val; 725c349dbc7Sjsg } else if (property == config->tv_right_margin_property) { 726c349dbc7Sjsg state->tv.margins.right = val; 727c349dbc7Sjsg } else if (property == config->tv_top_margin_property) { 728c349dbc7Sjsg state->tv.margins.top = val; 729c349dbc7Sjsg } else if (property == config->tv_bottom_margin_property) { 730c349dbc7Sjsg state->tv.margins.bottom = val; 731f005ef32Sjsg } else if (property == config->legacy_tv_mode_property) { 732f005ef32Sjsg state->tv.legacy_mode = val; 733c349dbc7Sjsg } else if (property == config->tv_mode_property) { 734c349dbc7Sjsg state->tv.mode = val; 735c349dbc7Sjsg } else if (property == config->tv_brightness_property) { 736c349dbc7Sjsg state->tv.brightness = val; 737c349dbc7Sjsg } else if (property == config->tv_contrast_property) { 738c349dbc7Sjsg state->tv.contrast = val; 739c349dbc7Sjsg } else if (property == config->tv_flicker_reduction_property) { 740c349dbc7Sjsg state->tv.flicker_reduction = val; 741c349dbc7Sjsg } else if (property == config->tv_overscan_property) { 742c349dbc7Sjsg state->tv.overscan = val; 743c349dbc7Sjsg } else if (property == config->tv_saturation_property) { 744c349dbc7Sjsg state->tv.saturation = val; 745c349dbc7Sjsg } else if (property == config->tv_hue_property) { 746c349dbc7Sjsg state->tv.hue = val; 747c349dbc7Sjsg } else if (property == config->link_status_property) { 748c349dbc7Sjsg /* Never downgrade from GOOD to BAD on userspace's request here, 749c349dbc7Sjsg * only hw issues can do that. 750c349dbc7Sjsg * 751c349dbc7Sjsg * For an atomic property the userspace doesn't need to be able 752c349dbc7Sjsg * to understand all the properties, but needs to be able to 753c349dbc7Sjsg * restore the state it wants on VT switch. So if the userspace 754c349dbc7Sjsg * tries to change the link_status from GOOD to BAD, driver 755c349dbc7Sjsg * silently rejects it and returns a 0. This prevents userspace 7565ca02815Sjsg * from accidentally breaking the display when it restores the 757c349dbc7Sjsg * state. 758c349dbc7Sjsg */ 759c349dbc7Sjsg if (state->link_status != DRM_LINK_STATUS_GOOD) 760c349dbc7Sjsg state->link_status = val; 761c349dbc7Sjsg } else if (property == config->hdr_output_metadata_property) { 762c349dbc7Sjsg ret = drm_atomic_replace_property_blob_from_id(dev, 763c349dbc7Sjsg &state->hdr_output_metadata, 764c349dbc7Sjsg val, 765c349dbc7Sjsg sizeof(struct hdr_output_metadata), -1, 766c349dbc7Sjsg &replaced); 767c349dbc7Sjsg return ret; 768c349dbc7Sjsg } else if (property == config->aspect_ratio_property) { 769c349dbc7Sjsg state->picture_aspect_ratio = val; 770c349dbc7Sjsg } else if (property == config->content_type_property) { 771c349dbc7Sjsg state->content_type = val; 772c349dbc7Sjsg } else if (property == connector->scaling_mode_property) { 773c349dbc7Sjsg state->scaling_mode = val; 774c349dbc7Sjsg } else if (property == config->content_protection_property) { 775c349dbc7Sjsg if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) { 7761bb76ff1Sjsg drm_dbg_kms(dev, "only drivers can set CP Enabled\n"); 777c349dbc7Sjsg return -EINVAL; 778c349dbc7Sjsg } 779c349dbc7Sjsg state->content_protection = val; 780c349dbc7Sjsg } else if (property == config->hdcp_content_type_property) { 781c349dbc7Sjsg state->hdcp_content_type = val; 782c349dbc7Sjsg } else if (property == connector->colorspace_property) { 783c349dbc7Sjsg state->colorspace = val; 784c349dbc7Sjsg } else if (property == config->writeback_fb_id_property) { 785c349dbc7Sjsg struct drm_framebuffer *fb; 786c349dbc7Sjsg int ret; 787ad8b1aafSjsg 788c349dbc7Sjsg fb = drm_framebuffer_lookup(dev, file_priv, val); 789c349dbc7Sjsg ret = drm_atomic_set_writeback_fb_for_connector(state, fb); 790c349dbc7Sjsg if (fb) 791c349dbc7Sjsg drm_framebuffer_put(fb); 792c349dbc7Sjsg return ret; 793c349dbc7Sjsg } else if (property == config->writeback_out_fence_ptr_property) { 794c349dbc7Sjsg s32 __user *fence_ptr = u64_to_user_ptr(val); 795c349dbc7Sjsg 796c349dbc7Sjsg return set_out_fence_for_connector(state->state, connector, 797c349dbc7Sjsg fence_ptr); 798c349dbc7Sjsg } else if (property == connector->max_bpc_property) { 799c349dbc7Sjsg state->max_requested_bpc = val; 8001bb76ff1Sjsg } else if (property == connector->privacy_screen_sw_state_property) { 8011bb76ff1Sjsg state->privacy_screen_sw_state = val; 802c349dbc7Sjsg } else if (connector->funcs->atomic_set_property) { 803c349dbc7Sjsg return connector->funcs->atomic_set_property(connector, 804c349dbc7Sjsg state, property, val); 805c349dbc7Sjsg } else { 8065ca02815Sjsg drm_dbg_atomic(connector->dev, 807f005ef32Sjsg "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]\n", 808c349dbc7Sjsg connector->base.id, connector->name, 809c349dbc7Sjsg property->base.id, property->name); 810c349dbc7Sjsg return -EINVAL; 811c349dbc7Sjsg } 812c349dbc7Sjsg 813c349dbc7Sjsg return 0; 814c349dbc7Sjsg } 815c349dbc7Sjsg 816c349dbc7Sjsg static int 817c349dbc7Sjsg drm_atomic_connector_get_property(struct drm_connector *connector, 818c349dbc7Sjsg const struct drm_connector_state *state, 819c349dbc7Sjsg struct drm_property *property, uint64_t *val) 820c349dbc7Sjsg { 821c349dbc7Sjsg struct drm_device *dev = connector->dev; 822c349dbc7Sjsg struct drm_mode_config *config = &dev->mode_config; 823c349dbc7Sjsg 824c349dbc7Sjsg if (property == config->prop_crtc_id) { 825c349dbc7Sjsg *val = (state->crtc) ? state->crtc->base.id : 0; 826c349dbc7Sjsg } else if (property == config->dpms_property) { 827c349dbc7Sjsg if (state->crtc && state->crtc->state->self_refresh_active) 828c349dbc7Sjsg *val = DRM_MODE_DPMS_ON; 829c349dbc7Sjsg else 830c349dbc7Sjsg *val = connector->dpms; 831c349dbc7Sjsg } else if (property == config->tv_select_subconnector_property) { 832f005ef32Sjsg *val = state->tv.select_subconnector; 833f005ef32Sjsg } else if (property == config->tv_subconnector_property) { 834c349dbc7Sjsg *val = state->tv.subconnector; 835c349dbc7Sjsg } else if (property == config->tv_left_margin_property) { 836c349dbc7Sjsg *val = state->tv.margins.left; 837c349dbc7Sjsg } else if (property == config->tv_right_margin_property) { 838c349dbc7Sjsg *val = state->tv.margins.right; 839c349dbc7Sjsg } else if (property == config->tv_top_margin_property) { 840c349dbc7Sjsg *val = state->tv.margins.top; 841c349dbc7Sjsg } else if (property == config->tv_bottom_margin_property) { 842c349dbc7Sjsg *val = state->tv.margins.bottom; 843f005ef32Sjsg } else if (property == config->legacy_tv_mode_property) { 844f005ef32Sjsg *val = state->tv.legacy_mode; 845c349dbc7Sjsg } else if (property == config->tv_mode_property) { 846c349dbc7Sjsg *val = state->tv.mode; 847c349dbc7Sjsg } else if (property == config->tv_brightness_property) { 848c349dbc7Sjsg *val = state->tv.brightness; 849c349dbc7Sjsg } else if (property == config->tv_contrast_property) { 850c349dbc7Sjsg *val = state->tv.contrast; 851c349dbc7Sjsg } else if (property == config->tv_flicker_reduction_property) { 852c349dbc7Sjsg *val = state->tv.flicker_reduction; 853c349dbc7Sjsg } else if (property == config->tv_overscan_property) { 854c349dbc7Sjsg *val = state->tv.overscan; 855c349dbc7Sjsg } else if (property == config->tv_saturation_property) { 856c349dbc7Sjsg *val = state->tv.saturation; 857c349dbc7Sjsg } else if (property == config->tv_hue_property) { 858c349dbc7Sjsg *val = state->tv.hue; 859c349dbc7Sjsg } else if (property == config->link_status_property) { 860c349dbc7Sjsg *val = state->link_status; 861c349dbc7Sjsg } else if (property == config->aspect_ratio_property) { 862c349dbc7Sjsg *val = state->picture_aspect_ratio; 863c349dbc7Sjsg } else if (property == config->content_type_property) { 864c349dbc7Sjsg *val = state->content_type; 865c349dbc7Sjsg } else if (property == connector->colorspace_property) { 866c349dbc7Sjsg *val = state->colorspace; 867c349dbc7Sjsg } else if (property == connector->scaling_mode_property) { 868c349dbc7Sjsg *val = state->scaling_mode; 869c349dbc7Sjsg } else if (property == config->hdr_output_metadata_property) { 870c349dbc7Sjsg *val = state->hdr_output_metadata ? 871c349dbc7Sjsg state->hdr_output_metadata->base.id : 0; 872c349dbc7Sjsg } else if (property == config->content_protection_property) { 873c349dbc7Sjsg *val = state->content_protection; 874c349dbc7Sjsg } else if (property == config->hdcp_content_type_property) { 875c349dbc7Sjsg *val = state->hdcp_content_type; 876c349dbc7Sjsg } else if (property == config->writeback_fb_id_property) { 877c349dbc7Sjsg /* Writeback framebuffer is one-shot, write and forget */ 878c349dbc7Sjsg *val = 0; 879c349dbc7Sjsg } else if (property == config->writeback_out_fence_ptr_property) { 880c349dbc7Sjsg *val = 0; 881c349dbc7Sjsg } else if (property == connector->max_bpc_property) { 882c349dbc7Sjsg *val = state->max_requested_bpc; 8831bb76ff1Sjsg } else if (property == connector->privacy_screen_sw_state_property) { 8841bb76ff1Sjsg *val = state->privacy_screen_sw_state; 885c349dbc7Sjsg } else if (connector->funcs->atomic_get_property) { 886c349dbc7Sjsg return connector->funcs->atomic_get_property(connector, 887c349dbc7Sjsg state, property, val); 888c349dbc7Sjsg } else { 889f005ef32Sjsg drm_dbg_atomic(dev, 890f005ef32Sjsg "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]\n", 891f005ef32Sjsg connector->base.id, connector->name, 892f005ef32Sjsg property->base.id, property->name); 893c349dbc7Sjsg return -EINVAL; 894c349dbc7Sjsg } 895c349dbc7Sjsg 896c349dbc7Sjsg return 0; 897c349dbc7Sjsg } 898c349dbc7Sjsg 899c349dbc7Sjsg int drm_atomic_get_property(struct drm_mode_object *obj, 900c349dbc7Sjsg struct drm_property *property, uint64_t *val) 901c349dbc7Sjsg { 902c349dbc7Sjsg struct drm_device *dev = property->dev; 903c349dbc7Sjsg int ret; 904c349dbc7Sjsg 905c349dbc7Sjsg switch (obj->type) { 906c349dbc7Sjsg case DRM_MODE_OBJECT_CONNECTOR: { 907c349dbc7Sjsg struct drm_connector *connector = obj_to_connector(obj); 908ad8b1aafSjsg 909c349dbc7Sjsg WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); 910c349dbc7Sjsg ret = drm_atomic_connector_get_property(connector, 911c349dbc7Sjsg connector->state, property, val); 912c349dbc7Sjsg break; 913c349dbc7Sjsg } 914c349dbc7Sjsg case DRM_MODE_OBJECT_CRTC: { 915c349dbc7Sjsg struct drm_crtc *crtc = obj_to_crtc(obj); 916ad8b1aafSjsg 917c349dbc7Sjsg WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 918c349dbc7Sjsg ret = drm_atomic_crtc_get_property(crtc, 919c349dbc7Sjsg crtc->state, property, val); 920c349dbc7Sjsg break; 921c349dbc7Sjsg } 922c349dbc7Sjsg case DRM_MODE_OBJECT_PLANE: { 923c349dbc7Sjsg struct drm_plane *plane = obj_to_plane(obj); 924ad8b1aafSjsg 925c349dbc7Sjsg WARN_ON(!drm_modeset_is_locked(&plane->mutex)); 926c349dbc7Sjsg ret = drm_atomic_plane_get_property(plane, 927c349dbc7Sjsg plane->state, property, val); 928c349dbc7Sjsg break; 929c349dbc7Sjsg } 930c349dbc7Sjsg default: 931f005ef32Sjsg drm_dbg_atomic(dev, "[OBJECT:%d] has no properties\n", obj->id); 932c349dbc7Sjsg ret = -EINVAL; 933c349dbc7Sjsg break; 934c349dbc7Sjsg } 935c349dbc7Sjsg 936c349dbc7Sjsg return ret; 937c349dbc7Sjsg } 938c349dbc7Sjsg 939c349dbc7Sjsg /* 940c349dbc7Sjsg * The big monster ioctl 941c349dbc7Sjsg */ 942c349dbc7Sjsg 943c349dbc7Sjsg static struct drm_pending_vblank_event *create_vblank_event( 944c349dbc7Sjsg struct drm_crtc *crtc, uint64_t user_data) 945c349dbc7Sjsg { 946c349dbc7Sjsg struct drm_pending_vblank_event *e = NULL; 947c349dbc7Sjsg 948c349dbc7Sjsg e = kzalloc(sizeof *e, GFP_KERNEL); 949c349dbc7Sjsg if (!e) 950c349dbc7Sjsg return NULL; 951c349dbc7Sjsg 952c349dbc7Sjsg e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 953c349dbc7Sjsg e->event.base.length = sizeof(e->event); 954c349dbc7Sjsg e->event.vbl.crtc_id = crtc->base.id; 955c349dbc7Sjsg e->event.vbl.user_data = user_data; 956c349dbc7Sjsg 957c349dbc7Sjsg return e; 958c349dbc7Sjsg } 959c349dbc7Sjsg 960c349dbc7Sjsg int drm_atomic_connector_commit_dpms(struct drm_atomic_state *state, 961c349dbc7Sjsg struct drm_connector *connector, 962c349dbc7Sjsg int mode) 963c349dbc7Sjsg { 964c349dbc7Sjsg struct drm_connector *tmp_connector; 965c349dbc7Sjsg struct drm_connector_state *new_conn_state; 966c349dbc7Sjsg struct drm_crtc *crtc; 967c349dbc7Sjsg struct drm_crtc_state *crtc_state; 968c349dbc7Sjsg int i, ret, old_mode = connector->dpms; 969c349dbc7Sjsg bool active = false; 970c349dbc7Sjsg 971c349dbc7Sjsg ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, 972c349dbc7Sjsg state->acquire_ctx); 973c349dbc7Sjsg if (ret) 974c349dbc7Sjsg return ret; 975c349dbc7Sjsg 976c349dbc7Sjsg if (mode != DRM_MODE_DPMS_ON) 977c349dbc7Sjsg mode = DRM_MODE_DPMS_OFF; 978c349dbc7Sjsg connector->dpms = mode; 979c349dbc7Sjsg 980c349dbc7Sjsg crtc = connector->state->crtc; 981c349dbc7Sjsg if (!crtc) 982c349dbc7Sjsg goto out; 983c349dbc7Sjsg ret = drm_atomic_add_affected_connectors(state, crtc); 984c349dbc7Sjsg if (ret) 985c349dbc7Sjsg goto out; 986c349dbc7Sjsg 987c349dbc7Sjsg crtc_state = drm_atomic_get_crtc_state(state, crtc); 988c349dbc7Sjsg if (IS_ERR(crtc_state)) { 989c349dbc7Sjsg ret = PTR_ERR(crtc_state); 990c349dbc7Sjsg goto out; 991c349dbc7Sjsg } 992c349dbc7Sjsg 993c349dbc7Sjsg for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) { 994c349dbc7Sjsg if (new_conn_state->crtc != crtc) 995c349dbc7Sjsg continue; 996c349dbc7Sjsg if (tmp_connector->dpms == DRM_MODE_DPMS_ON) { 997c349dbc7Sjsg active = true; 998c349dbc7Sjsg break; 999c349dbc7Sjsg } 1000c349dbc7Sjsg } 1001c349dbc7Sjsg 1002c349dbc7Sjsg crtc_state->active = active; 1003c349dbc7Sjsg ret = drm_atomic_commit(state); 1004c349dbc7Sjsg out: 1005c349dbc7Sjsg if (ret != 0) 1006c349dbc7Sjsg connector->dpms = old_mode; 1007c349dbc7Sjsg return ret; 1008c349dbc7Sjsg } 1009c349dbc7Sjsg 1010c349dbc7Sjsg int drm_atomic_set_property(struct drm_atomic_state *state, 1011c349dbc7Sjsg struct drm_file *file_priv, 1012c349dbc7Sjsg struct drm_mode_object *obj, 1013c349dbc7Sjsg struct drm_property *prop, 1014c349dbc7Sjsg uint64_t prop_value) 1015c349dbc7Sjsg { 1016c349dbc7Sjsg struct drm_mode_object *ref; 1017c349dbc7Sjsg int ret; 1018c349dbc7Sjsg 1019c349dbc7Sjsg if (!drm_property_change_valid_get(prop, prop_value, &ref)) 1020c349dbc7Sjsg return -EINVAL; 1021c349dbc7Sjsg 1022c349dbc7Sjsg switch (obj->type) { 1023c349dbc7Sjsg case DRM_MODE_OBJECT_CONNECTOR: { 1024c349dbc7Sjsg struct drm_connector *connector = obj_to_connector(obj); 1025c349dbc7Sjsg struct drm_connector_state *connector_state; 1026c349dbc7Sjsg 1027c349dbc7Sjsg connector_state = drm_atomic_get_connector_state(state, connector); 1028c349dbc7Sjsg if (IS_ERR(connector_state)) { 1029c349dbc7Sjsg ret = PTR_ERR(connector_state); 1030c349dbc7Sjsg break; 1031c349dbc7Sjsg } 1032c349dbc7Sjsg 1033c349dbc7Sjsg ret = drm_atomic_connector_set_property(connector, 1034c349dbc7Sjsg connector_state, file_priv, 1035c349dbc7Sjsg prop, prop_value); 1036c349dbc7Sjsg break; 1037c349dbc7Sjsg } 1038c349dbc7Sjsg case DRM_MODE_OBJECT_CRTC: { 1039c349dbc7Sjsg struct drm_crtc *crtc = obj_to_crtc(obj); 1040c349dbc7Sjsg struct drm_crtc_state *crtc_state; 1041c349dbc7Sjsg 1042c349dbc7Sjsg crtc_state = drm_atomic_get_crtc_state(state, crtc); 1043c349dbc7Sjsg if (IS_ERR(crtc_state)) { 1044c349dbc7Sjsg ret = PTR_ERR(crtc_state); 1045c349dbc7Sjsg break; 1046c349dbc7Sjsg } 1047c349dbc7Sjsg 1048c349dbc7Sjsg ret = drm_atomic_crtc_set_property(crtc, 1049c349dbc7Sjsg crtc_state, prop, prop_value); 1050c349dbc7Sjsg break; 1051c349dbc7Sjsg } 1052c349dbc7Sjsg case DRM_MODE_OBJECT_PLANE: { 1053c349dbc7Sjsg struct drm_plane *plane = obj_to_plane(obj); 1054c349dbc7Sjsg struct drm_plane_state *plane_state; 1055c349dbc7Sjsg 1056c349dbc7Sjsg plane_state = drm_atomic_get_plane_state(state, plane); 1057c349dbc7Sjsg if (IS_ERR(plane_state)) { 1058c349dbc7Sjsg ret = PTR_ERR(plane_state); 1059c349dbc7Sjsg break; 1060c349dbc7Sjsg } 1061c349dbc7Sjsg 1062c349dbc7Sjsg ret = drm_atomic_plane_set_property(plane, 1063c349dbc7Sjsg plane_state, file_priv, 1064c349dbc7Sjsg prop, prop_value); 1065c349dbc7Sjsg break; 1066c349dbc7Sjsg } 1067c349dbc7Sjsg default: 1068f005ef32Sjsg drm_dbg_atomic(prop->dev, "[OBJECT:%d] has no properties\n", obj->id); 1069c349dbc7Sjsg ret = -EINVAL; 1070c349dbc7Sjsg break; 1071c349dbc7Sjsg } 1072c349dbc7Sjsg 1073c349dbc7Sjsg drm_property_change_valid_put(prop, ref); 1074c349dbc7Sjsg return ret; 1075c349dbc7Sjsg } 1076c349dbc7Sjsg 1077c349dbc7Sjsg /** 1078c349dbc7Sjsg * DOC: explicit fencing properties 1079c349dbc7Sjsg * 1080c349dbc7Sjsg * Explicit fencing allows userspace to control the buffer synchronization 10815ca02815Sjsg * between devices. A Fence or a group of fences are transferred to/from 1082c349dbc7Sjsg * userspace using Sync File fds and there are two DRM properties for that. 1083c349dbc7Sjsg * IN_FENCE_FD on each DRM Plane to send fences to the kernel and 1084c349dbc7Sjsg * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel. 1085c349dbc7Sjsg * 1086c349dbc7Sjsg * As a contrast, with implicit fencing the kernel keeps track of any 1087c349dbc7Sjsg * ongoing rendering, and automatically ensures that the atomic update waits 10881bb76ff1Sjsg * for any pending rendering to complete. This is usually tracked in &struct 10891bb76ff1Sjsg * dma_resv which can also contain mandatory kernel fences. Implicit syncing 10901bb76ff1Sjsg * is how Linux traditionally worked (e.g. DRI2/3 on X.org), whereas explicit 10911bb76ff1Sjsg * fencing is what Android wants. 1092c349dbc7Sjsg * 1093c349dbc7Sjsg * "IN_FENCE_FD”: 1094c349dbc7Sjsg * Use this property to pass a fence that DRM should wait on before 1095c349dbc7Sjsg * proceeding with the Atomic Commit request and show the framebuffer for 1096c349dbc7Sjsg * the plane on the screen. The fence can be either a normal fence or a 1097c349dbc7Sjsg * merged one, the sync_file framework will handle both cases and use a 1098c349dbc7Sjsg * fence_array if a merged fence is received. Passing -1 here means no 1099c349dbc7Sjsg * fences to wait on. 1100c349dbc7Sjsg * 1101c349dbc7Sjsg * If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag 1102c349dbc7Sjsg * it will only check if the Sync File is a valid one. 1103c349dbc7Sjsg * 1104c349dbc7Sjsg * On the driver side the fence is stored on the @fence parameter of 1105c349dbc7Sjsg * &struct drm_plane_state. Drivers which also support implicit fencing 11061bb76ff1Sjsg * should extract the implicit fence using drm_gem_plane_helper_prepare_fb(), 1107c349dbc7Sjsg * to make sure there's consistent behaviour between drivers in precedence 1108c349dbc7Sjsg * of implicit vs. explicit fencing. 1109c349dbc7Sjsg * 1110c349dbc7Sjsg * "OUT_FENCE_PTR”: 1111c349dbc7Sjsg * Use this property to pass a file descriptor pointer to DRM. Once the 1112c349dbc7Sjsg * Atomic Commit request call returns OUT_FENCE_PTR will be filled with 1113c349dbc7Sjsg * the file descriptor number of a Sync File. This Sync File contains the 1114c349dbc7Sjsg * CRTC fence that will be signaled when all framebuffers present on the 1115c349dbc7Sjsg * Atomic Commit * request for that given CRTC are scanned out on the 1116c349dbc7Sjsg * screen. 1117c349dbc7Sjsg * 1118c349dbc7Sjsg * The Atomic Commit request fails if a invalid pointer is passed. If the 1119c349dbc7Sjsg * Atomic Commit request fails for any other reason the out fence fd 1120c349dbc7Sjsg * returned will be -1. On a Atomic Commit with the 1121c349dbc7Sjsg * DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1. 1122c349dbc7Sjsg * 1123c349dbc7Sjsg * Note that out-fences don't have a special interface to drivers and are 1124c349dbc7Sjsg * internally represented by a &struct drm_pending_vblank_event in struct 1125c349dbc7Sjsg * &drm_crtc_state, which is also used by the nonblocking atomic commit 1126c349dbc7Sjsg * helpers and for the DRM event handling for existing userspace. 1127c349dbc7Sjsg */ 1128c349dbc7Sjsg 1129c349dbc7Sjsg struct drm_out_fence_state { 1130c349dbc7Sjsg s32 __user *out_fence_ptr; 1131c349dbc7Sjsg struct sync_file *sync_file; 1132c349dbc7Sjsg int fd; 1133c349dbc7Sjsg }; 1134c349dbc7Sjsg 1135c349dbc7Sjsg static int setup_out_fence(struct drm_out_fence_state *fence_state, 1136c349dbc7Sjsg struct dma_fence *fence) 1137c349dbc7Sjsg { 1138c349dbc7Sjsg fence_state->fd = get_unused_fd_flags(O_CLOEXEC); 1139c349dbc7Sjsg if (fence_state->fd < 0) 1140c349dbc7Sjsg return fence_state->fd; 1141c349dbc7Sjsg 1142c349dbc7Sjsg if (put_user(fence_state->fd, fence_state->out_fence_ptr)) 1143c349dbc7Sjsg return -EFAULT; 1144c349dbc7Sjsg 1145c349dbc7Sjsg fence_state->sync_file = sync_file_create(fence); 1146c349dbc7Sjsg if (!fence_state->sync_file) 1147c349dbc7Sjsg return -ENOMEM; 1148c349dbc7Sjsg 1149c349dbc7Sjsg return 0; 1150c349dbc7Sjsg } 1151c349dbc7Sjsg 1152c349dbc7Sjsg static int prepare_signaling(struct drm_device *dev, 1153c349dbc7Sjsg struct drm_atomic_state *state, 1154c349dbc7Sjsg struct drm_mode_atomic *arg, 1155c349dbc7Sjsg struct drm_file *file_priv, 1156c349dbc7Sjsg struct drm_out_fence_state **fence_state, 1157c349dbc7Sjsg unsigned int *num_fences) 1158c349dbc7Sjsg { 1159c349dbc7Sjsg struct drm_crtc *crtc; 1160c349dbc7Sjsg struct drm_crtc_state *crtc_state; 1161c349dbc7Sjsg struct drm_connector *conn; 1162c349dbc7Sjsg struct drm_connector_state *conn_state; 1163c349dbc7Sjsg int i, c = 0, ret; 1164c349dbc7Sjsg 1165c349dbc7Sjsg if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) 1166c349dbc7Sjsg return 0; 1167c349dbc7Sjsg 1168c349dbc7Sjsg for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 1169c349dbc7Sjsg s32 __user *fence_ptr; 1170c349dbc7Sjsg 1171c349dbc7Sjsg fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); 1172c349dbc7Sjsg 1173c349dbc7Sjsg if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) { 1174c349dbc7Sjsg struct drm_pending_vblank_event *e; 1175c349dbc7Sjsg 1176c349dbc7Sjsg e = create_vblank_event(crtc, arg->user_data); 1177c349dbc7Sjsg if (!e) 1178c349dbc7Sjsg return -ENOMEM; 1179c349dbc7Sjsg 1180c349dbc7Sjsg crtc_state->event = e; 1181c349dbc7Sjsg } 1182c349dbc7Sjsg 1183c349dbc7Sjsg if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { 1184c349dbc7Sjsg struct drm_pending_vblank_event *e = crtc_state->event; 1185c349dbc7Sjsg 1186c349dbc7Sjsg if (!file_priv) 1187c349dbc7Sjsg continue; 1188c349dbc7Sjsg 1189c349dbc7Sjsg ret = drm_event_reserve_init(dev, file_priv, &e->base, 1190c349dbc7Sjsg &e->event.base); 1191c349dbc7Sjsg if (ret) { 1192c349dbc7Sjsg kfree(e); 1193c349dbc7Sjsg crtc_state->event = NULL; 1194c349dbc7Sjsg return ret; 1195c349dbc7Sjsg } 1196c349dbc7Sjsg } 1197c349dbc7Sjsg 1198c349dbc7Sjsg if (fence_ptr) { 1199c349dbc7Sjsg struct dma_fence *fence; 1200c349dbc7Sjsg struct drm_out_fence_state *f; 1201c349dbc7Sjsg 1202c349dbc7Sjsg #ifdef __linux__ 1203c349dbc7Sjsg f = krealloc(*fence_state, sizeof(**fence_state) * 1204c349dbc7Sjsg (*num_fences + 1), GFP_KERNEL); 1205c349dbc7Sjsg if (!f) 1206c349dbc7Sjsg return -ENOMEM; 1207c349dbc7Sjsg #else 1208c349dbc7Sjsg f = kmalloc(sizeof(**fence_state) * 1209c349dbc7Sjsg (*num_fences + 1), GFP_KERNEL); 1210c349dbc7Sjsg if (!f) 1211c349dbc7Sjsg return -ENOMEM; 1212c349dbc7Sjsg memcpy(f, *fence_state, 1213c349dbc7Sjsg sizeof(**fence_state) * (*num_fences)); 1214c349dbc7Sjsg kfree(*fence_state); 1215c349dbc7Sjsg #endif 1216c349dbc7Sjsg 1217c349dbc7Sjsg memset(&f[*num_fences], 0, sizeof(*f)); 1218c349dbc7Sjsg 1219c349dbc7Sjsg f[*num_fences].out_fence_ptr = fence_ptr; 1220c349dbc7Sjsg *fence_state = f; 1221c349dbc7Sjsg 1222c349dbc7Sjsg fence = drm_crtc_create_fence(crtc); 1223c349dbc7Sjsg if (!fence) 1224c349dbc7Sjsg return -ENOMEM; 1225c349dbc7Sjsg 1226c349dbc7Sjsg ret = setup_out_fence(&f[(*num_fences)++], fence); 1227c349dbc7Sjsg if (ret) { 1228c349dbc7Sjsg dma_fence_put(fence); 1229c349dbc7Sjsg return ret; 1230c349dbc7Sjsg } 1231c349dbc7Sjsg 1232c349dbc7Sjsg crtc_state->event->base.fence = fence; 1233c349dbc7Sjsg } 1234c349dbc7Sjsg 1235c349dbc7Sjsg c++; 1236c349dbc7Sjsg } 1237c349dbc7Sjsg 1238c349dbc7Sjsg for_each_new_connector_in_state(state, conn, conn_state, i) { 1239c349dbc7Sjsg struct drm_writeback_connector *wb_conn; 1240c349dbc7Sjsg struct drm_out_fence_state *f; 1241c349dbc7Sjsg struct dma_fence *fence; 1242c349dbc7Sjsg s32 __user *fence_ptr; 1243c349dbc7Sjsg 1244c349dbc7Sjsg if (!conn_state->writeback_job) 1245c349dbc7Sjsg continue; 1246c349dbc7Sjsg 1247c349dbc7Sjsg fence_ptr = get_out_fence_for_connector(state, conn); 1248c349dbc7Sjsg if (!fence_ptr) 1249c349dbc7Sjsg continue; 1250c349dbc7Sjsg 1251c349dbc7Sjsg #ifdef __linux__ 1252c349dbc7Sjsg f = krealloc(*fence_state, sizeof(**fence_state) * 1253c349dbc7Sjsg (*num_fences + 1), GFP_KERNEL); 1254c349dbc7Sjsg if (!f) 1255c349dbc7Sjsg return -ENOMEM; 1256c349dbc7Sjsg #else 1257c349dbc7Sjsg f = kmalloc(sizeof(**fence_state) * 1258c349dbc7Sjsg (*num_fences + 1), GFP_KERNEL); 1259c349dbc7Sjsg if (!f) 1260c349dbc7Sjsg return -ENOMEM; 1261c349dbc7Sjsg memcpy(f, *fence_state, 1262c349dbc7Sjsg sizeof(**fence_state) * (*num_fences)); 1263c349dbc7Sjsg kfree(*fence_state); 1264c349dbc7Sjsg #endif 1265c349dbc7Sjsg 1266c349dbc7Sjsg memset(&f[*num_fences], 0, sizeof(*f)); 1267c349dbc7Sjsg 1268c349dbc7Sjsg f[*num_fences].out_fence_ptr = fence_ptr; 1269c349dbc7Sjsg *fence_state = f; 1270c349dbc7Sjsg 1271c349dbc7Sjsg wb_conn = drm_connector_to_writeback(conn); 1272c349dbc7Sjsg fence = drm_writeback_get_out_fence(wb_conn); 1273c349dbc7Sjsg if (!fence) 1274c349dbc7Sjsg return -ENOMEM; 1275c349dbc7Sjsg 1276c349dbc7Sjsg ret = setup_out_fence(&f[(*num_fences)++], fence); 1277c349dbc7Sjsg if (ret) { 1278c349dbc7Sjsg dma_fence_put(fence); 1279c349dbc7Sjsg return ret; 1280c349dbc7Sjsg } 1281c349dbc7Sjsg 1282c349dbc7Sjsg conn_state->writeback_job->out_fence = fence; 1283c349dbc7Sjsg } 1284c349dbc7Sjsg 1285c349dbc7Sjsg /* 1286c349dbc7Sjsg * Having this flag means user mode pends on event which will never 1287c349dbc7Sjsg * reach due to lack of at least one CRTC for signaling 1288c349dbc7Sjsg */ 1289f005ef32Sjsg if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) { 1290f005ef32Sjsg drm_dbg_atomic(dev, "need at least one CRTC for DRM_MODE_PAGE_FLIP_EVENT"); 1291c349dbc7Sjsg return -EINVAL; 1292f005ef32Sjsg } 1293c349dbc7Sjsg 1294c349dbc7Sjsg return 0; 1295c349dbc7Sjsg } 1296c349dbc7Sjsg 1297c349dbc7Sjsg static void complete_signaling(struct drm_device *dev, 1298c349dbc7Sjsg struct drm_atomic_state *state, 1299c349dbc7Sjsg struct drm_out_fence_state *fence_state, 1300c349dbc7Sjsg unsigned int num_fences, 1301c349dbc7Sjsg bool install_fds) 1302c349dbc7Sjsg { 1303c349dbc7Sjsg struct drm_crtc *crtc; 1304c349dbc7Sjsg struct drm_crtc_state *crtc_state; 1305c349dbc7Sjsg int i; 1306c349dbc7Sjsg 1307c349dbc7Sjsg if (install_fds) { 1308c349dbc7Sjsg for (i = 0; i < num_fences; i++) 1309c349dbc7Sjsg fd_install(fence_state[i].fd, 1310c349dbc7Sjsg fence_state[i].sync_file->file); 1311c349dbc7Sjsg 1312c349dbc7Sjsg kfree(fence_state); 1313c349dbc7Sjsg return; 1314c349dbc7Sjsg } 1315c349dbc7Sjsg 1316c349dbc7Sjsg for_each_new_crtc_in_state(state, crtc, crtc_state, i) { 1317c349dbc7Sjsg struct drm_pending_vblank_event *event = crtc_state->event; 1318c349dbc7Sjsg /* 1319c349dbc7Sjsg * Free the allocated event. drm_atomic_helper_setup_commit 1320c349dbc7Sjsg * can allocate an event too, so only free it if it's ours 1321c349dbc7Sjsg * to prevent a double free in drm_atomic_state_clear. 1322c349dbc7Sjsg */ 1323c349dbc7Sjsg if (event && (event->base.fence || event->base.file_priv)) { 1324c349dbc7Sjsg drm_event_cancel_free(dev, &event->base); 1325c349dbc7Sjsg crtc_state->event = NULL; 1326c349dbc7Sjsg } 1327c349dbc7Sjsg } 1328c349dbc7Sjsg 1329c349dbc7Sjsg if (!fence_state) 1330c349dbc7Sjsg return; 1331c349dbc7Sjsg 1332c349dbc7Sjsg for (i = 0; i < num_fences; i++) { 1333c349dbc7Sjsg if (fence_state[i].sync_file) 1334c349dbc7Sjsg fput(fence_state[i].sync_file->file); 1335c349dbc7Sjsg if (fence_state[i].fd >= 0) 1336c349dbc7Sjsg put_unused_fd(fence_state[i].fd); 1337c349dbc7Sjsg 1338c349dbc7Sjsg /* If this fails log error to the user */ 1339c349dbc7Sjsg if (fence_state[i].out_fence_ptr && 1340c349dbc7Sjsg put_user(-1, fence_state[i].out_fence_ptr)) 13415ca02815Sjsg drm_dbg_atomic(dev, "Couldn't clear out_fence_ptr\n"); 1342c349dbc7Sjsg } 1343c349dbc7Sjsg 1344c349dbc7Sjsg kfree(fence_state); 1345c349dbc7Sjsg } 1346c349dbc7Sjsg 1347c349dbc7Sjsg int drm_mode_atomic_ioctl(struct drm_device *dev, 1348c349dbc7Sjsg void *data, struct drm_file *file_priv) 1349c349dbc7Sjsg { 1350c349dbc7Sjsg struct drm_mode_atomic *arg = data; 1351c349dbc7Sjsg uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); 1352c349dbc7Sjsg uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); 1353c349dbc7Sjsg uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); 1354c349dbc7Sjsg uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); 1355c349dbc7Sjsg unsigned int copied_objs, copied_props; 1356c349dbc7Sjsg struct drm_atomic_state *state; 1357c349dbc7Sjsg struct drm_modeset_acquire_ctx ctx; 1358c349dbc7Sjsg struct drm_out_fence_state *fence_state; 1359c349dbc7Sjsg int ret = 0; 1360c349dbc7Sjsg unsigned int i, j, num_fences; 1361c349dbc7Sjsg 1362c349dbc7Sjsg /* disallow for drivers not supporting atomic: */ 1363c349dbc7Sjsg if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) 1364c349dbc7Sjsg return -EOPNOTSUPP; 1365c349dbc7Sjsg 1366c349dbc7Sjsg /* disallow for userspace that has not enabled atomic cap (even 1367c349dbc7Sjsg * though this may be a bit overkill, since legacy userspace 1368c349dbc7Sjsg * wouldn't know how to call this ioctl) 1369c349dbc7Sjsg */ 13705ca02815Sjsg if (!file_priv->atomic) { 13715ca02815Sjsg drm_dbg_atomic(dev, 13725ca02815Sjsg "commit failed: atomic cap not enabled\n"); 1373c349dbc7Sjsg return -EINVAL; 13745ca02815Sjsg } 1375c349dbc7Sjsg 13765ca02815Sjsg if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) { 13775ca02815Sjsg drm_dbg_atomic(dev, "commit failed: invalid flag\n"); 1378c349dbc7Sjsg return -EINVAL; 13795ca02815Sjsg } 1380c349dbc7Sjsg 13815ca02815Sjsg if (arg->reserved) { 13825ca02815Sjsg drm_dbg_atomic(dev, "commit failed: reserved field set\n"); 1383c349dbc7Sjsg return -EINVAL; 13845ca02815Sjsg } 1385c349dbc7Sjsg 13865ca02815Sjsg if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) { 13875ca02815Sjsg drm_dbg_atomic(dev, 13885ca02815Sjsg "commit failed: invalid flag DRM_MODE_PAGE_FLIP_ASYNC\n"); 1389c349dbc7Sjsg return -EINVAL; 13905ca02815Sjsg } 1391c349dbc7Sjsg 1392c349dbc7Sjsg /* can't test and expect an event at the same time. */ 1393c349dbc7Sjsg if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) && 13945ca02815Sjsg (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) { 13955ca02815Sjsg drm_dbg_atomic(dev, 13965ca02815Sjsg "commit failed: page-flip event requested with test-only commit\n"); 1397c349dbc7Sjsg return -EINVAL; 13985ca02815Sjsg } 1399c349dbc7Sjsg 1400c349dbc7Sjsg state = drm_atomic_state_alloc(dev); 1401c349dbc7Sjsg if (!state) 1402c349dbc7Sjsg return -ENOMEM; 1403c349dbc7Sjsg 1404c349dbc7Sjsg drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); 1405c349dbc7Sjsg state->acquire_ctx = &ctx; 1406c349dbc7Sjsg state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); 1407c349dbc7Sjsg 1408c349dbc7Sjsg retry: 1409c349dbc7Sjsg copied_objs = 0; 1410c349dbc7Sjsg copied_props = 0; 1411c349dbc7Sjsg fence_state = NULL; 1412c349dbc7Sjsg num_fences = 0; 1413c349dbc7Sjsg 1414c349dbc7Sjsg for (i = 0; i < arg->count_objs; i++) { 1415c349dbc7Sjsg uint32_t obj_id, count_props; 1416c349dbc7Sjsg struct drm_mode_object *obj; 1417c349dbc7Sjsg 1418c349dbc7Sjsg if (get_user(obj_id, objs_ptr + copied_objs)) { 1419c349dbc7Sjsg ret = -EFAULT; 1420c349dbc7Sjsg goto out; 1421c349dbc7Sjsg } 1422c349dbc7Sjsg 1423c349dbc7Sjsg obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY); 1424c349dbc7Sjsg if (!obj) { 1425f005ef32Sjsg drm_dbg_atomic(dev, "cannot find object ID %d", obj_id); 1426c349dbc7Sjsg ret = -ENOENT; 1427c349dbc7Sjsg goto out; 1428c349dbc7Sjsg } 1429c349dbc7Sjsg 1430c349dbc7Sjsg if (!obj->properties) { 1431f005ef32Sjsg drm_dbg_atomic(dev, "[OBJECT:%d] has no properties", obj_id); 1432c349dbc7Sjsg drm_mode_object_put(obj); 1433c349dbc7Sjsg ret = -ENOENT; 1434c349dbc7Sjsg goto out; 1435c349dbc7Sjsg } 1436c349dbc7Sjsg 1437c349dbc7Sjsg if (get_user(count_props, count_props_ptr + copied_objs)) { 1438c349dbc7Sjsg drm_mode_object_put(obj); 1439c349dbc7Sjsg ret = -EFAULT; 1440c349dbc7Sjsg goto out; 1441c349dbc7Sjsg } 1442c349dbc7Sjsg 1443c349dbc7Sjsg copied_objs++; 1444c349dbc7Sjsg 1445c349dbc7Sjsg for (j = 0; j < count_props; j++) { 1446c349dbc7Sjsg uint32_t prop_id; 1447c349dbc7Sjsg uint64_t prop_value; 1448c349dbc7Sjsg struct drm_property *prop; 1449c349dbc7Sjsg 1450c349dbc7Sjsg if (get_user(prop_id, props_ptr + copied_props)) { 1451c349dbc7Sjsg drm_mode_object_put(obj); 1452c349dbc7Sjsg ret = -EFAULT; 1453c349dbc7Sjsg goto out; 1454c349dbc7Sjsg } 1455c349dbc7Sjsg 1456c349dbc7Sjsg prop = drm_mode_obj_find_prop_id(obj, prop_id); 1457c349dbc7Sjsg if (!prop) { 1458f005ef32Sjsg drm_dbg_atomic(dev, 1459f005ef32Sjsg "[OBJECT:%d] cannot find property ID %d", 1460f005ef32Sjsg obj_id, prop_id); 1461c349dbc7Sjsg drm_mode_object_put(obj); 1462c349dbc7Sjsg ret = -ENOENT; 1463c349dbc7Sjsg goto out; 1464c349dbc7Sjsg } 1465c349dbc7Sjsg 1466c349dbc7Sjsg if (copy_from_user(&prop_value, 1467c349dbc7Sjsg prop_values_ptr + copied_props, 1468c349dbc7Sjsg sizeof(prop_value))) { 1469c349dbc7Sjsg drm_mode_object_put(obj); 1470c349dbc7Sjsg ret = -EFAULT; 1471c349dbc7Sjsg goto out; 1472c349dbc7Sjsg } 1473c349dbc7Sjsg 1474c349dbc7Sjsg ret = drm_atomic_set_property(state, file_priv, 1475c349dbc7Sjsg obj, prop, prop_value); 1476c349dbc7Sjsg if (ret) { 1477c349dbc7Sjsg drm_mode_object_put(obj); 1478c349dbc7Sjsg goto out; 1479c349dbc7Sjsg } 1480c349dbc7Sjsg 1481c349dbc7Sjsg copied_props++; 1482c349dbc7Sjsg } 1483c349dbc7Sjsg 1484c349dbc7Sjsg drm_mode_object_put(obj); 1485c349dbc7Sjsg } 1486c349dbc7Sjsg 1487c349dbc7Sjsg ret = prepare_signaling(dev, state, arg, file_priv, &fence_state, 1488c349dbc7Sjsg &num_fences); 1489c349dbc7Sjsg if (ret) 1490c349dbc7Sjsg goto out; 1491c349dbc7Sjsg 1492c349dbc7Sjsg if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { 1493c349dbc7Sjsg ret = drm_atomic_check_only(state); 1494c349dbc7Sjsg } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { 1495c349dbc7Sjsg ret = drm_atomic_nonblocking_commit(state); 1496c349dbc7Sjsg } else { 1497c349dbc7Sjsg ret = drm_atomic_commit(state); 1498c349dbc7Sjsg } 1499c349dbc7Sjsg 1500c349dbc7Sjsg out: 1501c349dbc7Sjsg complete_signaling(dev, state, fence_state, num_fences, !ret); 1502c349dbc7Sjsg 1503c349dbc7Sjsg if (ret == -EDEADLK) { 1504c349dbc7Sjsg drm_atomic_state_clear(state); 1505c349dbc7Sjsg ret = drm_modeset_backoff(&ctx); 1506c349dbc7Sjsg if (!ret) 1507c349dbc7Sjsg goto retry; 1508c349dbc7Sjsg } 1509c349dbc7Sjsg 1510c349dbc7Sjsg drm_atomic_state_put(state); 1511c349dbc7Sjsg 1512c349dbc7Sjsg drm_modeset_drop_locks(&ctx); 1513c349dbc7Sjsg drm_modeset_acquire_fini(&ctx); 1514c349dbc7Sjsg 1515c349dbc7Sjsg return ret; 1516c349dbc7Sjsg } 1517