drm_crtc.c 32.9 KB
Newer Older
D
Dave Airlie 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * Copyright (c) 2006-2008 Intel Corporation
 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
 * Copyright (c) 2008 Red Hat Inc.
 *
 * DRM core CRTC related functions
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting documentation, and
 * that the name of the copyright holders not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  The copyright holders make no representations
 * about the suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 *
 * Authors:
 *      Keith Packard
 *	Eric Anholt <eric@anholt.net>
 *      Dave Airlie <airlied@linux.ie>
 *      Jesse Barnes <jesse.barnes@intel.com>
 */
32
#include <linux/ctype.h>
D
Dave Airlie 已提交
33
#include <linux/list.h>
34
#include <linux/slab.h>
35
#include <linux/export.h>
36 37 38 39
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
40
#include <drm/drm_modeset_lock.h>
R
Rob Clark 已提交
41
#include <drm/drm_atomic.h>
D
Daniel Vetter 已提交
42
#include <drm/drm_auth.h>
43
#include <drm/drm_framebuffer.h>
D
Dave Airlie 已提交
44

45
#include "drm_crtc_internal.h"
46
#include "drm_internal.h"
47

D
Dave Airlie 已提交
48 49 50
/*
 * Global properties
 */
51
static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
R
Rob Clark 已提交
52 53 54 55 56
	{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
	{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
	{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
};

D
Daniel Vetter 已提交
57 58
/*
 * Optional properties
59
 */
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/**
 * drm_crtc_force_disable - Forcibly turn off a CRTC
 * @crtc: CRTC to turn off
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_crtc_force_disable(struct drm_crtc *crtc)
{
	struct drm_mode_set set = {
		.crtc = crtc,
	};

	return drm_mode_set_config_internal(&set);
}
EXPORT_SYMBOL(drm_crtc_force_disable);

/**
 * drm_crtc_force_disable_all - Forcibly turn off all enabled CRTCs
 * @dev: DRM device whose CRTCs to turn off
 *
 * Drivers may want to call this on unload to ensure that all displays are
 * unlit and the GPU is in a consistent, low power state. Takes modeset locks.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_crtc_force_disable_all(struct drm_device *dev)
{
	struct drm_crtc *crtc;
	int ret = 0;

	drm_modeset_lock_all(dev);
	drm_for_each_crtc(crtc, dev)
		if (crtc->enabled) {
			ret = drm_crtc_force_disable(crtc);
			if (ret)
				goto out;
		}
out:
	drm_modeset_unlock_all(dev);
	return ret;
}
EXPORT_SYMBOL(drm_crtc_force_disable_all);

105 106
DEFINE_WW_CLASS(crtc_ww_class);

107 108 109 110 111 112 113 114 115 116 117 118
static unsigned int drm_num_crtcs(struct drm_device *dev)
{
	unsigned int num = 0;
	struct drm_crtc *tmp;

	drm_for_each_crtc(tmp, dev) {
		num++;
	}

	return num;
}

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
static int drm_crtc_register_all(struct drm_device *dev)
{
	struct drm_crtc *crtc;
	int ret = 0;

	drm_for_each_crtc(crtc, dev) {
		if (crtc->funcs->late_register)
			ret = crtc->funcs->late_register(crtc);
		if (ret)
			return ret;
	}

	return 0;
}

static void drm_crtc_unregister_all(struct drm_device *dev)
{
	struct drm_crtc *crtc;

	drm_for_each_crtc(crtc, dev) {
		if (crtc->funcs->early_unregister)
			crtc->funcs->early_unregister(crtc);
	}
}

D
Dave Airlie 已提交
144
/**
145 146
 * drm_crtc_init_with_planes - Initialise a new CRTC object with
 *    specified primary and cursor planes.
D
Dave Airlie 已提交
147 148
 * @dev: DRM device
 * @crtc: CRTC object to init
149 150
 * @primary: Primary plane for CRTC
 * @cursor: Cursor plane for CRTC
D
Dave Airlie 已提交
151
 * @funcs: callbacks for the new CRTC
152
 * @name: printf style format string for the CRTC name, or NULL for default name
D
Dave Airlie 已提交
153
 *
154 155 156 157 158
 * Inits a new object created as base part of a driver crtc object. Drivers
 * should use this function instead of drm_crtc_init(), which is only provided
 * for backwards compatibility with drivers which do not yet support universal
 * planes). For really simple hardware which has only 1 plane look at
 * drm_simple_display_pipe_init() instead.
159
 *
160
 * Returns:
161
 * Zero on success, error code on failure.
D
Dave Airlie 已提交
162
 */
163 164
int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
			      struct drm_plane *primary,
165
			      struct drm_plane *cursor,
166 167
			      const struct drm_crtc_funcs *funcs,
			      const char *name, ...)
D
Dave Airlie 已提交
168
{
169
	struct drm_mode_config *config = &dev->mode_config;
170 171
	int ret;

172 173 174
	WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
	WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);

D
Dave Airlie 已提交
175 176 177
	crtc->dev = dev;
	crtc->funcs = funcs;

178 179 180
	INIT_LIST_HEAD(&crtc->commit_list);
	spin_lock_init(&crtc->commit_lock);

181
	drm_modeset_lock_init(&crtc->mutex);
182 183
	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
	if (ret)
184
		return ret;
D
Dave Airlie 已提交
185

186 187 188 189 190 191 192 193 194 195 196
	if (name) {
		va_list ap;

		va_start(ap, name);
		crtc->name = kvasprintf(GFP_KERNEL, name, ap);
		va_end(ap);
	} else {
		crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
				       drm_num_crtcs(dev));
	}
	if (!crtc->name) {
197
		drm_mode_object_unregister(dev, &crtc->base);
198 199 200
		return -ENOMEM;
	}

