drm_crtc_helper.c 28.1 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>
 *
 * 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/export.h>
33
#include <linux/moduleparam.h>
34

D
Dave Airlie 已提交
35 36
#include "drmP.h"
#include "drm_crtc.h"
37
#include "drm_fourcc.h"
D
Dave Airlie 已提交
38
#include "drm_crtc_helper.h"
39
#include "drm_fb_helper.h"
40
#include "drm_edid.h"
D
Dave Airlie 已提交
41

42 43 44
static bool drm_kms_helper_poll = true;
module_param_named(poll, drm_kms_helper_poll, bool, 0600);

45 46 47
static void drm_mode_validate_flag(struct drm_connector *connector,
				   int flags)
{
48
	struct drm_display_mode *mode;
49 50 51 52

	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
		return;

53
	list_for_each_entry(mode, &connector->modes, head) {
54 55 56 57 58 59 60 61 62 63 64
		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
				!(flags & DRM_MODE_FLAG_INTERLACE))
			mode->status = MODE_NO_INTERLACE;
		if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
				!(flags & DRM_MODE_FLAG_DBLSCAN))
			mode->status = MODE_NO_DBLESCAN;
	}

	return;
}

D
Dave Airlie 已提交
65
/**
66
 * drm_helper_probe_single_connector_modes - get complete set of display modes
D
Dave Airlie 已提交
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
 * @dev: DRM device
 * @maxX: max width for modes
 * @maxY: max height for modes
 *
 * LOCKING:
 * Caller must hold mode config lock.
 *
 * Based on @dev's mode_config layout, scan all the connectors and try to detect
 * modes on them.  Modes will first be added to the connector's probed_modes
 * list, then culled (based on validity and the @maxX, @maxY parameters) and
 * put into the normal modes list.
 *
 * Intended to be used either at bootup time or when major configuration
 * changes have occurred.
 *
 * FIXME: take into account monitor limits
J
Jesse Barnes 已提交
83 84 85
 *
 * RETURNS:
 * Number of modes found on @connector.
D
Dave Airlie 已提交
86
 */
J
Jesse Barnes 已提交
87 88
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
					    uint32_t maxX, uint32_t maxY)
D
Dave Airlie 已提交
89 90
{
	struct drm_device *dev = connector->dev;
91
	struct drm_display_mode *mode;
D
Dave Airlie 已提交
92 93
	struct drm_connector_helper_funcs *connector_funcs =
		connector->helper_private;
J
Jesse Barnes 已提交
94
	int count = 0;
95
	int mode_flags = 0;
D
Dave Airlie 已提交
96

97 98
	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
			drm_get_connector_name(connector));
D
Dave Airlie 已提交
99
	/* set all modes to the unverified state */
100
	list_for_each_entry(mode, &connector->modes, head)
D
Dave Airlie 已提交
101 102
		mode->status = MODE_UNVERIFIED;

103 104 105 106 107 108 109
	if (connector->force) {
		if (connector->force == DRM_FORCE_ON)
			connector->status = connector_status_connected;
		else
			connector->status = connector_status_disconnected;
		if (connector->funcs->force)
			connector->funcs->force(connector);
110
	} else {
111
		connector->status = connector->funcs->detect(connector, true);
112
		drm_kms_helper_poll_enable(dev);
113
	}
D
Dave Airlie 已提交
114 115

	if (connector->status == connector_status_disconnected) {
116 117
		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
			connector->base.id, drm_get_connector_name(connector));
118
		drm_mode_connector_update_edid_property(connector, NULL);
119
		goto prune;
D
Dave Airlie 已提交
120 121
	}

122 123 124 125 126 127
#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
	count = drm_load_edid_firmware(connector);
	if (count == 0)
#endif
		count = (*connector_funcs->get_modes)(connector);

128
	if (count == 0 && connector->status == connector_status_connected)
129
		count = drm_add_modes_noedid(connector, 1024, 768);
130 131
	if (count == 0)
		goto prune;
D
Dave Airlie 已提交
132

J
Jesse Barnes 已提交
133
	drm_mode_connector_list_update(connector);
