2 * Copyright (c) 2006-2009 Red Hat Inc.
3 * Copyright (c) 2006-2008 Intel Corporation
4 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
6 * DRM framebuffer helper functions
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.
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
27 * Dave Airlie <airlied@linux.ie>
28 * Jesse Barnes <jesse.barnes@intel.com>
30 #include <linux/sysrq.h>
34 #include "drm_fb_helper.h"
35 #include "drm_crtc_helper.h"
37 MODULE_AUTHOR("David Airlie, Jesse Barnes");
38 MODULE_DESCRIPTION("DRM KMS helper");
39 MODULE_LICENSE("GPL and additional rights");
41 static LIST_HEAD(kernel_fb_helper_list
);
43 int drm_fb_helper_add_connector(struct drm_connector
*connector
)
45 connector
->fb_helper_private
= kzalloc(sizeof(struct drm_fb_helper_connector
), GFP_KERNEL
);
46 if (!connector
->fb_helper_private
)
51 EXPORT_SYMBOL(drm_fb_helper_add_connector
);
53 static int my_atoi(const char *name
)
60 val
= 10*val
+(*name
-'0');
69 * drm_fb_helper_connector_parse_command_line - parse command line for connector
70 * @connector - connector to parse line for
71 * @mode_option - per connector mode option
73 * This parses the connector specific then generic command lines for
74 * modes and options to configure the connector.
76 * This uses the same parameters as the fb modedb.c, except for extra
77 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
79 * enable/enable Digital/disable bit at the end
81 static bool drm_fb_helper_connector_parse_command_line(struct drm_connector
*connector
,
82 const char *mode_option
)
86 int res_specified
= 0, bpp_specified
= 0, refresh_specified
= 0;
87 unsigned int xres
= 0, yres
= 0, bpp
= 32, refresh
= 0;
88 int yres_specified
= 0, cvt
= 0, rb
= 0, interlace
= 0, margins
= 0;
90 enum drm_connector_force force
= DRM_FORCE_UNSPECIFIED
;
91 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
92 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
97 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
99 mode_option
= fb_mode_option
;
102 cmdline_mode
->specified
= false;
107 namelen
= strlen(name
);
108 for (i
= namelen
-1; i
>= 0; i
--) {
112 if (!refresh_specified
&& !bpp_specified
&&
114 refresh
= my_atoi(&name
[i
+1]);
115 refresh_specified
= 1;
123 if (!bpp_specified
&& !yres_specified
) {
124 bpp
= my_atoi(&name
[i
+1]);
132 if (!yres_specified
) {
133 yres
= my_atoi(&name
[i
+1]);
156 force
= DRM_FORCE_ON
;
159 if ((connector
->connector_type
!= DRM_MODE_CONNECTOR_DVII
) ||
160 (connector
->connector_type
!= DRM_MODE_CONNECTOR_HDMIB
))
161 force
= DRM_FORCE_ON
;
163 force
= DRM_FORCE_ON_DIGITAL
;
166 force
= DRM_FORCE_OFF
;
172 if (i
< 0 && yres_specified
) {
173 xres
= my_atoi(name
);
178 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
179 drm_get_connector_name(connector
), xres
, yres
,
180 (refresh
) ? refresh
: 60, (rb
) ? " reduced blanking" :
181 "", (margins
) ? " with margins" : "", (interlace
) ?
187 case DRM_FORCE_OFF
: s
= "OFF"; break;
188 case DRM_FORCE_ON_DIGITAL
: s
= "ON - dig"; break;
190 case DRM_FORCE_ON
: s
= "ON"; break;
193 DRM_INFO("forcing %s connector %s\n",
194 drm_get_connector_name(connector
), s
);
195 connector
->force
= force
;
199 cmdline_mode
->specified
= true;
200 cmdline_mode
->xres
= xres
;
201 cmdline_mode
->yres
= yres
;
204 if (refresh_specified
) {
205 cmdline_mode
->refresh_specified
= true;
206 cmdline_mode
->refresh
= refresh
;
210 cmdline_mode
->bpp_specified
= true;
211 cmdline_mode
->bpp
= bpp
;
213 cmdline_mode
->rb
= rb
? true : false;
214 cmdline_mode
->cvt
= cvt
? true : false;
215 cmdline_mode
->interlace
= interlace
? true : false;
220 int drm_fb_helper_parse_command_line(struct drm_device
*dev
)
222 struct drm_connector
*connector
;
224 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
227 /* do something on return - turn off connector maybe */
228 if (fb_get_options(drm_get_connector_name(connector
), &option
))
231 drm_fb_helper_connector_parse_command_line(connector
, option
);
236 bool drm_fb_helper_force_kernel_mode(void)
239 bool ret
, error
= false;
240 struct drm_fb_helper
*helper
;
242 if (list_empty(&kernel_fb_helper_list
))
245 list_for_each_entry(helper
, &kernel_fb_helper_list
, kernel_fb_list
) {
246 for (i
= 0; i
< helper
->crtc_count
; i
++) {
247 struct drm_mode_set
*mode_set
= &helper
->crtc_info
[i
].mode_set
;
248 ret
= drm_crtc_helper_set_config(mode_set
);
256 int drm_fb_helper_panic(struct notifier_block
*n
, unsigned long ununsed
,
259 DRM_ERROR("panic occurred, switching back to text console\n");
260 return drm_fb_helper_force_kernel_mode();
263 EXPORT_SYMBOL(drm_fb_helper_panic
);
265 static struct notifier_block paniced
= {
266 .notifier_call
= drm_fb_helper_panic
,
270 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
272 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
274 void drm_fb_helper_restore(void)
277 ret
= drm_fb_helper_force_kernel_mode();
279 DRM_ERROR("Failed to restore crtc configuration\n");
281 EXPORT_SYMBOL(drm_fb_helper_restore
);
283 static void drm_fb_helper_restore_work_fn(struct work_struct
*ignored
)
285 drm_fb_helper_restore();
287 static DECLARE_WORK(drm_fb_helper_restore_work
, drm_fb_helper_restore_work_fn
);
289 static void drm_fb_helper_sysrq(int dummy1
, struct tty_struct
*dummy3
)
291 schedule_work(&drm_fb_helper_restore_work
);
294 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op
= {
295 .handler
= drm_fb_helper_sysrq
,
296 .help_msg
= "force-fb(V)",
297 .action_msg
= "Restore framebuffer console",
300 static void drm_fb_helper_on(struct fb_info
*info
)
302 struct drm_fb_helper
*fb_helper
= info
->par
;
303 struct drm_device
*dev
= fb_helper
->dev
;
304 struct drm_crtc
*crtc
;
305 struct drm_encoder
*encoder
;
309 * For each CRTC in this fb, turn the crtc on then,
310 * find all associated encoders and turn them on.
312 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
313 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
314 struct drm_crtc_helper_funcs
*crtc_funcs
=
315 crtc
->helper_private
;
317 /* Only mess with CRTCs in this fb */
318 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
322 mutex_lock(&dev
->mode_config
.mutex
);
323 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_ON
);
324 mutex_unlock(&dev
->mode_config
.mutex
);
326 /* Found a CRTC on this fb, now find encoders */
327 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
328 if (encoder
->crtc
== crtc
) {
329 struct drm_encoder_helper_funcs
*encoder_funcs
;
331 encoder_funcs
= encoder
->helper_private
;
332 mutex_lock(&dev
->mode_config
.mutex
);
333 encoder_funcs
->dpms(encoder
, DRM_MODE_DPMS_ON
);
334 mutex_unlock(&dev
->mode_config
.mutex
);
341 static void drm_fb_helper_off(struct fb_info
*info
, int dpms_mode
)
343 struct drm_fb_helper
*fb_helper
= info
->par
;
344 struct drm_device
*dev
= fb_helper
->dev
;
345 struct drm_crtc
*crtc
;
346 struct drm_encoder
*encoder
;
350 * For each CRTC in this fb, find all associated encoders
351 * and turn them off, then turn off the CRTC.
353 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
354 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
355 struct drm_crtc_helper_funcs
*crtc_funcs
=
356 crtc
->helper_private
;
358 /* Only mess with CRTCs in this fb */
359 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
363 /* Found a CRTC on this fb, now find encoders */
364 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
365 if (encoder
->crtc
== crtc
) {
366 struct drm_encoder_helper_funcs
*encoder_funcs
;
368 encoder_funcs
= encoder
->helper_private
;
369 mutex_lock(&dev
->mode_config
.mutex
);
370 encoder_funcs
->dpms(encoder
, dpms_mode
);
371 mutex_unlock(&dev
->mode_config
.mutex
);
374 if (dpms_mode
== DRM_MODE_DPMS_OFF
) {
375 mutex_lock(&dev
->mode_config
.mutex
);
376 crtc_funcs
->dpms(crtc
, dpms_mode
);
377 mutex_unlock(&dev
->mode_config
.mutex
);
383 int drm_fb_helper_blank(int blank
, struct fb_info
*info
)
386 case FB_BLANK_UNBLANK
:
387 drm_fb_helper_on(info
);
389 case FB_BLANK_NORMAL
:
390 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
392 case FB_BLANK_HSYNC_SUSPEND
:
393 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
395 case FB_BLANK_VSYNC_SUSPEND
:
396 drm_fb_helper_off(info
, DRM_MODE_DPMS_SUSPEND
);
398 case FB_BLANK_POWERDOWN
:
399 drm_fb_helper_off(info
, DRM_MODE_DPMS_OFF
);
404 EXPORT_SYMBOL(drm_fb_helper_blank
);
406 static void drm_fb_helper_crtc_free(struct drm_fb_helper
*helper
)
410 for (i
= 0; i
< helper
->crtc_count
; i
++)
411 kfree(helper
->crtc_info
[i
].mode_set
.connectors
);
412 kfree(helper
->crtc_info
);
415 int drm_fb_helper_init_crtc_count(struct drm_fb_helper
*helper
, int crtc_count
, int max_conn_count
)
417 struct drm_device
*dev
= helper
->dev
;
418 struct drm_crtc
*crtc
;
422 helper
->crtc_info
= kcalloc(crtc_count
, sizeof(struct drm_fb_helper_crtc
), GFP_KERNEL
);
423 if (!helper
->crtc_info
)
426 helper
->crtc_count
= crtc_count
;
428 for (i
= 0; i
< crtc_count
; i
++) {
429 helper
->crtc_info
[i
].mode_set
.connectors
=
430 kcalloc(max_conn_count
,
431 sizeof(struct drm_connector
*),
434 if (!helper
->crtc_info
[i
].mode_set
.connectors
) {
438 helper
->crtc_info
[i
].mode_set
.num_connectors
= 0;
442 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
443 helper
->crtc_info
[i
].crtc_id
= crtc
->base
.id
;
444 helper
->crtc_info
[i
].mode_set
.crtc
= crtc
;
447 helper
->conn_limit
= max_conn_count
;
450 drm_fb_helper_crtc_free(helper
);
453 EXPORT_SYMBOL(drm_fb_helper_init_crtc_count
);
455 int drm_fb_helper_setcolreg(unsigned regno
,
460 struct fb_info
*info
)
462 struct drm_fb_helper
*fb_helper
= info
->par
;
463 struct drm_device
*dev
= fb_helper
->dev
;
464 struct drm_crtc
*crtc
;
467 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
468 struct drm_framebuffer
*fb
= fb_helper
->fb
;
470 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
471 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
474 if (i
== fb_helper
->crtc_count
)
480 if (fb
->depth
== 8) {
481 fb_helper
->funcs
->gamma_set(crtc
, red
, green
, blue
, regno
);
488 fb
->pseudo_palette
[regno
] = ((red
& 0xf800) >> 1) |
489 ((green
& 0xf800) >> 6) |
490 ((blue
& 0xf800) >> 11);
493 fb
->pseudo_palette
[regno
] = (red
& 0xf800) |
494 ((green
& 0xfc00) >> 5) |
495 ((blue
& 0xf800) >> 11);
499 fb
->pseudo_palette
[regno
] =
500 (((red
>> 8) & 0xff) << info
->var
.red
.offset
) |
501 (((green
>> 8) & 0xff) << info
->var
.green
.offset
) |
502 (((blue
>> 8) & 0xff) << info
->var
.blue
.offset
);
509 EXPORT_SYMBOL(drm_fb_helper_setcolreg
);
511 int drm_fb_helper_check_var(struct fb_var_screeninfo
*var
,
512 struct fb_info
*info
)
514 struct drm_fb_helper
*fb_helper
= info
->par
;
515 struct drm_framebuffer
*fb
= fb_helper
->fb
;
518 if (var
->pixclock
== -1 || !var
->pixclock
)
521 /* Need to resize the fb object !!! */
522 if (var
->xres
> fb
->width
|| var
->yres
> fb
->height
) {
523 DRM_ERROR("Requested width/height is greater than current fb "
524 "object %dx%d > %dx%d\n", var
->xres
, var
->yres
,
525 fb
->width
, fb
->height
);
526 DRM_ERROR("Need resizing code.\n");
530 switch (var
->bits_per_pixel
) {
532 depth
= (var
->green
.length
== 6) ? 16 : 15;
535 depth
= (var
->transp
.length
> 0) ? 32 : 24;
538 depth
= var
->bits_per_pixel
;
545 var
->green
.offset
= 0;
546 var
->blue
.offset
= 0;
548 var
->green
.length
= 8;
549 var
->blue
.length
= 8;
550 var
->transp
.length
= 0;
551 var
->transp
.offset
= 0;
554 var
->red
.offset
= 10;
555 var
->green
.offset
= 5;
556 var
->blue
.offset
= 0;
558 var
->green
.length
= 5;
559 var
->blue
.length
= 5;
560 var
->transp
.length
= 1;
561 var
->transp
.offset
= 15;
564 var
->red
.offset
= 11;
565 var
->green
.offset
= 5;
566 var
->blue
.offset
= 0;
568 var
->green
.length
= 6;
569 var
->blue
.length
= 5;
570 var
->transp
.length
= 0;
571 var
->transp
.offset
= 0;
574 var
->red
.offset
= 16;
575 var
->green
.offset
= 8;
576 var
->blue
.offset
= 0;
578 var
->green
.length
= 8;
579 var
->blue
.length
= 8;
580 var
->transp
.length
= 0;
581 var
->transp
.offset
= 0;
584 var
->red
.offset
= 16;
585 var
->green
.offset
= 8;
586 var
->blue
.offset
= 0;
588 var
->green
.length
= 8;
589 var
->blue
.length
= 8;
590 var
->transp
.length
= 8;
591 var
->transp
.offset
= 24;
598 EXPORT_SYMBOL(drm_fb_helper_check_var
);
600 /* this will let fbcon do the mode init */
601 int drm_fb_helper_set_par(struct fb_info
*info
)
603 struct drm_fb_helper
*fb_helper
= info
->par
;
604 struct drm_device
*dev
= fb_helper
->dev
;
605 struct fb_var_screeninfo
*var
= &info
->var
;
606 struct drm_crtc
*crtc
;
610 if (var
->pixclock
!= -1) {
611 DRM_ERROR("PIXEL CLCOK SET\n");
615 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
617 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
618 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
621 if (i
== fb_helper
->crtc_count
)
624 if (crtc
->fb
== fb_helper
->crtc_info
[i
].mode_set
.fb
) {
625 mutex_lock(&dev
->mode_config
.mutex
);
626 ret
= crtc
->funcs
->set_config(&fb_helper
->crtc_info
->mode_set
);
627 mutex_unlock(&dev
->mode_config
.mutex
);
634 EXPORT_SYMBOL(drm_fb_helper_set_par
);
636 int drm_fb_helper_pan_display(struct fb_var_screeninfo
*var
,
637 struct fb_info
*info
)
639 struct drm_fb_helper
*fb_helper
= info
->par
;
640 struct drm_device
*dev
= fb_helper
->dev
;
641 struct drm_mode_set
*modeset
;
642 struct drm_crtc
*crtc
;
646 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
647 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
648 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
652 if (i
== fb_helper
->crtc_count
)
655 modeset
= &fb_helper
->crtc_info
[i
].mode_set
;
657 modeset
->x
= var
->xoffset
;
658 modeset
->y
= var
->yoffset
;
660 if (modeset
->num_connectors
) {
661 mutex_lock(&dev
->mode_config
.mutex
);
662 ret
= crtc
->funcs
->set_config(modeset
);
663 mutex_unlock(&dev
->mode_config
.mutex
);
665 info
->var
.xoffset
= var
->xoffset
;
666 info
->var
.yoffset
= var
->yoffset
;
672 EXPORT_SYMBOL(drm_fb_helper_pan_display
);
674 int drm_fb_helper_single_fb_probe(struct drm_device
*dev
,
675 int (*fb_create
)(struct drm_device
*dev
,
678 uint32_t surface_width
,
679 uint32_t surface_height
,
680 uint32_t surface_depth
,
681 uint32_t surface_bpp
,
682 struct drm_framebuffer
**fb_ptr
))
684 struct drm_crtc
*crtc
;
685 struct drm_connector
*connector
;
686 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
687 unsigned int surface_width
= 0, surface_height
= 0;
690 int ret
, i
, conn_count
= 0;
691 struct fb_info
*info
;
692 struct drm_framebuffer
*fb
;
693 struct drm_mode_set
*modeset
= NULL
;
694 struct drm_fb_helper
*fb_helper
;
695 uint32_t surface_depth
= 24, surface_bpp
= 32;
697 /* first up get a count of crtcs now in use and new min/maxes width/heights */
698 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
699 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
701 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
706 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
708 if (cmdline_mode
->bpp_specified
) {
709 switch (cmdline_mode
->bpp
) {
711 surface_depth
= surface_bpp
= 8;
718 surface_depth
= surface_bpp
= 16;
721 surface_depth
= surface_bpp
= 24;
732 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
733 if (drm_helper_crtc_in_use(crtc
)) {
734 if (crtc
->desired_mode
) {
735 if (crtc
->desired_mode
->hdisplay
< fb_width
)
736 fb_width
= crtc
->desired_mode
->hdisplay
;
738 if (crtc
->desired_mode
->vdisplay
< fb_height
)
739 fb_height
= crtc
->desired_mode
->vdisplay
;
741 if (crtc
->desired_mode
->hdisplay
> surface_width
)
742 surface_width
= crtc
->desired_mode
->hdisplay
;
744 if (crtc
->desired_mode
->vdisplay
> surface_height
)
745 surface_height
= crtc
->desired_mode
->vdisplay
;
751 if (crtc_count
== 0 || fb_width
== -1 || fb_height
== -1) {
752 /* hmm everyone went away - assume VGA cable just fell out
753 and will come back later. */
757 /* do we have an fb already? */
758 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
759 ret
= (*fb_create
)(dev
, fb_width
, fb_height
, surface_width
,
760 surface_height
, surface_depth
, surface_bpp
,
766 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
767 struct drm_framebuffer
, filp_head
);
769 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
770 As really we can't resize an fbdev that is in the wild currently due to fbdev
771 not really being designed for the lower layers moving stuff around under it.
772 - so in the grand style of things - punt. */
773 if ((fb
->width
< surface_width
) ||
774 (fb
->height
< surface_height
)) {
775 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
781 fb_helper
= info
->par
;
784 /* okay we need to setup new connector sets in the crtcs */
785 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
786 modeset
= &fb_helper
->crtc_info
[crtc_count
].mode_set
;
789 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
790 if (connector
->encoder
)
791 if (connector
->encoder
->crtc
== modeset
->crtc
) {
792 modeset
->connectors
[conn_count
] = connector
;
794 if (conn_count
> fb_helper
->conn_limit
)
799 for (i
= conn_count
; i
< fb_helper
->conn_limit
; i
++)
800 modeset
->connectors
[i
] = NULL
;
802 modeset
->crtc
= crtc
;
805 modeset
->num_connectors
= conn_count
;
806 if (modeset
->crtc
->desired_mode
) {
808 drm_mode_destroy(dev
, modeset
->mode
);
809 modeset
->mode
= drm_mode_duplicate(dev
,
810 modeset
->crtc
->desired_mode
);
813 fb_helper
->crtc_count
= crtc_count
;
817 info
->var
.pixclock
= -1;
818 if (register_framebuffer(info
) < 0)
821 drm_fb_helper_set_par(info
);
823 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
826 /* Switch back to kernel console on panic */
827 /* multi card linked list maybe */
828 if (list_empty(&kernel_fb_helper_list
)) {
829 printk(KERN_INFO
"registered panic notifier\n");
830 atomic_notifier_chain_register(&panic_notifier_list
,
832 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
834 list_add(&fb_helper
->kernel_fb_list
, &kernel_fb_helper_list
);
837 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe
);
839 void drm_fb_helper_free(struct drm_fb_helper
*helper
)
841 list_del(&helper
->kernel_fb_list
);
842 if (list_empty(&kernel_fb_helper_list
)) {
843 printk(KERN_INFO
"unregistered panic notifier\n");
844 atomic_notifier_chain_unregister(&panic_notifier_list
,
846 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
848 drm_fb_helper_crtc_free(helper
);
850 EXPORT_SYMBOL(drm_fb_helper_free
);
852 void drm_fb_helper_fill_fix(struct fb_info
*info
, uint32_t pitch
)
854 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
855 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
856 info
->fix
.type_aux
= 0;
857 info
->fix
.xpanstep
= 1; /* doing it in hw */
858 info
->fix
.ypanstep
= 1; /* doing it in hw */
859 info
->fix
.ywrapstep
= 0;
860 info
->fix
.accel
= FB_ACCEL_NONE
;
861 info
->fix
.type_aux
= 0;
863 info
->fix
.line_length
= pitch
;
866 EXPORT_SYMBOL(drm_fb_helper_fill_fix
);
868 void drm_fb_helper_fill_var(struct fb_info
*info
, struct drm_framebuffer
*fb
,
869 uint32_t fb_width
, uint32_t fb_height
)
871 info
->pseudo_palette
= fb
->pseudo_palette
;
872 info
->var
.xres_virtual
= fb
->width
;
873 info
->var
.yres_virtual
= fb
->height
;
874 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
875 info
->var
.xoffset
= 0;
876 info
->var
.yoffset
= 0;
877 info
->var
.activate
= FB_ACTIVATE_NOW
;
878 info
->var
.height
= -1;
879 info
->var
.width
= -1;
883 info
->var
.red
.offset
= 0;
884 info
->var
.green
.offset
= 0;
885 info
->var
.blue
.offset
= 0;
886 info
->var
.red
.length
= 8; /* 8bit DAC */
887 info
->var
.green
.length
= 8;
888 info
->var
.blue
.length
= 8;
889 info
->var
.transp
.offset
= 0;
890 info
->var
.transp
.length
= 0;
893 info
->var
.red
.offset
= 10;
894 info
->var
.green
.offset
= 5;
895 info
->var
.blue
.offset
= 0;
896 info
->var
.red
.length
= 5;
897 info
->var
.green
.length
= 5;
898 info
->var
.blue
.length
= 5;
899 info
->var
.transp
.offset
= 15;
900 info
->var
.transp
.length
= 1;
903 info
->var
.red
.offset
= 11;
904 info
->var
.green
.offset
= 5;
905 info
->var
.blue
.offset
= 0;
906 info
->var
.red
.length
= 5;
907 info
->var
.green
.length
= 6;
908 info
->var
.blue
.length
= 5;
909 info
->var
.transp
.offset
= 0;
912 info
->var
.red
.offset
= 16;
913 info
->var
.green
.offset
= 8;
914 info
->var
.blue
.offset
= 0;
915 info
->var
.red
.length
= 8;
916 info
->var
.green
.length
= 8;
917 info
->var
.blue
.length
= 8;
918 info
->var
.transp
.offset
= 0;
919 info
->var
.transp
.length
= 0;
922 info
->var
.red
.offset
= 16;
923 info
->var
.green
.offset
= 8;
924 info
->var
.blue
.offset
= 0;
925 info
->var
.red
.length
= 8;
926 info
->var
.green
.length
= 8;
927 info
->var
.blue
.length
= 8;
928 info
->var
.transp
.offset
= 24;
929 info
->var
.transp
.length
= 8;
935 info
->var
.xres
= fb_width
;
936 info
->var
.yres
= fb_height
;
938 EXPORT_SYMBOL(drm_fb_helper_fill_var
);