P
Paulo Zanoni 已提交
201 202
	crtc->base.properties = &crtc->properties;

203
	list_add_tail(&crtc->head, &config->crtc_list);
C
Chris Wilson 已提交
204
	crtc->index = config->num_crtc++;
205

206
	crtc->primary = primary;
207
	crtc->cursor = cursor;
208 209
	if (primary)
		primary->possible_crtcs = 1 << drm_crtc_index(crtc);
210 211
	if (cursor)
		cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
212

213 214
	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
		drm_object_attach_property(&crtc->base, config->prop_active, 0);
D
Daniel Stone 已提交
215
		drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
216 217
	}

218
	return 0;
D
Dave Airlie 已提交
219
}
220
EXPORT_SYMBOL(drm_crtc_init_with_planes);
D
Dave Airlie 已提交
221 222

/**
223
 * drm_crtc_cleanup - Clean up the core crtc usage
D
Dave Airlie 已提交
224 225
 * @crtc: CRTC to cleanup
 *
226 227 228
 * This function cleans up @crtc and removes it from the DRM mode setting
 * core. Note that the function does *not* free the crtc structure itself,
 * this is the responsibility of the caller.
D
Dave Airlie 已提交
229 230 231 232 233
 */
void drm_crtc_cleanup(struct drm_crtc *crtc)
{
	struct drm_device *dev = crtc->dev;

C
Chris Wilson 已提交
234 235 236 237 238
	/* Note that the crtc_list is considered to be static; should we
	 * remove the drm_crtc at runtime we would have to decrement all
	 * the indices on the drm_crtc after us in the crtc_list.
	 */

239 240
	kfree(crtc->gamma_store);
	crtc->gamma_store = NULL;
D
Dave Airlie 已提交
241

242 243
	drm_modeset_lock_fini(&crtc->mutex);

244
	drm_mode_object_unregister(dev, &crtc->base);
D
Dave Airlie 已提交
245 246
	list_del(&crtc->head);
	dev->mode_config.num_crtc--;
247 248 249 250

	WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
	if (crtc->state && crtc->funcs->atomic_destroy_state)
		crtc->funcs->atomic_destroy_state(crtc, crtc->state);
251

252 253
	kfree(crtc->name);

254
	memset(crtc, 0, sizeof(*crtc));
D
Dave Airlie 已提交
255 256 257
}
EXPORT_SYMBOL(drm_crtc_cleanup);

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
int drm_modeset_register_all(struct drm_device *dev)
{
	int ret;

	ret = drm_plane_register_all(dev);
	if (ret)
		goto err_plane;

	ret = drm_crtc_register_all(dev);
	if  (ret)
		goto err_crtc;

	ret = drm_encoder_register_all(dev);
	if (ret)
		goto err_encoder;

	ret = drm_connector_register_all(dev);
	if (ret)
		goto err_connector;

	return 0;

err_connector:
	drm_encoder_unregister_all(dev);
err_encoder:
	drm_crtc_unregister_all(dev);
err_crtc:
	drm_plane_unregister_all(dev);
err_plane:
	return ret;
}

void drm_modeset_unregister_all(struct drm_device *dev)
{
	drm_connector_unregister_all(dev);
	drm_encoder_unregister_all(dev);
	drm_crtc_unregister_all(dev);
	drm_plane_unregister_all(dev);
}

R
Rob Clark 已提交
298
static int drm_mode_create_standard_properties(struct drm_device *dev)
D
Dave Airlie 已提交
299
{
R
Rob Clark 已提交
300
	struct drm_property *prop;
D
Daniel Vetter 已提交
301
	int ret;
D
Dave Airlie 已提交
302

D
Daniel Vetter 已提交
303 304 305
	ret = drm_connector_create_standard_properties(dev);
	if (ret)
		return ret;
R
Rob Clark 已提交
306

R
Rob Clark 已提交
307
	prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
R
Rob Clark 已提交
308 309
					"type", drm_plane_type_enum_list,
					ARRAY_SIZE(drm_plane_type_enum_list));
R
Rob Clark 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
	if (!prop)
		return -ENOMEM;
	dev->mode_config.plane_type_property = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_X", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_x = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_Y", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_y = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_W", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_w = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"SRC_H", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_src_h = prop;

	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
			"CRTC_X", INT_MIN, INT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_crtc_x = prop;

	prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
			"CRTC_Y", INT_MIN, INT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_crtc_y = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"CRTC_W", 0, INT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_crtc_w = prop;

	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
			"CRTC_H", 0, INT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_crtc_h = prop;

	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
			"FB_ID", DRM_MODE_OBJECT_FB);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_fb_id = prop;

	prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
			"CRTC_ID", DRM_MODE_OBJECT_CRTC);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_crtc_id = prop;