D
Dave Airlie 已提交
134 135 136 137

	if (maxX && maxY)
		drm_mode_validate_size(dev, &connector->modes, maxX,
				       maxY, 0);
138 139 140 141 142 143 144

	if (connector->interlace_allowed)
		mode_flags |= DRM_MODE_FLAG_INTERLACE;
	if (connector->doublescan_allowed)
		mode_flags |= DRM_MODE_FLAG_DBLSCAN;
	drm_mode_validate_flag(connector, mode_flags);

145
	list_for_each_entry(mode, &connector->modes, head) {
D
Dave Airlie 已提交
146 147 148 149 150
		if (mode->status == MODE_OK)
			mode->status = connector_funcs->mode_valid(connector,
								   mode);
	}

151
prune:
D
Dave Airlie 已提交
152 153
	drm_mode_prune_invalid(dev, &connector->modes, true);

J
Jesse Barnes 已提交
154 155
	if (list_empty(&connector->modes))
		return 0;
D
Dave Airlie 已提交
156 157 158

	drm_mode_sort(&connector->modes);

159 160
	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
			drm_get_connector_name(connector));
161
	list_for_each_entry(mode, &connector->modes, head) {
D
Dave Airlie 已提交
162 163 164 165 166
		mode->vrefresh = drm_mode_vrefresh(mode);

		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
		drm_mode_debug_printmodeline(mode);
	}
J
Jesse Barnes 已提交
167 168

	return count;
D
Dave Airlie 已提交
169 170 171
}
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
/**
 * drm_helper_encoder_in_use - check if a given encoder is in use
 * @encoder: encoder to check
 *
 * LOCKING:
 * Caller must hold mode config lock.
 *
 * Walk @encoders's DRM device's mode_config and see if it's in use.
 *
 * RETURNS:
 * True if @encoder is part of the mode_config, false otherwise.
 */
bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
{
	struct drm_connector *connector;
	struct drm_device *dev = encoder->dev;
	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
		if (connector->encoder == encoder)
			return true;
	return false;
}
EXPORT_SYMBOL(drm_helper_encoder_in_use);

D
Dave Airlie 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
/**
 * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
 * @crtc: CRTC to check
 *
 * LOCKING:
 * Caller must hold mode config lock.
 *
 * Walk @crtc's DRM device's mode_config and see if it's in use.
 *
 * RETURNS:
 * True if @crtc is part of the mode_config, false otherwise.
 */
bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
{
	struct drm_encoder *encoder;
	struct drm_device *dev = crtc->dev;
	/* FIXME: Locking around list access? */
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
213
		if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))
D
Dave Airlie 已提交
214 215 216 217 218
			return true;
	return false;
}
EXPORT_SYMBOL(drm_helper_crtc_in_use);

219 220 221 222 223 224 225 226 227 228 229
static void
drm_encoder_disable(struct drm_encoder *encoder)
{
	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;

	if (encoder_funcs->disable)
		(*encoder_funcs->disable)(encoder);
	else
		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
}

D
Dave Airlie 已提交
230
/**
231
 * drm_helper_disable_unused_functions - disable unused objects
D
Dave Airlie 已提交
232 233 234 235 236 237 238 239 240 241 242
 * @dev: DRM device
 *
 * LOCKING:
 * Caller must hold mode config lock.
 *
 * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled
 * by calling its dpms function, which should power it off.
 */
void drm_helper_disable_unused_functions(struct drm_device *dev)
{
	struct drm_encoder *encoder;
243
	struct drm_connector *connector;
D
Dave Airlie 已提交
244 245
	struct drm_crtc *crtc;

246 247 248 249 250 251 252
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (!connector->encoder)
			continue;
		if (connector->status == connector_status_disconnected)
			connector->encoder = NULL;
	}

D
Dave Airlie 已提交
253
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
254
		if (!drm_helper_encoder_in_use(encoder)) {
255
			drm_encoder_disable(encoder);
256 257
			/* disconnector encoder from any connector */
			encoder->crtc = NULL;
258
		}
