xref: /dragonfly/sys/dev/drm/drm_crtc_helper.c (revision 158486a6)
1 /*
2  * Copyright (c) 2006-2008 Intel Corporation
3  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
4  *
5  * DRM core CRTC related functions
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that copyright
10  * notice and this permission notice appear in supporting documentation, and
11  * that the name of the copyright holders not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  The copyright holders make no representations
14  * about the suitability of this software for any purpose.  It is provided "as
15  * is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23  * OF THIS SOFTWARE.
24  *
25  * Authors:
26  *      Keith Packard
27  *	Eric Anholt <eric@anholt.net>
28  *      Dave Airlie <airlied@linux.ie>
29  *      Jesse Barnes <jesse.barnes@intel.com>
30  *
31  * $FreeBSD: src/sys/dev/drm2/drm_crtc_helper.c,v 1.1 2012/05/22 11:07:44 kib Exp $
32  */
33 
34 #include <linux/export.h>
35 
36 #include <drm/drmP.h>
37 #include <drm/drm_crtc.h>
38 #include <uapi_drm/drm_fourcc.h>
39 #include <drm/drm_crtc_helper.h>
40 #include <drm/drm_fb_helper.h>
41 #include <drm/drm_edid.h>
42 
43 bool
44 drm_fetch_cmdline_mode_from_kenv(struct drm_connector *connector,
45     struct drm_cmdline_mode *cmdline_mode)
46 {
47 	char *tun_var_name, *tun_mode;
48 	static const char tun_prefix[] = "drm_mode.";
49 	bool res;
50 
51 	res = false;
52 	tun_var_name = kmalloc(sizeof(tun_prefix) +
53 	    strlen(drm_get_connector_name(connector)), M_TEMP, M_WAITOK);
54 	strcpy(tun_var_name, tun_prefix);
55 	strcat(tun_var_name, drm_get_connector_name(connector));
56 	tun_mode = kgetenv(tun_var_name);
57 	if (tun_mode != NULL) {
58 		res = drm_mode_parse_command_line_for_connector(tun_mode,
59 		    connector, cmdline_mode);
60 		kfreeenv(tun_mode);
61 	}
62 	drm_free(tun_var_name, M_TEMP);
63 	return (res);
64 }
65 
66 /**
67  * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
68  * 						connector list
69  * @dev: drm device to operate on
70  *
71  * Some userspace presumes that the first connected connector is the main
72  * display, where it's supposed to display e.g. the login screen. For
73  * laptops, this should be the main panel. Use this function to sort all
74  * (eDP/LVDS) panels to the front of the connector list, instead of
75  * painstakingly trying to initialize them in the right order.
76  */
77 void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
78 {
79 	struct drm_connector *connector, *tmp;
80 	struct list_head panel_list;
81 
82 	INIT_LIST_HEAD(&panel_list);
83 
84 	list_for_each_entry_safe(connector, tmp,
85 				 &dev->mode_config.connector_list, head) {
86 		if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
87 		    connector->connector_type == DRM_MODE_CONNECTOR_eDP)
88 			list_move_tail(&connector->head, &panel_list);
89 	}
90 
91 	list_splice(&panel_list, &dev->mode_config.connector_list);
92 }
93 EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
94 
95 static bool drm_kms_helper_poll = true;
96 
97 static void drm_mode_validate_flag(struct drm_connector *connector,
98 				   int flags)
99 {
100 	struct drm_display_mode *mode;
101 
102 	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
103 		return;
104 
105 	list_for_each_entry(mode, &connector->modes, head) {
106 		if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
107 				!(flags & DRM_MODE_FLAG_INTERLACE))
108 			mode->status = MODE_NO_INTERLACE;
109 		if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
110 				!(flags & DRM_MODE_FLAG_DBLSCAN))
111 			mode->status = MODE_NO_DBLESCAN;
112 	}
113 
114 	return;
115 }
116 
117 /**
118  * drm_helper_probe_single_connector_modes - get complete set of display modes
119  * @connector: connector to probe
120  * @maxX: max width for modes
121  * @maxY: max height for modes
122  *
123  * LOCKING:
124  * Caller must hold mode config lock.
125  *
126  * Based on the helper callbacks implemented by @connector try to detect all
127  * valid modes.  Modes will first be added to the connector's probed_modes list,
128  * then culled (based on validity and the @maxX, @maxY parameters) and put into
129  * the normal modes list.
130  *
131  * Intended to be use as a generic implementation of the ->probe() @connector
132  * callback for drivers that use the crtc helpers for output mode filtering and
133  * detection.
134  *
135  * RETURNS:
136  * Number of modes found on @connector.
137  */
138 int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
139 					    uint32_t maxX, uint32_t maxY)
140 {
141 	struct drm_device *dev = connector->dev;
142 	struct drm_display_mode *mode;
143 	struct drm_connector_helper_funcs *connector_funcs =
144 		connector->helper_private;
145 	int count = 0;
146 	int mode_flags = 0;
147 
148 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
149 			drm_get_connector_name(connector));
150 	/* set all modes to the unverified state */
151 	list_for_each_entry(mode, &connector->modes, head)
152 		mode->status = MODE_UNVERIFIED;
153 
154 	if (connector->force) {
155 		if (connector->force == DRM_FORCE_ON)
156 			connector->status = connector_status_connected;
157 		else
158 			connector->status = connector_status_disconnected;
159 		if (connector->funcs->force)
160 			connector->funcs->force(connector);
161 	} else {
162 		connector->status = connector->funcs->detect(connector, true);
163 	}
164 
165 	/* Re-enable polling in case the global poll config changed. */
166 	if (drm_kms_helper_poll != dev->mode_config.poll_running)
167 		drm_kms_helper_poll_enable(dev);
168 
169 	dev->mode_config.poll_running = drm_kms_helper_poll;
170 
171 	if (connector->status == connector_status_disconnected) {
172 		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
173 			connector->base.id, drm_get_connector_name(connector));
174 		drm_mode_connector_update_edid_property(connector, NULL);
175 		goto prune;
176 	}
177 
178 #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
179 	count = drm_load_edid_firmware(connector);
180 	if (count == 0)
181 #endif
182 		count = (*connector_funcs->get_modes)(connector);
183 
184 	if (count == 0 && connector->status == connector_status_connected)
185 		count = drm_add_modes_noedid(connector, 1024, 768);
186 	if (count == 0)
187 		goto prune;
188 
189 	drm_mode_connector_list_update(connector);
190 
191 	if (maxX && maxY)
192 		drm_mode_validate_size(dev, &connector->modes, maxX,
193 				       maxY, 0);
194 
195 	if (connector->interlace_allowed)
196 		mode_flags |= DRM_MODE_FLAG_INTERLACE;
197 	if (connector->doublescan_allowed)
198 		mode_flags |= DRM_MODE_FLAG_DBLSCAN;
199 	drm_mode_validate_flag(connector, mode_flags);
200 
201 	list_for_each_entry(mode, &connector->modes, head) {
202 		if (mode->status == MODE_OK)
203 			mode->status = connector_funcs->mode_valid(connector,
204 								   mode);
205 	}
206 
207 prune:
208 	drm_mode_prune_invalid(dev, &connector->modes, true);
209 
210 	if (list_empty(&connector->modes))
211 		return 0;
212 
213 	drm_mode_sort(&connector->modes);
214 
215 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
216 			drm_get_connector_name(connector));
217 	list_for_each_entry(mode, &connector->modes, head) {
218 		mode->vrefresh = drm_mode_vrefresh(mode);
219 
220 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
221 		drm_mode_debug_printmodeline(mode);
222 	}
223 
224 	return count;
225 }
226 EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
227 
228 /**
229  * drm_helper_encoder_in_use - check if a given encoder is in use
230  * @encoder: encoder to check
231  *
232  * LOCKING:
233  * Caller must hold mode config lock.
234  *
235  * Walk @encoders's DRM device's mode_config and see if it's in use.
236  *
237  * RETURNS:
238  * True if @encoder is part of the mode_config, false otherwise.
239  */
240 bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
241 {
242 	struct drm_connector *connector;
243 	struct drm_device *dev = encoder->dev;
244 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
245 		if (connector->encoder == encoder)
246 			return true;
247 	return false;
248 }
249 EXPORT_SYMBOL(drm_helper_encoder_in_use);
250 
251 /**
252  * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
253  * @crtc: CRTC to check
254  *
255  * LOCKING:
256  * Caller must hold mode config lock.
257  *
258  * Walk @crtc's DRM device's mode_config and see if it's in use.
259  *
260  * RETURNS:
261  * True if @crtc is part of the mode_config, false otherwise.
262  */
263 bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
264 {
265 	struct drm_encoder *encoder;
266 	struct drm_device *dev = crtc->dev;
267 	/* FIXME: Locking around list access? */
268 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
269 		if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))
270 			return true;
271 	return false;
272 }
273 EXPORT_SYMBOL(drm_helper_crtc_in_use);
274 
275 static void
276 drm_encoder_disable(struct drm_encoder *encoder)
277 {
278 	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
279 
280 	if (encoder_funcs->disable)
281 		(*encoder_funcs->disable)(encoder);
282 	else
283 		(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
284 }
285 
286 /**
287  * drm_helper_disable_unused_functions - disable unused objects
288  * @dev: DRM device
289  *
290  * LOCKING:
291  * Caller must hold mode config lock.
292  *
293  * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled
294  * by calling its dpms function, which should power it off.
295  */
296 void drm_helper_disable_unused_functions(struct drm_device *dev)
297 {
298 	struct drm_encoder *encoder;
299 	struct drm_connector *connector;
300 	struct drm_crtc *crtc;
301 
302 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
303 		if (!connector->encoder)
304 			continue;
305 		if (connector->status == connector_status_disconnected)
306 			connector->encoder = NULL;
307 	}
308 
309 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
310 		if (!drm_helper_encoder_in_use(encoder)) {
311 			drm_encoder_disable(encoder);
312 			/* disconnector encoder from any connector */
313 			encoder->crtc = NULL;
314 		}
315 	}
316 
317 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
318 		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
319 		crtc->enabled = drm_helper_crtc_in_use(crtc);
320 		if (!crtc->enabled) {
321 			if (crtc_funcs->disable)
322 				(*crtc_funcs->disable)(crtc);
323 			else
324 				(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
325 			crtc->fb = NULL;
326 		}
327 	}
328 }
329 EXPORT_SYMBOL(drm_helper_disable_unused_functions);
330 
331 /**
332  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
333  * @encoder: encoder to test
334  * @crtc: crtc to test
335  *
336  * Return false if @encoder can't be driven by @crtc, true otherwise.
337  */
338 static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
339 				struct drm_crtc *crtc)
340 {
341 	struct drm_device *dev;
342 	struct drm_crtc *tmp;
343 	int crtc_mask = 1;
344 
345 	WARN(!crtc, "checking null crtc?\n");
346 
347 	dev = crtc->dev;
348 
349 	list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
350 		if (tmp == crtc)
351 			break;
352 		crtc_mask <<= 1;
353 	}
354 
355 	if (encoder->possible_crtcs & crtc_mask)
356 		return true;
357 	return false;
358 }
359 
360 /*
361  * Check the CRTC we're going to map each output to vs. its current
362  * CRTC.  If they don't match, we have to disable the output and the CRTC
363  * since the driver will have to re-route things.
364  */
365 static void
366 drm_crtc_prepare_encoders(struct drm_device *dev)
367 {
368 	struct drm_encoder_helper_funcs *encoder_funcs;
369 	struct drm_encoder *encoder;
370 
371 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
372 		encoder_funcs = encoder->helper_private;
373 		/* Disable unused encoders */
374 		if (encoder->crtc == NULL)
375 			drm_encoder_disable(encoder);
376 		/* Disable encoders whose CRTC is about to change */
377 		if (encoder_funcs->get_crtc &&
378 		    encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
379 			drm_encoder_disable(encoder);
380 	}
381 }
382 
383 /**
384  * drm_crtc_helper_set_mode - internal helper to set a mode
385  * @crtc: CRTC to program
386  * @mode: mode to use
387  * @x: horizontal offset into the surface
388  * @y: vertical offset into the surface
389  * @old_fb: old framebuffer, for cleanup
390  *
391  * LOCKING:
392  * Caller must hold mode config lock.
393  *
394  * Try to set @mode on @crtc.  Give @crtc and its associated connectors a chance
395  * to fixup or reject the mode prior to trying to set it. This is an internal
396  * helper that drivers could e.g. use to update properties that require the
397  * entire output pipe to be disabled and re-enabled in a new configuration. For
398  * example for changing whether audio is enabled on a hdmi link or for changing
399  * panel fitter or dither attributes. It is also called by the
400  * drm_crtc_helper_set_config() helper function to drive the mode setting
401  * sequence.
402  *
403  * RETURNS:
404  * True if the mode was set successfully, or false otherwise.
405  */
406 bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
407 			      struct drm_display_mode *mode,
408 			      int x, int y,
409 			      struct drm_framebuffer *old_fb)
410 {
411 	struct drm_device *dev = crtc->dev;
412 	struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
413 	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
414 	struct drm_encoder_helper_funcs *encoder_funcs;
415 	int saved_x, saved_y;
416 	struct drm_encoder *encoder;
417 	bool ret = true;
418 
419 	crtc->enabled = drm_helper_crtc_in_use(crtc);
420 	if (!crtc->enabled)
421 		return true;
422 
423 	adjusted_mode = drm_mode_duplicate(dev, mode);
424 	if (!adjusted_mode)
425 		return false;
426 
427 	saved_hwmode = crtc->hwmode;
428 	saved_mode = crtc->mode;
429 	saved_x = crtc->x;
430 	saved_y = crtc->y;
431 
432 	/* Update crtc values up front so the driver can rely on them for mode
433 	 * setting.
434 	 */
435 	crtc->mode = *mode;
436 	crtc->x = x;
437 	crtc->y = y;
438 
439 	/* Pass our mode to the connectors and the CRTC to give them a chance to
440 	 * adjust it according to limitations or connector properties, and also
441 	 * a chance to reject the mode entirely.
442 	 */
443 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
444 
445 		if (encoder->crtc != crtc)
446 			continue;
447 		encoder_funcs = encoder->helper_private;
448 		if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
449 						      adjusted_mode))) {
450 			DRM_DEBUG_KMS("Encoder fixup failed\n");
451 			goto done;
452 		}
453 	}
454 
455 	if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
456 		DRM_DEBUG_KMS("CRTC fixup failed\n");
457 		goto done;
458 	}
459 	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
460 
461 	/* Prepare the encoders and CRTCs before setting the mode. */
462 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
463 
464 		if (encoder->crtc != crtc)
465 			continue;
466 		encoder_funcs = encoder->helper_private;
467 		/* Disable the encoders as the first thing we do. */
468 		encoder_funcs->prepare(encoder);
469 	}
470 
471 	drm_crtc_prepare_encoders(dev);
472 
473 	crtc_funcs->prepare(crtc);
474 
475 	/* Set up the DPLL and any encoders state that needs to adjust or depend
476 	 * on the DPLL.
477 	 */
478 	ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
479 	if (!ret)
480 	    goto done;
481 
482 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
483 
484 		if (encoder->crtc != crtc)
485 			continue;
486 
487 		DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
488 			encoder->base.id, drm_get_encoder_name(encoder),
489 			mode->base.id, mode->name);
490 		encoder_funcs = encoder->helper_private;
491 		encoder_funcs->mode_set(encoder, mode, adjusted_mode);
492 	}
493 
494 	/* Now enable the clocks, plane, pipe, and connectors that we set up. */
495 	crtc_funcs->commit(crtc);
496 
497 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
498 
499 		if (encoder->crtc != crtc)
500 			continue;
501 
502 		encoder_funcs = encoder->helper_private;
503 		encoder_funcs->commit(encoder);
504 
505 	}
506 
507 	/* Store real post-adjustment hardware mode. */
508 	crtc->hwmode = *adjusted_mode;
509 
510 	/* Calculate and store various constants which
511 	 * are later needed by vblank and swap-completion
512 	 * timestamping. They are derived from true hwmode.
513 	 */
514 	drm_calc_timestamping_constants(crtc);
515 
516 	/* FIXME: add subpixel order */
517 done:
518 	drm_mode_destroy(dev, adjusted_mode);
519 	if (!ret) {
520 		crtc->hwmode = saved_hwmode;
521 		crtc->mode = saved_mode;
522 		crtc->x = saved_x;
523 		crtc->y = saved_y;
524 	}
525 
526 	return ret;
527 }
528 EXPORT_SYMBOL(drm_crtc_helper_set_mode);
529 
530 
531 static int
532 drm_crtc_helper_disable(struct drm_crtc *crtc)
533 {
534 	struct drm_device *dev = crtc->dev;
535 	struct drm_connector *connector;
536 	struct drm_encoder *encoder;
537 
538 	/* Decouple all encoders and their attached connectors from this crtc */
539 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
540 		if (encoder->crtc != crtc)
541 			continue;
542 
543 		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
544 			if (connector->encoder != encoder)
545 				continue;
546 
547 			connector->encoder = NULL;
548 		}
549 	}
550 
551 	drm_helper_disable_unused_functions(dev);
552 	return 0;
553 }
554 
555 /**
556  * drm_crtc_helper_set_config - set a new config from userspace
557  * @set: mode set configuration
558  *
559  * LOCKING:
560  * Caller must hold mode config lock.
561  *
562  * Setup a new configuration, provided by the upper layers (either an ioctl call
563  * from userspace or internally e.g. from the fbdev suppport code) in @set, and
564  * enable it. This is the main helper functions for drivers that implement
565  * kernel mode setting with the crtc helper functions and the assorted
566  * ->prepare(), ->modeset() and ->commit() helper callbacks.
567  *
568  * RETURNS:
569  * Returns 0 on success, -ERRNO on failure.
570  */
571 int drm_crtc_helper_set_config(struct drm_mode_set *set)
572 {
573 	struct drm_device *dev;
574 	struct drm_crtc *save_crtcs, *new_crtc, *crtc;
575 	struct drm_encoder *save_encoders, *new_encoder, *encoder;
576 	struct drm_framebuffer *old_fb = NULL;
577 	bool mode_changed = false; /* if true do a full mode set */
578 	bool fb_changed = false; /* if true and !mode_changed just do a flip */
579 	struct drm_connector *save_connectors, *connector;
580 	int count = 0, ro, fail = 0;
581 	struct drm_crtc_helper_funcs *crtc_funcs;
582 	struct drm_mode_set save_set;
583 	int ret;
584 	int i;
585 
586 	DRM_DEBUG_KMS("\n");
587 
588 	if (!set)
589 		return -EINVAL;
590 
591 	if (!set->crtc)
592 		return -EINVAL;
593 
594 	if (!set->crtc->helper_private)
595 		return -EINVAL;
596 
597 	crtc_funcs = set->crtc->helper_private;
598 
599 	if (!set->mode)
600 		set->fb = NULL;
601 
602 	if (set->fb) {
603 		DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
604 				set->crtc->base.id, set->fb->base.id,
605 				(int)set->num_connectors, set->x, set->y);
606 	} else {
607 		DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
608 		return drm_crtc_helper_disable(set->crtc);
609 	}
610 
611 	dev = set->crtc->dev;
612 
613 	/* Allocate space for the backup of all (non-pointer) crtc, encoder and
614 	 * connector data. */
615 	save_crtcs = kmalloc(dev->mode_config.num_crtc * sizeof(struct drm_crtc),
616 	    M_DRM, M_WAITOK | M_ZERO);
617 	save_encoders = kmalloc(dev->mode_config.num_encoder *
618 	    sizeof(struct drm_encoder), M_DRM, M_WAITOK | M_ZERO);
619 	save_connectors = kmalloc(dev->mode_config.num_connector *
620 	    sizeof(struct drm_connector), M_DRM, M_WAITOK | M_ZERO);
621 
622 	/* Copy data. Note that driver private data is not affected.
623 	 * Should anything bad happen only the expected state is
624 	 * restored, not the drivers personal bookkeeping.
625 	 */
626 	count = 0;
627 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
628 		save_crtcs[count++] = *crtc;
629 	}
630 
631 	count = 0;
632 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
633 		save_encoders[count++] = *encoder;
634 	}
635 
636 	count = 0;
637 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
638 		save_connectors[count++] = *connector;
639 	}
640 
641 	save_set.crtc = set->crtc;
642 	save_set.mode = &set->crtc->mode;
643 	save_set.x = set->crtc->x;
644 	save_set.y = set->crtc->y;
645 	save_set.fb = set->crtc->fb;
646 
647 	/* We should be able to check here if the fb has the same properties
648 	 * and then just flip_or_move it */
649 	if (set->crtc->fb != set->fb) {
650 		/* If we have no fb then treat it as a full mode set */
651 		if (set->crtc->fb == NULL) {
652 			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
653 			mode_changed = true;
654 		} else if (set->fb == NULL) {
655 			mode_changed = true;
656 		} else if (set->fb->depth != set->crtc->fb->depth) {
657 			mode_changed = true;
658 		} else if (set->fb->bits_per_pixel !=
659 			   set->crtc->fb->bits_per_pixel) {
660 			mode_changed = true;
661 		} else
662 			fb_changed = true;
663 	}
664 
665 	if (set->x != set->crtc->x || set->y != set->crtc->y)
666 		fb_changed = true;
667 
668 	if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
669 		DRM_DEBUG_KMS("modes are different, full mode set\n");
670 		drm_mode_debug_printmodeline(&set->crtc->mode);
671 		drm_mode_debug_printmodeline(set->mode);
672 		mode_changed = true;
673 	}
674 
675 	/* a) traverse passed in connector list and get encoders for them */
676 	count = 0;
677 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
678 		struct drm_connector_helper_funcs *connector_funcs =
679 			connector->helper_private;
680 		new_encoder = connector->encoder;
681 		for (ro = 0; ro < set->num_connectors; ro++) {
682 			if (set->connectors[ro] == connector) {
683 				new_encoder = connector_funcs->best_encoder(connector);
684 				/* if we can't get an encoder for a connector
685 				   we are setting now - then fail */
686 				if (new_encoder == NULL)
687 					/* don't break so fail path works correct */
688 					fail = 1;
689 				break;
690 			}
691 		}
692 
693 		if (new_encoder != connector->encoder) {
694 			DRM_DEBUG_KMS("encoder changed, full mode switch\n");
695 			mode_changed = true;
696 			/* If the encoder is reused for another connector, then
697 			 * the appropriate crtc will be set later.
698 			 */
699 			if (connector->encoder)
700 				connector->encoder->crtc = NULL;
701 			connector->encoder = new_encoder;
702 		}
703 	}
704 
705 	if (fail) {
706 		ret = -EINVAL;
707 		goto fail;
708 	}
709 
710 	count = 0;
711 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
712 		if (!connector->encoder)
713 			continue;
714 
715 		if (connector->encoder->crtc == set->crtc)
716 			new_crtc = NULL;
717 		else
718 			new_crtc = connector->encoder->crtc;
719 
720 		for (ro = 0; ro < set->num_connectors; ro++) {
721 			if (set->connectors[ro] == connector)
722 				new_crtc = set->crtc;
723 		}
724 
725 		/* Make sure the new CRTC will work with the encoder */
726 		if (new_crtc &&
727 		    !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
728 			ret = -EINVAL;
729 			goto fail;
730 		}
731 		if (new_crtc != connector->encoder->crtc) {
732 			DRM_DEBUG_KMS("crtc changed, full mode switch\n");
733 			mode_changed = true;
734 			connector->encoder->crtc = new_crtc;
735 		}
736 		if (new_crtc) {
737 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
738 				connector->base.id, drm_get_connector_name(connector),
739 				new_crtc->base.id);
740 		} else {
741 			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
742 				connector->base.id, drm_get_connector_name(connector));
743 		}
744 	}
745 
746 	/* mode_set_base is not a required function */
747 	if (fb_changed && !crtc_funcs->mode_set_base)
748 		mode_changed = true;
749 
750 	if (mode_changed) {
751 		set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
752 		if (set->crtc->enabled) {
753 			DRM_DEBUG_KMS("attempting to set mode from"
754 					" userspace\n");
755 			drm_mode_debug_printmodeline(set->mode);
756 			old_fb = set->crtc->fb;
757 			set->crtc->fb = set->fb;
758 			if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
759 						      set->x, set->y,
760 						      old_fb)) {
761 				DRM_ERROR("failed to set mode on [CRTC:%d]\n",
762 					  set->crtc->base.id);
763 				set->crtc->fb = old_fb;
764 				ret = -EINVAL;
765 				goto fail;
766 			}
767 			DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
768 			for (i = 0; i < set->num_connectors; i++) {
769 				DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
770 					      drm_get_connector_name(set->connectors[i]));
771 				set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
772 			}
773 		}
774 		drm_helper_disable_unused_functions(dev);
775 	} else if (fb_changed) {
776 		set->crtc->x = set->x;
777 		set->crtc->y = set->y;
778 
779 		old_fb = set->crtc->fb;
780 		if (set->crtc->fb != set->fb)
781 			set->crtc->fb = set->fb;
782 		ret = crtc_funcs->mode_set_base(set->crtc,
783 						set->x, set->y, old_fb);
784 		if (ret != 0) {
785 			set->crtc->fb = old_fb;
786 			goto fail;
787 		}
788 	}
789 
790 	kfree(save_connectors);
791 	kfree(save_encoders);
792 	kfree(save_crtcs);
793 	return 0;
794 
795 fail:
796 	/* Restore all previous data. */
797 	count = 0;
798 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
799 		*crtc = save_crtcs[count++];
800 	}
801 
802 	count = 0;
803 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
804 		*encoder = save_encoders[count++];
805 	}
806 
807 	count = 0;
808 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
809 		*connector = save_connectors[count++];
810 	}
811 
812 	/* Try to restore the config */
813 	if (mode_changed &&
814 	    !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
815 				      save_set.y, save_set.fb))
816 		DRM_ERROR("failed to restore config after modeset failure\n");
817 
818 	drm_free(save_connectors, M_DRM);
819 	drm_free(save_encoders, M_DRM);
820 	drm_free(save_crtcs, M_DRM);
821 	return ret;
822 }
823 EXPORT_SYMBOL(drm_crtc_helper_set_config);
824 
825 static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
826 {
827 	int dpms = DRM_MODE_DPMS_OFF;
828 	struct drm_connector *connector;
829 	struct drm_device *dev = encoder->dev;
830 
831 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
832 		if (connector->encoder == encoder)
833 			if (connector->dpms < dpms)
834 				dpms = connector->dpms;
835 	return dpms;
836 }
837 
838 static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
839 {
840 	int dpms = DRM_MODE_DPMS_OFF;
841 	struct drm_connector *connector;
842 	struct drm_device *dev = crtc->dev;
843 
844 	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
845 		if (connector->encoder && connector->encoder->crtc == crtc)
846 			if (connector->dpms < dpms)
847 				dpms = connector->dpms;
848 	return dpms;
849 }
850 
851 /**
852  * drm_helper_connector_dpms() - connector dpms helper implementation
853  * @connector: affected connector
854  * @mode: DPMS mode
855  *
856  * This is the main helper function provided by the crtc helper framework for
857  * implementing the DPMS connector attribute. It computes the new desired DPMS
858  * state for all encoders and crtcs in the output mesh and calls the ->dpms()
859  * callback provided by the driver appropriately.
860  */
861 void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
862 {
863 	struct drm_encoder *encoder = connector->encoder;
864 	struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
865 	int old_dpms;
866 
867 	if (mode == connector->dpms)
868 		return;
869 
870 	old_dpms = connector->dpms;
871 	connector->dpms = mode;
872 
873 	/* from off to on, do crtc then encoder */
874 	if (mode < old_dpms) {
875 		if (crtc) {
876 			struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
877 			if (crtc_funcs->dpms)
878 				(*crtc_funcs->dpms) (crtc,
879 						     drm_helper_choose_crtc_dpms(crtc));
880 		}
881 		if (encoder) {
882 			struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
883 			if (encoder_funcs->dpms)
884 				(*encoder_funcs->dpms) (encoder,
885 							drm_helper_choose_encoder_dpms(encoder));
886 		}
887 	}
888 
889 	/* from on to off, do encoder then crtc */
890 	if (mode > old_dpms) {
891 		if (encoder) {
892 			struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
893 			if (encoder_funcs->dpms)
894 				(*encoder_funcs->dpms) (encoder,
895 							drm_helper_choose_encoder_dpms(encoder));
896 		}
897 		if (crtc) {
898 			struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
899 			if (crtc_funcs->dpms)
900 				(*crtc_funcs->dpms) (crtc,
901 						     drm_helper_choose_crtc_dpms(crtc));
902 		}
903 	}
904 
905 	return;
906 }
907 EXPORT_SYMBOL(drm_helper_connector_dpms);
908 
909 int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
910 				   struct drm_mode_fb_cmd2 *mode_cmd)
911 {
912 	int i;
913 
914 	fb->width = mode_cmd->width;
915 	fb->height = mode_cmd->height;
916 	for (i = 0; i < 4; i++) {
917 		fb->pitches[i] = mode_cmd->pitches[i];
918 		fb->offsets[i] = mode_cmd->offsets[i];
919 	}
920 	drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
921 				    &fb->bits_per_pixel);
922 	fb->pixel_format = mode_cmd->pixel_format;
923 
924 	return 0;
925 }
926 EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
927 
928 int drm_helper_resume_force_mode(struct drm_device *dev)
929 {
930 	struct drm_crtc *crtc;
931 	struct drm_encoder *encoder;
932 	struct drm_encoder_helper_funcs *encoder_funcs;
933 	struct drm_crtc_helper_funcs *crtc_funcs;
934 	int ret;
935 
936 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
937 
938 		if (!crtc->enabled)
939 			continue;
940 
941 		ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
942 					       crtc->x, crtc->y, crtc->fb);
943 
944 		if (ret == false)
945 			DRM_ERROR("failed to set mode on crtc %p\n", crtc);
946 
947 		/* Turn off outputs that were already powered off */
948 		if (drm_helper_choose_crtc_dpms(crtc)) {
949 			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
950 
951 				if(encoder->crtc != crtc)
952 					continue;
953 
954 				encoder_funcs = encoder->helper_private;
955 				if (encoder_funcs->dpms)
956 					(*encoder_funcs->dpms) (encoder,
957 								drm_helper_choose_encoder_dpms(encoder));
958 			}
959 
960 			crtc_funcs = crtc->helper_private;
961 			if (crtc_funcs->dpms)
962 				(*crtc_funcs->dpms) (crtc,
963 						     drm_helper_choose_crtc_dpms(crtc));
964 		}
965 	}
966 	/* disable the unused connectors while restoring the modesetting */
967 	drm_helper_disable_unused_functions(dev);
968 	return 0;
969 }
970 EXPORT_SYMBOL(drm_helper_resume_force_mode);
971 
972 void drm_kms_helper_hotplug_event(struct drm_device *dev)
973 {
974 #if 0
975 	/* send a uevent + call fbdev */
976 	drm_sysfs_hotplug_event(dev);
977 	if (dev->mode_config.funcs->output_poll_changed)
978 		dev->mode_config.funcs->output_poll_changed(dev);
979 #endif
980 }
981 EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
982 
983 #define DRM_OUTPUT_POLL_PERIOD (10 * hz)
984 static void output_poll_execute(void *ctx, int pending)
985 {
986 	struct drm_device *dev;
987 	struct drm_connector *connector;
988 	enum drm_connector_status old_status;
989 	bool repoll = false, changed = false;
990 
991 	if (!drm_kms_helper_poll)
992 		return;
993 
994 	dev = ctx;
995 
996 	lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE);
997 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
998 
999 		/* Ignore forced connectors. */
1000 		if (connector->force)
1001 			continue;
1002 
1003 		/* Ignore HPD capable connectors and connectors where we don't
1004 		 * want any hotplug detection at all for polling. */
1005 		if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD)
1006 			continue;
1007 
1008 		repoll = true;
1009 
1010 		old_status = connector->status;
1011 		/* if we are connected and don't want to poll for disconnect
1012 		   skip it */
1013 		if (old_status == connector_status_connected &&
1014 		    !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
1015 			continue;
1016 
1017 		connector->status = connector->funcs->detect(connector, false);
1018 		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
1019 			      connector->base.id,
1020 			      drm_get_connector_name(connector),
1021 			      old_status, connector->status);
1022 		if (old_status != connector->status)
1023 			changed = true;
1024 	}
1025 
1026 	lockmgr(&dev->mode_config.mutex, LK_RELEASE);
1027 
1028 	if (changed)
1029 		drm_kms_helper_hotplug_event(dev);
1030 
1031 	if (repoll) {
1032 		taskqueue_enqueue_timeout(taskqueue_thread[mycpuid],
1033 		    &dev->mode_config.output_poll_task,
1034 		    DRM_OUTPUT_POLL_PERIOD);
1035 	}
1036 }
1037 
1038 void drm_kms_helper_poll_disable(struct drm_device *dev)
1039 {
1040 	if (!dev->mode_config.poll_enabled)
1041 		return;
1042 	taskqueue_cancel_timeout(taskqueue_thread[mycpuid],
1043 	    &dev->mode_config.output_poll_task, NULL);
1044 }
1045 EXPORT_SYMBOL(drm_kms_helper_poll_disable);
1046 
1047 void drm_kms_helper_poll_enable(struct drm_device *dev)
1048 {
1049 	bool poll = false;
1050 	struct drm_connector *connector;
1051 
1052 	if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)
1053 		return;
1054 
1055 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1056 		if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT |
1057 					 DRM_CONNECTOR_POLL_DISCONNECT))
1058 			poll = true;
1059 	}
1060 
1061 	if (poll) {
1062 		taskqueue_enqueue_timeout(taskqueue_thread[mycpuid],
1063 		    &dev->mode_config.output_poll_task, DRM_OUTPUT_POLL_PERIOD);
1064 	}
1065 }
1066 EXPORT_SYMBOL(drm_kms_helper_poll_enable);
1067 
1068 void drm_kms_helper_poll_init(struct drm_device *dev)
1069 {
1070 	TIMEOUT_TASK_INIT(taskqueue_thread[mycpuid], &dev->mode_config.output_poll_task,
1071 	    0, output_poll_execute, dev);
1072 	dev->mode_config.poll_enabled = true;
1073 
1074 	drm_kms_helper_poll_enable(dev);
1075 }
1076 EXPORT_SYMBOL(drm_kms_helper_poll_init);
1077 
1078 void drm_kms_helper_poll_fini(struct drm_device *dev)
1079 {
1080 	drm_kms_helper_poll_disable(dev);
1081 }
1082 EXPORT_SYMBOL(drm_kms_helper_poll_fini);
1083 
1084 void drm_helper_hpd_irq_event(struct drm_device *dev)
1085 {
1086 	struct drm_connector *connector;
1087 	enum drm_connector_status old_status;
1088 	bool changed = false;
1089 
1090 	if (!dev->mode_config.poll_enabled)
1091 		return;
1092 
1093 	lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE);
1094 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1095 
1096 		/* Only handle HPD capable connectors. */
1097 		if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
1098 			continue;
1099 
1100 		old_status = connector->status;
1101 
1102 		connector->status = connector->funcs->detect(connector, false);
1103 		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
1104 			      connector->base.id,
1105 			      drm_get_connector_name(connector),
1106 			      old_status, connector->status);
1107 		if (old_status != connector->status)
1108 			changed = true;
1109 	}
1110 
1111 	lockmgr(&dev->mode_config.mutex, LK_RELEASE);
1112 
1113 	if (changed)
1114 		drm_kms_helper_hotplug_event(dev);
1115 }
1116 EXPORT_SYMBOL(drm_helper_hpd_irq_event);
1117