R
Rob Clark 已提交
373

374 375 376 377 378 379
	prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
			"ACTIVE");
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_active = prop;

D
Daniel Stone 已提交
380 381 382 383 384 385 386
	prop = drm_property_create(dev,
			DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
			"MODE_ID", 0);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.prop_mode_id = prop;

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
	prop = drm_property_create(dev,
			DRM_MODE_PROP_BLOB,
			"DEGAMMA_LUT", 0);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.degamma_lut_property = prop;

	prop = drm_property_create_range(dev,
			DRM_MODE_PROP_IMMUTABLE,
			"DEGAMMA_LUT_SIZE", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.degamma_lut_size_property = prop;

	prop = drm_property_create(dev,
			DRM_MODE_PROP_BLOB,
			"CTM", 0);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.ctm_property = prop;

	prop = drm_property_create(dev,
			DRM_MODE_PROP_BLOB,
			"GAMMA_LUT", 0);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.gamma_lut_property = prop;

	prop = drm_property_create_range(dev,
			DRM_MODE_PROP_IMMUTABLE,
			"GAMMA_LUT_SIZE", 0, UINT_MAX);
	if (!prop)
		return -ENOMEM;
	dev->mode_config.gamma_lut_size_property = prop;

R
Rob Clark 已提交
422 423 424
	return 0;
}

D
Dave Airlie 已提交
425 426
/**
 * drm_mode_getresources - get graphics configuration
427 428 429
 * @dev: drm device for the ioctl
 * @data: data pointer for the ioctl
 * @file_priv: drm file for the ioctl call
D
Dave Airlie 已提交
430 431 432 433 434 435
 *
 * Construct a set of configuration description structures and return
 * them to the user, including CRTC, connector and framebuffer configuration.
 *
 * Called by the user via ioctl.
 *
436
 * Returns:
D
Daniel Vetter 已提交
437
 * Zero on success, negative errno on failure.
D
Dave Airlie 已提交
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
 */
