OSDN Git Service

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