drm/kms: fix kms helper license + Kconfig
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_fb_helper.c
1 /*
2  * Copyright (c) 2006-2009 Red Hat Inc.
3  * Copyright (c) 2006-2008 Intel Corporation
4  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
5  *
6  * DRM framebuffer helper functions
7  *
8  * Permission to use, copy, modify, distribute, and sell this software and its
9  * documentation for any purpose is hereby granted without fee, provided that
10  * the above copyright notice appear in all copies and that both that copyright
11  * notice and this permission notice appear in supporting documentation, and
12  * that the name of the copyright holders not be used in advertising or
13  * publicity pertaining to distribution of the software without specific,
14  * written prior permission.  The copyright holders make no representations
15  * about the suitability of this software for any purpose.  It is provided "as
16  * is" without express or implied warranty.
17  *
18  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24  * OF THIS SOFTWARE.
25  *
26  * Authors:
27  *      Dave Airlie <airlied@linux.ie>
28  *      Jesse Barnes <jesse.barnes@intel.com>
29  */
30 #include <linux/sysrq.h>
31 #include <linux/fb.h>
32 #include "drmP.h"
33 #include "drm_crtc.h"
34 #include "drm_fb_helper.h"
35 #include "drm_crtc_helper.h"
36
37 MODULE_AUTHOR("David Airlie, Jesse Barnes");
38 MODULE_DESCRIPTION("DRM KMS helper");
39 MODULE_LICENSE("GPL and additional rights");
40
41 static LIST_HEAD(kernel_fb_helper_list);
42
43 bool drm_fb_helper_force_kernel_mode(void)
44 {
45         int i = 0;
46         bool ret, error = false;
47         struct drm_fb_helper *helper;
48
49         if (list_empty(&kernel_fb_helper_list))
50                 return false;
51
52         list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
53                 for (i = 0; i < helper->crtc_count; i++) {
54                         struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
55                         ret = drm_crtc_helper_set_config(mode_set);
56                         if (ret)
57                                 error = true;
58                 }
59         }
60         return error;
61 }
62
63 int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
64                         void *panic_str)
65 {
66         DRM_ERROR("panic occurred, switching back to text console\n");
67         return drm_fb_helper_force_kernel_mode();
68         return 0;
69 }
70 EXPORT_SYMBOL(drm_fb_helper_panic);
71
72 static struct notifier_block paniced = {
73         .notifier_call = drm_fb_helper_panic,
74 };
75
76 /**
77  * drm_fb_helper_restore - restore the framebuffer console (kernel) config
78  *
79  * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
80  */
81 void drm_fb_helper_restore(void)
82 {
83         bool ret;
84         ret = drm_fb_helper_force_kernel_mode();
85         if (ret == true)
86                 DRM_ERROR("Failed to restore crtc configuration\n");
87 }
88 EXPORT_SYMBOL(drm_fb_helper_restore);
89
90 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
91 {
92         drm_fb_helper_restore();
93 }
94 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
95
96 static void drm_fb_helper_sysrq(int dummy1, struct tty_struct *dummy3)
97 {
98         schedule_work(&drm_fb_helper_restore_work);
99 }
100
101 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
102         .handler = drm_fb_helper_sysrq,
103         .help_msg = "force-fb(V)",
104         .action_msg = "Restore framebuffer console",
105 };
106
107 static void drm_fb_helper_on(struct fb_info *info)
108 {
109         struct drm_fb_helper *fb_helper = info->par;
110         struct drm_device *dev = fb_helper->dev;
111         struct drm_crtc *crtc;
112         struct drm_encoder *encoder;
113         int i;
114
115         /*
116          * For each CRTC in this fb, turn the crtc on then,
117          * find all associated encoders and turn them on.
118          */
119         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
120                 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
121
122                 for (i = 0; i < fb_helper->crtc_count; i++) {
123                         if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
124                                 break;
125                 }
126
127                 mutex_lock(&dev->mode_config.mutex);
128                 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
129                 mutex_unlock(&dev->mode_config.mutex);
130
131                 /* Found a CRTC on this fb, now find encoders */
132                 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
133                         if (encoder->crtc == crtc) {
134                                 struct drm_encoder_helper_funcs *encoder_funcs;
135
136                                 encoder_funcs = encoder->helper_private;
137                                 mutex_lock(&dev->mode_config.mutex);
138                                 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
139                                 mutex_unlock(&dev->mode_config.mutex);
140                         }
141                 }
142         }
143 }
144
145 static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
146 {
147         struct drm_fb_helper *fb_helper = info->par;
148         struct drm_device *dev = fb_helper->dev;
149         struct drm_crtc *crtc;
150         struct drm_encoder *encoder;
151         int i;
152
153         /*
154          * For each CRTC in this fb, find all associated encoders
155          * and turn them off, then turn off the CRTC.
156          */
157         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
158                 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
159
160                 for (i = 0; i < fb_helper->crtc_count; i++) {
161                         if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
162                                 break;
163                 }
164
165                 /* Found a CRTC on this fb, now find encoders */
166                 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
167                         if (encoder->crtc == crtc) {
168                                 struct drm_encoder_helper_funcs *encoder_funcs;
169
170                                 encoder_funcs = encoder->helper_private;
171                                 mutex_lock(&dev->mode_config.mutex);
172                                 encoder_funcs->dpms(encoder, dpms_mode);
173                                 mutex_unlock(&dev->mode_config.mutex);
174                         }
175                 }
176                 if (dpms_mode == DRM_MODE_DPMS_OFF) {
177                         mutex_lock(&dev->mode_config.mutex);
178                         crtc_funcs->dpms(crtc, dpms_mode);
179                         mutex_unlock(&dev->mode_config.mutex);
180                 }
181         }
182 }
183
184 int drm_fb_helper_blank(int blank, struct fb_info *info)
185 {
186         switch (blank) {
187         case FB_BLANK_UNBLANK:
188                 drm_fb_helper_on(info);
189                 break;
190         case FB_BLANK_NORMAL:
191                 drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
192                 break;
193         case FB_BLANK_HSYNC_SUSPEND:
194                 drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
195                 break;
196         case FB_BLANK_VSYNC_SUSPEND:
197                 drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
198                 break;
199         case FB_BLANK_POWERDOWN:
200                 drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
201                 break;
202         }
203         return 0;
204 }
205 EXPORT_SYMBOL(drm_fb_helper_blank);
206
207 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
208 {
209         int i;
210
211         for (i = 0; i < helper->crtc_count; i++)
212                 kfree(helper->crtc_info[i].mode_set.connectors);
213         kfree(helper->crtc_info);
214 }
215
216 int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
217 {
218         struct drm_device *dev = helper->dev;
219         struct drm_crtc *crtc;
220         int ret = 0;
221         int i;
222
223         helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
224         if (!helper->crtc_info)
225                 return -ENOMEM;
226
227         helper->crtc_count = crtc_count;
228
229         for (i = 0; i < crtc_count; i++) {
230                 helper->crtc_info[i].mode_set.connectors =
231                         kcalloc(max_conn_count,
232                                 sizeof(struct drm_connector *),
233                                 GFP_KERNEL);
234
235                 if (!helper->crtc_info[i].mode_set.connectors) {
236                         ret = -ENOMEM;
237                         goto out_free;
238                 }
239                 helper->crtc_info[i].mode_set.num_connectors = 0;
240         }
241
242         i = 0;
243         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
244                 helper->crtc_info[i].crtc_id = crtc->base.id;
245                 helper->crtc_info[i].mode_set.crtc = crtc;
246                 i++;
247         }
248         helper->conn_limit = max_conn_count;
249         return 0;
250 out_free:
251         drm_fb_helper_crtc_free(helper);
252         return -ENOMEM;
253 }
254 EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
255
256 int drm_fb_helper_setcolreg(unsigned regno,
257                             unsigned red,
258                             unsigned green,
259                             unsigned blue,
260                             unsigned transp,
261                             struct fb_info *info)
262 {
263         struct drm_fb_helper *fb_helper = info->par;
264         struct drm_device *dev = fb_helper->dev;
265         struct drm_crtc *crtc;
266         int i;
267
268         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
269                 struct drm_framebuffer *fb = fb_helper->fb;
270
271                 for (i = 0; i < fb_helper->crtc_count; i++) {
272                         if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
273                                 break;
274                 }
275                 if (i == fb_helper->crtc_count)
276                         continue;
277
278                 if (regno > 255)
279                         return 1;
280
281                 if (fb->depth == 8) {
282                         fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
283                         return 0;
284                 }
285
286                 if (regno < 16) {
287                         switch (fb->depth) {
288                         case 15:
289                                 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
290                                         ((green & 0xf800) >>  6) |
291                                         ((blue & 0xf800) >> 11);
292                                 break;
293                         case 16:
294                                 fb->pseudo_palette[regno] = (red & 0xf800) |
295                                         ((green & 0xfc00) >>  5) |
296                                         ((blue  & 0xf800) >> 11);
297                                 break;
298                         case 24:
299                         case 32:
300                                 fb->pseudo_palette[regno] =
301                                         (((red >> 8) & 0xff) << info->var.red.offset) |
302                                         (((green >> 8) & 0xff) << info->var.green.offset) |
303                                         (((blue >> 8) & 0xff) << info->var.blue.offset);
304                                 break;
305                         }
306                 }
307         }
308         return 0;
309 }
310 EXPORT_SYMBOL(drm_fb_helper_setcolreg);
311
312 int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
313                             struct fb_info *info)
314 {
315         struct drm_fb_helper *fb_helper = info->par;
316         struct drm_framebuffer *fb = fb_helper->fb;
317         int depth;
318
319         if (var->pixclock == -1 || !var->pixclock)
320                 return -EINVAL;
321
322         /* Need to resize the fb object !!! */
323         if (var->xres > fb->width || var->yres > fb->height) {
324                 DRM_ERROR("Requested width/height is greater than current fb "
325                            "object %dx%d > %dx%d\n", var->xres, var->yres,
326                            fb->width, fb->height);
327                 DRM_ERROR("Need resizing code.\n");
328                 return -EINVAL;
329         }
330
331         switch (var->bits_per_pixel) {
332         case 16:
333                 depth = (var->green.length == 6) ? 16 : 15;
334                 break;
335         case 32:
336                 depth = (var->transp.length > 0) ? 32 : 24;
337                 break;
338         default:
339                 depth = var->bits_per_pixel;
340                 break;
341         }
342
343         switch (depth) {
344         case 8:
345                 var->red.offset = 0;
346                 var->green.offset = 0;
347                 var->blue.offset = 0;
348                 var->red.length = 8;
349                 var->green.length = 8;
350                 var->blue.length = 8;
351                 var->transp.length = 0;
352                 var->transp.offset = 0;
353                 break;
354         case 15:
355                 var->red.offset = 10;
356                 var->green.offset = 5;
357                 var->blue.offset = 0;
358                 var->red.length = 5;
359                 var->green.length = 5;
360                 var->blue.length = 5;
361                 var->transp.length = 1;
362                 var->transp.offset = 15;
363                 break;
364         case 16:
365                 var->red.offset = 11;
366                 var->green.offset = 5;
367                 var->blue.offset = 0;
368                 var->red.length = 5;
369                 var->green.length = 6;
370                 var->blue.length = 5;
371                 var->transp.length = 0;
372                 var->transp.offset = 0;
373                 break;
374         case 24:
375                 var->red.offset = 16;
376                 var->green.offset = 8;
377                 var->blue.offset = 0;
378                 var->red.length = 8;
379                 var->green.length = 8;
380                 var->blue.length = 8;
381                 var->transp.length = 0;
382                 var->transp.offset = 0;
383                 break;
384         case 32:
385                 var->red.offset = 16;
386                 var->green.offset = 8;
387                 var->blue.offset = 0;
388                 var->red.length = 8;
389                 var->green.length = 8;
390                 var->blue.length = 8;
391                 var->transp.length = 8;
392                 var->transp.offset = 24;
393                 break;
394         default:
395                 return -EINVAL;
396         }
397         return 0;
398 }
399 EXPORT_SYMBOL(drm_fb_helper_check_var);
400
401 /* this will let fbcon do the mode init */
402 int drm_fb_helper_set_par(struct fb_info *info)
403 {
404         struct drm_fb_helper *fb_helper = info->par;
405         struct drm_device *dev = fb_helper->dev;
406         struct fb_var_screeninfo *var = &info->var;
407         struct drm_crtc *crtc;
408         int ret;
409         int i;
410
411         if (var->pixclock != -1) {
412                 DRM_ERROR("PIXEL CLCOK SET\n");
413                 return -EINVAL;
414         }
415
416         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
417
418                 for (i = 0; i < fb_helper->crtc_count; i++) {
419                         if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
420                                 break;
421                 }
422                 if (i == fb_helper->crtc_count)
423                         continue;
424
425                 if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
426                         mutex_lock(&dev->mode_config.mutex);
427                         ret = crtc->funcs->set_config(&fb_helper->crtc_info->mode_set);
428                         mutex_unlock(&dev->mode_config.mutex);
429                         if (ret)
430                                 return ret;
431                 }
432         }
433         return 0;
434 }
435 EXPORT_SYMBOL(drm_fb_helper_set_par);
436
437 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
438                               struct fb_info *info)
439 {
440         struct drm_fb_helper *fb_helper = info->par;
441         struct drm_device *dev = fb_helper->dev;
442         struct drm_mode_set *modeset;
443         struct drm_crtc *crtc;
444         int ret = 0;
445         int i;
446
447         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
448                 for (i = 0; i < fb_helper->crtc_count; i++) {
449                         if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
450                                 break;
451                 }
452
453                 if (i == fb_helper->crtc_count)
454                         continue;
455
456                 modeset = &fb_helper->crtc_info[i].mode_set;
457
458                 modeset->x = var->xoffset;
459                 modeset->y = var->yoffset;
460
461                 if (modeset->num_connectors) {
462                         mutex_lock(&dev->mode_config.mutex);
463                         ret = crtc->funcs->set_config(modeset);
464                         mutex_unlock(&dev->mode_config.mutex);
465                         if (!ret) {
466                                 info->var.xoffset = var->xoffset;
467                                 info->var.yoffset = var->yoffset;
468                         }
469                 }
470         }
471         return ret;
472 }
473 EXPORT_SYMBOL(drm_fb_helper_pan_display);
474
475 int drm_fb_helper_single_fb_probe(struct drm_device *dev,
476                                   int (*fb_create)(struct drm_device *dev,
477                                                    uint32_t fb_width,
478                                                    uint32_t fb_height,
479                                                    uint32_t surface_width,
480                                                    uint32_t surface_height,
481                                                    struct drm_framebuffer **fb_ptr))
482 {
483         struct drm_crtc *crtc;
484         struct drm_connector *connector;
485         unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
486         unsigned int surface_width = 0, surface_height = 0;
487         int new_fb = 0;
488         int crtc_count = 0;
489         int ret, i, conn_count = 0;
490         struct fb_info *info;
491         struct drm_framebuffer *fb;
492         struct drm_mode_set *modeset = NULL;
493         struct drm_fb_helper *fb_helper;
494
495         /* first up get a count of crtcs now in use and new min/maxes width/heights */
496         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
497                 if (drm_helper_crtc_in_use(crtc)) {
498                         if (crtc->desired_mode) {
499                                 if (crtc->desired_mode->hdisplay < fb_width)
500                                         fb_width = crtc->desired_mode->hdisplay;
501
502                                 if (crtc->desired_mode->vdisplay < fb_height)
503                                         fb_height = crtc->desired_mode->vdisplay;
504
505                                 if (crtc->desired_mode->hdisplay > surface_width)
506                                         surface_width = crtc->desired_mode->hdisplay;
507
508                                 if (crtc->desired_mode->vdisplay > surface_height)
509                                         surface_height = crtc->desired_mode->vdisplay;
510                         }
511                         crtc_count++;
512                 }
513         }
514
515         if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
516                 /* hmm everyone went away - assume VGA cable just fell out
517                    and will come back later. */
518                 return 0;
519         }
520
521         /* do we have an fb already? */
522         if (list_empty(&dev->mode_config.fb_kernel_list)) {
523                 ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
524                                    surface_height, &fb);
525                 if (ret)
526                         return -EINVAL;
527                 new_fb = 1;
528         } else {
529                 fb = list_first_entry(&dev->mode_config.fb_kernel_list,
530                                       struct drm_framebuffer, filp_head);
531
532                 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
533                    As really we can't resize an fbdev that is in the wild currently due to fbdev
534                    not really being designed for the lower layers moving stuff around under it.
535                    - so in the grand style of things - punt. */
536                 if ((fb->width < surface_width) ||
537                     (fb->height < surface_height)) {
538                         DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
539                         return -EINVAL;
540                 }
541         }
542
543         info = fb->fbdev;
544         fb_helper = info->par;
545
546         crtc_count = 0;
547         /* okay we need to setup new connector sets in the crtcs */
548         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
549                 modeset = &fb_helper->crtc_info[crtc_count].mode_set;
550                 modeset->fb = fb;
551                 conn_count = 0;
552                 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
553                         if (connector->encoder)
554                                 if (connector->encoder->crtc == modeset->crtc) {
555                                         modeset->connectors[conn_count] = connector;
556                                         conn_count++;
557                                         if (conn_count > fb_helper->conn_limit)
558                                                 BUG();
559                                 }
560                 }
561
562                 for (i = conn_count; i < fb_helper->conn_limit; i++)
563                         modeset->connectors[i] = NULL;
564
565                 modeset->crtc = crtc;
566                 crtc_count++;
567
568                 modeset->num_connectors = conn_count;
569                 if (modeset->crtc->desired_mode) {
570                         if (modeset->mode)
571                                 drm_mode_destroy(dev, modeset->mode);
572                         modeset->mode = drm_mode_duplicate(dev,
573                                                            modeset->crtc->desired_mode);
574                 }
575         }
576         fb_helper->crtc_count = crtc_count;
577         fb_helper->fb = fb;
578
579         if (new_fb) {
580                 info->var.pixclock = -1;
581                 if (register_framebuffer(info) < 0)
582                         return -EINVAL;
583         } else {
584                 drm_fb_helper_set_par(info);
585         }
586         printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
587                info->fix.id);
588
589         /* Switch back to kernel console on panic */
590         /* multi card linked list maybe */
591         if (list_empty(&kernel_fb_helper_list)) {
592                 printk(KERN_INFO "registered panic notifier\n");
593                 atomic_notifier_chain_register(&panic_notifier_list,
594                                                &paniced);
595                 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
596         }
597         list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
598         return 0;
599 }
600 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
601
602 void drm_fb_helper_free(struct drm_fb_helper *helper)
603 {
604         list_del(&helper->kernel_fb_list);
605         if (list_empty(&kernel_fb_helper_list)) {
606                 printk(KERN_INFO "unregistered panic notifier\n");
607                 atomic_notifier_chain_unregister(&panic_notifier_list,
608                                                  &paniced);
609                 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
610         }
611         drm_fb_helper_crtc_free(helper);
612 }
613 EXPORT_SYMBOL(drm_fb_helper_free);
614
615 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch)
616 {
617         info->fix.type = FB_TYPE_PACKED_PIXELS;
618         info->fix.visual = FB_VISUAL_TRUECOLOR;
619         info->fix.type_aux = 0;
620         info->fix.xpanstep = 1; /* doing it in hw */
621         info->fix.ypanstep = 1; /* doing it in hw */
622         info->fix.ywrapstep = 0;
623         info->fix.accel = FB_ACCEL_NONE;
624         info->fix.type_aux = 0;
625
626         info->fix.line_length = pitch;
627         return;
628 }
629 EXPORT_SYMBOL(drm_fb_helper_fill_fix);
630
631 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
632                             uint32_t fb_width, uint32_t fb_height)
633 {
634         info->pseudo_palette = fb->pseudo_palette;
635         info->var.xres_virtual = fb->width;
636         info->var.yres_virtual = fb->height;
637         info->var.bits_per_pixel = fb->bits_per_pixel;
638         info->var.xoffset = 0;
639         info->var.yoffset = 0;
640         info->var.activate = FB_ACTIVATE_NOW;
641         info->var.height = -1;
642         info->var.width = -1;
643
644         switch (fb->depth) {
645         case 8:
646                 info->var.red.offset = 0;
647                 info->var.green.offset = 0;
648                 info->var.blue.offset = 0;
649                 info->var.red.length = 8; /* 8bit DAC */
650                 info->var.green.length = 8;
651                 info->var.blue.length = 8;
652                 info->var.transp.offset = 0;
653                 info->var.transp.length = 0;
654                 break;
655         case 15:
656                 info->var.red.offset = 10;
657                 info->var.green.offset = 5;
658                 info->var.blue.offset = 0;
659                 info->var.red.length = 5;
660                 info->var.green.length = 5;
661                 info->var.blue.length = 5;
662                 info->var.transp.offset = 15;
663                 info->var.transp.length = 1;
664                 break;
665         case 16:
666                 info->var.red.offset = 11;
667                 info->var.green.offset = 5;
668                 info->var.blue.offset = 0;
669                 info->var.red.length = 5;
670                 info->var.green.length = 6;
671                 info->var.blue.length = 5;
672                 info->var.transp.offset = 0;
673                 break;
674         case 24:
675                 info->var.red.offset = 16;
676                 info->var.green.offset = 8;
677                 info->var.blue.offset = 0;
678                 info->var.red.length = 8;
679                 info->var.green.length = 8;
680                 info->var.blue.length = 8;
681                 info->var.transp.offset = 0;
682                 info->var.transp.length = 0;
683                 break;
684         case 32:
685                 info->var.red.offset = 16;
686                 info->var.green.offset = 8;
687                 info->var.blue.offset = 0;
688                 info->var.red.length = 8;
689                 info->var.green.length = 8;
690                 info->var.blue.length = 8;
691                 info->var.transp.offset = 24;
692                 info->var.transp.length = 8;
693                 break;
694         default:
695                 break;
696         }
697
698         info->var.xres = fb_width;
699         info->var.yres = fb_height;
700 }
701 EXPORT_SYMBOL(drm_fb_helper_fill_var);