int drm_mode_getresources(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
{
	struct drm_mode_card_res *card_res = data;
	struct list_head *lh;
	struct drm_framebuffer *fb;
	struct drm_connector *connector;
	struct drm_crtc *crtc;
	struct drm_encoder *encoder;
	int ret = 0;
	int connector_count = 0;
	int crtc_count = 0;
	int fb_count = 0;
	int encoder_count = 0;
453
	int copied = 0;
D
Dave Airlie 已提交
454 455 456 457 458
	uint32_t __user *fb_id;
	uint32_t __user *crtc_id;
	uint32_t __user *connector_id;
	uint32_t __user *encoder_id;

459 460 461
	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;

D
Dave Airlie 已提交
462

463
	mutex_lock(&file_priv->fbs_lock);
D
Dave Airlie 已提交
464 465 466 467 468 469 470
	/*
	 * For the non-control nodes we need to limit the list of resources
	 * by IDs in the group list for this node
	 */
	list_for_each(lh, &file_priv->fbs)
		fb_count++;

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
	/* handle this in 4 parts */
	/* FBs */
	if (card_res->count_fbs >= fb_count) {
		copied = 0;
		fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
		list_for_each_entry(fb, &file_priv->fbs, filp_head) {
			if (put_user(fb->base.id, fb_id + copied)) {
				mutex_unlock(&file_priv->fbs_lock);
				return -EFAULT;
			}
			copied++;
		}
	}
	card_res->count_fbs = fb_count;
	mutex_unlock(&file_priv->fbs_lock);

487 488 489
	/* mode_config.mutex protects the connector list against e.g. DP MST
	 * connector hot-adding. CRTC/Plane lists are invariant. */
	mutex_lock(&dev->mode_config.mutex);
490 491
	drm_for_each_crtc(crtc, dev)
		crtc_count++;
D
Dave Airlie 已提交
492

493 494
	drm_for_each_connector(connector, dev)
		connector_count++;
D
Dave Airlie 已提交
495

496 497
	drm_for_each_encoder(encoder, dev)
		encoder_count++;
D
Dave Airlie 已提交
498 499 500 501 502 503 504 505 506 507

	card_res->max_height = dev->mode_config.max_height;
	card_res->min_height = dev->mode_config.min_height;
	card_res->max_width = dev->mode_config.max_width;
	card_res->min_width = dev->mode_config.min_width;

	/* CRTCs */
	if (card_res->count_crtcs >= crtc_count) {
		copied = 0;
		crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
508 509 510 511
		drm_for_each_crtc(crtc, dev) {
			if (put_user(crtc->base.id, crtc_id + copied)) {
				ret = -EFAULT;
				goto out;
D
Dave Airlie 已提交
512
			}
513
			copied++;
D
Dave Airlie 已提交
514 515 516 517 518 519 520 521
		}
	}
	card_res->count_crtcs = crtc_count;

	/* Encoders */
	if (card_res->count_encoders >= encoder_count) {
		copied = 0;
		encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
522 523 524 525 526
		drm_for_each_encoder(encoder, dev) {
			if (put_user(encoder->base.id, encoder_id +
				     copied)) {
				ret = -EFAULT;
				goto out;
D
Dave Airlie 已提交
527
			}
528
			copied++;
D
Dave Airlie 已提交
529 530 531 532 533 534 535 536
		}
	}
	card_res->count_encoders = encoder_count;

	/* Connectors */
	if (card_res->count_connectors >= connector_count) {
		copied = 0;
		connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
537 538 539 540 541
		drm_for_each_connector(connector, dev) {
			if (put_user(connector->base.id,
				     connector_id + copied)) {
				ret = -EFAULT;
				goto out;
D
Dave Airlie 已提交
542
			}
543
			copied++;
D
Dave Airlie 已提交
544 545 546 547 548
		}
	}
	card_res->count_connectors = connector_count;

out:
549
	mutex_unlock(&dev->mode_config.mutex);
D
Dave Airlie 已提交
550 551 552 553 554
	return ret;
}

/**
 * drm_mode_getcrtc - get CRTC configuration
555 556 557
 * @dev: drm device for the ioctl
 * @data: data pointer for the ioctl
 * @file_priv: drm file for the ioctl call
D
Dave Airlie 已提交
558 559 560 561 562
 *
 * Construct a CRTC configuration structure to return to the user.
 *
 * Called by the user via ioctl.
 *
563
 * Returns:
D
Daniel Vetter 已提交
564
 * Zero on success, negative errno on failure.
D
Dave Airlie 已提交
565 566 567 568 569 570 571
 */
int drm_mode_getcrtc(struct drm_device *dev,
		     void *data, struct drm_file *file_priv)
{
	struct drm_mode_crtc *crtc_resp = data;
	struct drm_crtc *crtc;

572 573 574
	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;

R
Rob Clark 已提交
575
	crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
576 577
	if (!crtc)
		return -ENOENT;
D
Dave Airlie 已提交
578

579
	drm_modeset_lock_crtc(crtc, crtc->primary);
D
Dave Airlie 已提交
580
	crtc_resp->gamma_size = crtc->gamma_size;
581 582
	if (crtc->primary->fb)
		crtc_resp->fb_id = crtc->primary->fb->base.id;
D
Dave Airlie 已提交
583 584 585
	else
		crtc_resp->fb_id = 0;

586 587 588 589
	if (crtc->state) {
		crtc_resp->x = crtc->primary->state->src_x >> 16;
		crtc_resp->y = crtc->primary->state->src_y >> 16;
		if (crtc->state->enable) {
590
			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
591
			crtc_resp->mode_valid = 1;
D
Dave Airlie 已提交
592

593 594 595
		} else {
			crtc_resp->mode_valid = 0;
		}
D
Dave Airlie 已提交
596
	} else {
597 598 599
		crtc_resp->x = crtc->x;
		crtc_resp->y = crtc->y;
		if (crtc->enabled) {
600
			drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
601 602 603 604 605
			crtc_resp->mode_valid = 1;

		} else {
			crtc_resp->mode_valid = 0;
		}
D
Dave Airlie 已提交
606
	}
607
	drm_modeset_unlock_crtc(crtc);
D
Dave Airlie 已提交
608

609
	return 0;
D
Dave Airlie 已提交
610 611
}

612 613 614 615 616 617
/**
 * drm_mode_set_config_internal - helper to call ->set_config
 * @set: modeset config to set
 *
 * This is a little helper to wrap internal calls to the ->set_config driver
 * interface. The only thing it adds is correct refcounting dance.
618
 *
619
 * Returns:
D
Daniel Vetter 已提交
620
 * Zero on success, negative errno on failure.
621 622 623 624
 */
int drm_mode_set_config_internal(struct drm_mode_set *set)
{
	struct drm_crtc *crtc = set->crtc;
D
Daniel Vetter 已提交
625 626
	struct drm_framebuffer *fb;
	struct drm_crtc *tmp;
627 628
	int ret;

D
Daniel Vetter 已提交
629 630 631 632 633
	/*
	 * NOTE: ->set_config can also disable other crtcs (if we steal all
	 * connectors from it), hence we need to refcount the fbs across all
	 * crtcs. Atomic modeset will have saner semantics ...
	 */
634
	drm_for_each_crtc(tmp, crtc->dev)
635
		tmp->primary->old_fb = tmp->primary->fb;
D
Daniel Vetter 已提交
636

637
	fb = set->fb;
638

639 640
	ret = crtc->funcs->set_config(set);
	if (ret == 0) {
641
		crtc->primary->crtc = crtc;
642
		crtc->primary->fb = fb;
D
Daniel Vetter 已提交
643
	}
644

645
	drm_for_each_crtc(tmp, crtc->dev) {
646 647
		if (tmp->primary->fb)
			drm_framebuffer_reference(tmp->primary->fb);
648 649 650
		if (tmp->primary->old_fb)
			drm_framebuffer_unreference(tmp->primary->old_fb);
		tmp->primary->old_fb = NULL;
651 652 653
	}

	return ret;
654 655 656
}
EXPORT_SYMBOL(drm_mode_set_config_internal);

657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
/**
 * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode
 * @mode: mode to query
 * @hdisplay: hdisplay value to fill in
 * @vdisplay: vdisplay value to fill in
 *
 * The vdisplay value will be doubled if the specified mode is a stereo mode of
 * the appropriate layout.
 */
void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
			    int *hdisplay, int *vdisplay)
{
	struct drm_display_mode adjusted;

	drm_mode_copy(&adjusted, mode);
	drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
	*hdisplay = adjusted.crtc_hdisplay;
	*vdisplay = adjusted.crtc_vdisplay;
}
EXPORT_SYMBOL(drm_crtc_get_hv_timing);

