Line data Source code
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 :
32 : #ifdef __linux__
33 : #include <linux/kernel.h>
34 : #include <linux/export.h>
35 : #include <linux/moduleparam.h>
36 : #endif
37 :
38 : #include <dev/pci/drm/drmP.h>
39 : #include <dev/pci/drm/drm_atomic.h>
40 : #include <dev/pci/drm/drm_crtc.h>
41 : #include <dev/pci/drm/drm_fourcc.h>
42 : #include <dev/pci/drm/drm_crtc_helper.h>
43 : #include <dev/pci/drm/drm_fb_helper.h>
44 : #include <dev/pci/drm/drm_plane_helper.h>
45 : #include <dev/pci/drm/drm_atomic_helper.h>
46 : #include <dev/pci/drm/drm_edid.h>
47 :
48 : /**
49 : * DOC: overview
50 : *
51 : * The CRTC modeset helper library provides a default set_config implementation
52 : * in drm_crtc_helper_set_config(). Plus a few other convenience functions using
53 : * the same callbacks which drivers can use to e.g. restore the modeset
54 : * configuration on resume with drm_helper_resume_force_mode().
55 : *
56 : * The driver callbacks are mostly compatible with the atomic modeset helpers,
57 : * except for the handling of the primary plane: Atomic helpers require that the
58 : * primary plane is implemented as a real standalone plane and not directly tied
59 : * to the CRTC state. For easier transition this library provides functions to
60 : * implement the old semantics required by the CRTC helpers using the new plane
61 : * and atomic helper callbacks.
62 : *
63 : * Drivers are strongly urged to convert to the atomic helpers (by way of first
64 : * converting to the plane helpers). New drivers must not use these functions
65 : * but need to implement the atomic interface instead, potentially using the
66 : * atomic helpers for that.
67 : */
68 : MODULE_AUTHOR("David Airlie, Jesse Barnes");
69 : MODULE_DESCRIPTION("DRM KMS helper");
70 : MODULE_LICENSE("GPL and additional rights");
71 :
72 : /**
73 : * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
74 : * connector list
75 : * @dev: drm device to operate on
76 : *
77 : * Some userspace presumes that the first connected connector is the main
78 : * display, where it's supposed to display e.g. the login screen. For
79 : * laptops, this should be the main panel. Use this function to sort all
80 : * (eDP/LVDS) panels to the front of the connector list, instead of
81 : * painstakingly trying to initialize them in the right order.
82 : */
83 0 : void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
84 : {
85 : struct drm_connector *connector, *tmp;
86 0 : struct list_head panel_list;
87 :
88 0 : INIT_LIST_HEAD(&panel_list);
89 :
90 0 : list_for_each_entry_safe(connector, tmp,
91 : &dev->mode_config.connector_list, head) {
92 0 : if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
93 0 : connector->connector_type == DRM_MODE_CONNECTOR_eDP)
94 0 : list_move_tail(&connector->head, &panel_list);
95 : }
96 :
97 0 : list_splice(&panel_list, &dev->mode_config.connector_list);
98 0 : }
99 : EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
100 :
101 : /**
102 : * drm_helper_encoder_in_use - check if a given encoder is in use
103 : * @encoder: encoder to check
104 : *
105 : * Checks whether @encoder is with the current mode setting output configuration
106 : * in use by any connector. This doesn't mean that it is actually enabled since
107 : * the DPMS state is tracked separately.
108 : *
109 : * Returns:
110 : * True if @encoder is used, false otherwise.
111 : */
112 0 : bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
113 : {
114 : struct drm_connector *connector;
115 0 : struct drm_device *dev = encoder->dev;
116 :
117 : /*
118 : * We can expect this mutex to be locked if we are not panicking.
119 : * Locking is currently fubar in the panic handler.
120 : */
121 0 : if (!oops_in_progress) {
122 0 : WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
123 0 : WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
124 0 : }
125 :
126 0 : drm_for_each_connector(connector, dev)
127 0 : if (connector->encoder == encoder)
128 0 : return true;
129 0 : return false;
130 0 : }
131 : EXPORT_SYMBOL(drm_helper_encoder_in_use);
132 :
133 : /**
134 : * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
135 : * @crtc: CRTC to check
136 : *
137 : * Checks whether @crtc is with the current mode setting output configuration
138 : * in use by any connector. This doesn't mean that it is actually enabled since
139 : * the DPMS state is tracked separately.
140 : *
141 : * Returns:
142 : * True if @crtc is used, false otherwise.
143 : */
144 0 : bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
145 : {
146 : struct drm_encoder *encoder;
147 0 : struct drm_device *dev = crtc->dev;
148 :
149 : /*
150 : * We can expect this mutex to be locked if we are not panicking.
151 : * Locking is currently fubar in the panic handler.
152 : */
153 0 : if (!oops_in_progress)
154 0 : WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
155 :
156 0 : drm_for_each_encoder(encoder, dev)
157 0 : if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))
158 0 : return true;
159 0 : return false;
160 0 : }
161 : EXPORT_SYMBOL(drm_helper_crtc_in_use);
162 :
163 : static void
164 0 : drm_encoder_disable(struct drm_encoder *encoder)
165 : {
166 0 : const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
167 :
168 0 : drm_bridge_disable(encoder->bridge);
169 :
170 0 : if (encoder_funcs->disable)
171 0 : (*encoder_funcs->disable)(encoder);
172 : else
173 0 : (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
174 :
175 0 : drm_bridge_post_disable(encoder->bridge);
176 0 : }
177 :
178 0 : static void __drm_helper_disable_unused_functions(struct drm_device *dev)
179 : {
180 : struct drm_encoder *encoder;
181 : struct drm_crtc *crtc;
182 :
183 0 : drm_warn_on_modeset_not_all_locked(dev);
184 :
185 0 : drm_for_each_encoder(encoder, dev) {
186 0 : if (!drm_helper_encoder_in_use(encoder)) {
187 0 : drm_encoder_disable(encoder);
188 : /* disconnect encoder from any connector */
189 0 : encoder->crtc = NULL;
190 0 : }
191 : }
192 :
193 0 : drm_for_each_crtc(crtc, dev) {
194 0 : const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
195 0 : crtc->enabled = drm_helper_crtc_in_use(crtc);
196 0 : if (!crtc->enabled) {
197 0 : if (crtc_funcs->disable)
198 0 : (*crtc_funcs->disable)(crtc);
199 : else
200 0 : (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
201 0 : crtc->primary->fb = NULL;
202 0 : }
203 : }
204 0 : }
205 :
206 : /**
207 : * drm_helper_disable_unused_functions - disable unused objects
208 : * @dev: DRM device
209 : *
210 : * This function walks through the entire mode setting configuration of @dev. It
211 : * will remove any crtc links of unused encoders and encoder links of
212 : * disconnected connectors. Then it will disable all unused encoders and crtcs
213 : * either by calling their disable callback if available or by calling their
214 : * dpms callback with DRM_MODE_DPMS_OFF.
215 : */
216 0 : void drm_helper_disable_unused_functions(struct drm_device *dev)
217 : {
218 0 : drm_modeset_lock_all(dev);
219 0 : __drm_helper_disable_unused_functions(dev);
220 0 : drm_modeset_unlock_all(dev);
221 0 : }
222 : EXPORT_SYMBOL(drm_helper_disable_unused_functions);
223 :
224 : /*
225 : * Check the CRTC we're going to map each output to vs. its current
226 : * CRTC. If they don't match, we have to disable the output and the CRTC
227 : * since the driver will have to re-route things.
228 : */
229 : static void
230 0 : drm_crtc_prepare_encoders(struct drm_device *dev)
231 : {
232 : const struct drm_encoder_helper_funcs *encoder_funcs;
233 : struct drm_encoder *encoder;
234 :
235 0 : drm_for_each_encoder(encoder, dev) {
236 0 : encoder_funcs = encoder->helper_private;
237 : /* Disable unused encoders */
238 0 : if (encoder->crtc == NULL)
239 0 : drm_encoder_disable(encoder);
240 : /* Disable encoders whose CRTC is about to change */
241 0 : if (encoder_funcs->get_crtc &&
242 0 : encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
243 0 : drm_encoder_disable(encoder);
244 : }
245 0 : }
246 :
247 : /**
248 : * drm_crtc_helper_set_mode - internal helper to set a mode
249 : * @crtc: CRTC to program
250 : * @mode: mode to use
251 : * @x: horizontal offset into the surface
252 : * @y: vertical offset into the surface
253 : * @old_fb: old framebuffer, for cleanup
254 : *
255 : * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance
256 : * to fixup or reject the mode prior to trying to set it. This is an internal
257 : * helper that drivers could e.g. use to update properties that require the
258 : * entire output pipe to be disabled and re-enabled in a new configuration. For
259 : * example for changing whether audio is enabled on a hdmi link or for changing
260 : * panel fitter or dither attributes. It is also called by the
261 : * drm_crtc_helper_set_config() helper function to drive the mode setting
262 : * sequence.
263 : *
264 : * Returns:
265 : * True if the mode was set successfully, false otherwise.
266 : */
267 0 : bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
268 : struct drm_display_mode *mode,
269 : int x, int y,
270 : struct drm_framebuffer *old_fb)
271 : {
272 0 : struct drm_device *dev = crtc->dev;
273 0 : struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
274 0 : const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
275 : const struct drm_encoder_helper_funcs *encoder_funcs;
276 : int saved_x, saved_y;
277 : bool saved_enabled;
278 : struct drm_encoder *encoder;
279 : bool ret = true;
280 :
281 0 : drm_warn_on_modeset_not_all_locked(dev);
282 :
283 0 : saved_enabled = crtc->enabled;
284 0 : crtc->enabled = drm_helper_crtc_in_use(crtc);
285 0 : if (!crtc->enabled)
286 0 : return true;
287 :
288 0 : adjusted_mode = drm_mode_duplicate(dev, mode);
289 0 : if (!adjusted_mode) {
290 0 : crtc->enabled = saved_enabled;
291 0 : return false;
292 : }
293 :
294 0 : saved_mode = crtc->mode;
295 0 : saved_hwmode = crtc->hwmode;
296 0 : saved_x = crtc->x;
297 0 : saved_y = crtc->y;
298 :
299 : /* Update crtc values up front so the driver can rely on them for mode
300 : * setting.
301 : */
302 0 : crtc->mode = *mode;
303 0 : crtc->x = x;
304 0 : crtc->y = y;
305 :
306 : /* Pass our mode to the connectors and the CRTC to give them a chance to
307 : * adjust it according to limitations or connector properties, and also
308 : * a chance to reject the mode entirely.
309 : */
310 0 : drm_for_each_encoder(encoder, dev) {
311 :
312 0 : if (encoder->crtc != crtc)
313 : continue;
314 :
315 0 : ret = drm_bridge_mode_fixup(encoder->bridge,
316 : mode, adjusted_mode);
317 0 : if (!ret) {
318 : DRM_DEBUG_KMS("Bridge fixup failed\n");
319 : goto done;
320 : }
321 :
322 0 : encoder_funcs = encoder->helper_private;
323 0 : if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
324 : adjusted_mode))) {
325 : DRM_DEBUG_KMS("Encoder fixup failed\n");
326 : goto done;
327 : }
328 : }
329 :
330 0 : if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
331 : DRM_DEBUG_KMS("CRTC fixup failed\n");
332 : goto done;
333 : }
334 : DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
335 :
336 0 : crtc->hwmode = *adjusted_mode;
337 :
338 : /* Prepare the encoders and CRTCs before setting the mode. */
339 0 : drm_for_each_encoder(encoder, dev) {
340 :
341 0 : if (encoder->crtc != crtc)
342 : continue;
343 :
344 0 : drm_bridge_disable(encoder->bridge);
345 :
346 0 : encoder_funcs = encoder->helper_private;
347 : /* Disable the encoders as the first thing we do. */
348 0 : encoder_funcs->prepare(encoder);
349 :
350 0 : drm_bridge_post_disable(encoder->bridge);
351 0 : }
352 :
353 0 : drm_crtc_prepare_encoders(dev);
354 :
355 0 : crtc_funcs->prepare(crtc);
356 :
357 : /* Set up the DPLL and any encoders state that needs to adjust or depend
358 : * on the DPLL.
359 : */
360 0 : ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
361 0 : if (!ret)
362 : goto done;
363 :
364 0 : drm_for_each_encoder(encoder, dev) {
365 :
366 0 : if (encoder->crtc != crtc)
367 : continue;
368 :
369 : DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
370 : encoder->base.id, encoder->name,
371 : mode->base.id, mode->name);
372 0 : encoder_funcs = encoder->helper_private;
373 0 : encoder_funcs->mode_set(encoder, mode, adjusted_mode);
374 :
375 0 : drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode);
376 0 : }
377 :
378 : /* Now enable the clocks, plane, pipe, and connectors that we set up. */
379 0 : crtc_funcs->commit(crtc);
380 :
381 0 : drm_for_each_encoder(encoder, dev) {
382 :
383 0 : if (encoder->crtc != crtc)
384 : continue;
385 :
386 0 : drm_bridge_pre_enable(encoder->bridge);
387 :
388 0 : encoder_funcs = encoder->helper_private;
389 0 : encoder_funcs->commit(encoder);
390 :
391 0 : drm_bridge_enable(encoder->bridge);
392 0 : }
393 :
394 : /* Calculate and store various constants which
395 : * are later needed by vblank and swap-completion
396 : * timestamping. They are derived from true hwmode.
397 : */
398 0 : drm_calc_timestamping_constants(crtc, &crtc->hwmode);
399 :
400 : /* FIXME: add subpixel order */
401 : done:
402 0 : drm_mode_destroy(dev, adjusted_mode);
403 0 : if (!ret) {
404 0 : crtc->enabled = saved_enabled;
405 0 : crtc->mode = saved_mode;
406 0 : crtc->hwmode = saved_hwmode;
407 0 : crtc->x = saved_x;
408 0 : crtc->y = saved_y;
409 0 : }
410 :
411 0 : return ret;
412 0 : }
413 : EXPORT_SYMBOL(drm_crtc_helper_set_mode);
414 :
415 : static void
416 0 : drm_crtc_helper_disable(struct drm_crtc *crtc)
417 : {
418 0 : struct drm_device *dev = crtc->dev;
419 : struct drm_connector *connector;
420 : struct drm_encoder *encoder;
421 :
422 : /* Decouple all encoders and their attached connectors from this crtc */
423 0 : drm_for_each_encoder(encoder, dev) {
424 0 : if (encoder->crtc != crtc)
425 : continue;
426 :
427 0 : drm_for_each_connector(connector, dev) {
428 0 : if (connector->encoder != encoder)
429 : continue;
430 :
431 0 : connector->encoder = NULL;
432 :
433 : /*
434 : * drm_helper_disable_unused_functions() ought to be
435 : * doing this, but since we've decoupled the encoder
436 : * from the connector above, the required connection
437 : * between them is henceforth no longer available.
438 : */
439 0 : connector->dpms = DRM_MODE_DPMS_OFF;
440 0 : }
441 : }
442 :
443 0 : __drm_helper_disable_unused_functions(dev);
444 0 : }
445 :
446 : /**
447 : * drm_crtc_helper_set_config - set a new config from userspace
448 : * @set: mode set configuration
449 : *
450 : * Setup a new configuration, provided by the upper layers (either an ioctl call
451 : * from userspace or internally e.g. from the fbdev support code) in @set, and
452 : * enable it. This is the main helper functions for drivers that implement
453 : * kernel mode setting with the crtc helper functions and the assorted
454 : * ->prepare(), ->modeset() and ->commit() helper callbacks.
455 : *
456 : * Returns:
457 : * Returns 0 on success, negative errno numbers on failure.
458 : */
459 0 : int drm_crtc_helper_set_config(struct drm_mode_set *set)
460 : {
461 : struct drm_device *dev;
462 : struct drm_crtc *new_crtc;
463 : struct drm_encoder *save_encoders, *new_encoder, *encoder;
464 : bool mode_changed = false; /* if true do a full mode set */
465 : bool fb_changed = false; /* if true and !mode_changed just do a flip */
466 : struct drm_connector *save_connectors, *connector;
467 : int count = 0, ro, fail = 0;
468 : const struct drm_crtc_helper_funcs *crtc_funcs;
469 : struct drm_mode_set save_set;
470 : int ret;
471 : int i;
472 :
473 : DRM_DEBUG_KMS("\n");
474 :
475 0 : BUG_ON(!set);
476 0 : BUG_ON(!set->crtc);
477 0 : BUG_ON(!set->crtc->helper_private);
478 :
479 : /* Enforce sane interface api - has been abused by the fb helper. */
480 0 : BUG_ON(!set->mode && set->fb);
481 0 : BUG_ON(set->fb && set->num_connectors == 0);
482 :
483 0 : crtc_funcs = set->crtc->helper_private;
484 :
485 0 : if (!set->mode)
486 0 : set->fb = NULL;
487 :
488 0 : if (set->fb) {
489 : DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
490 : set->crtc->base.id, set->fb->base.id,
491 : (int)set->num_connectors, set->x, set->y);
492 : } else {
493 : DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
494 0 : drm_crtc_helper_disable(set->crtc);
495 0 : return 0;
496 : }
497 :
498 0 : dev = set->crtc->dev;
499 :
500 0 : drm_warn_on_modeset_not_all_locked(dev);
501 :
502 : /*
503 : * Allocate space for the backup of all (non-pointer) encoder and
504 : * connector data.
505 : */
506 0 : save_encoders = kzalloc(dev->mode_config.num_encoder *
507 : sizeof(struct drm_encoder), GFP_KERNEL);
508 0 : if (!save_encoders)
509 0 : return -ENOMEM;
510 :
511 0 : save_connectors = kzalloc(dev->mode_config.num_connector *
512 : sizeof(struct drm_connector), GFP_KERNEL);
513 0 : if (!save_connectors) {
514 0 : kfree(save_encoders);
515 0 : return -ENOMEM;
516 : }
517 :
518 : /*
519 : * Copy data. Note that driver private data is not affected.
520 : * Should anything bad happen only the expected state is
521 : * restored, not the drivers personal bookkeeping.
522 : */
523 : count = 0;
524 0 : drm_for_each_encoder(encoder, dev) {
525 0 : save_encoders[count++] = *encoder;
526 : }
527 :
528 : count = 0;
529 0 : drm_for_each_connector(connector, dev) {
530 0 : save_connectors[count++] = *connector;
531 : }
532 :
533 0 : save_set.crtc = set->crtc;
534 0 : save_set.mode = &set->crtc->mode;
535 0 : save_set.x = set->crtc->x;
536 0 : save_set.y = set->crtc->y;
537 0 : save_set.fb = set->crtc->primary->fb;
538 :
539 : /* We should be able to check here if the fb has the same properties
540 : * and then just flip_or_move it */
541 0 : if (set->crtc->primary->fb != set->fb) {
542 : /* If we have no fb then treat it as a full mode set */
543 0 : if (set->crtc->primary->fb == NULL) {
544 : DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
545 : mode_changed = true;
546 0 : } else if (set->fb == NULL) {
547 : mode_changed = true;
548 0 : } else if (set->fb->pixel_format !=
549 0 : set->crtc->primary->fb->pixel_format) {
550 : mode_changed = true;
551 0 : } else
552 : fb_changed = true;
553 : }
554 :
555 0 : if (set->x != set->crtc->x || set->y != set->crtc->y)
556 0 : fb_changed = true;
557 :
558 0 : if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
559 : DRM_DEBUG_KMS("modes are different, full mode set\n");
560 0 : drm_mode_debug_printmodeline(&set->crtc->mode);
561 0 : drm_mode_debug_printmodeline(set->mode);
562 : mode_changed = true;
563 0 : }
564 :
565 : /* a) traverse passed in connector list and get encoders for them */
566 : count = 0;
567 0 : drm_for_each_connector(connector, dev) {
568 : const struct drm_connector_helper_funcs *connector_funcs =
569 0 : connector->helper_private;
570 0 : new_encoder = connector->encoder;
571 0 : for (ro = 0; ro < set->num_connectors; ro++) {
572 0 : if (set->connectors[ro] == connector) {
573 0 : new_encoder = connector_funcs->best_encoder(connector);
574 : /* if we can't get an encoder for a connector
575 : we are setting now - then fail */
576 0 : if (new_encoder == NULL)
577 : /* don't break so fail path works correct */
578 0 : fail = 1;
579 :
580 0 : if (connector->dpms != DRM_MODE_DPMS_ON) {
581 : DRM_DEBUG_KMS("connector dpms not on, full mode switch\n");
582 : mode_changed = true;
583 0 : }
584 :
585 : break;
586 : }
587 : }
588 :
589 0 : if (new_encoder != connector->encoder) {
590 : DRM_DEBUG_KMS("encoder changed, full mode switch\n");
591 : mode_changed = true;
592 : /* If the encoder is reused for another connector, then
593 : * the appropriate crtc will be set later.
594 : */
595 0 : if (connector->encoder)
596 0 : connector->encoder->crtc = NULL;
597 0 : connector->encoder = new_encoder;
598 0 : }
599 : }
600 :
601 0 : if (fail) {
602 : ret = -EINVAL;
603 0 : goto fail;
604 : }
605 :
606 : count = 0;
607 0 : drm_for_each_connector(connector, dev) {
608 0 : if (!connector->encoder)
609 : continue;
610 :
611 0 : if (connector->encoder->crtc == set->crtc)
612 0 : new_crtc = NULL;
613 : else
614 : new_crtc = connector->encoder->crtc;
615 :
616 0 : for (ro = 0; ro < set->num_connectors; ro++) {
617 0 : if (set->connectors[ro] == connector)
618 0 : new_crtc = set->crtc;
619 : }
620 :
621 : /* Make sure the new CRTC will work with the encoder */
622 0 : if (new_crtc &&
623 0 : !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
624 : ret = -EINVAL;
625 0 : goto fail;
626 : }
627 0 : if (new_crtc != connector->encoder->crtc) {
628 : DRM_DEBUG_KMS("crtc changed, full mode switch\n");
629 : mode_changed = true;
630 0 : connector->encoder->crtc = new_crtc;
631 0 : }
632 : if (new_crtc) {
633 : DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
634 : connector->base.id, connector->name,
635 : new_crtc->base.id);
636 : } else {
637 : DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
638 : connector->base.id, connector->name);
639 : }
640 0 : }
641 :
642 : /* mode_set_base is not a required function */
643 0 : if (fb_changed && !crtc_funcs->mode_set_base)
644 0 : mode_changed = true;
645 :
646 0 : if (mode_changed) {
647 0 : if (drm_helper_crtc_in_use(set->crtc)) {
648 : DRM_DEBUG_KMS("attempting to set mode from"
649 : " userspace\n");
650 0 : drm_mode_debug_printmodeline(set->mode);
651 0 : set->crtc->primary->fb = set->fb;
652 0 : if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
653 0 : set->x, set->y,
654 : save_set.fb)) {
655 0 : DRM_ERROR("failed to set mode on [CRTC:%d]\n",
656 : set->crtc->base.id);
657 0 : set->crtc->primary->fb = save_set.fb;
658 : ret = -EINVAL;
659 0 : goto fail;
660 : }
661 : DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
662 0 : for (i = 0; i < set->num_connectors; i++) {
663 : DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
664 : set->connectors[i]->name);
665 0 : set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
666 : }
667 : }
668 0 : __drm_helper_disable_unused_functions(dev);
669 0 : } else if (fb_changed) {
670 0 : set->crtc->x = set->x;
671 0 : set->crtc->y = set->y;
672 0 : set->crtc->primary->fb = set->fb;
673 0 : ret = crtc_funcs->mode_set_base(set->crtc,
674 0 : set->x, set->y, save_set.fb);
675 0 : if (ret != 0) {
676 0 : set->crtc->x = save_set.x;
677 0 : set->crtc->y = save_set.y;
678 0 : set->crtc->primary->fb = save_set.fb;
679 0 : goto fail;
680 : }
681 : }
682 :
683 0 : kfree(save_connectors);
684 0 : kfree(save_encoders);
685 0 : return 0;
686 :
687 : fail:
688 : /* Restore all previous data. */
689 : count = 0;
690 0 : drm_for_each_encoder(encoder, dev) {
691 0 : *encoder = save_encoders[count++];
692 : }
693 :
694 : count = 0;
695 0 : drm_for_each_connector(connector, dev) {
696 0 : *connector = save_connectors[count++];
697 : }
698 :
699 : /* Try to restore the config */
700 0 : if (mode_changed &&
701 0 : !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
702 : save_set.y, save_set.fb))
703 0 : DRM_ERROR("failed to restore config after modeset failure\n");
704 :
705 0 : kfree(save_connectors);
706 0 : kfree(save_encoders);
707 0 : return ret;
708 0 : }
709 : EXPORT_SYMBOL(drm_crtc_helper_set_config);
710 :
711 0 : static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
712 : {
713 : int dpms = DRM_MODE_DPMS_OFF;
714 : struct drm_connector *connector;
715 0 : struct drm_device *dev = encoder->dev;
716 :
717 0 : drm_for_each_connector(connector, dev)
718 0 : if (connector->encoder == encoder)
719 0 : if (connector->dpms < dpms)
720 0 : dpms = connector->dpms;
721 0 : return dpms;
722 : }
723 :
724 : /* Helper which handles bridge ordering around encoder dpms */
725 0 : static void drm_helper_encoder_dpms(struct drm_encoder *encoder, int mode)
726 : {
727 0 : struct drm_bridge *bridge = encoder->bridge;
728 : const struct drm_encoder_helper_funcs *encoder_funcs;
729 :
730 0 : if (mode == DRM_MODE_DPMS_ON)
731 0 : drm_bridge_pre_enable(bridge);
732 : else
733 0 : drm_bridge_disable(bridge);
734 :
735 0 : encoder_funcs = encoder->helper_private;
736 0 : if (encoder_funcs->dpms)
737 0 : encoder_funcs->dpms(encoder, mode);
738 :
739 0 : if (mode == DRM_MODE_DPMS_ON)
740 0 : drm_bridge_enable(bridge);
741 : else
742 0 : drm_bridge_post_disable(bridge);
743 0 : }
744 :
745 0 : static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
746 : {
747 : int dpms = DRM_MODE_DPMS_OFF;
748 : struct drm_connector *connector;
749 0 : struct drm_device *dev = crtc->dev;
750 :
751 0 : drm_for_each_connector(connector, dev)
752 0 : if (connector->encoder && connector->encoder->crtc == crtc)
753 0 : if (connector->dpms < dpms)
754 0 : dpms = connector->dpms;
755 0 : return dpms;
756 : }
757 :
758 : /**
759 : * drm_helper_connector_dpms() - connector dpms helper implementation
760 : * @connector: affected connector
761 : * @mode: DPMS mode
762 : *
763 : * This is the main helper function provided by the crtc helper framework for
764 : * implementing the DPMS connector attribute. It computes the new desired DPMS
765 : * state for all encoders and crtcs in the output mesh and calls the ->dpms()
766 : * callback provided by the driver appropriately.
767 : *
768 : * Returns:
769 : * Always returns 0.
770 : */
771 0 : int drm_helper_connector_dpms(struct drm_connector *connector, int mode)
772 : {
773 0 : struct drm_encoder *encoder = connector->encoder;
774 0 : struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
775 : int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF;
776 :
777 0 : if (mode == connector->dpms)
778 0 : return 0;
779 :
780 : old_dpms = connector->dpms;
781 0 : connector->dpms = mode;
782 :
783 0 : if (encoder)
784 0 : encoder_dpms = drm_helper_choose_encoder_dpms(encoder);
785 :
786 : /* from off to on, do crtc then encoder */
787 0 : if (mode < old_dpms) {
788 0 : if (crtc) {
789 0 : const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
790 0 : if (crtc_funcs->dpms)
791 0 : (*crtc_funcs->dpms) (crtc,
792 0 : drm_helper_choose_crtc_dpms(crtc));
793 0 : }
794 0 : if (encoder)
795 0 : drm_helper_encoder_dpms(encoder, encoder_dpms);
796 : }
797 :
798 : /* from on to off, do encoder then crtc */
799 0 : if (mode > old_dpms) {
800 0 : if (encoder)
801 0 : drm_helper_encoder_dpms(encoder, encoder_dpms);
802 0 : if (crtc) {
803 0 : const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
804 0 : if (crtc_funcs->dpms)
805 0 : (*crtc_funcs->dpms) (crtc,
806 0 : drm_helper_choose_crtc_dpms(crtc));
807 0 : }
808 : }
809 :
810 0 : return 0;
811 0 : }
812 : EXPORT_SYMBOL(drm_helper_connector_dpms);
813 :
814 : /**
815 : * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
816 : * @fb: drm_framebuffer object to fill out
817 : * @mode_cmd: metadata from the userspace fb creation request
818 : *
819 : * This helper can be used in a drivers fb_create callback to pre-fill the fb's
820 : * metadata fields.
821 : */
822 0 : void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
823 : struct drm_mode_fb_cmd2 *mode_cmd)
824 : {
825 : int i;
826 :
827 0 : fb->width = mode_cmd->width;
828 0 : fb->height = mode_cmd->height;
829 0 : for (i = 0; i < 4; i++) {
830 0 : fb->pitches[i] = mode_cmd->pitches[i];
831 0 : fb->offsets[i] = mode_cmd->offsets[i];
832 0 : fb->modifier[i] = mode_cmd->modifier[i];
833 : }
834 0 : drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
835 0 : &fb->bits_per_pixel);
836 0 : fb->pixel_format = mode_cmd->pixel_format;
837 0 : fb->flags = mode_cmd->flags;
838 0 : }
839 : EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
840 :
841 : /**
842 : * drm_helper_resume_force_mode - force-restore mode setting configuration
843 : * @dev: drm_device which should be restored
844 : *
845 : * Drivers which use the mode setting helpers can use this function to
846 : * force-restore the mode setting configuration e.g. on resume or when something
847 : * else might have trampled over the hw state (like some overzealous old BIOSen
848 : * tended to do).
849 : *
850 : * This helper doesn't provide a error return value since restoring the old
851 : * config should never fail due to resource allocation issues since the driver
852 : * has successfully set the restored configuration already. Hence this should
853 : * boil down to the equivalent of a few dpms on calls, which also don't provide
854 : * an error code.
855 : *
856 : * Drivers where simply restoring an old configuration again might fail (e.g.
857 : * due to slight differences in allocating shared resources when the
858 : * configuration is restored in a different order than when userspace set it up)
859 : * need to use their own restore logic.
860 : */
861 0 : void drm_helper_resume_force_mode(struct drm_device *dev)
862 : {
863 : struct drm_crtc *crtc;
864 : struct drm_encoder *encoder;
865 : const struct drm_crtc_helper_funcs *crtc_funcs;
866 : int encoder_dpms;
867 : bool ret;
868 :
869 0 : drm_modeset_lock_all(dev);
870 0 : drm_for_each_crtc(crtc, dev) {
871 :
872 0 : if (!crtc->enabled)
873 : continue;
874 :
875 0 : ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
876 0 : crtc->x, crtc->y, crtc->primary->fb);
877 :
878 : /* Restoring the old config should never fail! */
879 0 : if (ret == false)
880 0 : DRM_ERROR("failed to set mode on crtc %p\n", crtc);
881 :
882 : /* Turn off outputs that were already powered off */
883 0 : if (drm_helper_choose_crtc_dpms(crtc)) {
884 0 : drm_for_each_encoder(encoder, dev) {
885 :
886 0 : if(encoder->crtc != crtc)
887 : continue;
888 :
889 0 : encoder_dpms = drm_helper_choose_encoder_dpms(
890 : encoder);
891 :
892 0 : drm_helper_encoder_dpms(encoder, encoder_dpms);
893 0 : }
894 :
895 0 : crtc_funcs = crtc->helper_private;
896 0 : if (crtc_funcs->dpms)
897 0 : (*crtc_funcs->dpms) (crtc,
898 0 : drm_helper_choose_crtc_dpms(crtc));
899 : }
900 : }
901 :
902 : /* disable the unused connectors while restoring the modesetting */
903 0 : __drm_helper_disable_unused_functions(dev);
904 0 : drm_modeset_unlock_all(dev);
905 0 : }
906 : EXPORT_SYMBOL(drm_helper_resume_force_mode);
907 :
908 : /**
909 : * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
910 : * @crtc: DRM CRTC
911 : * @mode: DRM display mode which userspace requested
912 : * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
913 : * @x: x offset of the CRTC scanout area on the underlying framebuffer
914 : * @y: y offset of the CRTC scanout area on the underlying framebuffer
915 : * @old_fb: previous framebuffer
916 : *
917 : * This function implements a callback useable as the ->mode_set callback
918 : * required by the crtc helpers. Besides the atomic plane helper functions for
919 : * the primary plane the driver must also provide the ->mode_set_nofb callback
920 : * to set up the crtc.
921 : *
922 : * This is a transitional helper useful for converting drivers to the atomic
923 : * interfaces.
924 : */
925 0 : int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
926 : struct drm_display_mode *adjusted_mode, int x, int y,
927 : struct drm_framebuffer *old_fb)
928 : {
929 : struct drm_crtc_state *crtc_state;
930 0 : const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
931 : int ret;
932 :
933 0 : if (crtc->funcs->atomic_duplicate_state)
934 0 : crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
935 : else {
936 0 : if (!crtc->state)
937 0 : drm_atomic_helper_crtc_reset(crtc);
938 :
939 0 : crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc);
940 : }
941 :
942 0 : if (!crtc_state)
943 0 : return -ENOMEM;
944 :
945 0 : crtc_state->planes_changed = true;
946 0 : crtc_state->mode_changed = true;
947 0 : ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
948 0 : if (ret)
949 : goto out;
950 0 : drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
951 :
952 0 : if (crtc_funcs->atomic_check) {
953 0 : ret = crtc_funcs->atomic_check(crtc, crtc_state);
954 0 : if (ret)
955 : goto out;
956 : }
957 :
958 0 : swap(crtc->state, crtc_state);
959 :
960 0 : crtc_funcs->mode_set_nofb(crtc);
961 :
962 0 : ret = drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
963 :
964 : out:
965 0 : if (crtc_state) {
966 0 : if (crtc->funcs->atomic_destroy_state)
967 0 : crtc->funcs->atomic_destroy_state(crtc, crtc_state);
968 : else
969 0 : drm_atomic_helper_crtc_destroy_state(crtc, crtc_state);
970 : }
971 :
972 0 : return ret;
973 0 : }
974 : EXPORT_SYMBOL(drm_helper_crtc_mode_set);
975 :
976 : /**
977 : * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
978 : * @crtc: DRM CRTC
979 : * @x: x offset of the CRTC scanout area on the underlying framebuffer
980 : * @y: y offset of the CRTC scanout area on the underlying framebuffer
981 : * @old_fb: previous framebuffer
982 : *
983 : * This function implements a callback useable as the ->mode_set_base used
984 : * required by the crtc helpers. The driver must provide the atomic plane helper
985 : * functions for the primary plane.
986 : *
987 : * This is a transitional helper useful for converting drivers to the atomic
988 : * interfaces.
989 : */
990 0 : int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
991 : struct drm_framebuffer *old_fb)
992 : {
993 : struct drm_plane_state *plane_state;
994 0 : struct drm_plane *plane = crtc->primary;
995 :
996 0 : if (plane->funcs->atomic_duplicate_state)
997 0 : plane_state = plane->funcs->atomic_duplicate_state(plane);
998 0 : else if (plane->state)
999 0 : plane_state = drm_atomic_helper_plane_duplicate_state(plane);
1000 : else
1001 0 : plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
1002 0 : if (!plane_state)
1003 0 : return -ENOMEM;
1004 0 : plane_state->plane = plane;
1005 :
1006 0 : plane_state->crtc = crtc;
1007 0 : drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
1008 0 : plane_state->crtc_x = 0;
1009 0 : plane_state->crtc_y = 0;
1010 0 : plane_state->crtc_h = crtc->mode.vdisplay;
1011 0 : plane_state->crtc_w = crtc->mode.hdisplay;
1012 0 : plane_state->src_x = x << 16;
1013 0 : plane_state->src_y = y << 16;
1014 0 : plane_state->src_h = crtc->mode.vdisplay << 16;
1015 0 : plane_state->src_w = crtc->mode.hdisplay << 16;
1016 :
1017 0 : return drm_plane_helper_commit(plane, plane_state, old_fb);
1018 0 : }
1019 : EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
|