162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (C) 2014 Red Hat
362306a36Sopenharmony_ci * Copyright (C) 2014 Intel Corp.
462306a36Sopenharmony_ci * Copyright (C) 2018 Intel Corp.
562306a36Sopenharmony_ci * Copyright (c) 2020, The Linux Foundation. All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
862306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
962306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
1062306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1162306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
1262306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1562306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1862306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1962306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2062306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2162306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2262306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2362306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Authors:
2662306a36Sopenharmony_ci * Rob Clark <robdclark@gmail.com>
2762306a36Sopenharmony_ci * Daniel Vetter <daniel.vetter@ffwll.ch>
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <drm/drm_atomic_uapi.h>
3162306a36Sopenharmony_ci#include <drm/drm_atomic.h>
3262306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
3362306a36Sopenharmony_ci#include <drm/drm_print.h>
3462306a36Sopenharmony_ci#include <drm/drm_drv.h>
3562306a36Sopenharmony_ci#include <drm/drm_writeback.h>
3662306a36Sopenharmony_ci#include <drm/drm_vblank.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include <linux/dma-fence.h>
3962306a36Sopenharmony_ci#include <linux/uaccess.h>
4062306a36Sopenharmony_ci#include <linux/sync_file.h>
4162306a36Sopenharmony_ci#include <linux/file.h>
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include "drm_crtc_internal.h"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * DOC: overview
4762306a36Sopenharmony_ci *
4862306a36Sopenharmony_ci * This file contains the marshalling and demarshalling glue for the atomic UAPI
4962306a36Sopenharmony_ci * in all its forms: The monster ATOMIC IOCTL itself, code for GET_PROPERTY and
5062306a36Sopenharmony_ci * SET_PROPERTY IOCTLs. Plus interface functions for compatibility helpers and
5162306a36Sopenharmony_ci * drivers which have special needs to construct their own atomic updates, e.g.
5262306a36Sopenharmony_ci * for load detect or similar.
5362306a36Sopenharmony_ci */
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/**
5662306a36Sopenharmony_ci * drm_atomic_set_mode_for_crtc - set mode for CRTC
5762306a36Sopenharmony_ci * @state: the CRTC whose incoming state to update
5862306a36Sopenharmony_ci * @mode: kernel-internal mode to use for the CRTC, or NULL to disable
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci * Set a mode (originating from the kernel) on the desired CRTC state and update
6162306a36Sopenharmony_ci * the enable property.
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * RETURNS:
6462306a36Sopenharmony_ci * Zero on success, error code on failure. Cannot return -EDEADLK.
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ciint drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
6762306a36Sopenharmony_ci				 const struct drm_display_mode *mode)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct drm_crtc *crtc = state->crtc;
7062306a36Sopenharmony_ci	struct drm_mode_modeinfo umode;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Early return for no change. */
7362306a36Sopenharmony_ci	if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
7462306a36Sopenharmony_ci		return 0;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	drm_property_blob_put(state->mode_blob);
7762306a36Sopenharmony_ci	state->mode_blob = NULL;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (mode) {
8062306a36Sopenharmony_ci		struct drm_property_blob *blob;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci		drm_mode_convert_to_umode(&umode, mode);
8362306a36Sopenharmony_ci		blob = drm_property_create_blob(crtc->dev,
8462306a36Sopenharmony_ci						sizeof(umode), &umode);
8562306a36Sopenharmony_ci		if (IS_ERR(blob))
8662306a36Sopenharmony_ci			return PTR_ERR(blob);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		drm_mode_copy(&state->mode, mode);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		state->mode_blob = blob;
9162306a36Sopenharmony_ci		state->enable = true;
9262306a36Sopenharmony_ci		drm_dbg_atomic(crtc->dev,
9362306a36Sopenharmony_ci			       "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
9462306a36Sopenharmony_ci			       mode->name, crtc->base.id, crtc->name, state);
9562306a36Sopenharmony_ci	} else {
9662306a36Sopenharmony_ci		memset(&state->mode, 0, sizeof(state->mode));
9762306a36Sopenharmony_ci		state->enable = false;
9862306a36Sopenharmony_ci		drm_dbg_atomic(crtc->dev,
9962306a36Sopenharmony_ci			       "Set [NOMODE] for [CRTC:%d:%s] state %p\n",
10062306a36Sopenharmony_ci			       crtc->base.id, crtc->name, state);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/**
10862306a36Sopenharmony_ci * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC
10962306a36Sopenharmony_ci * @state: the CRTC whose incoming state to update
11062306a36Sopenharmony_ci * @blob: pointer to blob property to use for mode
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * Set a mode (originating from a blob property) on the desired CRTC state.
11362306a36Sopenharmony_ci * This function will take a reference on the blob property for the CRTC state,
11462306a36Sopenharmony_ci * and release the reference held on the state's existing mode property, if any
11562306a36Sopenharmony_ci * was set.
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * RETURNS:
11862306a36Sopenharmony_ci * Zero on success, error code on failure. Cannot return -EDEADLK.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_ciint drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
12162306a36Sopenharmony_ci				      struct drm_property_blob *blob)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct drm_crtc *crtc = state->crtc;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (blob == state->mode_blob)
12662306a36Sopenharmony_ci		return 0;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	drm_property_blob_put(state->mode_blob);
12962306a36Sopenharmony_ci	state->mode_blob = NULL;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	memset(&state->mode, 0, sizeof(state->mode));
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (blob) {
13462306a36Sopenharmony_ci		int ret;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		if (blob->length != sizeof(struct drm_mode_modeinfo)) {
13762306a36Sopenharmony_ci			drm_dbg_atomic(crtc->dev,
13862306a36Sopenharmony_ci				       "[CRTC:%d:%s] bad mode blob length: %zu\n",
13962306a36Sopenharmony_ci				       crtc->base.id, crtc->name,
14062306a36Sopenharmony_ci				       blob->length);
14162306a36Sopenharmony_ci			return -EINVAL;
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		ret = drm_mode_convert_umode(crtc->dev,
14562306a36Sopenharmony_ci					     &state->mode, blob->data);
14662306a36Sopenharmony_ci		if (ret) {
14762306a36Sopenharmony_ci			drm_dbg_atomic(crtc->dev,
14862306a36Sopenharmony_ci				       "[CRTC:%d:%s] invalid mode (ret=%d, status=%s):\n",
14962306a36Sopenharmony_ci				       crtc->base.id, crtc->name,
15062306a36Sopenharmony_ci				       ret, drm_get_mode_status_name(state->mode.status));
15162306a36Sopenharmony_ci			drm_mode_debug_printmodeline(&state->mode);
15262306a36Sopenharmony_ci			return -EINVAL;
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		state->mode_blob = drm_property_blob_get(blob);
15662306a36Sopenharmony_ci		state->enable = true;
15762306a36Sopenharmony_ci		drm_dbg_atomic(crtc->dev,
15862306a36Sopenharmony_ci			       "Set [MODE:%s] for [CRTC:%d:%s] state %p\n",
15962306a36Sopenharmony_ci			       state->mode.name, crtc->base.id, crtc->name,
16062306a36Sopenharmony_ci			       state);
16162306a36Sopenharmony_ci	} else {
16262306a36Sopenharmony_ci		state->enable = false;
16362306a36Sopenharmony_ci		drm_dbg_atomic(crtc->dev,
16462306a36Sopenharmony_ci			       "Set [NOMODE] for [CRTC:%d:%s] state %p\n",
16562306a36Sopenharmony_ci			       crtc->base.id, crtc->name, state);
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return 0;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/**
17362306a36Sopenharmony_ci * drm_atomic_set_crtc_for_plane - set CRTC for plane
17462306a36Sopenharmony_ci * @plane_state: the plane whose incoming state to update
17562306a36Sopenharmony_ci * @crtc: CRTC to use for the plane
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * Changing the assigned CRTC for a plane requires us to grab the lock and state
17862306a36Sopenharmony_ci * for the new CRTC, as needed. This function takes care of all these details
17962306a36Sopenharmony_ci * besides updating the pointer in the state object itself.
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci * Returns:
18262306a36Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
18362306a36Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic
18462306a36Sopenharmony_ci * sequence must be restarted. All other errors are fatal.
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_ciint
18762306a36Sopenharmony_cidrm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
18862306a36Sopenharmony_ci			      struct drm_crtc *crtc)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct drm_plane *plane = plane_state->plane;
19162306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
19262306a36Sopenharmony_ci	/* Nothing to do for same crtc*/
19362306a36Sopenharmony_ci	if (plane_state->crtc == crtc)
19462306a36Sopenharmony_ci		return 0;
19562306a36Sopenharmony_ci	if (plane_state->crtc) {
19662306a36Sopenharmony_ci		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
19762306a36Sopenharmony_ci						       plane_state->crtc);
19862306a36Sopenharmony_ci		if (WARN_ON(IS_ERR(crtc_state)))
19962306a36Sopenharmony_ci			return PTR_ERR(crtc_state);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		crtc_state->plane_mask &= ~drm_plane_mask(plane);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	plane_state->crtc = crtc;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (crtc) {
20762306a36Sopenharmony_ci		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
20862306a36Sopenharmony_ci						       crtc);
20962306a36Sopenharmony_ci		if (IS_ERR(crtc_state))
21062306a36Sopenharmony_ci			return PTR_ERR(crtc_state);
21162306a36Sopenharmony_ci		crtc_state->plane_mask |= drm_plane_mask(plane);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (crtc)
21562306a36Sopenharmony_ci		drm_dbg_atomic(plane->dev,
21662306a36Sopenharmony_ci			       "Link [PLANE:%d:%s] state %p to [CRTC:%d:%s]\n",
21762306a36Sopenharmony_ci			       plane->base.id, plane->name, plane_state,
21862306a36Sopenharmony_ci			       crtc->base.id, crtc->name);
21962306a36Sopenharmony_ci	else
22062306a36Sopenharmony_ci		drm_dbg_atomic(plane->dev,
22162306a36Sopenharmony_ci			       "Link [PLANE:%d:%s] state %p to [NOCRTC]\n",
22262306a36Sopenharmony_ci			       plane->base.id, plane->name, plane_state);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	return 0;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_set_crtc_for_plane);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/**
22962306a36Sopenharmony_ci * drm_atomic_set_fb_for_plane - set framebuffer for plane
23062306a36Sopenharmony_ci * @plane_state: atomic state object for the plane
23162306a36Sopenharmony_ci * @fb: fb to use for the plane
23262306a36Sopenharmony_ci *
23362306a36Sopenharmony_ci * Changing the assigned framebuffer for a plane requires us to grab a reference
23462306a36Sopenharmony_ci * to the new fb and drop the reference to the old fb, if there is one. This
23562306a36Sopenharmony_ci * function takes care of all these details besides updating the pointer in the
23662306a36Sopenharmony_ci * state object itself.
23762306a36Sopenharmony_ci */
23862306a36Sopenharmony_civoid
23962306a36Sopenharmony_cidrm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
24062306a36Sopenharmony_ci			    struct drm_framebuffer *fb)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct drm_plane *plane = plane_state->plane;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (fb)
24562306a36Sopenharmony_ci		drm_dbg_atomic(plane->dev,
24662306a36Sopenharmony_ci			       "Set [FB:%d] for [PLANE:%d:%s] state %p\n",
24762306a36Sopenharmony_ci			       fb->base.id, plane->base.id, plane->name,
24862306a36Sopenharmony_ci			       plane_state);
24962306a36Sopenharmony_ci	else
25062306a36Sopenharmony_ci		drm_dbg_atomic(plane->dev,
25162306a36Sopenharmony_ci			       "Set [NOFB] for [PLANE:%d:%s] state %p\n",
25262306a36Sopenharmony_ci			       plane->base.id, plane->name, plane_state);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	drm_framebuffer_assign(&plane_state->fb, fb);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_set_fb_for_plane);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/**
25962306a36Sopenharmony_ci * drm_atomic_set_crtc_for_connector - set CRTC for connector
26062306a36Sopenharmony_ci * @conn_state: atomic state object for the connector
26162306a36Sopenharmony_ci * @crtc: CRTC to use for the connector
26262306a36Sopenharmony_ci *
26362306a36Sopenharmony_ci * Changing the assigned CRTC for a connector requires us to grab the lock and
26462306a36Sopenharmony_ci * state for the new CRTC, as needed. This function takes care of all these
26562306a36Sopenharmony_ci * details besides updating the pointer in the state object itself.
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * Returns:
26862306a36Sopenharmony_ci * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
26962306a36Sopenharmony_ci * then the w/w mutex code has detected a deadlock and the entire atomic
27062306a36Sopenharmony_ci * sequence must be restarted. All other errors are fatal.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_ciint
27362306a36Sopenharmony_cidrm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state,
27462306a36Sopenharmony_ci				  struct drm_crtc *crtc)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct drm_connector *connector = conn_state->connector;
27762306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (conn_state->crtc == crtc)
28062306a36Sopenharmony_ci		return 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (conn_state->crtc) {
28362306a36Sopenharmony_ci		crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
28462306a36Sopenharmony_ci							   conn_state->crtc);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		crtc_state->connector_mask &=
28762306a36Sopenharmony_ci			~drm_connector_mask(conn_state->connector);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		drm_connector_put(conn_state->connector);
29062306a36Sopenharmony_ci		conn_state->crtc = NULL;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (crtc) {
29462306a36Sopenharmony_ci		crtc_state = drm_atomic_get_crtc_state(conn_state->state, crtc);
29562306a36Sopenharmony_ci		if (IS_ERR(crtc_state))
29662306a36Sopenharmony_ci			return PTR_ERR(crtc_state);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		crtc_state->connector_mask |=
29962306a36Sopenharmony_ci			drm_connector_mask(conn_state->connector);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		drm_connector_get(conn_state->connector);
30262306a36Sopenharmony_ci		conn_state->crtc = crtc;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		drm_dbg_atomic(connector->dev,
30562306a36Sopenharmony_ci			       "Link [CONNECTOR:%d:%s] state %p to [CRTC:%d:%s]\n",
30662306a36Sopenharmony_ci			       connector->base.id, connector->name,
30762306a36Sopenharmony_ci			       conn_state, crtc->base.id, crtc->name);
30862306a36Sopenharmony_ci	} else {
30962306a36Sopenharmony_ci		drm_dbg_atomic(connector->dev,
31062306a36Sopenharmony_ci			       "Link [CONNECTOR:%d:%s] state %p to [NOCRTC]\n",
31162306a36Sopenharmony_ci			       connector->base.id, connector->name,
31262306a36Sopenharmony_ci			       conn_state);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return 0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_atomic_set_crtc_for_connector);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic void set_out_fence_for_crtc(struct drm_atomic_state *state,
32062306a36Sopenharmony_ci				   struct drm_crtc *crtc, s32 __user *fence_ptr)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
32662306a36Sopenharmony_ci					  struct drm_crtc *crtc)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	s32 __user *fence_ptr;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
33162306a36Sopenharmony_ci	state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return fence_ptr;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int set_out_fence_for_connector(struct drm_atomic_state *state,
33762306a36Sopenharmony_ci					struct drm_connector *connector,
33862306a36Sopenharmony_ci					s32 __user *fence_ptr)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	unsigned int index = drm_connector_index(connector);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (!fence_ptr)
34362306a36Sopenharmony_ci		return 0;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (put_user(-1, fence_ptr))
34662306a36Sopenharmony_ci		return -EFAULT;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	state->connectors[index].out_fence_ptr = fence_ptr;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state,
35462306a36Sopenharmony_ci					       struct drm_connector *connector)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	unsigned int index = drm_connector_index(connector);
35762306a36Sopenharmony_ci	s32 __user *fence_ptr;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	fence_ptr = state->connectors[index].out_fence_ptr;
36062306a36Sopenharmony_ci	state->connectors[index].out_fence_ptr = NULL;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return fence_ptr;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic int
36662306a36Sopenharmony_cidrm_atomic_replace_property_blob_from_id(struct drm_device *dev,
36762306a36Sopenharmony_ci					 struct drm_property_blob **blob,
36862306a36Sopenharmony_ci					 uint64_t blob_id,
36962306a36Sopenharmony_ci					 ssize_t expected_size,
37062306a36Sopenharmony_ci					 ssize_t expected_elem_size,
37162306a36Sopenharmony_ci					 bool *replaced)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	struct drm_property_blob *new_blob = NULL;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	if (blob_id != 0) {
37662306a36Sopenharmony_ci		new_blob = drm_property_lookup_blob(dev, blob_id);
37762306a36Sopenharmony_ci		if (new_blob == NULL) {
37862306a36Sopenharmony_ci			drm_dbg_atomic(dev,
37962306a36Sopenharmony_ci				       "cannot find blob ID %llu\n", blob_id);
38062306a36Sopenharmony_ci			return -EINVAL;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		if (expected_size > 0 &&
38462306a36Sopenharmony_ci		    new_blob->length != expected_size) {
38562306a36Sopenharmony_ci			drm_dbg_atomic(dev,
38662306a36Sopenharmony_ci				       "[BLOB:%d] length %zu different from expected %zu\n",
38762306a36Sopenharmony_ci				       new_blob->base.id, new_blob->length, expected_size);
38862306a36Sopenharmony_ci			drm_property_blob_put(new_blob);
38962306a36Sopenharmony_ci			return -EINVAL;
39062306a36Sopenharmony_ci		}
39162306a36Sopenharmony_ci		if (expected_elem_size > 0 &&
39262306a36Sopenharmony_ci		    new_blob->length % expected_elem_size != 0) {
39362306a36Sopenharmony_ci			drm_dbg_atomic(dev,
39462306a36Sopenharmony_ci				       "[BLOB:%d] length %zu not divisible by element size %zu\n",
39562306a36Sopenharmony_ci				       new_blob->base.id, new_blob->length, expected_elem_size);
39662306a36Sopenharmony_ci			drm_property_blob_put(new_blob);
39762306a36Sopenharmony_ci			return -EINVAL;
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	*replaced |= drm_property_replace_blob(blob, new_blob);
40262306a36Sopenharmony_ci	drm_property_blob_put(new_blob);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
40862306a36Sopenharmony_ci		struct drm_crtc_state *state, struct drm_property *property,
40962306a36Sopenharmony_ci		uint64_t val)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
41262306a36Sopenharmony_ci	struct drm_mode_config *config = &dev->mode_config;
41362306a36Sopenharmony_ci	bool replaced = false;
41462306a36Sopenharmony_ci	int ret;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (property == config->prop_active)
41762306a36Sopenharmony_ci		state->active = val;
41862306a36Sopenharmony_ci	else if (property == config->prop_mode_id) {
41962306a36Sopenharmony_ci		struct drm_property_blob *mode =
42062306a36Sopenharmony_ci			drm_property_lookup_blob(dev, val);
42162306a36Sopenharmony_ci		ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
42262306a36Sopenharmony_ci		drm_property_blob_put(mode);
42362306a36Sopenharmony_ci		return ret;
42462306a36Sopenharmony_ci	} else if (property == config->prop_vrr_enabled) {
42562306a36Sopenharmony_ci		state->vrr_enabled = val;
42662306a36Sopenharmony_ci	} else if (property == config->degamma_lut_property) {
42762306a36Sopenharmony_ci		ret = drm_atomic_replace_property_blob_from_id(dev,
42862306a36Sopenharmony_ci					&state->degamma_lut,
42962306a36Sopenharmony_ci					val,
43062306a36Sopenharmony_ci					-1, sizeof(struct drm_color_lut),
43162306a36Sopenharmony_ci					&replaced);
43262306a36Sopenharmony_ci		state->color_mgmt_changed |= replaced;
43362306a36Sopenharmony_ci		return ret;
43462306a36Sopenharmony_ci	} else if (property == config->ctm_property) {
43562306a36Sopenharmony_ci		ret = drm_atomic_replace_property_blob_from_id(dev,
43662306a36Sopenharmony_ci					&state->ctm,
43762306a36Sopenharmony_ci					val,
43862306a36Sopenharmony_ci					sizeof(struct drm_color_ctm), -1,
43962306a36Sopenharmony_ci					&replaced);
44062306a36Sopenharmony_ci		state->color_mgmt_changed |= replaced;
44162306a36Sopenharmony_ci		return ret;
44262306a36Sopenharmony_ci	} else if (property == config->gamma_lut_property) {
44362306a36Sopenharmony_ci		ret = drm_atomic_replace_property_blob_from_id(dev,
44462306a36Sopenharmony_ci					&state->gamma_lut,
44562306a36Sopenharmony_ci					val,
44662306a36Sopenharmony_ci					-1, sizeof(struct drm_color_lut),
44762306a36Sopenharmony_ci					&replaced);
44862306a36Sopenharmony_ci		state->color_mgmt_changed |= replaced;
44962306a36Sopenharmony_ci		return ret;
45062306a36Sopenharmony_ci	} else if (property == config->prop_out_fence_ptr) {
45162306a36Sopenharmony_ci		s32 __user *fence_ptr = u64_to_user_ptr(val);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		if (!fence_ptr)
45462306a36Sopenharmony_ci			return 0;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		if (put_user(-1, fence_ptr))
45762306a36Sopenharmony_ci			return -EFAULT;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		set_out_fence_for_crtc(state->state, crtc, fence_ptr);
46062306a36Sopenharmony_ci	} else if (property == crtc->scaling_filter_property) {
46162306a36Sopenharmony_ci		state->scaling_filter = val;
46262306a36Sopenharmony_ci	} else if (crtc->funcs->atomic_set_property) {
46362306a36Sopenharmony_ci		return crtc->funcs->atomic_set_property(crtc, state, property, val);
46462306a36Sopenharmony_ci	} else {
46562306a36Sopenharmony_ci		drm_dbg_atomic(crtc->dev,
46662306a36Sopenharmony_ci			       "[CRTC:%d:%s] unknown property [PROP:%d:%s]\n",
46762306a36Sopenharmony_ci			       crtc->base.id, crtc->name,
46862306a36Sopenharmony_ci			       property->base.id, property->name);
46962306a36Sopenharmony_ci		return -EINVAL;
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return 0;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic int
47662306a36Sopenharmony_cidrm_atomic_crtc_get_property(struct drm_crtc *crtc,
47762306a36Sopenharmony_ci		const struct drm_crtc_state *state,
47862306a36Sopenharmony_ci		struct drm_property *property, uint64_t *val)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct drm_device *dev = crtc->dev;
48162306a36Sopenharmony_ci	struct drm_mode_config *config = &dev->mode_config;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (property == config->prop_active)
48462306a36Sopenharmony_ci		*val = drm_atomic_crtc_effectively_active(state);
48562306a36Sopenharmony_ci	else if (property == config->prop_mode_id)
48662306a36Sopenharmony_ci		*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
48762306a36Sopenharmony_ci	else if (property == config->prop_vrr_enabled)
48862306a36Sopenharmony_ci		*val = state->vrr_enabled;
48962306a36Sopenharmony_ci	else if (property == config->degamma_lut_property)
49062306a36Sopenharmony_ci		*val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
49162306a36Sopenharmony_ci	else if (property == config->ctm_property)
49262306a36Sopenharmony_ci		*val = (state->ctm) ? state->ctm->base.id : 0;
49362306a36Sopenharmony_ci	else if (property == config->gamma_lut_property)
49462306a36Sopenharmony_ci		*val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
49562306a36Sopenharmony_ci	else if (property == config->prop_out_fence_ptr)
49662306a36Sopenharmony_ci		*val = 0;
49762306a36Sopenharmony_ci	else if (property == crtc->scaling_filter_property)
49862306a36Sopenharmony_ci		*val = state->scaling_filter;
49962306a36Sopenharmony_ci	else if (crtc->funcs->atomic_get_property)
50062306a36Sopenharmony_ci		return crtc->funcs->atomic_get_property(crtc, state, property, val);
50162306a36Sopenharmony_ci	else {
50262306a36Sopenharmony_ci		drm_dbg_atomic(dev,
50362306a36Sopenharmony_ci			       "[CRTC:%d:%s] unknown property [PROP:%d:%s]\n",
50462306a36Sopenharmony_ci			       crtc->base.id, crtc->name,
50562306a36Sopenharmony_ci			       property->base.id, property->name);
50662306a36Sopenharmony_ci		return -EINVAL;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int drm_atomic_plane_set_property(struct drm_plane *plane,
51362306a36Sopenharmony_ci		struct drm_plane_state *state, struct drm_file *file_priv,
51462306a36Sopenharmony_ci		struct drm_property *property, uint64_t val)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct drm_device *dev = plane->dev;
51762306a36Sopenharmony_ci	struct drm_mode_config *config = &dev->mode_config;
51862306a36Sopenharmony_ci	bool replaced = false;
51962306a36Sopenharmony_ci	int ret;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (property == config->prop_fb_id) {
52262306a36Sopenharmony_ci		struct drm_framebuffer *fb;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		fb = drm_framebuffer_lookup(dev, file_priv, val);
52562306a36Sopenharmony_ci		drm_atomic_set_fb_for_plane(state, fb);
52662306a36Sopenharmony_ci		if (fb)
52762306a36Sopenharmony_ci			drm_framebuffer_put(fb);
52862306a36Sopenharmony_ci	} else if (property == config->prop_in_fence_fd) {
52962306a36Sopenharmony_ci		if (state->fence)
53062306a36Sopenharmony_ci			return -EINVAL;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		if (U642I64(val) == -1)
53362306a36Sopenharmony_ci			return 0;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		state->fence = sync_file_get_fence(val);
53662306a36Sopenharmony_ci		if (!state->fence)
53762306a36Sopenharmony_ci			return -EINVAL;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	} else if (property == config->prop_crtc_id) {
54062306a36Sopenharmony_ci		struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		if (val && !crtc) {
54362306a36Sopenharmony_ci			drm_dbg_atomic(dev,
54462306a36Sopenharmony_ci				       "[PROP:%d:%s] cannot find CRTC with ID %llu\n",
54562306a36Sopenharmony_ci				       property->base.id, property->name, val);
54662306a36Sopenharmony_ci			return -EACCES;
54762306a36Sopenharmony_ci		}
54862306a36Sopenharmony_ci		return drm_atomic_set_crtc_for_plane(state, crtc);
54962306a36Sopenharmony_ci	} else if (property == config->prop_crtc_x) {
55062306a36Sopenharmony_ci		state->crtc_x = U642I64(val);
55162306a36Sopenharmony_ci	} else if (property == config->prop_crtc_y) {
55262306a36Sopenharmony_ci		state->crtc_y = U642I64(val);
55362306a36Sopenharmony_ci	} else if (property == config->prop_crtc_w) {
55462306a36Sopenharmony_ci		state->crtc_w = val;
55562306a36Sopenharmony_ci	} else if (property == config->prop_crtc_h) {
55662306a36Sopenharmony_ci		state->crtc_h = val;
55762306a36Sopenharmony_ci	} else if (property == config->prop_src_x) {
55862306a36Sopenharmony_ci		state->src_x = val;
55962306a36Sopenharmony_ci	} else if (property == config->prop_src_y) {
56062306a36Sopenharmony_ci		state->src_y = val;
56162306a36Sopenharmony_ci	} else if (property == config->prop_src_w) {
56262306a36Sopenharmony_ci		state->src_w = val;
56362306a36Sopenharmony_ci	} else if (property == config->prop_src_h) {
56462306a36Sopenharmony_ci		state->src_h = val;
56562306a36Sopenharmony_ci	} else if (property == plane->alpha_property) {
56662306a36Sopenharmony_ci		state->alpha = val;
56762306a36Sopenharmony_ci	} else if (property == plane->blend_mode_property) {
56862306a36Sopenharmony_ci		state->pixel_blend_mode = val;
56962306a36Sopenharmony_ci	} else if (property == plane->rotation_property) {
57062306a36Sopenharmony_ci		if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
57162306a36Sopenharmony_ci			drm_dbg_atomic(plane->dev,
57262306a36Sopenharmony_ci				       "[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
57362306a36Sopenharmony_ci				       plane->base.id, plane->name, val);
57462306a36Sopenharmony_ci			return -EINVAL;
57562306a36Sopenharmony_ci		}
57662306a36Sopenharmony_ci		state->rotation = val;
57762306a36Sopenharmony_ci	} else if (property == plane->zpos_property) {
57862306a36Sopenharmony_ci		state->zpos = val;
57962306a36Sopenharmony_ci	} else if (property == plane->color_encoding_property) {
58062306a36Sopenharmony_ci		state->color_encoding = val;
58162306a36Sopenharmony_ci	} else if (property == plane->color_range_property) {
58262306a36Sopenharmony_ci		state->color_range = val;
58362306a36Sopenharmony_ci	} else if (property == config->prop_fb_damage_clips) {
58462306a36Sopenharmony_ci		ret = drm_atomic_replace_property_blob_from_id(dev,
58562306a36Sopenharmony_ci					&state->fb_damage_clips,
58662306a36Sopenharmony_ci					val,
58762306a36Sopenharmony_ci					-1,
58862306a36Sopenharmony_ci					sizeof(struct drm_rect),
58962306a36Sopenharmony_ci					&replaced);
59062306a36Sopenharmony_ci		return ret;
59162306a36Sopenharmony_ci	} else if (property == plane->scaling_filter_property) {
59262306a36Sopenharmony_ci		state->scaling_filter = val;
59362306a36Sopenharmony_ci	} else if (plane->funcs->atomic_set_property) {
59462306a36Sopenharmony_ci		return plane->funcs->atomic_set_property(plane, state,
59562306a36Sopenharmony_ci				property, val);
59662306a36Sopenharmony_ci	} else {
59762306a36Sopenharmony_ci		drm_dbg_atomic(plane->dev,
59862306a36Sopenharmony_ci			       "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n",
59962306a36Sopenharmony_ci			       plane->base.id, plane->name,
60062306a36Sopenharmony_ci			       property->base.id, property->name);
60162306a36Sopenharmony_ci		return -EINVAL;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic int
60862306a36Sopenharmony_cidrm_atomic_plane_get_property(struct drm_plane *plane,
60962306a36Sopenharmony_ci		const struct drm_plane_state *state,
61062306a36Sopenharmony_ci		struct drm_property *property, uint64_t *val)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct drm_device *dev = plane->dev;
61362306a36Sopenharmony_ci	struct drm_mode_config *config = &dev->mode_config;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (property == config->prop_fb_id) {
61662306a36Sopenharmony_ci		*val = (state->fb) ? state->fb->base.id : 0;
61762306a36Sopenharmony_ci	} else if (property == config->prop_in_fence_fd) {
61862306a36Sopenharmony_ci		*val = -1;
61962306a36Sopenharmony_ci	} else if (property == config->prop_crtc_id) {
62062306a36Sopenharmony_ci		*val = (state->crtc) ? state->crtc->base.id : 0;
62162306a36Sopenharmony_ci	} else if (property == config->prop_crtc_x) {
62262306a36Sopenharmony_ci		*val = I642U64(state->crtc_x);
62362306a36Sopenharmony_ci	} else if (property == config->prop_crtc_y) {
62462306a36Sopenharmony_ci		*val = I642U64(state->crtc_y);
62562306a36Sopenharmony_ci	} else if (property == config->prop_crtc_w) {
62662306a36Sopenharmony_ci		*val = state->crtc_w;
62762306a36Sopenharmony_ci	} else if (property == config->prop_crtc_h) {
62862306a36Sopenharmony_ci		*val = state->crtc_h;
62962306a36Sopenharmony_ci	} else if (property == config->prop_src_x) {
63062306a36Sopenharmony_ci		*val = state->src_x;
63162306a36Sopenharmony_ci	} else if (property == config->prop_src_y) {
63262306a36Sopenharmony_ci		*val = state->src_y;
63362306a36Sopenharmony_ci	} else if (property == config->prop_src_w) {
63462306a36Sopenharmony_ci		*val = state->src_w;
63562306a36Sopenharmony_ci	} else if (property == config->prop_src_h) {
63662306a36Sopenharmony_ci		*val = state->src_h;
63762306a36Sopenharmony_ci	} else if (property == plane->alpha_property) {
63862306a36Sopenharmony_ci		*val = state->alpha;
63962306a36Sopenharmony_ci	} else if (property == plane->blend_mode_property) {
64062306a36Sopenharmony_ci		*val = state->pixel_blend_mode;
64162306a36Sopenharmony_ci	} else if (property == plane->rotation_property) {
64262306a36Sopenharmony_ci		*val = state->rotation;
64362306a36Sopenharmony_ci	} else if (property == plane->zpos_property) {
64462306a36Sopenharmony_ci		*val = state->zpos;
64562306a36Sopenharmony_ci	} else if (property == plane->color_encoding_property) {
64662306a36Sopenharmony_ci		*val = state->color_encoding;
64762306a36Sopenharmony_ci	} else if (property == plane->color_range_property) {
64862306a36Sopenharmony_ci		*val = state->color_range;
64962306a36Sopenharmony_ci	} else if (property == config->prop_fb_damage_clips) {
65062306a36Sopenharmony_ci		*val = (state->fb_damage_clips) ?
65162306a36Sopenharmony_ci			state->fb_damage_clips->base.id : 0;
65262306a36Sopenharmony_ci	} else if (property == plane->scaling_filter_property) {
65362306a36Sopenharmony_ci		*val = state->scaling_filter;
65462306a36Sopenharmony_ci	} else if (plane->funcs->atomic_get_property) {
65562306a36Sopenharmony_ci		return plane->funcs->atomic_get_property(plane, state, property, val);
65662306a36Sopenharmony_ci	} else {
65762306a36Sopenharmony_ci		drm_dbg_atomic(dev,
65862306a36Sopenharmony_ci			       "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n",
65962306a36Sopenharmony_ci			       plane->base.id, plane->name,
66062306a36Sopenharmony_ci			       property->base.id, property->name);
66162306a36Sopenharmony_ci		return -EINVAL;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	return 0;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic int drm_atomic_set_writeback_fb_for_connector(
66862306a36Sopenharmony_ci		struct drm_connector_state *conn_state,
66962306a36Sopenharmony_ci		struct drm_framebuffer *fb)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	int ret;
67262306a36Sopenharmony_ci	struct drm_connector *conn = conn_state->connector;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	ret = drm_writeback_set_fb(conn_state, fb);
67562306a36Sopenharmony_ci	if (ret < 0)
67662306a36Sopenharmony_ci		return ret;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (fb)
67962306a36Sopenharmony_ci		drm_dbg_atomic(conn->dev,
68062306a36Sopenharmony_ci			       "Set [FB:%d] for connector state %p\n",
68162306a36Sopenharmony_ci			       fb->base.id, conn_state);
68262306a36Sopenharmony_ci	else
68362306a36Sopenharmony_ci		drm_dbg_atomic(conn->dev,
68462306a36Sopenharmony_ci			       "Set [NOFB] for connector state %p\n",
68562306a36Sopenharmony_ci			       conn_state);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	return 0;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_cistatic int drm_atomic_connector_set_property(struct drm_connector *connector,
69162306a36Sopenharmony_ci		struct drm_connector_state *state, struct drm_file *file_priv,
69262306a36Sopenharmony_ci		struct drm_property *property, uint64_t val)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct drm_device *dev = connector->dev;
69562306a36Sopenharmony_ci	struct drm_mode_config *config = &dev->mode_config;
69662306a36Sopenharmony_ci	bool replaced = false;
69762306a36Sopenharmony_ci	int ret;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (property == config->prop_crtc_id) {
70062306a36Sopenharmony_ci		struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		if (val && !crtc) {
70362306a36Sopenharmony_ci			drm_dbg_atomic(dev,
70462306a36Sopenharmony_ci				       "[PROP:%d:%s] cannot find CRTC with ID %llu\n",
70562306a36Sopenharmony_ci				       property->base.id, property->name, val);
70662306a36Sopenharmony_ci			return -EACCES;
70762306a36Sopenharmony_ci		}
70862306a36Sopenharmony_ci		return drm_atomic_set_crtc_for_connector(state, crtc);
70962306a36Sopenharmony_ci	} else if (property == config->dpms_property) {
71062306a36Sopenharmony_ci		/* setting DPMS property requires special handling, which
71162306a36Sopenharmony_ci		 * is done in legacy setprop path for us.  Disallow (for
71262306a36Sopenharmony_ci		 * now?) atomic writes to DPMS property:
71362306a36Sopenharmony_ci		 */
71462306a36Sopenharmony_ci		drm_dbg_atomic(dev,
71562306a36Sopenharmony_ci			       "legacy [PROP:%d:%s] can only be set via legacy uAPI\n",
71662306a36Sopenharmony_ci			       property->base.id, property->name);
71762306a36Sopenharmony_ci		return -EINVAL;
71862306a36Sopenharmony_ci	} else if (property == config->tv_select_subconnector_property) {
71962306a36Sopenharmony_ci		state->tv.select_subconnector = val;
72062306a36Sopenharmony_ci	} else if (property == config->tv_subconnector_property) {
72162306a36Sopenharmony_ci		state->tv.subconnector = val;
72262306a36Sopenharmony_ci	} else if (property == config->tv_left_margin_property) {
72362306a36Sopenharmony_ci		state->tv.margins.left = val;
72462306a36Sopenharmony_ci	} else if (property == config->tv_right_margin_property) {
72562306a36Sopenharmony_ci		state->tv.margins.right = val;
72662306a36Sopenharmony_ci	} else if (property == config->tv_top_margin_property) {
72762306a36Sopenharmony_ci		state->tv.margins.top = val;
72862306a36Sopenharmony_ci	} else if (property == config->tv_bottom_margin_property) {
72962306a36Sopenharmony_ci		state->tv.margins.bottom = val;
73062306a36Sopenharmony_ci	} else if (property == config->legacy_tv_mode_property) {
73162306a36Sopenharmony_ci		state->tv.legacy_mode = val;
73262306a36Sopenharmony_ci	} else if (property == config->tv_mode_property) {
73362306a36Sopenharmony_ci		state->tv.mode = val;
73462306a36Sopenharmony_ci	} else if (property == config->tv_brightness_property) {
73562306a36Sopenharmony_ci		state->tv.brightness = val;
73662306a36Sopenharmony_ci	} else if (property == config->tv_contrast_property) {
73762306a36Sopenharmony_ci		state->tv.contrast = val;
73862306a36Sopenharmony_ci	} else if (property == config->tv_flicker_reduction_property) {
73962306a36Sopenharmony_ci		state->tv.flicker_reduction = val;
74062306a36Sopenharmony_ci	} else if (property == config->tv_overscan_property) {
74162306a36Sopenharmony_ci		state->tv.overscan = val;
74262306a36Sopenharmony_ci	} else if (property == config->tv_saturation_property) {
74362306a36Sopenharmony_ci		state->tv.saturation = val;
74462306a36Sopenharmony_ci	} else if (property == config->tv_hue_property) {
74562306a36Sopenharmony_ci		state->tv.hue = val;
74662306a36Sopenharmony_ci	} else if (property == config->link_status_property) {
74762306a36Sopenharmony_ci		/* Never downgrade from GOOD to BAD on userspace's request here,
74862306a36Sopenharmony_ci		 * only hw issues can do that.
74962306a36Sopenharmony_ci		 *
75062306a36Sopenharmony_ci		 * For an atomic property the userspace doesn't need to be able
75162306a36Sopenharmony_ci		 * to understand all the properties, but needs to be able to
75262306a36Sopenharmony_ci		 * restore the state it wants on VT switch. So if the userspace
75362306a36Sopenharmony_ci		 * tries to change the link_status from GOOD to BAD, driver
75462306a36Sopenharmony_ci		 * silently rejects it and returns a 0. This prevents userspace
75562306a36Sopenharmony_ci		 * from accidentally breaking  the display when it restores the
75662306a36Sopenharmony_ci		 * state.
75762306a36Sopenharmony_ci		 */
75862306a36Sopenharmony_ci		if (state->link_status != DRM_LINK_STATUS_GOOD)
75962306a36Sopenharmony_ci			state->link_status = val;
76062306a36Sopenharmony_ci	} else if (property == config->hdr_output_metadata_property) {
76162306a36Sopenharmony_ci		ret = drm_atomic_replace_property_blob_from_id(dev,
76262306a36Sopenharmony_ci				&state->hdr_output_metadata,
76362306a36Sopenharmony_ci				val,
76462306a36Sopenharmony_ci				sizeof(struct hdr_output_metadata), -1,
76562306a36Sopenharmony_ci				&replaced);
76662306a36Sopenharmony_ci		return ret;
76762306a36Sopenharmony_ci	} else if (property == config->aspect_ratio_property) {
76862306a36Sopenharmony_ci		state->picture_aspect_ratio = val;
76962306a36Sopenharmony_ci	} else if (property == config->content_type_property) {
77062306a36Sopenharmony_ci		state->content_type = val;
77162306a36Sopenharmony_ci	} else if (property == connector->scaling_mode_property) {
77262306a36Sopenharmony_ci		state->scaling_mode = val;
77362306a36Sopenharmony_ci	} else if (property == config->content_protection_property) {
77462306a36Sopenharmony_ci		if (val == DRM_MODE_CONTENT_PROTECTION_ENABLED) {
77562306a36Sopenharmony_ci			drm_dbg_kms(dev, "only drivers can set CP Enabled\n");
77662306a36Sopenharmony_ci			return -EINVAL;
77762306a36Sopenharmony_ci		}
77862306a36Sopenharmony_ci		state->content_protection = val;
77962306a36Sopenharmony_ci	} else if (property == config->hdcp_content_type_property) {
78062306a36Sopenharmony_ci		state->hdcp_content_type = val;
78162306a36Sopenharmony_ci	} else if (property == connector->colorspace_property) {
78262306a36Sopenharmony_ci		state->colorspace = val;
78362306a36Sopenharmony_ci	} else if (property == config->writeback_fb_id_property) {
78462306a36Sopenharmony_ci		struct drm_framebuffer *fb;
78562306a36Sopenharmony_ci		int ret;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		fb = drm_framebuffer_lookup(dev, file_priv, val);
78862306a36Sopenharmony_ci		ret = drm_atomic_set_writeback_fb_for_connector(state, fb);
78962306a36Sopenharmony_ci		if (fb)
79062306a36Sopenharmony_ci			drm_framebuffer_put(fb);
79162306a36Sopenharmony_ci		return ret;
79262306a36Sopenharmony_ci	} else if (property == config->writeback_out_fence_ptr_property) {
79362306a36Sopenharmony_ci		s32 __user *fence_ptr = u64_to_user_ptr(val);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		return set_out_fence_for_connector(state->state, connector,
79662306a36Sopenharmony_ci						   fence_ptr);
79762306a36Sopenharmony_ci	} else if (property == connector->max_bpc_property) {
79862306a36Sopenharmony_ci		state->max_requested_bpc = val;
79962306a36Sopenharmony_ci	} else if (property == connector->privacy_screen_sw_state_property) {
80062306a36Sopenharmony_ci		state->privacy_screen_sw_state = val;
80162306a36Sopenharmony_ci	} else if (connector->funcs->atomic_set_property) {
80262306a36Sopenharmony_ci		return connector->funcs->atomic_set_property(connector,
80362306a36Sopenharmony_ci				state, property, val);
80462306a36Sopenharmony_ci	} else {
80562306a36Sopenharmony_ci		drm_dbg_atomic(connector->dev,
80662306a36Sopenharmony_ci			       "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]\n",
80762306a36Sopenharmony_ci			       connector->base.id, connector->name,
80862306a36Sopenharmony_ci			       property->base.id, property->name);
80962306a36Sopenharmony_ci		return -EINVAL;
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	return 0;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic int
81662306a36Sopenharmony_cidrm_atomic_connector_get_property(struct drm_connector *connector,
81762306a36Sopenharmony_ci		const struct drm_connector_state *state,
81862306a36Sopenharmony_ci		struct drm_property *property, uint64_t *val)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct drm_device *dev = connector->dev;
82162306a36Sopenharmony_ci	struct drm_mode_config *config = &dev->mode_config;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	if (property == config->prop_crtc_id) {
82462306a36Sopenharmony_ci		*val = (state->crtc) ? state->crtc->base.id : 0;
82562306a36Sopenharmony_ci	} else if (property == config->dpms_property) {
82662306a36Sopenharmony_ci		if (state->crtc && state->crtc->state->self_refresh_active)
82762306a36Sopenharmony_ci			*val = DRM_MODE_DPMS_ON;
82862306a36Sopenharmony_ci		else
82962306a36Sopenharmony_ci			*val = connector->dpms;
83062306a36Sopenharmony_ci	} else if (property == config->tv_select_subconnector_property) {
83162306a36Sopenharmony_ci		*val = state->tv.select_subconnector;
83262306a36Sopenharmony_ci	} else if (property == config->tv_subconnector_property) {
83362306a36Sopenharmony_ci		*val = state->tv.subconnector;
83462306a36Sopenharmony_ci	} else if (property == config->tv_left_margin_property) {
83562306a36Sopenharmony_ci		*val = state->tv.margins.left;
83662306a36Sopenharmony_ci	} else if (property == config->tv_right_margin_property) {
83762306a36Sopenharmony_ci		*val = state->tv.margins.right;
83862306a36Sopenharmony_ci	} else if (property == config->tv_top_margin_property) {
83962306a36Sopenharmony_ci		*val = state->tv.margins.top;
84062306a36Sopenharmony_ci	} else if (property == config->tv_bottom_margin_property) {
84162306a36Sopenharmony_ci		*val = state->tv.margins.bottom;
84262306a36Sopenharmony_ci	} else if (property == config->legacy_tv_mode_property) {
84362306a36Sopenharmony_ci		*val = state->tv.legacy_mode;
84462306a36Sopenharmony_ci	} else if (property == config->tv_mode_property) {
84562306a36Sopenharmony_ci		*val = state->tv.mode;
84662306a36Sopenharmony_ci	} else if (property == config->tv_brightness_property) {
84762306a36Sopenharmony_ci		*val = state->tv.brightness;
84862306a36Sopenharmony_ci	} else if (property == config->tv_contrast_property) {
84962306a36Sopenharmony_ci		*val = state->tv.contrast;
85062306a36Sopenharmony_ci	} else if (property == config->tv_flicker_reduction_property) {
85162306a36Sopenharmony_ci		*val = state->tv.flicker_reduction;
85262306a36Sopenharmony_ci	} else if (property == config->tv_overscan_property) {
85362306a36Sopenharmony_ci		*val = state->tv.overscan;
85462306a36Sopenharmony_ci	} else if (property == config->tv_saturation_property) {
85562306a36Sopenharmony_ci		*val = state->tv.saturation;
85662306a36Sopenharmony_ci	} else if (property == config->tv_hue_property) {
85762306a36Sopenharmony_ci		*val = state->tv.hue;
85862306a36Sopenharmony_ci	} else if (property == config->link_status_property) {
85962306a36Sopenharmony_ci		*val = state->link_status;
86062306a36Sopenharmony_ci	} else if (property == config->aspect_ratio_property) {
86162306a36Sopenharmony_ci		*val = state->picture_aspect_ratio;
86262306a36Sopenharmony_ci	} else if (property == config->content_type_property) {
86362306a36Sopenharmony_ci		*val = state->content_type;
86462306a36Sopenharmony_ci	} else if (property == connector->colorspace_property) {
86562306a36Sopenharmony_ci		*val = state->colorspace;
86662306a36Sopenharmony_ci	} else if (property == connector->scaling_mode_property) {
86762306a36Sopenharmony_ci		*val = state->scaling_mode;
86862306a36Sopenharmony_ci	} else if (property == config->hdr_output_metadata_property) {
86962306a36Sopenharmony_ci		*val = state->hdr_output_metadata ?
87062306a36Sopenharmony_ci			state->hdr_output_metadata->base.id : 0;
87162306a36Sopenharmony_ci	} else if (property == config->content_protection_property) {
87262306a36Sopenharmony_ci		*val = state->content_protection;
87362306a36Sopenharmony_ci	} else if (property == config->hdcp_content_type_property) {
87462306a36Sopenharmony_ci		*val = state->hdcp_content_type;
87562306a36Sopenharmony_ci	} else if (property == config->writeback_fb_id_property) {
87662306a36Sopenharmony_ci		/* Writeback framebuffer is one-shot, write and forget */
87762306a36Sopenharmony_ci		*val = 0;
87862306a36Sopenharmony_ci	} else if (property == config->writeback_out_fence_ptr_property) {
87962306a36Sopenharmony_ci		*val = 0;
88062306a36Sopenharmony_ci	} else if (property == connector->max_bpc_property) {
88162306a36Sopenharmony_ci		*val = state->max_requested_bpc;
88262306a36Sopenharmony_ci	} else if (property == connector->privacy_screen_sw_state_property) {
88362306a36Sopenharmony_ci		*val = state->privacy_screen_sw_state;
88462306a36Sopenharmony_ci	} else if (connector->funcs->atomic_get_property) {
88562306a36Sopenharmony_ci		return connector->funcs->atomic_get_property(connector,
88662306a36Sopenharmony_ci				state, property, val);
88762306a36Sopenharmony_ci	} else {
88862306a36Sopenharmony_ci		drm_dbg_atomic(dev,
88962306a36Sopenharmony_ci			       "[CONNECTOR:%d:%s] unknown property [PROP:%d:%s]\n",
89062306a36Sopenharmony_ci			       connector->base.id, connector->name,
89162306a36Sopenharmony_ci			       property->base.id, property->name);
89262306a36Sopenharmony_ci		return -EINVAL;
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	return 0;
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ciint drm_atomic_get_property(struct drm_mode_object *obj,
89962306a36Sopenharmony_ci		struct drm_property *property, uint64_t *val)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	struct drm_device *dev = property->dev;
90262306a36Sopenharmony_ci	int ret;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	switch (obj->type) {
90562306a36Sopenharmony_ci	case DRM_MODE_OBJECT_CONNECTOR: {
90662306a36Sopenharmony_ci		struct drm_connector *connector = obj_to_connector(obj);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci		WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
90962306a36Sopenharmony_ci		ret = drm_atomic_connector_get_property(connector,
91062306a36Sopenharmony_ci				connector->state, property, val);
91162306a36Sopenharmony_ci		break;
91262306a36Sopenharmony_ci	}
91362306a36Sopenharmony_ci	case DRM_MODE_OBJECT_CRTC: {
91462306a36Sopenharmony_ci		struct drm_crtc *crtc = obj_to_crtc(obj);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci		WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
91762306a36Sopenharmony_ci		ret = drm_atomic_crtc_get_property(crtc,
91862306a36Sopenharmony_ci				crtc->state, property, val);
91962306a36Sopenharmony_ci		break;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci	case DRM_MODE_OBJECT_PLANE: {
92262306a36Sopenharmony_ci		struct drm_plane *plane = obj_to_plane(obj);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci		WARN_ON(!drm_modeset_is_locked(&plane->mutex));
92562306a36Sopenharmony_ci		ret = drm_atomic_plane_get_property(plane,
92662306a36Sopenharmony_ci				plane->state, property, val);
92762306a36Sopenharmony_ci		break;
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci	default:
93062306a36Sopenharmony_ci		drm_dbg_atomic(dev, "[OBJECT:%d] has no properties\n", obj->id);
93162306a36Sopenharmony_ci		ret = -EINVAL;
93262306a36Sopenharmony_ci		break;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return ret;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci/*
93962306a36Sopenharmony_ci * The big monster ioctl
94062306a36Sopenharmony_ci */
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_cistatic struct drm_pending_vblank_event *create_vblank_event(
94362306a36Sopenharmony_ci		struct drm_crtc *crtc, uint64_t user_data)
94462306a36Sopenharmony_ci{
94562306a36Sopenharmony_ci	struct drm_pending_vblank_event *e = NULL;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	e = kzalloc(sizeof *e, GFP_KERNEL);
94862306a36Sopenharmony_ci	if (!e)
94962306a36Sopenharmony_ci		return NULL;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
95262306a36Sopenharmony_ci	e->event.base.length = sizeof(e->event);
95362306a36Sopenharmony_ci	e->event.vbl.crtc_id = crtc->base.id;
95462306a36Sopenharmony_ci	e->event.vbl.user_data = user_data;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	return e;
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ciint drm_atomic_connector_commit_dpms(struct drm_atomic_state *state,
96062306a36Sopenharmony_ci				     struct drm_connector *connector,
96162306a36Sopenharmony_ci				     int mode)
96262306a36Sopenharmony_ci{
96362306a36Sopenharmony_ci	struct drm_connector *tmp_connector;
96462306a36Sopenharmony_ci	struct drm_connector_state *new_conn_state;
96562306a36Sopenharmony_ci	struct drm_crtc *crtc;
96662306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
96762306a36Sopenharmony_ci	int i, ret, old_mode = connector->dpms;
96862306a36Sopenharmony_ci	bool active = false;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
97162306a36Sopenharmony_ci			       state->acquire_ctx);
97262306a36Sopenharmony_ci	if (ret)
97362306a36Sopenharmony_ci		return ret;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (mode != DRM_MODE_DPMS_ON)
97662306a36Sopenharmony_ci		mode = DRM_MODE_DPMS_OFF;
97762306a36Sopenharmony_ci	connector->dpms = mode;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	crtc = connector->state->crtc;
98062306a36Sopenharmony_ci	if (!crtc)
98162306a36Sopenharmony_ci		goto out;
98262306a36Sopenharmony_ci	ret = drm_atomic_add_affected_connectors(state, crtc);
98362306a36Sopenharmony_ci	if (ret)
98462306a36Sopenharmony_ci		goto out;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	crtc_state = drm_atomic_get_crtc_state(state, crtc);
98762306a36Sopenharmony_ci	if (IS_ERR(crtc_state)) {
98862306a36Sopenharmony_ci		ret = PTR_ERR(crtc_state);
98962306a36Sopenharmony_ci		goto out;
99062306a36Sopenharmony_ci	}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	for_each_new_connector_in_state(state, tmp_connector, new_conn_state, i) {
99362306a36Sopenharmony_ci		if (new_conn_state->crtc != crtc)
99462306a36Sopenharmony_ci			continue;
99562306a36Sopenharmony_ci		if (tmp_connector->dpms == DRM_MODE_DPMS_ON) {
99662306a36Sopenharmony_ci			active = true;
99762306a36Sopenharmony_ci			break;
99862306a36Sopenharmony_ci		}
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	crtc_state->active = active;
100262306a36Sopenharmony_ci	ret = drm_atomic_commit(state);
100362306a36Sopenharmony_ciout:
100462306a36Sopenharmony_ci	if (ret != 0)
100562306a36Sopenharmony_ci		connector->dpms = old_mode;
100662306a36Sopenharmony_ci	return ret;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ciint drm_atomic_set_property(struct drm_atomic_state *state,
101062306a36Sopenharmony_ci			    struct drm_file *file_priv,
101162306a36Sopenharmony_ci			    struct drm_mode_object *obj,
101262306a36Sopenharmony_ci			    struct drm_property *prop,
101362306a36Sopenharmony_ci			    uint64_t prop_value)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct drm_mode_object *ref;
101662306a36Sopenharmony_ci	int ret;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if (!drm_property_change_valid_get(prop, prop_value, &ref))
101962306a36Sopenharmony_ci		return -EINVAL;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	switch (obj->type) {
102262306a36Sopenharmony_ci	case DRM_MODE_OBJECT_CONNECTOR: {
102362306a36Sopenharmony_ci		struct drm_connector *connector = obj_to_connector(obj);
102462306a36Sopenharmony_ci		struct drm_connector_state *connector_state;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		connector_state = drm_atomic_get_connector_state(state, connector);
102762306a36Sopenharmony_ci		if (IS_ERR(connector_state)) {
102862306a36Sopenharmony_ci			ret = PTR_ERR(connector_state);
102962306a36Sopenharmony_ci			break;
103062306a36Sopenharmony_ci		}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci		ret = drm_atomic_connector_set_property(connector,
103362306a36Sopenharmony_ci				connector_state, file_priv,
103462306a36Sopenharmony_ci				prop, prop_value);
103562306a36Sopenharmony_ci		break;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci	case DRM_MODE_OBJECT_CRTC: {
103862306a36Sopenharmony_ci		struct drm_crtc *crtc = obj_to_crtc(obj);
103962306a36Sopenharmony_ci		struct drm_crtc_state *crtc_state;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci		crtc_state = drm_atomic_get_crtc_state(state, crtc);
104262306a36Sopenharmony_ci		if (IS_ERR(crtc_state)) {
104362306a36Sopenharmony_ci			ret = PTR_ERR(crtc_state);
104462306a36Sopenharmony_ci			break;
104562306a36Sopenharmony_ci		}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci		ret = drm_atomic_crtc_set_property(crtc,
104862306a36Sopenharmony_ci				crtc_state, prop, prop_value);
104962306a36Sopenharmony_ci		break;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci	case DRM_MODE_OBJECT_PLANE: {
105262306a36Sopenharmony_ci		struct drm_plane *plane = obj_to_plane(obj);
105362306a36Sopenharmony_ci		struct drm_plane_state *plane_state;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		plane_state = drm_atomic_get_plane_state(state, plane);
105662306a36Sopenharmony_ci		if (IS_ERR(plane_state)) {
105762306a36Sopenharmony_ci			ret = PTR_ERR(plane_state);
105862306a36Sopenharmony_ci			break;
105962306a36Sopenharmony_ci		}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci		ret = drm_atomic_plane_set_property(plane,
106262306a36Sopenharmony_ci				plane_state, file_priv,
106362306a36Sopenharmony_ci				prop, prop_value);
106462306a36Sopenharmony_ci		break;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci	default:
106762306a36Sopenharmony_ci		drm_dbg_atomic(prop->dev, "[OBJECT:%d] has no properties\n", obj->id);
106862306a36Sopenharmony_ci		ret = -EINVAL;
106962306a36Sopenharmony_ci		break;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	drm_property_change_valid_put(prop, ref);
107362306a36Sopenharmony_ci	return ret;
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci/**
107762306a36Sopenharmony_ci * DOC: explicit fencing properties
107862306a36Sopenharmony_ci *
107962306a36Sopenharmony_ci * Explicit fencing allows userspace to control the buffer synchronization
108062306a36Sopenharmony_ci * between devices. A Fence or a group of fences are transferred to/from
108162306a36Sopenharmony_ci * userspace using Sync File fds and there are two DRM properties for that.
108262306a36Sopenharmony_ci * IN_FENCE_FD on each DRM Plane to send fences to the kernel and
108362306a36Sopenharmony_ci * OUT_FENCE_PTR on each DRM CRTC to receive fences from the kernel.
108462306a36Sopenharmony_ci *
108562306a36Sopenharmony_ci * As a contrast, with implicit fencing the kernel keeps track of any
108662306a36Sopenharmony_ci * ongoing rendering, and automatically ensures that the atomic update waits
108762306a36Sopenharmony_ci * for any pending rendering to complete. This is usually tracked in &struct
108862306a36Sopenharmony_ci * dma_resv which can also contain mandatory kernel fences. Implicit syncing
108962306a36Sopenharmony_ci * is how Linux traditionally worked (e.g. DRI2/3 on X.org), whereas explicit
109062306a36Sopenharmony_ci * fencing is what Android wants.
109162306a36Sopenharmony_ci *
109262306a36Sopenharmony_ci * "IN_FENCE_FD”:
109362306a36Sopenharmony_ci *	Use this property to pass a fence that DRM should wait on before
109462306a36Sopenharmony_ci *	proceeding with the Atomic Commit request and show the framebuffer for
109562306a36Sopenharmony_ci *	the plane on the screen. The fence can be either a normal fence or a
109662306a36Sopenharmony_ci *	merged one, the sync_file framework will handle both cases and use a
109762306a36Sopenharmony_ci *	fence_array if a merged fence is received. Passing -1 here means no
109862306a36Sopenharmony_ci *	fences to wait on.
109962306a36Sopenharmony_ci *
110062306a36Sopenharmony_ci *	If the Atomic Commit request has the DRM_MODE_ATOMIC_TEST_ONLY flag
110162306a36Sopenharmony_ci *	it will only check if the Sync File is a valid one.
110262306a36Sopenharmony_ci *
110362306a36Sopenharmony_ci *	On the driver side the fence is stored on the @fence parameter of
110462306a36Sopenharmony_ci *	&struct drm_plane_state. Drivers which also support implicit fencing
110562306a36Sopenharmony_ci *	should extract the implicit fence using drm_gem_plane_helper_prepare_fb(),
110662306a36Sopenharmony_ci *	to make sure there's consistent behaviour between drivers in precedence
110762306a36Sopenharmony_ci *	of implicit vs. explicit fencing.
110862306a36Sopenharmony_ci *
110962306a36Sopenharmony_ci * "OUT_FENCE_PTR”:
111062306a36Sopenharmony_ci *	Use this property to pass a file descriptor pointer to DRM. Once the
111162306a36Sopenharmony_ci *	Atomic Commit request call returns OUT_FENCE_PTR will be filled with
111262306a36Sopenharmony_ci *	the file descriptor number of a Sync File. This Sync File contains the
111362306a36Sopenharmony_ci *	CRTC fence that will be signaled when all framebuffers present on the
111462306a36Sopenharmony_ci *	Atomic Commit * request for that given CRTC are scanned out on the
111562306a36Sopenharmony_ci *	screen.
111662306a36Sopenharmony_ci *
111762306a36Sopenharmony_ci *	The Atomic Commit request fails if a invalid pointer is passed. If the
111862306a36Sopenharmony_ci *	Atomic Commit request fails for any other reason the out fence fd
111962306a36Sopenharmony_ci *	returned will be -1. On a Atomic Commit with the
112062306a36Sopenharmony_ci *	DRM_MODE_ATOMIC_TEST_ONLY flag the out fence will also be set to -1.
112162306a36Sopenharmony_ci *
112262306a36Sopenharmony_ci *	Note that out-fences don't have a special interface to drivers and are
112362306a36Sopenharmony_ci *	internally represented by a &struct drm_pending_vblank_event in struct
112462306a36Sopenharmony_ci *	&drm_crtc_state, which is also used by the nonblocking atomic commit
112562306a36Sopenharmony_ci *	helpers and for the DRM event handling for existing userspace.
112662306a36Sopenharmony_ci */
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistruct drm_out_fence_state {
112962306a36Sopenharmony_ci	s32 __user *out_fence_ptr;
113062306a36Sopenharmony_ci	struct sync_file *sync_file;
113162306a36Sopenharmony_ci	int fd;
113262306a36Sopenharmony_ci};
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic int setup_out_fence(struct drm_out_fence_state *fence_state,
113562306a36Sopenharmony_ci			   struct dma_fence *fence)
113662306a36Sopenharmony_ci{
113762306a36Sopenharmony_ci	fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
113862306a36Sopenharmony_ci	if (fence_state->fd < 0)
113962306a36Sopenharmony_ci		return fence_state->fd;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (put_user(fence_state->fd, fence_state->out_fence_ptr))
114262306a36Sopenharmony_ci		return -EFAULT;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	fence_state->sync_file = sync_file_create(fence);
114562306a36Sopenharmony_ci	if (!fence_state->sync_file)
114662306a36Sopenharmony_ci		return -ENOMEM;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	return 0;
114962306a36Sopenharmony_ci}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_cistatic int prepare_signaling(struct drm_device *dev,
115262306a36Sopenharmony_ci				  struct drm_atomic_state *state,
115362306a36Sopenharmony_ci				  struct drm_mode_atomic *arg,
115462306a36Sopenharmony_ci				  struct drm_file *file_priv,
115562306a36Sopenharmony_ci				  struct drm_out_fence_state **fence_state,
115662306a36Sopenharmony_ci				  unsigned int *num_fences)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	struct drm_crtc *crtc;
115962306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
116062306a36Sopenharmony_ci	struct drm_connector *conn;
116162306a36Sopenharmony_ci	struct drm_connector_state *conn_state;
116262306a36Sopenharmony_ci	int i, c = 0, ret;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
116562306a36Sopenharmony_ci		return 0;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
116862306a36Sopenharmony_ci		s32 __user *fence_ptr;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci		fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
117362306a36Sopenharmony_ci			struct drm_pending_vblank_event *e;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci			e = create_vblank_event(crtc, arg->user_data);
117662306a36Sopenharmony_ci			if (!e)
117762306a36Sopenharmony_ci				return -ENOMEM;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci			crtc_state->event = e;
118062306a36Sopenharmony_ci		}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci		if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
118362306a36Sopenharmony_ci			struct drm_pending_vblank_event *e = crtc_state->event;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci			if (!file_priv)
118662306a36Sopenharmony_ci				continue;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci			ret = drm_event_reserve_init(dev, file_priv, &e->base,
118962306a36Sopenharmony_ci						     &e->event.base);
119062306a36Sopenharmony_ci			if (ret) {
119162306a36Sopenharmony_ci				kfree(e);
119262306a36Sopenharmony_ci				crtc_state->event = NULL;
119362306a36Sopenharmony_ci				return ret;
119462306a36Sopenharmony_ci			}
119562306a36Sopenharmony_ci		}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci		if (fence_ptr) {
119862306a36Sopenharmony_ci			struct dma_fence *fence;
119962306a36Sopenharmony_ci			struct drm_out_fence_state *f;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci			f = krealloc(*fence_state, sizeof(**fence_state) *
120262306a36Sopenharmony_ci				     (*num_fences + 1), GFP_KERNEL);
120362306a36Sopenharmony_ci			if (!f)
120462306a36Sopenharmony_ci				return -ENOMEM;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci			memset(&f[*num_fences], 0, sizeof(*f));
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci			f[*num_fences].out_fence_ptr = fence_ptr;
120962306a36Sopenharmony_ci			*fence_state = f;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci			fence = drm_crtc_create_fence(crtc);
121262306a36Sopenharmony_ci			if (!fence)
121362306a36Sopenharmony_ci				return -ENOMEM;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci			ret = setup_out_fence(&f[(*num_fences)++], fence);
121662306a36Sopenharmony_ci			if (ret) {
121762306a36Sopenharmony_ci				dma_fence_put(fence);
121862306a36Sopenharmony_ci				return ret;
121962306a36Sopenharmony_ci			}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci			crtc_state->event->base.fence = fence;
122262306a36Sopenharmony_ci		}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci		c++;
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	for_each_new_connector_in_state(state, conn, conn_state, i) {
122862306a36Sopenharmony_ci		struct drm_writeback_connector *wb_conn;
122962306a36Sopenharmony_ci		struct drm_out_fence_state *f;
123062306a36Sopenharmony_ci		struct dma_fence *fence;
123162306a36Sopenharmony_ci		s32 __user *fence_ptr;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci		if (!conn_state->writeback_job)
123462306a36Sopenharmony_ci			continue;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci		fence_ptr = get_out_fence_for_connector(state, conn);
123762306a36Sopenharmony_ci		if (!fence_ptr)
123862306a36Sopenharmony_ci			continue;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci		f = krealloc(*fence_state, sizeof(**fence_state) *
124162306a36Sopenharmony_ci			     (*num_fences + 1), GFP_KERNEL);
124262306a36Sopenharmony_ci		if (!f)
124362306a36Sopenharmony_ci			return -ENOMEM;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci		memset(&f[*num_fences], 0, sizeof(*f));
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci		f[*num_fences].out_fence_ptr = fence_ptr;
124862306a36Sopenharmony_ci		*fence_state = f;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci		wb_conn = drm_connector_to_writeback(conn);
125162306a36Sopenharmony_ci		fence = drm_writeback_get_out_fence(wb_conn);
125262306a36Sopenharmony_ci		if (!fence)
125362306a36Sopenharmony_ci			return -ENOMEM;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci		ret = setup_out_fence(&f[(*num_fences)++], fence);
125662306a36Sopenharmony_ci		if (ret) {
125762306a36Sopenharmony_ci			dma_fence_put(fence);
125862306a36Sopenharmony_ci			return ret;
125962306a36Sopenharmony_ci		}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci		conn_state->writeback_job->out_fence = fence;
126262306a36Sopenharmony_ci	}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	/*
126562306a36Sopenharmony_ci	 * Having this flag means user mode pends on event which will never
126662306a36Sopenharmony_ci	 * reach due to lack of at least one CRTC for signaling
126762306a36Sopenharmony_ci	 */
126862306a36Sopenharmony_ci	if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
126962306a36Sopenharmony_ci		drm_dbg_atomic(dev, "need at least one CRTC for DRM_MODE_PAGE_FLIP_EVENT");
127062306a36Sopenharmony_ci		return -EINVAL;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	return 0;
127462306a36Sopenharmony_ci}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_cistatic void complete_signaling(struct drm_device *dev,
127762306a36Sopenharmony_ci			       struct drm_atomic_state *state,
127862306a36Sopenharmony_ci			       struct drm_out_fence_state *fence_state,
127962306a36Sopenharmony_ci			       unsigned int num_fences,
128062306a36Sopenharmony_ci			       bool install_fds)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	struct drm_crtc *crtc;
128362306a36Sopenharmony_ci	struct drm_crtc_state *crtc_state;
128462306a36Sopenharmony_ci	int i;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (install_fds) {
128762306a36Sopenharmony_ci		for (i = 0; i < num_fences; i++)
128862306a36Sopenharmony_ci			fd_install(fence_state[i].fd,
128962306a36Sopenharmony_ci				   fence_state[i].sync_file->file);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci		kfree(fence_state);
129262306a36Sopenharmony_ci		return;
129362306a36Sopenharmony_ci	}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
129662306a36Sopenharmony_ci		struct drm_pending_vblank_event *event = crtc_state->event;
129762306a36Sopenharmony_ci		/*
129862306a36Sopenharmony_ci		 * Free the allocated event. drm_atomic_helper_setup_commit
129962306a36Sopenharmony_ci		 * can allocate an event too, so only free it if it's ours
130062306a36Sopenharmony_ci		 * to prevent a double free in drm_atomic_state_clear.
130162306a36Sopenharmony_ci		 */
130262306a36Sopenharmony_ci		if (event && (event->base.fence || event->base.file_priv)) {
130362306a36Sopenharmony_ci			drm_event_cancel_free(dev, &event->base);
130462306a36Sopenharmony_ci			crtc_state->event = NULL;
130562306a36Sopenharmony_ci		}
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (!fence_state)
130962306a36Sopenharmony_ci		return;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	for (i = 0; i < num_fences; i++) {
131262306a36Sopenharmony_ci		if (fence_state[i].sync_file)
131362306a36Sopenharmony_ci			fput(fence_state[i].sync_file->file);
131462306a36Sopenharmony_ci		if (fence_state[i].fd >= 0)
131562306a36Sopenharmony_ci			put_unused_fd(fence_state[i].fd);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci		/* If this fails log error to the user */
131862306a36Sopenharmony_ci		if (fence_state[i].out_fence_ptr &&
131962306a36Sopenharmony_ci		    put_user(-1, fence_state[i].out_fence_ptr))
132062306a36Sopenharmony_ci			drm_dbg_atomic(dev, "Couldn't clear out_fence_ptr\n");
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	kfree(fence_state);
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ciint drm_mode_atomic_ioctl(struct drm_device *dev,
132762306a36Sopenharmony_ci			  void *data, struct drm_file *file_priv)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct drm_mode_atomic *arg = data;
133062306a36Sopenharmony_ci	uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
133162306a36Sopenharmony_ci	uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
133262306a36Sopenharmony_ci	uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
133362306a36Sopenharmony_ci	uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
133462306a36Sopenharmony_ci	unsigned int copied_objs, copied_props;
133562306a36Sopenharmony_ci	struct drm_atomic_state *state;
133662306a36Sopenharmony_ci	struct drm_modeset_acquire_ctx ctx;
133762306a36Sopenharmony_ci	struct drm_out_fence_state *fence_state;
133862306a36Sopenharmony_ci	int ret = 0;
133962306a36Sopenharmony_ci	unsigned int i, j, num_fences;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	/* disallow for drivers not supporting atomic: */
134262306a36Sopenharmony_ci	if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
134362306a36Sopenharmony_ci		return -EOPNOTSUPP;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	/* disallow for userspace that has not enabled atomic cap (even
134662306a36Sopenharmony_ci	 * though this may be a bit overkill, since legacy userspace
134762306a36Sopenharmony_ci	 * wouldn't know how to call this ioctl)
134862306a36Sopenharmony_ci	 */
134962306a36Sopenharmony_ci	if (!file_priv->atomic) {
135062306a36Sopenharmony_ci		drm_dbg_atomic(dev,
135162306a36Sopenharmony_ci			       "commit failed: atomic cap not enabled\n");
135262306a36Sopenharmony_ci		return -EINVAL;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) {
135662306a36Sopenharmony_ci		drm_dbg_atomic(dev, "commit failed: invalid flag\n");
135762306a36Sopenharmony_ci		return -EINVAL;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	if (arg->reserved) {
136162306a36Sopenharmony_ci		drm_dbg_atomic(dev, "commit failed: reserved field set\n");
136262306a36Sopenharmony_ci		return -EINVAL;
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) {
136662306a36Sopenharmony_ci		drm_dbg_atomic(dev,
136762306a36Sopenharmony_ci			       "commit failed: invalid flag DRM_MODE_PAGE_FLIP_ASYNC\n");
136862306a36Sopenharmony_ci		return -EINVAL;
136962306a36Sopenharmony_ci	}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	/* can't test and expect an event at the same time. */
137262306a36Sopenharmony_ci	if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
137362306a36Sopenharmony_ci			(arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
137462306a36Sopenharmony_ci		drm_dbg_atomic(dev,
137562306a36Sopenharmony_ci			       "commit failed: page-flip event requested with test-only commit\n");
137662306a36Sopenharmony_ci		return -EINVAL;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	state = drm_atomic_state_alloc(dev);
138062306a36Sopenharmony_ci	if (!state)
138162306a36Sopenharmony_ci		return -ENOMEM;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
138462306a36Sopenharmony_ci	state->acquire_ctx = &ctx;
138562306a36Sopenharmony_ci	state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ciretry:
138862306a36Sopenharmony_ci	copied_objs = 0;
138962306a36Sopenharmony_ci	copied_props = 0;
139062306a36Sopenharmony_ci	fence_state = NULL;
139162306a36Sopenharmony_ci	num_fences = 0;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	for (i = 0; i < arg->count_objs; i++) {
139462306a36Sopenharmony_ci		uint32_t obj_id, count_props;
139562306a36Sopenharmony_ci		struct drm_mode_object *obj;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci		if (get_user(obj_id, objs_ptr + copied_objs)) {
139862306a36Sopenharmony_ci			ret = -EFAULT;
139962306a36Sopenharmony_ci			goto out;
140062306a36Sopenharmony_ci		}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci		obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
140362306a36Sopenharmony_ci		if (!obj) {
140462306a36Sopenharmony_ci			drm_dbg_atomic(dev, "cannot find object ID %d", obj_id);
140562306a36Sopenharmony_ci			ret = -ENOENT;
140662306a36Sopenharmony_ci			goto out;
140762306a36Sopenharmony_ci		}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		if (!obj->properties) {
141062306a36Sopenharmony_ci			drm_dbg_atomic(dev, "[OBJECT:%d] has no properties", obj_id);
141162306a36Sopenharmony_ci			drm_mode_object_put(obj);
141262306a36Sopenharmony_ci			ret = -ENOENT;
141362306a36Sopenharmony_ci			goto out;
141462306a36Sopenharmony_ci		}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci		if (get_user(count_props, count_props_ptr + copied_objs)) {
141762306a36Sopenharmony_ci			drm_mode_object_put(obj);
141862306a36Sopenharmony_ci			ret = -EFAULT;
141962306a36Sopenharmony_ci			goto out;
142062306a36Sopenharmony_ci		}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci		copied_objs++;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci		for (j = 0; j < count_props; j++) {
142562306a36Sopenharmony_ci			uint32_t prop_id;
142662306a36Sopenharmony_ci			uint64_t prop_value;
142762306a36Sopenharmony_ci			struct drm_property *prop;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci			if (get_user(prop_id, props_ptr + copied_props)) {
143062306a36Sopenharmony_ci				drm_mode_object_put(obj);
143162306a36Sopenharmony_ci				ret = -EFAULT;
143262306a36Sopenharmony_ci				goto out;
143362306a36Sopenharmony_ci			}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci			prop = drm_mode_obj_find_prop_id(obj, prop_id);
143662306a36Sopenharmony_ci			if (!prop) {
143762306a36Sopenharmony_ci				drm_dbg_atomic(dev,
143862306a36Sopenharmony_ci					       "[OBJECT:%d] cannot find property ID %d",
143962306a36Sopenharmony_ci					       obj_id, prop_id);
144062306a36Sopenharmony_ci				drm_mode_object_put(obj);
144162306a36Sopenharmony_ci				ret = -ENOENT;
144262306a36Sopenharmony_ci				goto out;
144362306a36Sopenharmony_ci			}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci			if (copy_from_user(&prop_value,
144662306a36Sopenharmony_ci					   prop_values_ptr + copied_props,
144762306a36Sopenharmony_ci					   sizeof(prop_value))) {
144862306a36Sopenharmony_ci				drm_mode_object_put(obj);
144962306a36Sopenharmony_ci				ret = -EFAULT;
145062306a36Sopenharmony_ci				goto out;
145162306a36Sopenharmony_ci			}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci			ret = drm_atomic_set_property(state, file_priv,
145462306a36Sopenharmony_ci						      obj, prop, prop_value);
145562306a36Sopenharmony_ci			if (ret) {
145662306a36Sopenharmony_ci				drm_mode_object_put(obj);
145762306a36Sopenharmony_ci				goto out;
145862306a36Sopenharmony_ci			}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci			copied_props++;
146162306a36Sopenharmony_ci		}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		drm_mode_object_put(obj);
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
146762306a36Sopenharmony_ci				&num_fences);
146862306a36Sopenharmony_ci	if (ret)
146962306a36Sopenharmony_ci		goto out;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
147262306a36Sopenharmony_ci		ret = drm_atomic_check_only(state);
147362306a36Sopenharmony_ci	} else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
147462306a36Sopenharmony_ci		ret = drm_atomic_nonblocking_commit(state);
147562306a36Sopenharmony_ci	} else {
147662306a36Sopenharmony_ci		ret = drm_atomic_commit(state);
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ciout:
148062306a36Sopenharmony_ci	complete_signaling(dev, state, fence_state, num_fences, !ret);
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if (ret == -EDEADLK) {
148362306a36Sopenharmony_ci		drm_atomic_state_clear(state);
148462306a36Sopenharmony_ci		ret = drm_modeset_backoff(&ctx);
148562306a36Sopenharmony_ci		if (!ret)
148662306a36Sopenharmony_ci			goto retry;
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	drm_atomic_state_put(state);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	drm_modeset_drop_locks(&ctx);
149262306a36Sopenharmony_ci	drm_modeset_acquire_fini(&ctx);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	return ret;
149562306a36Sopenharmony_ci}
1496