162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2016 Intel Corporation
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission to use, copy, modify, distribute, and sell this software and its
562306a36Sopenharmony_ci * documentation for any purpose is hereby granted without fee, provided that
662306a36Sopenharmony_ci * the above copyright notice appear in all copies and that both that copyright
762306a36Sopenharmony_ci * notice and this permission notice appear in supporting documentation, and
862306a36Sopenharmony_ci * that the name of the copyright holders not be used in advertising or
962306a36Sopenharmony_ci * publicity pertaining to distribution of the software without specific,
1062306a36Sopenharmony_ci * written prior permission.  The copyright holders make no representations
1162306a36Sopenharmony_ci * about the suitability of this software for any purpose.  It is provided "as
1262306a36Sopenharmony_ci * is" without express or implied warranty.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1562306a36Sopenharmony_ci * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1662306a36Sopenharmony_ci * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1762306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1862306a36Sopenharmony_ci * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1962306a36Sopenharmony_ci * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2062306a36Sopenharmony_ci * OF THIS SOFTWARE.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/uaccess.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <drm/drm_drv.h>
2662306a36Sopenharmony_ci#include <drm/drm_encoder.h>
2762306a36Sopenharmony_ci#include <drm/drm_file.h>
2862306a36Sopenharmony_ci#include <drm/drm_framebuffer.h>
2962306a36Sopenharmony_ci#include <drm/drm_managed.h>
3062306a36Sopenharmony_ci#include <drm/drm_mode_config.h>
3162306a36Sopenharmony_ci#include <drm/drm_print.h>
3262306a36Sopenharmony_ci#include <linux/dma-resv.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "drm_crtc_internal.h"
3562306a36Sopenharmony_ci#include "drm_internal.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciint drm_modeset_register_all(struct drm_device *dev)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	int ret;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	ret = drm_plane_register_all(dev);
4262306a36Sopenharmony_ci	if (ret)
4362306a36Sopenharmony_ci		goto err_plane;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	ret = drm_crtc_register_all(dev);
4662306a36Sopenharmony_ci	if  (ret)
4762306a36Sopenharmony_ci		goto err_crtc;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	ret = drm_encoder_register_all(dev);
5062306a36Sopenharmony_ci	if (ret)
5162306a36Sopenharmony_ci		goto err_encoder;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ret = drm_connector_register_all(dev);
5462306a36Sopenharmony_ci	if (ret)
5562306a36Sopenharmony_ci		goto err_connector;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	drm_debugfs_late_register(dev);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return 0;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cierr_connector:
6262306a36Sopenharmony_ci	drm_encoder_unregister_all(dev);
6362306a36Sopenharmony_cierr_encoder:
6462306a36Sopenharmony_ci	drm_crtc_unregister_all(dev);
6562306a36Sopenharmony_cierr_crtc:
6662306a36Sopenharmony_ci	drm_plane_unregister_all(dev);
6762306a36Sopenharmony_cierr_plane:
6862306a36Sopenharmony_ci	return ret;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_civoid drm_modeset_unregister_all(struct drm_device *dev)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	drm_connector_unregister_all(dev);
7462306a36Sopenharmony_ci	drm_encoder_unregister_all(dev);
7562306a36Sopenharmony_ci	drm_crtc_unregister_all(dev);
7662306a36Sopenharmony_ci	drm_plane_unregister_all(dev);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/**
8062306a36Sopenharmony_ci * drm_mode_getresources - get graphics configuration
8162306a36Sopenharmony_ci * @dev: drm device for the ioctl
8262306a36Sopenharmony_ci * @data: data pointer for the ioctl
8362306a36Sopenharmony_ci * @file_priv: drm file for the ioctl call
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * Construct a set of configuration description structures and return
8662306a36Sopenharmony_ci * them to the user, including CRTC, connector and framebuffer configuration.
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Called by the user via ioctl.
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci * Returns:
9162306a36Sopenharmony_ci * Zero on success, negative errno on failure.
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_ciint drm_mode_getresources(struct drm_device *dev, void *data,
9462306a36Sopenharmony_ci			  struct drm_file *file_priv)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct drm_mode_card_res *card_res = data;
9762306a36Sopenharmony_ci	struct drm_framebuffer *fb;
9862306a36Sopenharmony_ci	struct drm_connector *connector;
9962306a36Sopenharmony_ci	struct drm_crtc *crtc;
10062306a36Sopenharmony_ci	struct drm_encoder *encoder;
10162306a36Sopenharmony_ci	int count, ret = 0;
10262306a36Sopenharmony_ci	uint32_t __user *fb_id;
10362306a36Sopenharmony_ci	uint32_t __user *crtc_id;
10462306a36Sopenharmony_ci	uint32_t __user *connector_id;
10562306a36Sopenharmony_ci	uint32_t __user *encoder_id;
10662306a36Sopenharmony_ci	struct drm_connector_list_iter conn_iter;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (!drm_core_check_feature(dev, DRIVER_MODESET))
10962306a36Sopenharmony_ci		return -EOPNOTSUPP;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	mutex_lock(&file_priv->fbs_lock);
11262306a36Sopenharmony_ci	count = 0;
11362306a36Sopenharmony_ci	fb_id = u64_to_user_ptr(card_res->fb_id_ptr);
11462306a36Sopenharmony_ci	list_for_each_entry(fb, &file_priv->fbs, filp_head) {
11562306a36Sopenharmony_ci		if (count < card_res->count_fbs &&
11662306a36Sopenharmony_ci		    put_user(fb->base.id, fb_id + count)) {
11762306a36Sopenharmony_ci			mutex_unlock(&file_priv->fbs_lock);
11862306a36Sopenharmony_ci			return -EFAULT;
11962306a36Sopenharmony_ci		}
12062306a36Sopenharmony_ci		count++;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci	card_res->count_fbs = count;
12362306a36Sopenharmony_ci	mutex_unlock(&file_priv->fbs_lock);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	card_res->max_height = dev->mode_config.max_height;
12662306a36Sopenharmony_ci	card_res->min_height = dev->mode_config.min_height;
12762306a36Sopenharmony_ci	card_res->max_width = dev->mode_config.max_width;
12862306a36Sopenharmony_ci	card_res->min_width = dev->mode_config.min_width;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	count = 0;
13162306a36Sopenharmony_ci	crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
13262306a36Sopenharmony_ci	drm_for_each_crtc(crtc, dev) {
13362306a36Sopenharmony_ci		if (drm_lease_held(file_priv, crtc->base.id)) {
13462306a36Sopenharmony_ci			if (count < card_res->count_crtcs &&
13562306a36Sopenharmony_ci			    put_user(crtc->base.id, crtc_id + count))
13662306a36Sopenharmony_ci				return -EFAULT;
13762306a36Sopenharmony_ci			count++;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci	card_res->count_crtcs = count;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	count = 0;
14362306a36Sopenharmony_ci	encoder_id = u64_to_user_ptr(card_res->encoder_id_ptr);
14462306a36Sopenharmony_ci	drm_for_each_encoder(encoder, dev) {
14562306a36Sopenharmony_ci		if (count < card_res->count_encoders &&
14662306a36Sopenharmony_ci		    put_user(encoder->base.id, encoder_id + count))
14762306a36Sopenharmony_ci			return -EFAULT;
14862306a36Sopenharmony_ci		count++;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	card_res->count_encoders = count;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	drm_connector_list_iter_begin(dev, &conn_iter);
15362306a36Sopenharmony_ci	count = 0;
15462306a36Sopenharmony_ci	connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
15562306a36Sopenharmony_ci	drm_for_each_connector_iter(connector, &conn_iter) {
15662306a36Sopenharmony_ci		/* only expose writeback connectors if userspace understands them */
15762306a36Sopenharmony_ci		if (!file_priv->writeback_connectors &&
15862306a36Sopenharmony_ci		    (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK))
15962306a36Sopenharmony_ci			continue;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		if (drm_lease_held(file_priv, connector->base.id)) {
16262306a36Sopenharmony_ci			if (count < card_res->count_connectors &&
16362306a36Sopenharmony_ci			    put_user(connector->base.id, connector_id + count)) {
16462306a36Sopenharmony_ci				drm_connector_list_iter_end(&conn_iter);
16562306a36Sopenharmony_ci				return -EFAULT;
16662306a36Sopenharmony_ci			}
16762306a36Sopenharmony_ci			count++;
16862306a36Sopenharmony_ci		}
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci	card_res->count_connectors = count;
17162306a36Sopenharmony_ci	drm_connector_list_iter_end(&conn_iter);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return ret;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/**
17762306a36Sopenharmony_ci * drm_mode_config_reset - call ->reset callbacks
17862306a36Sopenharmony_ci * @dev: drm device
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * This functions calls all the crtc's, encoder's and connector's ->reset
18162306a36Sopenharmony_ci * callback. Drivers can use this in e.g. their driver load or resume code to
18262306a36Sopenharmony_ci * reset hardware and software state.
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_civoid drm_mode_config_reset(struct drm_device *dev)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct drm_crtc *crtc;
18762306a36Sopenharmony_ci	struct drm_plane *plane;
18862306a36Sopenharmony_ci	struct drm_encoder *encoder;
18962306a36Sopenharmony_ci	struct drm_connector *connector;
19062306a36Sopenharmony_ci	struct drm_connector_list_iter conn_iter;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	drm_for_each_plane(plane, dev)
19362306a36Sopenharmony_ci		if (plane->funcs->reset)
19462306a36Sopenharmony_ci			plane->funcs->reset(plane);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	drm_for_each_crtc(crtc, dev)
19762306a36Sopenharmony_ci		if (crtc->funcs->reset)
19862306a36Sopenharmony_ci			crtc->funcs->reset(crtc);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	drm_for_each_encoder(encoder, dev)
20162306a36Sopenharmony_ci		if (encoder->funcs && encoder->funcs->reset)
20262306a36Sopenharmony_ci			encoder->funcs->reset(encoder);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	drm_connector_list_iter_begin(dev, &conn_iter);
20562306a36Sopenharmony_ci	drm_for_each_connector_iter(connector, &conn_iter)
20662306a36Sopenharmony_ci		if (connector->funcs->reset)
20762306a36Sopenharmony_ci			connector->funcs->reset(connector);
20862306a36Sopenharmony_ci	drm_connector_list_iter_end(&conn_iter);
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_mode_config_reset);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/*
21362306a36Sopenharmony_ci * Global properties
21462306a36Sopenharmony_ci */
21562306a36Sopenharmony_cistatic const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
21662306a36Sopenharmony_ci	{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
21762306a36Sopenharmony_ci	{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
21862306a36Sopenharmony_ci	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int drm_mode_create_standard_properties(struct drm_device *dev)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct drm_property *prop;
22462306a36Sopenharmony_ci	int ret;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	ret = drm_connector_create_standard_properties(dev);
22762306a36Sopenharmony_ci	if (ret)
22862306a36Sopenharmony_ci		return ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
23162306a36Sopenharmony_ci					"type", drm_plane_type_enum_list,
23262306a36Sopenharmony_ci					ARRAY_SIZE(drm_plane_type_enum_list));
23362306a36Sopenharmony_ci	if (!prop)
23462306a36Sopenharmony_ci		return -ENOMEM;
23562306a36Sopenharmony_ci	dev->mode_config.plane_type_property = prop;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
23862306a36Sopenharmony_ci			"SRC_X", 0, UINT_MAX);
23962306a36Sopenharmony_ci	if (!prop)
24062306a36Sopenharmony_ci		return -ENOMEM;
24162306a36Sopenharmony_ci	dev->mode_config.prop_src_x = prop;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
24462306a36Sopenharmony_ci			"SRC_Y", 0, UINT_MAX);
24562306a36Sopenharmony_ci	if (!prop)
24662306a36Sopenharmony_ci		return -ENOMEM;
24762306a36Sopenharmony_ci	dev->mode_config.prop_src_y = prop;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
25062306a36Sopenharmony_ci			"SRC_W", 0, UINT_MAX);
25162306a36Sopenharmony_ci	if (!prop)
25262306a36Sopenharmony_ci		return -ENOMEM;
25362306a36Sopenharmony_ci	dev->mode_config.prop_src_w = prop;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
25662306a36Sopenharmony_ci			"SRC_H", 0, UINT_MAX);
25762306a36Sopenharmony_ci	if (!prop)
25862306a36Sopenharmony_ci		return -ENOMEM;
25962306a36Sopenharmony_ci	dev->mode_config.prop_src_h = prop;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
26262306a36Sopenharmony_ci			"CRTC_X", INT_MIN, INT_MAX);
26362306a36Sopenharmony_ci	if (!prop)
26462306a36Sopenharmony_ci		return -ENOMEM;
26562306a36Sopenharmony_ci	dev->mode_config.prop_crtc_x = prop;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
26862306a36Sopenharmony_ci			"CRTC_Y", INT_MIN, INT_MAX);
26962306a36Sopenharmony_ci	if (!prop)
27062306a36Sopenharmony_ci		return -ENOMEM;
27162306a36Sopenharmony_ci	dev->mode_config.prop_crtc_y = prop;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
27462306a36Sopenharmony_ci			"CRTC_W", 0, INT_MAX);
27562306a36Sopenharmony_ci	if (!prop)
27662306a36Sopenharmony_ci		return -ENOMEM;
27762306a36Sopenharmony_ci	dev->mode_config.prop_crtc_w = prop;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
28062306a36Sopenharmony_ci			"CRTC_H", 0, INT_MAX);
28162306a36Sopenharmony_ci	if (!prop)
28262306a36Sopenharmony_ci		return -ENOMEM;
28362306a36Sopenharmony_ci	dev->mode_config.prop_crtc_h = prop;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
28662306a36Sopenharmony_ci			"FB_ID", DRM_MODE_OBJECT_FB);
28762306a36Sopenharmony_ci	if (!prop)
28862306a36Sopenharmony_ci		return -ENOMEM;
28962306a36Sopenharmony_ci	dev->mode_config.prop_fb_id = prop;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
29262306a36Sopenharmony_ci			"IN_FENCE_FD", -1, INT_MAX);
29362306a36Sopenharmony_ci	if (!prop)
29462306a36Sopenharmony_ci		return -ENOMEM;
29562306a36Sopenharmony_ci	dev->mode_config.prop_in_fence_fd = prop;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
29862306a36Sopenharmony_ci			"OUT_FENCE_PTR", 0, U64_MAX);
29962306a36Sopenharmony_ci	if (!prop)
30062306a36Sopenharmony_ci		return -ENOMEM;
30162306a36Sopenharmony_ci	dev->mode_config.prop_out_fence_ptr = prop;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
30462306a36Sopenharmony_ci			"CRTC_ID", DRM_MODE_OBJECT_CRTC);
30562306a36Sopenharmony_ci	if (!prop)
30662306a36Sopenharmony_ci		return -ENOMEM;
30762306a36Sopenharmony_ci	dev->mode_config.prop_crtc_id = prop;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	prop = drm_property_create(dev,
31062306a36Sopenharmony_ci			DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
31162306a36Sopenharmony_ci			"FB_DAMAGE_CLIPS", 0);
31262306a36Sopenharmony_ci	if (!prop)
31362306a36Sopenharmony_ci		return -ENOMEM;
31462306a36Sopenharmony_ci	dev->mode_config.prop_fb_damage_clips = prop;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
31762306a36Sopenharmony_ci			"ACTIVE");
31862306a36Sopenharmony_ci	if (!prop)
31962306a36Sopenharmony_ci		return -ENOMEM;
32062306a36Sopenharmony_ci	dev->mode_config.prop_active = prop;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	prop = drm_property_create(dev,
32362306a36Sopenharmony_ci			DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
32462306a36Sopenharmony_ci			"MODE_ID", 0);
32562306a36Sopenharmony_ci	if (!prop)
32662306a36Sopenharmony_ci		return -ENOMEM;
32762306a36Sopenharmony_ci	dev->mode_config.prop_mode_id = prop;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	prop = drm_property_create_bool(dev, 0,
33062306a36Sopenharmony_ci			"VRR_ENABLED");
33162306a36Sopenharmony_ci	if (!prop)
33262306a36Sopenharmony_ci		return -ENOMEM;
33362306a36Sopenharmony_ci	dev->mode_config.prop_vrr_enabled = prop;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	prop = drm_property_create(dev,
33662306a36Sopenharmony_ci			DRM_MODE_PROP_BLOB,
33762306a36Sopenharmony_ci			"DEGAMMA_LUT", 0);
33862306a36Sopenharmony_ci	if (!prop)
33962306a36Sopenharmony_ci		return -ENOMEM;
34062306a36Sopenharmony_ci	dev->mode_config.degamma_lut_property = prop;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	prop = drm_property_create_range(dev,
34362306a36Sopenharmony_ci			DRM_MODE_PROP_IMMUTABLE,
34462306a36Sopenharmony_ci			"DEGAMMA_LUT_SIZE", 0, UINT_MAX);
34562306a36Sopenharmony_ci	if (!prop)
34662306a36Sopenharmony_ci		return -ENOMEM;
34762306a36Sopenharmony_ci	dev->mode_config.degamma_lut_size_property = prop;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	prop = drm_property_create(dev,
35062306a36Sopenharmony_ci			DRM_MODE_PROP_BLOB,
35162306a36Sopenharmony_ci			"CTM", 0);
35262306a36Sopenharmony_ci	if (!prop)
35362306a36Sopenharmony_ci		return -ENOMEM;
35462306a36Sopenharmony_ci	dev->mode_config.ctm_property = prop;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	prop = drm_property_create(dev,
35762306a36Sopenharmony_ci			DRM_MODE_PROP_BLOB,
35862306a36Sopenharmony_ci			"GAMMA_LUT", 0);
35962306a36Sopenharmony_ci	if (!prop)
36062306a36Sopenharmony_ci		return -ENOMEM;
36162306a36Sopenharmony_ci	dev->mode_config.gamma_lut_property = prop;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	prop = drm_property_create_range(dev,
36462306a36Sopenharmony_ci			DRM_MODE_PROP_IMMUTABLE,
36562306a36Sopenharmony_ci			"GAMMA_LUT_SIZE", 0, UINT_MAX);
36662306a36Sopenharmony_ci	if (!prop)
36762306a36Sopenharmony_ci		return -ENOMEM;
36862306a36Sopenharmony_ci	dev->mode_config.gamma_lut_size_property = prop;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	prop = drm_property_create(dev,
37162306a36Sopenharmony_ci				   DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_BLOB,
37262306a36Sopenharmony_ci				   "IN_FORMATS", 0);
37362306a36Sopenharmony_ci	if (!prop)
37462306a36Sopenharmony_ci		return -ENOMEM;
37562306a36Sopenharmony_ci	dev->mode_config.modifiers_property = prop;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void drm_mode_config_init_release(struct drm_device *dev, void *ptr)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	drm_mode_config_cleanup(dev);
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci/**
38662306a36Sopenharmony_ci * drmm_mode_config_init - managed DRM mode_configuration structure
38762306a36Sopenharmony_ci * 	initialization
38862306a36Sopenharmony_ci * @dev: DRM device
38962306a36Sopenharmony_ci *
39062306a36Sopenharmony_ci * Initialize @dev's mode_config structure, used for tracking the graphics
39162306a36Sopenharmony_ci * configuration of @dev.
39262306a36Sopenharmony_ci *
39362306a36Sopenharmony_ci * Since this initializes the modeset locks, no locking is possible. Which is no
39462306a36Sopenharmony_ci * problem, since this should happen single threaded at init time. It is the
39562306a36Sopenharmony_ci * driver's problem to ensure this guarantee.
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * Cleanup is automatically handled through registering drm_mode_config_cleanup
39862306a36Sopenharmony_ci * with drmm_add_action().
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * Returns: 0 on success, negative error value on failure.
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_ciint drmm_mode_config_init(struct drm_device *dev)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	int ret;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	mutex_init(&dev->mode_config.mutex);
40762306a36Sopenharmony_ci	drm_modeset_lock_init(&dev->mode_config.connection_mutex);
40862306a36Sopenharmony_ci	mutex_init(&dev->mode_config.idr_mutex);
40962306a36Sopenharmony_ci	mutex_init(&dev->mode_config.fb_lock);
41062306a36Sopenharmony_ci	mutex_init(&dev->mode_config.blob_lock);
41162306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.fb_list);
41262306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
41362306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.connector_list);
41462306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
41562306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.property_list);
41662306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
41762306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.plane_list);
41862306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev->mode_config.privobj_list);
41962306a36Sopenharmony_ci	idr_init_base(&dev->mode_config.object_idr, 1);
42062306a36Sopenharmony_ci	idr_init_base(&dev->mode_config.tile_idr, 1);
42162306a36Sopenharmony_ci	ida_init(&dev->mode_config.connector_ida);
42262306a36Sopenharmony_ci	spin_lock_init(&dev->mode_config.connector_list_lock);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	init_llist_head(&dev->mode_config.connector_free_list);
42562306a36Sopenharmony_ci	INIT_WORK(&dev->mode_config.connector_free_work, drm_connector_free_work_fn);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	ret = drm_mode_create_standard_properties(dev);
42862306a36Sopenharmony_ci	if (ret) {
42962306a36Sopenharmony_ci		drm_mode_config_cleanup(dev);
43062306a36Sopenharmony_ci		return ret;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* Just to be sure */
43462306a36Sopenharmony_ci	dev->mode_config.num_fb = 0;
43562306a36Sopenharmony_ci	dev->mode_config.num_connector = 0;
43662306a36Sopenharmony_ci	dev->mode_config.num_crtc = 0;
43762306a36Sopenharmony_ci	dev->mode_config.num_encoder = 0;
43862306a36Sopenharmony_ci	dev->mode_config.num_total_plane = 0;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_LOCKDEP)) {
44162306a36Sopenharmony_ci		struct drm_modeset_acquire_ctx modeset_ctx;
44262306a36Sopenharmony_ci		struct ww_acquire_ctx resv_ctx;
44362306a36Sopenharmony_ci		struct dma_resv resv;
44462306a36Sopenharmony_ci		int ret;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		dma_resv_init(&resv);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		drm_modeset_acquire_init(&modeset_ctx, 0);
44962306a36Sopenharmony_ci		ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
45062306a36Sopenharmony_ci				       &modeset_ctx);
45162306a36Sopenharmony_ci		if (ret == -EDEADLK)
45262306a36Sopenharmony_ci			ret = drm_modeset_backoff(&modeset_ctx);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		ww_acquire_init(&resv_ctx, &reservation_ww_class);
45562306a36Sopenharmony_ci		ret = dma_resv_lock(&resv, &resv_ctx);
45662306a36Sopenharmony_ci		if (ret == -EDEADLK)
45762306a36Sopenharmony_ci			dma_resv_lock_slow(&resv, &resv_ctx);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		dma_resv_unlock(&resv);
46062306a36Sopenharmony_ci		ww_acquire_fini(&resv_ctx);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		drm_modeset_drop_locks(&modeset_ctx);
46362306a36Sopenharmony_ci		drm_modeset_acquire_fini(&modeset_ctx);
46462306a36Sopenharmony_ci		dma_resv_fini(&resv);
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return drmm_add_action_or_reset(dev, drm_mode_config_init_release,
46862306a36Sopenharmony_ci					NULL);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ciEXPORT_SYMBOL(drmm_mode_config_init);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci/**
47362306a36Sopenharmony_ci * drm_mode_config_cleanup - free up DRM mode_config info
47462306a36Sopenharmony_ci * @dev: DRM device
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * Free up all the connectors and CRTCs associated with this DRM device, then
47762306a36Sopenharmony_ci * free up the framebuffers and associated buffer objects.
47862306a36Sopenharmony_ci *
47962306a36Sopenharmony_ci * Note that since this /should/ happen single-threaded at driver/device
48062306a36Sopenharmony_ci * teardown time, no locking is required. It's the driver's job to ensure that
48162306a36Sopenharmony_ci * this guarantee actually holds true.
48262306a36Sopenharmony_ci *
48362306a36Sopenharmony_ci * FIXME: With the managed drmm_mode_config_init() it is no longer necessary for
48462306a36Sopenharmony_ci * drivers to explicitly call this function.
48562306a36Sopenharmony_ci */
48662306a36Sopenharmony_civoid drm_mode_config_cleanup(struct drm_device *dev)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct drm_connector *connector;
48962306a36Sopenharmony_ci	struct drm_connector_list_iter conn_iter;
49062306a36Sopenharmony_ci	struct drm_crtc *crtc, *ct;
49162306a36Sopenharmony_ci	struct drm_encoder *encoder, *enct;
49262306a36Sopenharmony_ci	struct drm_framebuffer *fb, *fbt;
49362306a36Sopenharmony_ci	struct drm_property *property, *pt;
49462306a36Sopenharmony_ci	struct drm_property_blob *blob, *bt;
49562306a36Sopenharmony_ci	struct drm_plane *plane, *plt;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
49862306a36Sopenharmony_ci				 head) {
49962306a36Sopenharmony_ci		encoder->funcs->destroy(encoder);
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	drm_connector_list_iter_begin(dev, &conn_iter);
50362306a36Sopenharmony_ci	drm_for_each_connector_iter(connector, &conn_iter) {
50462306a36Sopenharmony_ci		/* drm_connector_list_iter holds an full reference to the
50562306a36Sopenharmony_ci		 * current connector itself, which means it is inherently safe
50662306a36Sopenharmony_ci		 * against unreferencing the current connector - but not against
50762306a36Sopenharmony_ci		 * deleting it right away. */
50862306a36Sopenharmony_ci		drm_connector_put(connector);
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci	drm_connector_list_iter_end(&conn_iter);
51162306a36Sopenharmony_ci	/* connector_iter drops references in a work item. */
51262306a36Sopenharmony_ci	flush_work(&dev->mode_config.connector_free_work);
51362306a36Sopenharmony_ci	if (WARN_ON(!list_empty(&dev->mode_config.connector_list))) {
51462306a36Sopenharmony_ci		drm_connector_list_iter_begin(dev, &conn_iter);
51562306a36Sopenharmony_ci		drm_for_each_connector_iter(connector, &conn_iter)
51662306a36Sopenharmony_ci			DRM_ERROR("connector %s leaked!\n", connector->name);
51762306a36Sopenharmony_ci		drm_connector_list_iter_end(&conn_iter);
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
52162306a36Sopenharmony_ci				 head) {
52262306a36Sopenharmony_ci		drm_property_destroy(dev, property);
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
52662306a36Sopenharmony_ci				 head) {
52762306a36Sopenharmony_ci		plane->funcs->destroy(plane);
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
53162306a36Sopenharmony_ci		crtc->funcs->destroy(crtc);
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
53562306a36Sopenharmony_ci				 head_global) {
53662306a36Sopenharmony_ci		drm_property_blob_put(blob);
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/*
54062306a36Sopenharmony_ci	 * Single-threaded teardown context, so it's not required to grab the
54162306a36Sopenharmony_ci	 * fb_lock to protect against concurrent fb_list access. Contrary, it
54262306a36Sopenharmony_ci	 * would actually deadlock with the drm_framebuffer_cleanup function.
54362306a36Sopenharmony_ci	 *
54462306a36Sopenharmony_ci	 * Also, if there are any framebuffers left, that's a driver leak now,
54562306a36Sopenharmony_ci	 * so politely WARN about this.
54662306a36Sopenharmony_ci	 */
54762306a36Sopenharmony_ci	WARN_ON(!list_empty(&dev->mode_config.fb_list));
54862306a36Sopenharmony_ci	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
54962306a36Sopenharmony_ci		struct drm_printer p = drm_debug_printer("[leaked fb]");
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
55262306a36Sopenharmony_ci		drm_framebuffer_print_info(&p, 1, fb);
55362306a36Sopenharmony_ci		drm_framebuffer_free(&fb->base.refcount);
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	ida_destroy(&dev->mode_config.connector_ida);
55762306a36Sopenharmony_ci	idr_destroy(&dev->mode_config.tile_idr);
55862306a36Sopenharmony_ci	idr_destroy(&dev->mode_config.object_idr);
55962306a36Sopenharmony_ci	drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ciEXPORT_SYMBOL(drm_mode_config_cleanup);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic u32 full_encoder_mask(struct drm_device *dev)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct drm_encoder *encoder;
56662306a36Sopenharmony_ci	u32 encoder_mask = 0;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	drm_for_each_encoder(encoder, dev)
56962306a36Sopenharmony_ci		encoder_mask |= drm_encoder_mask(encoder);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	return encoder_mask;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci/*
57562306a36Sopenharmony_ci * For some reason we want the encoder itself included in
57662306a36Sopenharmony_ci * possible_clones. Make life easy for drivers by allowing them
57762306a36Sopenharmony_ci * to leave possible_clones unset if no cloning is possible.
57862306a36Sopenharmony_ci */
57962306a36Sopenharmony_cistatic void fixup_encoder_possible_clones(struct drm_encoder *encoder)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	if (encoder->possible_clones == 0)
58262306a36Sopenharmony_ci		encoder->possible_clones = drm_encoder_mask(encoder);
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic void validate_encoder_possible_clones(struct drm_encoder *encoder)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	struct drm_device *dev = encoder->dev;
58862306a36Sopenharmony_ci	u32 encoder_mask = full_encoder_mask(dev);
58962306a36Sopenharmony_ci	struct drm_encoder *other;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	drm_for_each_encoder(other, dev) {
59262306a36Sopenharmony_ci		WARN(!!(encoder->possible_clones & drm_encoder_mask(other)) !=
59362306a36Sopenharmony_ci		     !!(other->possible_clones & drm_encoder_mask(encoder)),
59462306a36Sopenharmony_ci		     "possible_clones mismatch: "
59562306a36Sopenharmony_ci		     "[ENCODER:%d:%s] mask=0x%x possible_clones=0x%x vs. "
59662306a36Sopenharmony_ci		     "[ENCODER:%d:%s] mask=0x%x possible_clones=0x%x\n",
59762306a36Sopenharmony_ci		     encoder->base.id, encoder->name,
59862306a36Sopenharmony_ci		     drm_encoder_mask(encoder), encoder->possible_clones,
59962306a36Sopenharmony_ci		     other->base.id, other->name,
60062306a36Sopenharmony_ci		     drm_encoder_mask(other), other->possible_clones);
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	WARN((encoder->possible_clones & drm_encoder_mask(encoder)) == 0 ||
60462306a36Sopenharmony_ci	     (encoder->possible_clones & ~encoder_mask) != 0,
60562306a36Sopenharmony_ci	     "Bogus possible_clones: "
60662306a36Sopenharmony_ci	     "[ENCODER:%d:%s] possible_clones=0x%x (full encoder mask=0x%x)\n",
60762306a36Sopenharmony_ci	     encoder->base.id, encoder->name,
60862306a36Sopenharmony_ci	     encoder->possible_clones, encoder_mask);
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic u32 full_crtc_mask(struct drm_device *dev)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	struct drm_crtc *crtc;
61462306a36Sopenharmony_ci	u32 crtc_mask = 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	drm_for_each_crtc(crtc, dev)
61762306a36Sopenharmony_ci		crtc_mask |= drm_crtc_mask(crtc);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return crtc_mask;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic void validate_encoder_possible_crtcs(struct drm_encoder *encoder)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	u32 crtc_mask = full_crtc_mask(encoder->dev);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	WARN((encoder->possible_crtcs & crtc_mask) == 0 ||
62762306a36Sopenharmony_ci	     (encoder->possible_crtcs & ~crtc_mask) != 0,
62862306a36Sopenharmony_ci	     "Bogus possible_crtcs: "
62962306a36Sopenharmony_ci	     "[ENCODER:%d:%s] possible_crtcs=0x%x (full crtc mask=0x%x)\n",
63062306a36Sopenharmony_ci	     encoder->base.id, encoder->name,
63162306a36Sopenharmony_ci	     encoder->possible_crtcs, crtc_mask);
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_civoid drm_mode_config_validate(struct drm_device *dev)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct drm_encoder *encoder;
63762306a36Sopenharmony_ci	struct drm_crtc *crtc;
63862306a36Sopenharmony_ci	struct drm_plane *plane;
63962306a36Sopenharmony_ci	u32 primary_with_crtc = 0, cursor_with_crtc = 0;
64062306a36Sopenharmony_ci	unsigned int num_primary = 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (!drm_core_check_feature(dev, DRIVER_MODESET))
64362306a36Sopenharmony_ci		return;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	drm_for_each_encoder(encoder, dev)
64662306a36Sopenharmony_ci		fixup_encoder_possible_clones(encoder);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	drm_for_each_encoder(encoder, dev) {
64962306a36Sopenharmony_ci		validate_encoder_possible_clones(encoder);
65062306a36Sopenharmony_ci		validate_encoder_possible_crtcs(encoder);
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	drm_for_each_crtc(crtc, dev) {
65462306a36Sopenharmony_ci		WARN(!crtc->primary, "Missing primary plane on [CRTC:%d:%s]\n",
65562306a36Sopenharmony_ci		     crtc->base.id, crtc->name);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		WARN(crtc->cursor && crtc->funcs->cursor_set,
65862306a36Sopenharmony_ci		     "[CRTC:%d:%s] must not have both a cursor plane and a cursor_set func",
65962306a36Sopenharmony_ci		     crtc->base.id, crtc->name);
66062306a36Sopenharmony_ci		WARN(crtc->cursor && crtc->funcs->cursor_set2,
66162306a36Sopenharmony_ci		     "[CRTC:%d:%s] must not have both a cursor plane and a cursor_set2 func",
66262306a36Sopenharmony_ci		     crtc->base.id, crtc->name);
66362306a36Sopenharmony_ci		WARN(crtc->cursor && crtc->funcs->cursor_move,
66462306a36Sopenharmony_ci		     "[CRTC:%d:%s] must not have both a cursor plane and a cursor_move func",
66562306a36Sopenharmony_ci		     crtc->base.id, crtc->name);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		if (crtc->primary) {
66862306a36Sopenharmony_ci			WARN(!(crtc->primary->possible_crtcs & drm_crtc_mask(crtc)),
66962306a36Sopenharmony_ci			     "Bogus primary plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n",
67062306a36Sopenharmony_ci			     crtc->primary->base.id, crtc->primary->name,
67162306a36Sopenharmony_ci			     crtc->base.id, crtc->name);
67262306a36Sopenharmony_ci			WARN(primary_with_crtc & drm_plane_mask(crtc->primary),
67362306a36Sopenharmony_ci			     "Primary plane [PLANE:%d:%s] used for multiple CRTCs",
67462306a36Sopenharmony_ci			     crtc->primary->base.id, crtc->primary->name);
67562306a36Sopenharmony_ci			primary_with_crtc |= drm_plane_mask(crtc->primary);
67662306a36Sopenharmony_ci		}
67762306a36Sopenharmony_ci		if (crtc->cursor) {
67862306a36Sopenharmony_ci			WARN(!(crtc->cursor->possible_crtcs & drm_crtc_mask(crtc)),
67962306a36Sopenharmony_ci			     "Bogus cursor plane possible_crtcs: [PLANE:%d:%s] must be compatible with [CRTC:%d:%s]\n",
68062306a36Sopenharmony_ci			     crtc->cursor->base.id, crtc->cursor->name,
68162306a36Sopenharmony_ci			     crtc->base.id, crtc->name);
68262306a36Sopenharmony_ci			WARN(cursor_with_crtc & drm_plane_mask(crtc->cursor),
68362306a36Sopenharmony_ci			     "Cursor plane [PLANE:%d:%s] used for multiple CRTCs",
68462306a36Sopenharmony_ci			     crtc->cursor->base.id, crtc->cursor->name);
68562306a36Sopenharmony_ci			cursor_with_crtc |= drm_plane_mask(crtc->cursor);
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	drm_for_each_plane(plane, dev) {
69062306a36Sopenharmony_ci		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
69162306a36Sopenharmony_ci			num_primary++;
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	WARN(num_primary != dev->mode_config.num_crtc,
69562306a36Sopenharmony_ci	     "Must have as many primary planes as there are CRTCs, but have %u primary planes and %u CRTCs",
69662306a36Sopenharmony_ci	     num_primary, dev->mode_config.num_crtc);
69762306a36Sopenharmony_ci}
698