678 679 680 681 682 683 684 685
/**
 * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
 *     CRTC viewport
 * @crtc: CRTC that framebuffer will be displayed on
 * @x: x panning
 * @y: y panning
 * @mode: mode that framebuffer will be displayed under
 * @fb: framebuffer to check size of
686
 */
687 688 689 690
int drm_crtc_check_viewport(const struct drm_crtc *crtc,
			    int x, int y,
			    const struct drm_display_mode *mode,
			    const struct drm_framebuffer *fb)
691 692 693 694

{
	int hdisplay, vdisplay;

695
	drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
696

697
	if (crtc->state &&
698 699
	    crtc->primary->state->rotation & (DRM_ROTATE_90 |
					      DRM_ROTATE_270))
700 701
		swap(hdisplay, vdisplay);

D
Daniel Vetter 已提交
702 703 704
	return drm_framebuffer_check_src_coords(x << 16, y << 16,
						hdisplay << 16, vdisplay << 16,
						fb);
705
}
706
EXPORT_SYMBOL(drm_crtc_check_viewport);
707

D
Dave Airlie 已提交
708 709
/**
 * drm_mode_setcrtc - set CRTC configuration
710 711 712
 * @dev: drm device for the ioctl
 * @data: data pointer for the ioctl
 * @file_priv: drm file for the ioctl call
D
Dave Airlie 已提交
713 714 715 716 717
 *
 * Build a new CRTC configuration based on user request.
 *
 * Called by the user via ioctl.
 *
718
 * Returns:
D
Daniel Vetter 已提交
719
 * Zero on success, negative errno on failure.
D
Dave Airlie 已提交
720 721 722 723 724 725
 */
int drm_mode_setcrtc(struct drm_device *dev, void *data,
		     struct drm_file *file_priv)
{
	struct drm_mode_config *config = &dev->mode_config;
	struct drm_mode_crtc *crtc_req = data;
726
	struct drm_crtc *crtc;
D
Dave Airlie 已提交
727 728 729 730 731
	struct drm_connector **connector_set = NULL, *connector;
	struct drm_framebuffer *fb = NULL;
	struct drm_display_mode *mode = NULL;
	struct drm_mode_set set;
	uint32_t __user *set_connectors_ptr;
732
	int ret;
D
Dave Airlie 已提交
733 734
	int i;

735 736 737
	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;

738 739 740 741 742
	/*
	 * Universal plane src offsets are only 16.16, prevent havoc for
	 * drivers using universal plane code internally.
	 */
	if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
743 744
		return -ERANGE;

745
	drm_modeset_lock_all(dev);
R
Rob Clark 已提交
746 747
	crtc = drm_crtc_find(dev, crtc_req->crtc_id);
	if (!crtc) {
748
		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
749
		ret = -ENOENT;
D
Dave Airlie 已提交
750 751
		goto out;
	}
752
	DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
D
Dave Airlie 已提交
753 754 755 756 757

	if (crtc_req->mode_valid) {
		/* If we have a mode we need a framebuffer. */
		/* If we pass -1, set the mode with the currently bound fb */
		if (crtc_req->fb_id == -1) {
758
			if (!crtc->primary->fb) {
759 760 761
				DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
				ret = -EINVAL;
				goto out;
D
Dave Airlie 已提交
762
			}
763
			fb = crtc->primary->fb;
764 765
			/* Make refcounting symmetric with the lookup path. */
			drm_framebuffer_reference(fb);
D
Dave Airlie 已提交
766
		} else {
767 768
			fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
			if (!fb) {
769 770
				DRM_DEBUG_KMS("Unknown FB ID%d\n",
						crtc_req->fb_id);
771
				ret = -ENOENT;
D
Dave Airlie 已提交
772 773 774 775 776
				goto out;
			}
		}

		mode = drm_mode_create(dev);
777 778 779 780 781
		if (!mode) {
			ret = -ENOMEM;
			goto out;
		}

782
		ret = drm_mode_convert_umode(mode, &crtc_req->mode);
783 784 785 786 787
		if (ret) {
			DRM_DEBUG_KMS("Invalid mode\n");
			goto out;
		}

788 789 790 791 792 793 794 795 796 797 798
		/*
		 * Check whether the primary plane supports the fb pixel format.
		 * Drivers not implementing the universal planes API use a
		 * default formats list provided by the DRM core which doesn't
		 * match real hardware capabilities. Skip the check in that
		 * case.
		 */
		if (!crtc->primary->format_default) {
			ret = drm_plane_check_pixel_format(crtc->primary,
							   fb->pixel_format);
			if (ret) {
799
				char *format_name = drm_get_format_name(fb->pixel_format);
800 801
				DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name);
				kfree(format_name);
802 803 804 805
				goto out;
			}
		}

806 807 808
		ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
					      mode, fb);
		if (ret)
809
			goto out;
810