D
Dave Airlie 已提交
259 260 261 262 263 264
	}

	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
		crtc->enabled = drm_helper_crtc_in_use(crtc);
		if (!crtc->enabled) {
265 266 267 268
			if (crtc_funcs->disable)
				(*crtc_funcs->disable)(crtc);
			else
				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
D
Dave Airlie 已提交
269 270 271 272 273 274
			crtc->fb = NULL;
		}
	}
}
EXPORT_SYMBOL(drm_helper_disable_unused_functions);

275 276 277 278 279 280 281 282 283 284 285 286 287 288
/**
 * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
 * @encoder: encoder to test
 * @crtc: crtc to test
 *
 * Return false if @encoder can't be driven by @crtc, true otherwise.
 */
static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
				struct drm_crtc *crtc)
{
	struct drm_device *dev;
	struct drm_crtc *tmp;
	int crtc_mask = 1;

J
Joe Perches 已提交
289
	WARN(!crtc, "checking null crtc?\n");
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

	dev = crtc->dev;

	list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
		if (tmp == crtc)
			break;
		crtc_mask <<= 1;
	}

	if (encoder->possible_crtcs & crtc_mask)
		return true;
	return false;
}

/*
 * Check the CRTC we're going to map each output to vs. its current
 * CRTC.  If they don't match, we have to disable the output and the CRTC
 * since the driver will have to re-route things.
 */
static void
drm_crtc_prepare_encoders(struct drm_device *dev)
{
	struct drm_encoder_helper_funcs *encoder_funcs;
	struct drm_encoder *encoder;

	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		encoder_funcs = encoder->helper_private;
		/* Disable unused encoders */
		if (encoder->crtc == NULL)
319
			drm_encoder_disable(encoder);
320 321 322
		/* Disable encoders whose CRTC is about to change */
		if (encoder_funcs->get_crtc &&
		    encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
323
			drm_encoder_disable(encoder);
324 325 326
	}
}

D
Dave Airlie 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
/**
 * drm_crtc_set_mode - set a mode
 * @crtc: CRTC to program
 * @mode: mode to use
 * @x: width of mode
 * @y: height of mode
 *
 * LOCKING:
 * Caller must hold mode config lock.
 *
 * Try to set @mode on @crtc.  Give @crtc and its associated connectors a chance
 * to fixup or reject the mode prior to trying to set it.
 *
 * RETURNS:
 * True if the mode was set successfully, or false otherwise.
 */
bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
			      struct drm_display_mode *mode,
345 346
			      int x, int y,
			      struct drm_framebuffer *old_fb)
D
Dave Airlie 已提交
347 348
{
	struct drm_device *dev = crtc->dev;
349
	struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
D
Dave Airlie 已提交
350 351 352 353 354 355 356 357 358 359
	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
	struct drm_encoder_helper_funcs *encoder_funcs;
	int saved_x, saved_y;
	struct drm_encoder *encoder;
	bool ret = true;

	crtc->enabled = drm_helper_crtc_in_use(crtc);
	if (!crtc->enabled)
		return true;

360
	adjusted_mode = drm_mode_duplicate(dev, mode);
361 362
	if (!adjusted_mode)
		return false;
363

364
	saved_hwmode = crtc->hwmode;
D
Dave Airlie 已提交
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
	saved_mode = crtc->mode;
	saved_x = crtc->x;
	saved_y = crtc->y;

	/* Update crtc values up front so the driver can rely on them for mode
	 * setting.
	 */
	crtc->mode = *mode;
	crtc->x = x;
	crtc->y = y;

	/* Pass our mode to the connectors and the CRTC to give them a chance to
	 * adjust it according to limitations or connector properties, and also
	 * a chance to reject the mode entirely.
	 */
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {

		if (encoder->crtc != crtc)
			continue;
		encoder_funcs = encoder->helper_private;
		if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
						      adjusted_mode))) {
387
			DRM_DEBUG_KMS("Encoder fixup failed\n");
D
Dave Airlie 已提交
388 389 390 391 392
			goto done;
		}
	}

	if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
393
		DRM_DEBUG_KMS("CRTC fixup failed\n");
D
Dave Airlie 已提交
394 395
		goto done;
	}
396
	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
