aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc_helper.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-11-07 17:05:41 -0500
committerDave Airlie <airlied@linux.ie>2008-12-29 02:47:23 -0500
commitf453ba0460742ad027ae0c4c7d61e62817b3e7ef (patch)
tree29e6ecacd6e8971aa62e1825d77f2c1876ac3eb2 /drivers/gpu/drm/drm_crtc_helper.c
parentde151cf67ce52ed2d88083daa5e60c7858947329 (diff)
DRM: add mode setting support
Add mode setting support to the DRM layer. This is a fairly big chunk of work that allows DRM drivers to provide full output control and configuration capabilities to userspace. It was motivated by several factors: - the fb layer's APIs aren't suited for anything but simple configurations - coordination between the fb layer, DRM layer, and various userspace drivers is poor to non-existent (radeonfb excepted) - user level mode setting drivers makes displaying panic & oops messages more difficult - suspend/resume of graphics state is possible in many more configurations with kernel level support This commit just adds the core DRM part of the mode setting APIs. Driver specific commits using these new structure and APIs will follow. Co-authors: Jesse Barnes <jbarnes@virtuousgeek.org>, Jakob Bornecrantz <jakob@tungstengraphics.com> Contributors: Alan Hourihane <alanh@tungstengraphics.com>, Maarten Maathuis <madman2003@gmail.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c822
1 files changed, 822 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
new file mode 100644
index 000000000000..887ed33b0694
--- /dev/null
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -0,0 +1,822 @@
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#include "drmP.h"
33#include "drm_crtc.h"
34#include "drm_crtc_helper.h"
35
36/*
37 * Detailed mode info for a standard 640x480@60Hz monitor
38 */
39static struct drm_display_mode std_mode[] = {
40 { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656,
41 752, 800, 0, 480, 490, 492, 525, 0,
42 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
43};
44
45/**
46 * drm_helper_probe_connector_modes - get complete set of display modes
47 * @dev: DRM device
48 * @maxX: max width for modes
49 * @maxY: max height for modes
50 *
51 * LOCKING:
52 * Caller must hold mode config lock.
53 *
54 * Based on @dev's mode_config layout, scan all the connectors and try to detect
55 * modes on them. Modes will first be added to the connector's probed_modes
56 * list, then culled (based on validity and the @maxX, @maxY parameters) and
57 * put into the normal modes list.
58 *
59 * Intended to be used either at bootup time or when major configuration
60 * changes have occurred.
61 *
62 * FIXME: take into account monitor limits
63 */
64void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
65 uint32_t maxX, uint32_t maxY)
66{
67 struct drm_device *dev = connector->dev;
68 struct drm_display_mode *mode, *t;
69 struct drm_connector_helper_funcs *connector_funcs =
70 connector->helper_private;
71 int ret;
72
73 DRM_DEBUG("%s\n", drm_get_connector_name(connector));
74 /* set all modes to the unverified state */
75 list_for_each_entry_safe(mode, t, &connector->modes, head)
76 mode->status = MODE_UNVERIFIED;
77
78 connector->status = connector->funcs->detect(connector);
79
80 if (connector->status == connector_status_disconnected) {
81 DRM_DEBUG("%s is disconnected\n",
82 drm_get_connector_name(connector));
83 /* TODO set EDID to NULL */
84 return;
85 }
86
87 ret = (*connector_funcs->get_modes)(connector);
88
89 if (ret) {
90 drm_mode_connector_list_update(connector);
91 }
92
93 if (maxX && maxY)
94 drm_mode_validate_size(dev, &connector->modes, maxX,
95 maxY, 0);
96 list_for_each_entry_safe(mode, t, &connector->modes, head) {
97 if (mode->status == MODE_OK)
98 mode->status = connector_funcs->mode_valid(connector,
99 mode);
100 }
101
102
103 drm_mode_prune_invalid(dev, &connector->modes, true);
104
105 if (list_empty(&connector->modes)) {
106 struct drm_display_mode *stdmode;
107
108 DRM_DEBUG("No valid modes on %s\n",
109 drm_get_connector_name(connector));
110
111 /* Should we do this here ???
112 * When no valid EDID modes are available we end up
113 * here and bailed in the past, now we add a standard
114 * 640x480@60Hz mode and carry on.
115 */
116 stdmode = drm_mode_duplicate(dev, &std_mode[0]);
117 drm_mode_probed_add(connector, stdmode);
118 drm_mode_list_concat(&connector->probed_modes,
119 &connector->modes);
120
121 DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
122 drm_get_connector_name(connector));
123 }
124
125 drm_mode_sort(&connector->modes);
126
127 DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector));
128 list_for_each_entry_safe(mode, t, &connector->modes, head) {
129 mode->vrefresh = drm_mode_vrefresh(mode);
130
131 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
132 drm_mode_debug_printmodeline(mode);
133 }
134}
135EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
136
137void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
138 uint32_t maxY)
139{
140 struct drm_connector *connector;
141
142 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
143 drm_helper_probe_single_connector_modes(connector, maxX, maxY);
144 }
145}
146EXPORT_SYMBOL(drm_helper_probe_connector_modes);
147
148
149/**
150 * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
151 * @crtc: CRTC to check
152 *
153 * LOCKING:
154 * Caller must hold mode config lock.
155 *
156 * Walk @crtc's DRM device's mode_config and see if it's in use.
157 *
158 * RETURNS:
159 * True if @crtc is part of the mode_config, false otherwise.
160 */
161bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
162{
163 struct drm_encoder *encoder;
164 struct drm_device *dev = crtc->dev;
165 /* FIXME: Locking around list access? */
166 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
167 if (encoder->crtc == crtc)
168 return true;
169 return false;
170}
171EXPORT_SYMBOL(drm_helper_crtc_in_use);
172
173/**
174 * drm_disable_unused_functions - disable unused objects
175 * @dev: DRM device
176 *
177 * LOCKING:
178 * Caller must hold mode config lock.
179 *
180 * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled
181 * by calling its dpms function, which should power it off.
182 */
183void drm_helper_disable_unused_functions(struct drm_device *dev)
184{
185 struct drm_encoder *encoder;
186 struct drm_encoder_helper_funcs *encoder_funcs;
187 struct drm_crtc *crtc;
188
189 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
190 encoder_funcs = encoder->helper_private;
191 if (!encoder->crtc)
192 (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
193 }
194
195 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
196 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
197 crtc->enabled = drm_helper_crtc_in_use(crtc);
198 if (!crtc->enabled) {
199 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
200 crtc->fb = NULL;
201 }
202 }
203}
204EXPORT_SYMBOL(drm_helper_disable_unused_functions);
205
206static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height)
207{
208 struct drm_display_mode *mode;
209
210 list_for_each_entry(mode, &connector->modes, head) {
211 if (drm_mode_width(mode) > width ||
212 drm_mode_height(mode) > height)
213 continue;
214 if (mode->type & DRM_MODE_TYPE_PREFERRED)
215 return mode;
216 }
217 return NULL;
218}
219
220static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
221{
222 bool enable;
223
224 if (strict) {
225 enable = connector->status == connector_status_connected;
226 } else {
227 enable = connector->status != connector_status_disconnected;
228 }
229 return enable;
230}
231
232static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
233{
234 bool any_enabled = false;
235 struct drm_connector *connector;
236 int i = 0;
237
238 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
239 enabled[i] = drm_connector_enabled(connector, true);
240 any_enabled |= enabled[i];
241 i++;
242 }
243
244 if (any_enabled)
245 return;
246
247 i = 0;
248 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
249 enabled[i] = drm_connector_enabled(connector, false);
250 i++;
251 }
252}
253
254static bool drm_target_preferred(struct drm_device *dev,
255 struct drm_display_mode **modes,
256 bool *enabled, int width, int height)
257{
258 struct drm_connector *connector;
259 int i = 0;
260
261 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
262
263 if (enabled[i] == false) {
264 i++;
265 continue;
266 }
267
268 modes[i] = drm_has_preferred_mode(connector, width, height);
269 if (!modes[i]) {
270 list_for_each_entry(modes[i], &connector->modes, head)
271 break;
272 }
273 i++;
274 }
275 return true;
276}
277
278static int drm_pick_crtcs(struct drm_device *dev,
279 struct drm_crtc **best_crtcs,
280 struct drm_display_mode **modes,
281 int n, int width, int height)
282{
283 int c, o;
284 struct drm_connector *connector;
285 struct drm_connector_helper_funcs *connector_funcs;
286 struct drm_encoder *encoder;
287 struct drm_crtc *best_crtc;
288 int my_score, best_score, score;
289 struct drm_crtc **crtcs, *crtc;
290
291 if (n == dev->mode_config.num_connector)
292 return 0;
293 c = 0;
294 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
295 if (c == n)
296 break;
297 c++;
298 }
299
300 best_crtcs[n] = NULL;
301 best_crtc = NULL;
302 best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height);
303 if (modes[n] == NULL)
304 return best_score;
305
306 crtcs = kmalloc(dev->mode_config.num_connector *
307 sizeof(struct drm_crtc *), GFP_KERNEL);
308 if (!crtcs)
309 return best_score;
310
311 my_score = 1;
312 if (connector->status == connector_status_connected)
313 my_score++;
314 if (drm_has_preferred_mode(connector, width, height))
315 my_score++;
316
317 connector_funcs = connector->helper_private;
318 encoder = connector_funcs->best_encoder(connector);
319 if (!encoder)
320 goto out;
321
322 connector->encoder = encoder;
323
324 /* select a crtc for this connector and then attempt to configure
325 remaining connectors */
326 c = 0;
327 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
328
329 if ((connector->encoder->possible_crtcs & (1 << c)) == 0) {
330 c++;
331 continue;
332 }
333
334 for (o = 0; o < n; o++)
335 if (best_crtcs[o] == crtc)
336 break;
337
338 if (o < n) {
339 /* ignore cloning for now */
340 c++;
341 continue;
342 }
343
344 crtcs[n] = crtc;
345 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *));
346 score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1,
347 width, height);
348 if (score > best_score) {
349 best_crtc = crtc;
350 best_score = score;
351 memcpy(best_crtcs, crtcs,
352 dev->mode_config.num_connector *
353 sizeof(struct drm_crtc *));
354 }
355 c++;
356 }
357out:
358 kfree(crtcs);
359 return best_score;
360}
361
362static void drm_setup_crtcs(struct drm_device *dev)
363{
364 struct drm_crtc **crtcs;
365 struct drm_display_mode **modes;
366 struct drm_encoder *encoder;
367 struct drm_connector *connector;
368 bool *enabled;
369 int width, height;
370 int i, ret;
371
372 width = dev->mode_config.max_width;
373 height = dev->mode_config.max_height;
374
375 /* clean out all the encoder/crtc combos */
376 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
377 encoder->crtc = NULL;
378 }
379
380 crtcs = kcalloc(dev->mode_config.num_connector,
381 sizeof(struct drm_crtc *), GFP_KERNEL);
382 modes = kcalloc(dev->mode_config.num_connector,
383 sizeof(struct drm_display_mode *), GFP_KERNEL);
384 enabled = kcalloc(dev->mode_config.num_connector,
385 sizeof(bool), GFP_KERNEL);
386
387 drm_enable_connectors(dev, enabled);
388
389 ret = drm_target_preferred(dev, modes, enabled, width, height);
390 if (!ret)
391 DRM_ERROR("Unable to find initial modes\n");
392
393 drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
394
395 i = 0;
396 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
397 struct drm_display_mode *mode = modes[i];
398 struct drm_crtc *crtc = crtcs[i];
399
400 if (connector->encoder == NULL) {
401 i++;
402 continue;
403 }
404
405 if (mode && crtc) {
406 crtc->desired_mode = mode;
407 connector->encoder->crtc = crtc;
408 } else
409 connector->encoder->crtc = NULL;
410 i++;
411 }
412
413 kfree(crtcs);
414 kfree(modes);
415 kfree(enabled);
416}
417/**
418 * drm_crtc_set_mode - set a mode
419 * @crtc: CRTC to program
420 * @mode: mode to use
421 * @x: width of mode
422 * @y: height of mode
423 *
424 * LOCKING:
425 * Caller must hold mode config lock.
426 *
427 * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance
428 * to fixup or reject the mode prior to trying to set it.
429 *
430 * RETURNS:
431 * True if the mode was set successfully, or false otherwise.
432 */
433bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
434 struct drm_display_mode *mode,
435 int x, int y)
436{
437 struct drm_device *dev = crtc->dev;
438 struct drm_display_mode *adjusted_mode, saved_mode;
439 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
440 struct drm_encoder_helper_funcs *encoder_funcs;
441 int saved_x, saved_y;
442 struct drm_encoder *encoder;
443 bool ret = true;
444
445 adjusted_mode = drm_mode_duplicate(dev, mode);
446
447 crtc->enabled = drm_helper_crtc_in_use(crtc);
448
449 if (!crtc->enabled)
450 return true;
451
452 saved_mode = crtc->mode;
453 saved_x = crtc->x;
454 saved_y = crtc->y;
455
456 /* Update crtc values up front so the driver can rely on them for mode
457 * setting.
458 */
459 crtc->mode = *mode;
460 crtc->x = x;
461 crtc->y = y;
462
463 if (drm_mode_equal(&saved_mode, &crtc->mode)) {
464 if (saved_x != crtc->x || saved_y != crtc->y) {
465 crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y);
466 goto done;
467 }
468 }
469
470 /* Pass our mode to the connectors and the CRTC to give them a chance to
471 * adjust it according to limitations or connector properties, and also
472 * a chance to reject the mode entirely.
473 */
474 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
475
476 if (encoder->crtc != crtc)
477 continue;
478 encoder_funcs = encoder->helper_private;
479 if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
480 adjusted_mode))) {
481 goto done;
482 }
483 }
484
485 if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
486 goto done;
487 }
488
489 /* Prepare the encoders and CRTCs before setting the mode. */
490 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
491
492 if (encoder->crtc != crtc)
493 continue;
494 encoder_funcs = encoder->helper_private;
495 /* Disable the encoders as the first thing we do. */
496 encoder_funcs->prepare(encoder);
497 }
498
499 crtc_funcs->prepare(crtc);
500
501 /* Set up the DPLL and any encoders state that needs to adjust or depend
502 * on the DPLL.
503 */
504 crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y);
505
506 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
507
508 if (encoder->crtc != crtc)
509 continue;
510
511 DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder),
512 mode->name, mode->base.id);
513 encoder_funcs = encoder->helper_private;
514 encoder_funcs->mode_set(encoder, mode, adjusted_mode);
515 }
516
517 /* Now enable the clocks, plane, pipe, and connectors that we set up. */
518 crtc_funcs->commit(crtc);
519
520 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
521
522 if (encoder->crtc != crtc)
523 continue;
524
525 encoder_funcs = encoder->helper_private;
526 encoder_funcs->commit(encoder);
527
528 }
529
530 /* XXX free adjustedmode */
531 drm_mode_destroy(dev, adjusted_mode);
532 /* FIXME: add subpixel order */
533done:
534 if (!ret) {
535 crtc->mode = saved_mode;
536 crtc->x = saved_x;
537 crtc->y = saved_y;
538 }
539
540 return ret;
541}
542EXPORT_SYMBOL(drm_crtc_helper_set_mode);
543
544
545/**
546 * drm_crtc_helper_set_config - set a new config from userspace
547 * @crtc: CRTC to setup
548 * @crtc_info: user provided configuration
549 * @new_mode: new mode to set
550 * @connector_set: set of connectors for the new config
551 * @fb: new framebuffer
552 *
553 * LOCKING:
554 * Caller must hold mode config lock.
555 *
556 * Setup a new configuration, provided by the user in @crtc_info, and enable
557 * it.
558 *
559 * RETURNS:
560 * Zero. (FIXME)
561 */
562int drm_crtc_helper_set_config(struct drm_mode_set *set)
563{
564 struct drm_device *dev;
565 struct drm_crtc **save_crtcs, *new_crtc;
566 struct drm_encoder **save_encoders, *new_encoder;
567 bool save_enabled;
568 bool changed = false;
569 bool flip_or_move = false;
570 struct drm_connector *connector;
571 int count = 0, ro, fail = 0;
572 struct drm_crtc_helper_funcs *crtc_funcs;
573 int ret = 0;
574
575 DRM_DEBUG("\n");
576
577 if (!set)
578 return -EINVAL;
579
580 if (!set->crtc)
581 return -EINVAL;
582
583 if (!set->crtc->helper_private)
584 return -EINVAL;
585
586 crtc_funcs = set->crtc->helper_private;
587
588 DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %d (x, y) (%i, %i)\n",
589 set->crtc, set->crtc->base.id, set->fb, set->connectors,
590 (int)set->num_connectors, set->x, set->y);
591
592 dev = set->crtc->dev;
593
594 /* save previous config */
595 save_enabled = set->crtc->enabled;
596
597 /* this is meant to be num_connector not num_crtc */
598 save_crtcs = kzalloc(dev->mode_config.num_connector *
599 sizeof(struct drm_crtc *), GFP_KERNEL);
600 if (!save_crtcs)
601 return -ENOMEM;
602
603 save_encoders = kzalloc(dev->mode_config.num_connector *
604 sizeof(struct drm_encoders *), GFP_KERNEL);
605 if (!save_encoders) {
606 kfree(save_crtcs);
607 return -ENOMEM;
608 }
609
610 /* We should be able to check here if the fb has the same properties
611 * and then just flip_or_move it */
612 if (set->crtc->fb != set->fb) {
613 /* if we have no fb then its a change not a flip */
614 if (set->crtc->fb == NULL)
615 changed = true;
616 else
617 flip_or_move = true;
618 }
619
620 if (set->x != set->crtc->x || set->y != set->crtc->y)
621 flip_or_move = true;
622
623 if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
624 DRM_DEBUG("modes are different\n");
625 drm_mode_debug_printmodeline(&set->crtc->mode);
626 drm_mode_debug_printmodeline(set->mode);
627 changed = true;
628 }
629
630 /* a) traverse passed in connector list and get encoders for them */
631 count = 0;
632 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
633 struct drm_connector_helper_funcs *connector_funcs =
634 connector->helper_private;
635 save_encoders[count++] = connector->encoder;
636 new_encoder = connector->encoder;
637 for (ro = 0; ro < set->num_connectors; ro++) {
638 if (set->connectors[ro] == connector) {
639 new_encoder = connector_funcs->best_encoder(connector);
640 /* if we can't get an encoder for a connector
641 we are setting now - then fail */
642 if (new_encoder == NULL)
643 /* don't break so fail path works correct */
644 fail = 1;
645 break;
646 }
647 }
648
649 if (new_encoder != connector->encoder) {
650 changed = true;
651 connector->encoder = new_encoder;
652 }
653 }
654
655 if (fail) {
656 ret = -EINVAL;
657 goto fail_no_encoder;
658 }
659
660 count = 0;
661 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
662 if (!connector->encoder)
663 continue;
664
665 save_crtcs[count++] = connector->encoder->crtc;
666
667 if (connector->encoder->crtc == set->crtc)
668 new_crtc = NULL;
669 else
670 new_crtc = connector->encoder->crtc;
671
672 for (ro = 0; ro < set->num_connectors; ro++) {
673 if (set->connectors[ro] == connector)
674 new_crtc = set->crtc;
675 }
676 if (new_crtc != connector->encoder->crtc) {
677 changed = true;
678 connector->encoder->crtc = new_crtc;
679 }
680 }
681
682 /* mode_set_base is not a required function */
683 if (flip_or_move && !crtc_funcs->mode_set_base)
684 changed = true;
685
686 if (changed) {
687 set->crtc->fb = set->fb;
688 set->crtc->enabled = (set->mode != NULL);
689 if (set->mode != NULL) {
690 DRM_DEBUG("attempting to set mode from userspace\n");
691 drm_mode_debug_printmodeline(set->mode);
692 if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
693 set->x, set->y)) {
694 ret = -EINVAL;
695 goto fail_set_mode;
696 }
697 /* TODO are these needed? */
698 set->crtc->desired_x = set->x;
699 set->crtc->desired_y = set->y;
700 set->crtc->desired_mode = set->mode;
701 }
702 drm_helper_disable_unused_functions(dev);
703 } else if (flip_or_move) {
704 if (set->crtc->fb != set->fb)
705 set->crtc->fb = set->fb;
706 crtc_funcs->mode_set_base(set->crtc, set->x, set->y);
707 }
708
709 kfree(save_encoders);
710 kfree(save_crtcs);
711 return 0;
712
713fail_set_mode:
714 set->crtc->enabled = save_enabled;
715 count = 0;
716 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
717 connector->encoder->crtc = save_crtcs[count++];
718fail_no_encoder:
719 kfree(save_crtcs);
720 count = 0;
721 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
722 connector->encoder = save_encoders[count++];
723 }
724 kfree(save_encoders);
725 return ret;
726}
727EXPORT_SYMBOL(drm_crtc_helper_set_config);
728
729bool drm_helper_plugged_event(struct drm_device *dev)
730{
731 DRM_DEBUG("\n");
732
733 drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
734 dev->mode_config.max_height);
735
736 drm_setup_crtcs(dev);
737
738 /* alert the driver fb layer */
739 dev->mode_config.funcs->fb_changed(dev);
740
741 /* FIXME: send hotplug event */
742 return true;
743}
744/**
745 * drm_initial_config - setup a sane initial connector configuration
746 * @dev: DRM device
747 * @can_grow: this configuration is growable
748 *
749 * LOCKING:
750 * Called at init time, must take mode config lock.
751 *
752 * Scan the CRTCs and connectors and try to put together an initial setup.
753 * At the moment, this is a cloned configuration across all heads with
754 * a new framebuffer object as the backing store.
755 *
756 * RETURNS:
757 * Zero if everything went ok, nonzero otherwise.
758 */
759bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
760{
761 int ret = false;
762
763 drm_helper_plugged_event(dev);
764 return ret;
765}
766EXPORT_SYMBOL(drm_helper_initial_config);
767
768/**
769 * drm_hotplug_stage_two
770 * @dev DRM device
771 * @connector hotpluged connector
772 *
773 * LOCKING.
774 * Caller must hold mode config lock, function might grab struct lock.
775 *
776 * Stage two of a hotplug.
777 *
778 * RETURNS:
779 * Zero on success, errno on failure.
780 */
781int drm_helper_hotplug_stage_two(struct drm_device *dev)
782{
783 dev->mode_config.hotplug_counter++;
784
785 drm_helper_plugged_event(dev);
786
787 return 0;
788}
789EXPORT_SYMBOL(drm_helper_hotplug_stage_two);
790
791int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
792 struct drm_mode_fb_cmd *mode_cmd)
793{
794 fb->width = mode_cmd->width;
795 fb->height = mode_cmd->height;
796 fb->pitch = mode_cmd->pitch;
797 fb->bits_per_pixel = mode_cmd->bpp;
798 fb->depth = mode_cmd->depth;
799
800 return 0;
801}
802EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
803
804int drm_helper_resume_force_mode(struct drm_device *dev)
805{
806 struct drm_crtc *crtc;
807 int ret;
808
809 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
810
811 if (!crtc->enabled)
812 continue;
813
814 ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
815 crtc->y);
816
817 if (ret == false)
818 DRM_ERROR("failed to set mode on crtc %p\n", crtc);
819 }
820 return 0;
821}
822EXPORT_SYMBOL(drm_helper_resume_force_mode);