D
Dave Airlie 已提交
811 812 813
	}

	if (crtc_req->count_connectors == 0 && mode) {
814
		DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
D
Dave Airlie 已提交
815 816 817 818
		ret = -EINVAL;
		goto out;
	}

819
	if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
820
		DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
D
Dave Airlie 已提交
821 822 823 824 825 826 827 828 829 830 831 832 833 834
			  crtc_req->count_connectors);
		ret = -EINVAL;
		goto out;
	}

	if (crtc_req->count_connectors > 0) {
		u32 out_id;

		/* Avoid unbounded kernel memory allocation */
		if (crtc_req->count_connectors > config->num_connector) {
			ret = -EINVAL;
			goto out;
		}

835 836 837
		connector_set = kmalloc_array(crtc_req->count_connectors,
					      sizeof(struct drm_connector *),
					      GFP_KERNEL);
D
Dave Airlie 已提交
838 839 840 841 842 843
		if (!connector_set) {
			ret = -ENOMEM;
			goto out;
		}

		for (i = 0; i < crtc_req->count_connectors; i++) {
844
			connector_set[i] = NULL;
V
Ville Syrjälä 已提交
845
			set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
D
Dave Airlie 已提交
846 847 848 849 850
			if (get_user(out_id, &set_connectors_ptr[i])) {
				ret = -EFAULT;
				goto out;
			}

851
			connector = drm_connector_lookup(dev, out_id);
R
Rob Clark 已提交
852
			if (!connector) {
853 854
				DRM_DEBUG_KMS("Connector id %d unknown\n",
						out_id);
855
				ret = -ENOENT;
D
Dave Airlie 已提交
856 857
				goto out;
			}
858 859
			DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
					connector->base.id,
860
					connector->name);
D
Dave Airlie 已提交
861 862 863 864 865 866 867 868 869 870 871

			connector_set[i] = connector;
		}
	}

	set.crtc = crtc;
	set.x = crtc_req->x;
	set.y = crtc_req->y;
	set.mode = mode;
	set.connectors = connector_set;
	set.num_connectors = crtc_req->count_connectors;
872
	set.fb = fb;
873
	ret = drm_mode_set_config_internal(&set);
D
Dave Airlie 已提交
874 875

out:
876 877 878
	if (fb)
		drm_framebuffer_unreference(fb);

879 880 881 882 883 884
	if (connector_set) {
		for (i = 0; i < crtc_req->count_connectors; i++) {
			if (connector_set[i])
				drm_connector_unreference(connector_set[i]);
		}
	}
D
Dave Airlie 已提交
885
	kfree(connector_set);
886
	drm_mode_destroy(dev, mode);
887
	drm_modeset_unlock_all(dev);
D
Dave Airlie 已提交
888 889 890
	return ret;
}

891 892 893
int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
			       struct drm_property *property,
			       uint64_t value)
894
{
P
Paulo Zanoni 已提交
895 896
	int ret = -EINVAL;
	struct drm_crtc *crtc = obj_to_crtc(obj);
897

P
Paulo Zanoni 已提交
898 899 900 901
	if (crtc->funcs->set_property)
		ret = crtc->funcs->set_property(crtc, property, value);
	if (!ret)
		drm_object_property_set_value(obj, property, value);
902

P
Paulo Zanoni 已提交
903
	return ret;
904 905
}

906 907 908 909 910 911 912 913
/**
 * drm_mode_config_reset - call ->reset callbacks
 * @dev: drm device
 *
 * This functions calls all the crtc's, encoder's and connector's ->reset
 * callback. Drivers can use this in e.g. their driver load or resume code to
 * reset hardware and software state.
 */
914 915 916
void drm_mode_config_reset(struct drm_device *dev)
{
	struct drm_crtc *crtc;
D
Daniel Vetter 已提交
917
	struct drm_plane *plane;
918 919 920
	struct drm_encoder *encoder;
	struct drm_connector *connector;

921
	drm_for_each_plane(plane, dev)
D
Daniel Vetter 已提交
922 923 924
		if (plane->funcs->reset)
			plane->funcs->reset(plane);

925
	drm_for_each_crtc(crtc, dev)
926 927 928
		if (crtc->funcs->reset)
			crtc->funcs->reset(crtc);

929
	drm_for_each_encoder(encoder, dev)
930 931 932
		if (encoder->funcs->reset)
			encoder->funcs->reset(encoder);

933
	mutex_lock(&dev->mode_config.mutex);
D
Dave Airlie 已提交
934
	drm_for_each_connector(connector, dev)
935 936
		if (connector->funcs->reset)
			connector->funcs->reset(connector);
937
	mutex_unlock(&dev->mode_config.mutex);
938 939
}
EXPORT_SYMBOL(drm_mode_config_reset);
940

941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
/**
 * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer
 * @dev: DRM device
 * @data: ioctl data
 * @file_priv: DRM file info
 *
 * This creates a new dumb buffer in the driver's backing storage manager (GEM,
 * TTM or something else entirely) and returns the resulting buffer handle. This
 * handle can then be wrapped up into a framebuffer modeset object.
 *
 * Note that userspace is not allowed to use such objects for render
 * acceleration - drivers must create their own private ioctls for such a use
 * case.
 *
 * Called by the user via ioctl.
 *
 * Returns:
D
Daniel Vetter 已提交
958
 * Zero on success, negative errno on failure.
959
 */