D
Dave Airlie 已提交
397 398 399 400 401 402 403 404 405 406 407

	/* Prepare the encoders and CRTCs before setting the mode. */
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {

		if (encoder->crtc != crtc)
			continue;
		encoder_funcs = encoder->helper_private;
		/* Disable the encoders as the first thing we do. */
		encoder_funcs->prepare(encoder);
	}

408 409
	drm_crtc_prepare_encoders(dev);

D
Dave Airlie 已提交
410 411 412 413 414
	crtc_funcs->prepare(crtc);

	/* Set up the DPLL and any encoders state that needs to adjust or depend
	 * on the DPLL.
	 */
415 416 417
	ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
	if (!ret)
	    goto done;
D
Dave Airlie 已提交
418 419 420 421 422 423

	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {

		if (encoder->crtc != crtc)
			continue;

424 425 426
		DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
			encoder->base.id, drm_get_encoder_name(encoder),
			mode->base.id, mode->name);
D
Dave Airlie 已提交
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
		encoder_funcs = encoder->helper_private;
		encoder_funcs->mode_set(encoder, mode, adjusted_mode);
	}

	/* Now enable the clocks, plane, pipe, and connectors that we set up. */
	crtc_funcs->commit(crtc);

	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {

		if (encoder->crtc != crtc)
			continue;

		encoder_funcs = encoder->helper_private;
		encoder_funcs->commit(encoder);

	}

444 445 446 447 448 449 450 451 452
	/* Store real post-adjustment hardware mode. */
	crtc->hwmode = *adjusted_mode;

	/* Calculate and store various constants which
	 * are later needed by vblank and swap-completion
	 * timestamping. They are derived from true hwmode.
	 */
	drm_calc_timestamping_constants(crtc);

D
Dave Airlie 已提交
453 454
	/* FIXME: add subpixel order */
done:
455
	drm_mode_destroy(dev, adjusted_mode);
D
Dave Airlie 已提交
456
	if (!ret) {
457
		crtc->hwmode = saved_hwmode;
D
Dave Airlie 已提交
458 459 460 461 462 463 464 465 466 467
		crtc->mode = saved_mode;
		crtc->x = saved_x;
		crtc->y = saved_y;
	}

	return ret;
}
EXPORT_SYMBOL(drm_crtc_helper_set_mode);


468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
static int
drm_crtc_helper_disable(struct drm_crtc *crtc)
{
	struct drm_device *dev = crtc->dev;
	struct drm_connector *connector;
	struct drm_encoder *encoder;

	/* Decouple all encoders and their attached connectors from this crtc */
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		if (encoder->crtc != crtc)
			continue;

		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
			if (connector->encoder != encoder)
				continue;

			connector->encoder = NULL;
		}
	}

	drm_helper_disable_unused_functions(dev);
	return 0;
}

D
Dave Airlie 已提交
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
/**
 * drm_crtc_helper_set_config - set a new config from userspace
 * @crtc: CRTC to setup
 * @crtc_info: user provided configuration
 * @new_mode: new mode to set
 * @connector_set: set of connectors for the new config
 * @fb: new framebuffer
 *
 * LOCKING:
 * Caller must hold mode config lock.
 *
 * Setup a new configuration, provided by the user in @crtc_info, and enable
 * it.
 *
 * RETURNS:
 * Zero. (FIXME)
 */
int drm_crtc_helper_set_config(struct drm_mode_set *set)
{
	struct drm_device *dev;
512 513
	struct drm_crtc *save_crtcs, *new_crtc, *crtc;
	struct drm_encoder *save_encoders, *new_encoder, *encoder;
514
	struct drm_framebuffer *old_fb = NULL;
515 516
	bool mode_changed = false; /* if true do a full mode set */
	bool fb_changed = false; /* if true and !mode_changed just do a flip */
517
	struct drm_connector *save_connectors, *connector;
D
Dave Airlie 已提交
518 519
	int count = 0, ro, fail = 0;
	struct drm_crtc_helper_funcs *crtc_funcs;
520
	struct drm_mode_set save_set;
521
	int ret;
522
	int i;
D
Dave Airlie 已提交
523

524
	DRM_DEBUG_KMS("\n");
D
Dave Airlie 已提交
525 526 527 528 529 530 531 532 533 534 535 536

	if (!set)
		return -EINVAL;

	if (!set->crtc)
		return -EINVAL;

	if (!set->crtc->helper_private)
		return -EINVAL;

	crtc_funcs = set->crtc->helper_private;

537 538 539
	if (!set->mode)
		set->fb = NULL;

540 541 542 543 544
	if (set->fb) {
		DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
				set->crtc->base.id, set->fb->base.id,
				(int)set->num_connectors, set->x, set->y);
	} else {
545
		DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
546
		return drm_crtc_helper_disable(set->crtc);
547
	}
