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