960 961 962 963
int drm_mode_create_dumb_ioctl(struct drm_device *dev,
			       void *data, struct drm_file *file_priv)
{
	struct drm_mode_create_dumb *args = data;
964
	u32 cpp, stride, size;
965 966 967

	if (!dev->driver->dumb_create)
		return -ENOSYS;
968 969 970 971
	if (!args->width || !args->height || !args->bpp)
		return -EINVAL;

	/* overflow checks for 32bit size calculations */
972
	/* NOTE: DIV_ROUND_UP() can overflow */
973
	cpp = DIV_ROUND_UP(args->bpp, 8);
974
	if (!cpp || cpp > 0xffffffffU / args->width)
975 976 977 978 979 980 981 982 983 984
		return -EINVAL;
	stride = cpp * args->width;
	if (args->height > 0xffffffffU / stride)
		return -EINVAL;

	/* test for wrap-around */
	size = args->height * stride;
	if (PAGE_ALIGN(size) == 0)
		return -EINVAL;

985 986 987 988 989 990 991 992 993 994
	/*
	 * handle, pitch and size are output parameters. Zero them out to
	 * prevent drivers from accidentally using uninitialized data. Since
	 * not all existing userspace is clearing these fields properly we
	 * cannot reject IOCTL with garbage in them.
	 */
	args->handle = 0;
	args->pitch = 0;
	args->size = 0;

995 996 997
	return dev->driver->dumb_create(file_priv, dev, args);
}

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
/**
 * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer
 * @dev: DRM device
 * @data: ioctl data
 * @file_priv: DRM file info
 *
 * Allocate an offset in the drm device node's address space to be able to
 * memory map a dumb buffer.
 *
 * Called by the user via ioctl.
 *
 * Returns:
D
Daniel Vetter 已提交
1010
 * Zero on success, negative errno on failure.
1011
 */
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
			     void *data, struct drm_file *file_priv)
{
	struct drm_mode_map_dumb *args = data;

	/* call driver ioctl to get mmap offset */
	if (!dev->driver->dumb_map_offset)
		return -ENOSYS;

	return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
}

1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
/**
 * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer
 * @dev: DRM device
 * @data: ioctl data
 * @file_priv: DRM file info
 *
 * This destroys the userspace handle for the given dumb backing storage buffer.
 * Since buffer objects must be reference counted in the kernel a buffer object
 * won't be immediately freed if a framebuffer modeset object still uses it.
 *
 * Called by the user via ioctl.
 *
 * Returns:
D
Daniel Vetter 已提交
1037
 * Zero on success, negative errno on failure.
1038
 */
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
				void *data, struct drm_file *file_priv)
{
	struct drm_mode_destroy_dumb *args = data;

	if (!dev->driver->dumb_destroy)
		return -ENOSYS;

	return dev->driver->dumb_destroy(file_priv, dev, args->handle);
}
1049

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
/**
 * drm_mode_config_init - initialize DRM mode_configuration structure
 * @dev: DRM device
 *
 * Initialize @dev's mode_config structure, used for tracking the graphics
 * configuration of @dev.
 *
 * Since this initializes the modeset locks, no locking is possible. Which is no
 * problem, since this should happen single threaded at init time. It is the
 * driver's problem to ensure this guarantee.
 *
 */
void drm_mode_config_init(struct drm_device *dev)
{
	mutex_init(&dev->mode_config.mutex);
1065
	drm_modeset_lock_init(&dev->mode_config.connection_mutex);
1066 1067
	mutex_init(&dev->mode_config.idr_mutex);
	mutex_init(&dev->mode_config.fb_lock);
D
Daniel Stone 已提交
1068
	mutex_init(&dev->mode_config.blob_lock);
1069 1070 1071 1072 1073 1074 1075 1076
	INIT_LIST_HEAD(&dev->mode_config.fb_list);
	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
	INIT_LIST_HEAD(&dev->mode_config.connector_list);
	INIT_LIST_HEAD(&dev->mode_config.encoder_list);
	INIT_LIST_HEAD(&dev->mode_config.property_list);
	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
	INIT_LIST_HEAD(&dev->mode_config.plane_list);
	idr_init(&dev->mode_config.crtc_idr);
D
Dave Airlie 已提交
1077
	idr_init(&dev->mode_config.tile_idr);
1078
	ida_init(&dev->mode_config.connector_ida);
1079 1080

	drm_modeset_lock_all(dev);
R
Rob Clark 已提交
1081
	drm_mode_create_standard_properties(dev);
1082 1083 1084 1085 1086 1087 1088
	drm_modeset_unlock_all(dev);

	/* Just to be sure */
	dev->mode_config.num_fb = 0;
	dev->mode_config.num_connector = 0;
	dev->mode_config.num_crtc = 0;
	dev->mode_config.num_encoder = 0;
1089 1090
	dev->mode_config.num_overlay_plane = 0;
	dev->mode_config.num_total_plane = 0;
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
}
EXPORT_SYMBOL(drm_mode_config_init);