D
Dave Airlie 已提交
548 549 550

	dev = set->crtc->dev;

551 552 553 554
	/* Allocate space for the backup of all (non-pointer) crtc, encoder and
	 * connector data. */
	save_crtcs = kzalloc(dev->mode_config.num_crtc *
			     sizeof(struct drm_crtc), GFP_KERNEL);
D
Dave Airlie 已提交
555 556 557
	if (!save_crtcs)
		return -ENOMEM;

558 559
	save_encoders = kzalloc(dev->mode_config.num_encoder *
				sizeof(struct drm_encoder), GFP_KERNEL);
D
Dave Airlie 已提交
560 561 562 563 564
	if (!save_encoders) {
		kfree(save_crtcs);
		return -ENOMEM;
	}

565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
	save_connectors = kzalloc(dev->mode_config.num_connector *
				sizeof(struct drm_connector), GFP_KERNEL);
	if (!save_connectors) {
		kfree(save_crtcs);
		kfree(save_encoders);
		return -ENOMEM;
	}

	/* Copy data. Note that driver private data is not affected.
	 * Should anything bad happen only the expected state is
	 * restored, not the drivers personal bookkeeping.
	 */
	count = 0;
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		save_crtcs[count++] = *crtc;
	}

	count = 0;
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		save_encoders[count++] = *encoder;
	}

	count = 0;
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		save_connectors[count++] = *connector;
	}

592 593 594 595 596 597
	save_set.crtc = set->crtc;
	save_set.mode = &set->crtc->mode;
	save_set.x = set->crtc->x;
	save_set.y = set->crtc->y;
	save_set.fb = set->crtc->fb;

D
Dave Airlie 已提交
598 599 600
	/* We should be able to check here if the fb has the same properties
	 * and then just flip_or_move it */
	if (set->crtc->fb != set->fb) {
601
		/* If we have no fb then treat it as a full mode set */
602
		if (set->crtc->fb == NULL) {
603
			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
604
			mode_changed = true;
605 606
		} else if (set->fb == NULL) {
			mode_changed = true;
607 608 609 610 611
		} else if (set->fb->depth != set->crtc->fb->depth) {
			mode_changed = true;
		} else if (set->fb->bits_per_pixel !=
			   set->crtc->fb->bits_per_pixel) {
			mode_changed = true;
612
		} else
613
			fb_changed = true;
D
Dave Airlie 已提交
614 615 616
	}

	if (set->x != set->crtc->x || set->y != set->crtc->y)
617
		fb_changed = true;
D
Dave Airlie 已提交
618 619

	if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
620
		DRM_DEBUG_KMS("modes are different, full mode set\n");
D
Dave Airlie 已提交
621 622
		drm_mode_debug_printmodeline(&set->crtc->mode);
		drm_mode_debug_printmodeline(set->mode);
623
		mode_changed = true;
