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