/**
 * drm_mode_config_cleanup - free up DRM mode_config info
 * @dev: DRM device
 *
 * Free up all the connectors and CRTCs associated with this DRM device, then
 * free up the framebuffers and associated buffer objects.
 *
 * Note that since this /should/ happen single-threaded at driver/device
 * teardown time, no locking is required. It's the driver's job to ensure that
 * this guarantee actually holds true.
 *
 * FIXME: cleanup any dangling user buffer objects too
 */
void drm_mode_config_cleanup(struct drm_device *dev)
{
	struct drm_connector *connector, *ot;
	struct drm_crtc *crtc, *ct;
	struct drm_encoder *encoder, *enct;
	struct drm_framebuffer *fb, *fbt;
	struct drm_property *property, *pt;
	struct drm_property_blob *blob, *bt;
	struct drm_plane *plane, *plt;

	list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
				 head) {
		encoder->funcs->destroy(encoder);
	}

	list_for_each_entry_safe(connector, ot,
				 &dev->mode_config.connector_list, head) {
		connector->funcs->destroy(connector);
	}

	list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
				 head) {
		drm_property_destroy(dev, property);
	}

1132 1133 1134 1135 1136 1137 1138 1139 1140
	list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list,
				 head) {
		plane->funcs->destroy(plane);
	}

	list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
		crtc->funcs->destroy(crtc);
	}

1141
	list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list,
1142
				 head_global) {
1143
		drm_property_unreference_blob(blob);
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
	}

	/*
	 * Single-threaded teardown context, so it's not required to grab the
	 * fb_lock to protect against concurrent fb_list access. Contrary, it
	 * would actually deadlock with the drm_framebuffer_cleanup function.
	 *
	 * Also, if there are any framebuffers left, that's a driver leak now,
	 * so politely WARN about this.
	 */
	WARN_ON(!list_empty(&dev->mode_config.fb_list));
	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
1156
		drm_framebuffer_free(&fb->base.refcount);
1157 1158
	}

1159
	ida_destroy(&dev->mode_config.connector_ida);
D
Dave Airlie 已提交
1160
	idr_destroy(&dev->mode_config.tile_idr);
1161
	idr_destroy(&dev->mode_config.crtc_idr);
1162
	drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
1163 1164
}
EXPORT_SYMBOL(drm_mode_config_cleanup);
1165

D
Dave Airlie 已提交
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
/**
 * DOC: Tile group
 *
 * Tile groups are used to represent tiled monitors with a unique
 * integer identifier. Tiled monitors using DisplayID v1.3 have
 * a unique 8-byte handle, we store this in a tile group, so we
 * have a common identifier for all tiles in a monitor group.
 */
static void drm_tile_group_free(struct kref *kref)
{
	struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
	struct drm_device *dev = tg->dev;
	mutex_lock(&dev->mode_config.idr_mutex);
	idr_remove(&dev->mode_config.tile_idr, tg->id);
	mutex_unlock(&dev->mode_config.idr_mutex);
	kfree(tg);
}

/**
 * drm_mode_put_tile_group - drop a reference to a tile group.
 * @dev: DRM device
 * @tg: tile group to drop reference to.
 *
 * drop reference to tile group and free if 0.
 */
void drm_mode_put_tile_group(struct drm_device *dev,
			     struct drm_tile_group *tg)
{
	kref_put(&tg->refcount, drm_tile_group_free);
}

/**
 * drm_mode_get_tile_group - get a reference to an existing tile group
 * @dev: DRM device
 * @topology: 8-bytes unique per monitor.
 *
 * Use the unique bytes to get a reference to an existing tile group.
 *
 * RETURNS:
 * tile group or NULL if not found.
 */
struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
					       char topology[8])
{
	struct drm_tile_group *tg;
	int id;
	mutex_lock(&dev->mode_config.idr_mutex);
	idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
		if (!memcmp(tg->group_data, topology, 8)) {
			if (!kref_get_unless_zero(&tg->refcount))
				tg = NULL;
			mutex_unlock(&dev->mode_config.idr_mutex);
			return tg;
		}
	}
	mutex_unlock(&dev->mode_config.idr_mutex);
	return NULL;
}
R
Rob Clark 已提交
1224
EXPORT_SYMBOL(drm_mode_get_tile_group);
D
Dave Airlie 已提交
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262

/**
 * drm_mode_create_tile_group - create a tile group from a displayid description
 * @dev: DRM device
 * @topology: 8-bytes unique per monitor.
 *
 * Create a tile group for the unique monitor, and get a unique
 * identifier for the tile group.
 *
 * RETURNS:
 * new tile group or error.
 */
struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
						  char topology[8])
{
	struct drm_tile_group *tg;
	int ret;

	tg = kzalloc(sizeof(*tg), GFP_KERNEL);
	if (!tg)
		return ERR_PTR(-ENOMEM);

	kref_init(&tg->refcount);
	memcpy(tg->group_data, topology, 8);
	tg->dev = dev;

	mutex_lock(&dev->mode_config.idr_mutex);
	ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
	if (ret >= 0) {
		tg->id = ret;
	} else {
		kfree(tg);
		tg = ERR_PTR(ret);
	}

	mutex_unlock(&dev->mode_config.idr_mutex);
	return tg;
}
R
Rob Clark 已提交
1263
EXPORT_SYMBOL(drm_mode_create_tile_group);