D
Dave Airlie 已提交
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
	}

	/* a) traverse passed in connector list and get encoders for them */
	count = 0;
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		struct drm_connector_helper_funcs *connector_funcs =
			connector->helper_private;
		new_encoder = connector->encoder;
		for (ro = 0; ro < set->num_connectors; ro++) {
			if (set->connectors[ro] == connector) {
				new_encoder = connector_funcs->best_encoder(connector);
				/* if we can't get an encoder for a connector
				   we are setting now - then fail */
				if (new_encoder == NULL)
					/* don't break so fail path works correct */
					fail = 1;
				break;
			}
		}

		if (new_encoder != connector->encoder) {
645
			DRM_DEBUG_KMS("encoder changed, full mode switch\n");
646
			mode_changed = true;
647 648 649
			/* If the encoder is reused for another connector, then
			 * the appropriate crtc will be set later.
			 */
650 651
			if (connector->encoder)
				connector->encoder->crtc = NULL;
D
Dave Airlie 已提交
652 653 654 655 656 657
			connector->encoder = new_encoder;
		}
	}

	if (fail) {
		ret = -EINVAL;
658
		goto fail;
D
Dave Airlie 已提交
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
	}

	count = 0;
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (!connector->encoder)
			continue;

		if (connector->encoder->crtc == set->crtc)
			new_crtc = NULL;
		else
			new_crtc = connector->encoder->crtc;

		for (ro = 0; ro < set->num_connectors; ro++) {
			if (set->connectors[ro] == connector)
				new_crtc = set->crtc;
		}
675 676 677 678 679

		/* Make sure the new CRTC will work with the encoder */
		if (new_crtc &&
		    !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
			ret = -EINVAL;
680
			goto fail;
681
		}
D
Dave Airlie 已提交
682
		if (new_crtc != connector->encoder->crtc) {
683
			DRM_DEBUG_KMS("crtc changed, full mode switch\n");
684
			mode_changed = true;
D
Dave Airlie 已提交
685 686
			connector->encoder->crtc = new_crtc;
		}
687 688 689 690 691 692 693 694
		if (new_crtc) {
			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
				connector->base.id, drm_get_connector_name(connector),
				new_crtc->base.id);
		} else {
			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
				connector->base.id, drm_get_connector_name(connector));
		}
D
Dave Airlie 已提交
695 696 697
	}

	/* mode_set_base is not a required function */
698 699
	if (fb_changed && !crtc_funcs->mode_set_base)
		mode_changed = true;
D
Dave Airlie 已提交
700

701
	if (mode_changed) {
702 703
		set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
		if (set->crtc->enabled) {
704 705
			DRM_DEBUG_KMS("attempting to set mode from"
					" userspace\n");
D
Dave Airlie 已提交
706
			drm_mode_debug_printmodeline(set->mode);
707 708
			old_fb = set->crtc->fb;
			set->crtc->fb = set->fb;
D
Dave Airlie 已提交
709
			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
710 711
						      set->x, set->y,
						      old_fb)) {
712 713
				DRM_ERROR("failed to set mode on [CRTC:%d]\n",
					  set->crtc->base.id);
714
				set->crtc->fb = old_fb;
D
Dave Airlie 已提交
715
				ret = -EINVAL;
716
				goto fail;
D
Dave Airlie 已提交
717
			}
718 719 720 721
			DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
			for (i = 0; i < set->num_connectors; i++) {
				DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
					      drm_get_connector_name(set->connectors[i]));
722
				set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
723
			}
D
Dave Airlie 已提交
724 725
		}
		drm_helper_disable_unused_functions(dev);
726
	} else if (fb_changed) {
727 728 729
		set->crtc->x = set->x;
		set->crtc->y = set->y;

730
		old_fb = set->crtc->fb;
D
Dave Airlie 已提交
731 732
		if (set->crtc->fb != set->fb)
			set->crtc->fb = set->fb;
733 734
		ret = crtc_funcs->mode_set_base(set->crtc,
						set->x, set->y, old_fb);
735 736
		if (ret != 0) {
			set->crtc->fb = old_fb;
737
			goto fail;
738
		}
D
Dave Airlie 已提交
739 740
	}

741
	kfree(save_connectors);
D
Dave Airlie 已提交
742 743 744 745
	kfree(save_encoders);
	kfree(save_crtcs);
	return 0;

746 747
fail:
	/* Restore all previous data. */
D
Dave Airlie 已提交
748
	count = 0;
749 750 751
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		*crtc = save_crtcs[count++];
	}
752

753 754 755
	count = 0;
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		*encoder = save_encoders[count++];
756
	}
757

D
Dave Airlie 已提交
758 759
	count = 0;
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
760
		*connector = save_connectors[count++];
D
Dave Airlie 已提交
761
	}
762

763 764 765 766 767 768
	/* Try to restore the config */
	if (mode_changed &&
	    !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
				      save_set.y, save_set.fb))
		DRM_ERROR("failed to restore config after modeset failure\n");

769
	kfree(save_connectors);
D
Dave Airlie 已提交
770
	kfree(save_encoders);
771
	kfree(save_crtcs);
D
Dave Airlie 已提交
772 773 774 775
	return ret;
}
EXPORT_SYMBOL(drm_crtc_helper_set_config);

776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
{
	int dpms = DRM_MODE_DPMS_OFF;
	struct drm_connector *connector;
	struct drm_device *dev = encoder->dev;

	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
		if (connector->encoder == encoder)
			if (connector->dpms < dpms)
				dpms = connector->dpms;
	return dpms;
}

static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
{
	int dpms = DRM_MODE_DPMS_OFF;
	struct drm_connector *connector;
	struct drm_device *dev = crtc->dev;

	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
		if (connector->encoder && connector->encoder->crtc == crtc)
			if (connector->dpms < dpms)
				dpms = connector->dpms;
	return dpms;
}

/**
 * drm_helper_connector_dpms
 * @connector affected connector
 * @mode DPMS mode
 *
 * Calls the low-level connector DPMS function, then
 * calls appropriate encoder and crtc DPMS functions as well
 */
void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
{
	struct drm_encoder *encoder = connector->encoder;
	struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
	int old_dpms;

	if (mode == connector->dpms)
		return;

	old_dpms = connector->dpms;
	connector->dpms = mode;

	/* from off to on, do crtc then encoder */
	if (mode < old_dpms) {
		if (crtc) {
			struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
			if (crtc_funcs->dpms)
				(*crtc_funcs->dpms) (crtc,
						     drm_helper_choose_crtc_dpms(crtc));
		}
		if (encoder) {
			struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
			if (encoder_funcs->dpms)
				(*encoder_funcs->dpms) (encoder,
							drm_helper_choose_encoder_dpms(encoder));
		}
	}

	/* from on to off, do encoder then crtc */
	if (mode > old_dpms) {
		if (encoder) {
			struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
			if (encoder_funcs->dpms)
				(*encoder_funcs->dpms) (encoder,
							drm_helper_choose_encoder_dpms(encoder));
		}
		if (crtc) {
			struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
			if (crtc_funcs->dpms)
				(*crtc_funcs->dpms) (crtc,
						     drm_helper_choose_crtc_dpms(crtc));
		}
	}

	return;
}
EXPORT_SYMBOL(drm_helper_connector_dpms);

D
Dave Airlie 已提交
858
int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
859
				   struct drm_mode_fb_cmd2 *mode_cmd)
D
Dave Airlie 已提交
860
{
861 862
	int i;

D
Dave Airlie 已提交
863 864
	fb->width = mode_cmd->width;
	fb->height = mode_cmd->height;
865 866 867 868
	for (i = 0; i < 4; i++) {
		fb->pitches[i] = mode_cmd->pitches[i];
		fb->offsets[i] = mode_cmd->offsets[i];
	}
869
	drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
870 871
				    &fb->bits_per_pixel);
	fb->pixel_format = mode_cmd->pixel_format;
D
Dave Airlie 已提交
872 873 874 875 876 877 878 879

	return 0;
}
EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);

int drm_helper_resume_force_mode(struct drm_device *dev)
{
	struct drm_crtc *crtc;
880 881 882
	struct drm_encoder *encoder;
	struct drm_encoder_helper_funcs *encoder_funcs;
	struct drm_crtc_helper_funcs *crtc_funcs;
D
Dave Airlie 已提交
883 884 885 886 887 888 889
	int ret;

	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {

		if (!crtc->enabled)
			continue;

890 891
		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
					       crtc->x, crtc->y, crtc->fb);
D
Dave Airlie 已提交
892 893 894

		if (ret == false)
			DRM_ERROR("failed to set mode on crtc %p\n", crtc);
895 896 897 898 899 900 901 902 903 904 905 906 907

		/* Turn off outputs that were already powered off */
		if (drm_helper_choose_crtc_dpms(crtc)) {
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {

				if(encoder->crtc != crtc)
					continue;

				encoder_funcs = encoder->helper_private;
				if (encoder_funcs->dpms)
					(*encoder_funcs->dpms) (encoder,
								drm_helper_choose_encoder_dpms(encoder));
			}
908 909 910 911 912

			crtc_funcs = crtc->helper_private;
			if (crtc_funcs->dpms)
				(*crtc_funcs->dpms) (crtc,
						     drm_helper_choose_crtc_dpms(crtc));
913
		}
D
Dave Airlie 已提交
914
	}
915 916
	/* disable the unused connectors while restoring the modesetting */
	drm_helper_disable_unused_functions(dev);
D
Dave Airlie 已提交
917 918 919
	return 0;
}
EXPORT_SYMBOL(drm_helper_resume_force_mode);
920 921

#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
922
static void output_poll_execute(struct work_struct *work)
923
{
924 925
	struct delayed_work *delayed_work = to_delayed_work(work);
	struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
926
	struct drm_connector *connector;
927
	enum drm_connector_status old_status;
928 929
	bool repoll = false, changed = false;

930 931 932
	if (!drm_kms_helper_poll)
		return;

933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
	mutex_lock(&dev->mode_config.mutex);
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {

		/* if this is HPD or polled don't check it -
		   TV out for instance */
		if (!connector->polled)
			continue;

		else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
			repoll = true;

		old_status = connector->status;
		/* if we are connected and don't want to poll for disconnect
		   skip it */
		if (old_status == connector_status_connected &&
		    !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
		    !(connector->polled & DRM_CONNECTOR_POLL_HPD))
			continue;

952
		connector->status = connector->funcs->detect(connector, false);
953 954 955 956
		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
			      connector->base.id,
			      drm_get_connector_name(connector),
			      old_status, connector->status);
957
		if (old_status != connector->status)
958 959 960 961 962 963 964 965 966 967 968 969
			changed = true;
	}

	mutex_unlock(&dev->mode_config.mutex);

	if (changed) {
		/* send a uevent + call fbdev */
		drm_sysfs_hotplug_event(dev);
		if (dev->mode_config.funcs->output_poll_changed)
			dev->mode_config.funcs->output_poll_changed(dev);
	}

970 971
	if (repoll)
		queue_delayed_work(system_nrt_wq, delayed_work, DRM_OUTPUT_POLL_PERIOD);
972 973
}

974 975 976 977
void drm_kms_helper_poll_disable(struct drm_device *dev)
{
	if (!dev->mode_config.poll_enabled)
		return;
978
	cancel_delayed_work_sync(&dev->mode_config.output_poll_work);
979 980 981 982
}
EXPORT_SYMBOL(drm_kms_helper_poll_disable);

void drm_kms_helper_poll_enable(struct drm_device *dev)
983 984
{
	bool poll = false;
985
	struct drm_connector *connector;
986

987 988 989
	if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
		return;

990 991 992 993 994
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (connector->polled)
			poll = true;
	}

995 996
	if (poll)
		queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);
997
}
998 999 1000 1001
EXPORT_SYMBOL(drm_kms_helper_poll_enable);

void drm_kms_helper_poll_init(struct drm_device *dev)
{
1002
	INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);
1003 1004 1005 1006
	dev->mode_config.poll_enabled = true;

	drm_kms_helper_poll_enable(dev);
}
1007 1008 1009 1010
EXPORT_SYMBOL(drm_kms_helper_poll_init);

void drm_kms_helper_poll_fini(struct drm_device *dev)
{
1011
	drm_kms_helper_poll_disable(dev);
1012 1013 1014 1015 1016 1017 1018
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);

void drm_helper_hpd_irq_event(struct drm_device *dev)
{
	if (!dev->mode_config.poll_enabled)
		return;
1019

1020 1021
	/* kill timer and schedule immediate execution, this doesn't block */
	cancel_delayed_work(&dev->mode_config.output_poll_work);
1022 1023
	if (drm_kms_helper_poll)
		queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0);
1024 1025
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);