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
)
52 EXPORT_SYMBOL(drm_fb_helper_add_connector
);
54 static int my_atoi(const char *name
)
61 val
= 10*val
+(*name
-'0');
70 * drm_fb_helper_connector_parse_command_line - parse command line for connector
71 * @connector - connector to parse line for
72 * @mode_option - per connector mode option
74 * This parses the connector specific then generic command lines for
75 * modes and options to configure the connector.
77 * This uses the same parameters as the fb modedb.c, except for extra
78 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
80 * enable/enable Digital/disable bit at the end
82 static bool drm_fb_helper_connector_parse_command_line(struct drm_connector
*connector
,
83 const char *mode_option
)
87 int res_specified
= 0, bpp_specified
= 0, refresh_specified
= 0;
88 unsigned int xres
= 0, yres
= 0, bpp
= 32, refresh
= 0;
89 int yres_specified
= 0, cvt
= 0, rb
= 0, interlace
= 0, margins
= 0;
91 enum drm_connector_force force
= DRM_FORCE_UNSPECIFIED
;
92 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
93 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
98 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
100 mode_option
= fb_mode_option
;
103 cmdline_mode
->specified
= false;
108 namelen
= strlen(name
);
109 for (i
= namelen
-1; i
>= 0; i
--) {
113 if (!refresh_specified
&& !bpp_specified
&&
115 refresh
= my_atoi(&name
[i
+1]);
116 refresh_specified
= 1;
124 if (!bpp_specified
&& !yres_specified
) {
125 bpp
= my_atoi(&name
[i
+1]);
133 if (!yres_specified
) {
134 yres
= my_atoi(&name
[i
+1]);
157 force
= DRM_FORCE_ON
;
160 if ((connector
->connector_type
!= DRM_MODE_CONNECTOR_DVII
) ||
161 (connector
->connector_type
!= DRM_MODE_CONNECTOR_HDMIB
))
162 force
= DRM_FORCE_ON
;
164 force
= DRM_FORCE_ON_DIGITAL
;
167 force
= DRM_FORCE_OFF
;
173 if (i
< 0 && yres_specified
) {
174 xres
= my_atoi(name
);
179 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
180 drm_get_connector_name(connector
), xres
, yres
,
181 (refresh
) ? refresh
: 60, (rb
) ? " reduced blanking" :
182 "", (margins
) ? " with margins" : "", (interlace
) ?
188 case DRM_FORCE_OFF
: s
= "OFF"; break;
189 case DRM_FORCE_ON_DIGITAL
: s
= "ON - dig"; break;
191 case DRM_FORCE_ON
: s
= "ON"; break;
194 DRM_INFO("forcing %s connector %s\n",
195 drm_get_connector_name(connector
), s
);
196 connector
->force
= force
;
200 cmdline_mode
->specified
= true;
201 cmdline_mode
->xres
= xres
;
202 cmdline_mode
->yres
= yres
;
205 if (refresh_specified
) {
206 cmdline_mode
->refresh_specified
= true;
207 cmdline_mode
->refresh
= refresh
;
211 cmdline_mode
->bpp_specified
= true;
212 cmdline_mode
->bpp
= bpp
;
214 cmdline_mode
->rb
= rb
? true : false;
215 cmdline_mode
->cvt
= cvt
? true : false;
216 cmdline_mode
->interlace
= interlace
? true : false;
221 int drm_fb_helper_parse_command_line(struct drm_device
*dev
)
223 struct drm_connector
*connector
;
225 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
228 /* do something on return - turn off connector maybe */
229 if (fb_get_options(drm_get_connector_name(connector
), &option
))
232 drm_fb_helper_connector_parse_command_line(connector
, option
);
237 bool drm_fb_helper_force_kernel_mode(void)
240 bool ret
, error
= false;
241 struct drm_fb_helper
*helper
;
243 if (list_empty(&kernel_fb_helper_list
))
246 list_for_each_entry(helper
, &kernel_fb_helper_list
, kernel_fb_list
) {
247 for (i
= 0; i
< helper
->crtc_count
; i
++) {
248 struct drm_mode_set
*mode_set
= &helper
->crtc_info
[i
].mode_set
;
249 ret
= drm_crtc_helper_set_config(mode_set
);
257 int drm_fb_helper_panic(struct notifier_block
*n
, unsigned long ununsed
,
260 DRM_ERROR("panic occurred, switching back to text console\n");
261 return drm_fb_helper_force_kernel_mode();
264 EXPORT_SYMBOL(drm_fb_helper_panic
);
266 static struct notifier_block paniced
= {
267 .notifier_call
= drm_fb_helper_panic
,
271 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
273 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
275 void drm_fb_helper_restore(void)
278 ret
= drm_fb_helper_force_kernel_mode();
280 DRM_ERROR("Failed to restore crtc configuration\n");
282 EXPORT_SYMBOL(drm_fb_helper_restore
);
284 static void drm_fb_helper_restore_work_fn(struct work_struct
*ignored
)
286 drm_fb_helper_restore();
288 static DECLARE_WORK(drm_fb_helper_restore_work
, drm_fb_helper_restore_work_fn
);
290 static void drm_fb_helper_sysrq(int dummy1
, struct tty_struct
*dummy3
)
292 schedule_work(&drm_fb_helper_restore_work
);
295 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op
= {
296 .handler
= drm_fb_helper_sysrq
,
297 .help_msg
= "force-fb(V)",
298 .action_msg
= "Restore framebuffer console",
301 static void drm_fb_helper_on(struct fb_info
*info
)
303 struct drm_fb_helper
*fb_helper
= info
->par
;
304 struct drm_device
*dev
= fb_helper
->dev
;
305 struct drm_crtc
*crtc
;
306 struct drm_encoder
*encoder
;
310 * For each CRTC in this fb, turn the crtc on then,
311 * find all associated encoders and turn them on.
313 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
314 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
315 struct drm_crtc_helper_funcs
*crtc_funcs
=
316 crtc
->helper_private
;
318 /* Only mess with CRTCs in this fb */
319 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
323 mutex_lock(&dev
->mode_config
.mutex
);
324 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_ON
);
325 mutex_unlock(&dev
->mode_config
.mutex
);
327 /* Found a CRTC on this fb, now find encoders */
328 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
329 if (encoder
->crtc
== crtc
) {
330 struct drm_encoder_helper_funcs
*encoder_funcs
;
332 encoder_funcs
= encoder
->helper_private
;
333 mutex_lock(&dev
->mode_config
.mutex
);
334 encoder_funcs
->dpms(encoder
, DRM_MODE_DPMS_ON
);
335 mutex_unlock(&dev
->mode_config
.mutex
);
342 static void drm_fb_helper_off(struct fb_info
*info
, int dpms_mode
)
344 struct drm_fb_helper
*fb_helper
= info
->par
;
345 struct drm_device
*dev
= fb_helper
->dev
;
346 struct drm_crtc
*crtc
;
347 struct drm_encoder
*encoder
;
351 * For each CRTC in this fb, find all associated encoders
352 * and turn them off, then turn off the CRTC.
354 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
355 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
356 struct drm_crtc_helper_funcs
*crtc_funcs
=
357 crtc
->helper_private
;
359 /* Only mess with CRTCs in this fb */
360 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
364 /* Found a CRTC on this fb, now find encoders */
365 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
366 if (encoder
->crtc
== crtc
) {
367 struct drm_encoder_helper_funcs
*encoder_funcs
;
369 encoder_funcs
= encoder
->helper_private
;
370 mutex_lock(&dev
->mode_config
.mutex
);
371 encoder_funcs
->dpms(encoder
, dpms_mode
);
372 mutex_unlock(&dev
->mode_config
.mutex
);
375 if (dpms_mode
== DRM_MODE_DPMS_OFF
) {
376 mutex_lock(&dev
->mode_config
.mutex
);
377 crtc_funcs
->dpms(crtc
, dpms_mode
);
378 mutex_unlock(&dev
->mode_config
.mutex
);
384 int drm_fb_helper_blank(int blank
, struct fb_info
*info
)
387 case FB_BLANK_UNBLANK
:
388 drm_fb_helper_on(info
);
390 case FB_BLANK_NORMAL
:
391 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
393 case FB_BLANK_HSYNC_SUSPEND
:
394 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
396 case FB_BLANK_VSYNC_SUSPEND
:
397 drm_fb_helper_off(info
, DRM_MODE_DPMS_SUSPEND
);
399 case FB_BLANK_POWERDOWN
:
400 drm_fb_helper_off(info
, DRM_MODE_DPMS_OFF
);
405 EXPORT_SYMBOL(drm_fb_helper_blank
);
407 static void drm_fb_helper_crtc_free(struct drm_fb_helper
*helper
)
411 for (i
= 0; i
< helper
->crtc_count
; i
++)
412 kfree(helper
->crtc_info
[i
].mode_set
.connectors
);
413 kfree(helper
->crtc_info
);
416 int drm_fb_helper_init_crtc_count(struct drm_fb_helper
*helper
, int crtc_count
, int max_conn_count
)
418 struct drm_device
*dev
= helper
->dev
;
419 struct drm_crtc
*crtc
;
423 helper
->crtc_info
= kcalloc(crtc_count
, sizeof(struct drm_fb_helper_crtc
), GFP_KERNEL
);
424 if (!helper
->crtc_info
)
427 helper
->crtc_count
= crtc_count
;
429 for (i
= 0; i
< crtc_count
; i
++) {
430 helper
->crtc_info
[i
].mode_set
.connectors
=
431 kcalloc(max_conn_count
,
432 sizeof(struct drm_connector
*),
435 if (!helper
->crtc_info
[i
].mode_set
.connectors
) {
439 helper
->crtc_info
[i
].mode_set
.num_connectors
= 0;
443 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
444 helper
->crtc_info
[i
].crtc_id
= crtc
->base
.id
;
445 helper
->crtc_info
[i
].mode_set
.crtc
= crtc
;
448 helper
->conn_limit
= max_conn_count
;
451 drm_fb_helper_crtc_free(helper
);
454 EXPORT_SYMBOL(drm_fb_helper_init_crtc_count
);
456 int drm_fb_helper_setcolreg(unsigned regno
,
461 struct fb_info
*info
)
463 struct drm_fb_helper
*fb_helper
= info
->par
;
464 struct drm_device
*dev
= fb_helper
->dev
;
465 struct drm_crtc
*crtc
;
468 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
469 struct drm_framebuffer
*fb
= fb_helper
->fb
;
471 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
472 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
475 if (i
== fb_helper
->crtc_count
)
481 if (fb
->depth
== 8) {
482 fb_helper
->funcs
->gamma_set(crtc
, red
, green
, blue
, regno
);
489 fb
->pseudo_palette
[regno
] = ((red
& 0xf800) >> 1) |
490 ((green
& 0xf800) >> 6) |
491 ((blue
& 0xf800) >> 11);
494 fb
->pseudo_palette
[regno
] = (red
& 0xf800) |
495 ((green
& 0xfc00) >> 5) |
496 ((blue
& 0xf800) >> 11);
500 fb
->pseudo_palette
[regno
] =
501 (((red
>> 8) & 0xff) << info
->var
.red
.offset
) |
502 (((green
>> 8) & 0xff) << info
->var
.green
.offset
) |
503 (((blue
>> 8) & 0xff) << info
->var
.blue
.offset
);
510 EXPORT_SYMBOL(drm_fb_helper_setcolreg
);
512 int drm_fb_helper_check_var(struct fb_var_screeninfo
*var
,
513 struct fb_info
*info
)
515 struct drm_fb_helper
*fb_helper
= info
->par
;
516 struct drm_framebuffer
*fb
= fb_helper
->fb
;
519 if (var
->pixclock
== -1 || !var
->pixclock
)
522 /* Need to resize the fb object !!! */
523 if (var
->xres
> fb
->width
|| var
->yres
> fb
->height
) {
524 DRM_ERROR("Requested width/height is greater than current fb "
525 "object %dx%d > %dx%d\n", var
->xres
, var
->yres
,
526 fb
->width
, fb
->height
);
527 DRM_ERROR("Need resizing code.\n");
531 switch (var
->bits_per_pixel
) {
533 depth
= (var
->green
.length
== 6) ? 16 : 15;
536 depth
= (var
->transp
.length
> 0) ? 32 : 24;
539 depth
= var
->bits_per_pixel
;
546 var
->green
.offset
= 0;
547 var
->blue
.offset
= 0;
549 var
->green
.length
= 8;
550 var
->blue
.length
= 8;
551 var
->transp
.length
= 0;
552 var
->transp
.offset
= 0;
555 var
->red
.offset
= 10;
556 var
->green
.offset
= 5;
557 var
->blue
.offset
= 0;
559 var
->green
.length
= 5;
560 var
->blue
.length
= 5;
561 var
->transp
.length
= 1;
562 var
->transp
.offset
= 15;
565 var
->red
.offset
= 11;
566 var
->green
.offset
= 5;
567 var
->blue
.offset
= 0;
569 var
->green
.length
= 6;
570 var
->blue
.length
= 5;
571 var
->transp
.length
= 0;
572 var
->transp
.offset
= 0;
575 var
->red
.offset
= 16;
576 var
->green
.offset
= 8;
577 var
->blue
.offset
= 0;
579 var
->green
.length
= 8;
580 var
->blue
.length
= 8;
581 var
->transp
.length
= 0;
582 var
->transp
.offset
= 0;
585 var
->red
.offset
= 16;
586 var
->green
.offset
= 8;
587 var
->blue
.offset
= 0;
589 var
->green
.length
= 8;
590 var
->blue
.length
= 8;
591 var
->transp
.length
= 8;
592 var
->transp
.offset
= 24;
599 EXPORT_SYMBOL(drm_fb_helper_check_var
);
601 /* this will let fbcon do the mode init */
602 int drm_fb_helper_set_par(struct fb_info
*info
)
604 struct drm_fb_helper
*fb_helper
= info
->par
;
605 struct drm_device
*dev
= fb_helper
->dev
;
606 struct fb_var_screeninfo
*var
= &info
->var
;
607 struct drm_crtc
*crtc
;
611 if (var
->pixclock
!= -1) {
612 DRM_ERROR("PIXEL CLCOK SET\n");
616 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
618 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
619 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
622 if (i
== fb_helper
->crtc_count
)
625 if (crtc
->fb
== fb_helper
->crtc_info
[i
].mode_set
.fb
) {
626 mutex_lock(&dev
->mode_config
.mutex
);
627 ret
= crtc
->funcs
->set_config(&fb_helper
->crtc_info
->mode_set
);
628 mutex_unlock(&dev
->mode_config
.mutex
);
635 EXPORT_SYMBOL(drm_fb_helper_set_par
);
637 int drm_fb_helper_pan_display(struct fb_var_screeninfo
*var
,
638 struct fb_info
*info
)
640 struct drm_fb_helper
*fb_helper
= info
->par
;
641 struct drm_device
*dev
= fb_helper
->dev
;
642 struct drm_mode_set
*modeset
;
643 struct drm_crtc
*crtc
;
647 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
648 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
649 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
653 if (i
== fb_helper
->crtc_count
)
656 modeset
= &fb_helper
->crtc_info
[i
].mode_set
;
658 modeset
->x
= var
->xoffset
;
659 modeset
->y
= var
->yoffset
;
661 if (modeset
->num_connectors
) {
662 mutex_lock(&dev
->mode_config
.mutex
);
663 ret
= crtc
->funcs
->set_config(modeset
);
664 mutex_unlock(&dev
->mode_config
.mutex
);
666 info
->var
.xoffset
= var
->xoffset
;
667 info
->var
.yoffset
= var
->yoffset
;
673 EXPORT_SYMBOL(drm_fb_helper_pan_display
);
675 int drm_fb_helper_single_fb_probe(struct drm_device
*dev
,
676 int (*fb_create
)(struct drm_device
*dev
,
679 uint32_t surface_width
,
680 uint32_t surface_height
,
681 uint32_t surface_depth
,
682 uint32_t surface_bpp
,
683 struct drm_framebuffer
**fb_ptr
))
685 struct drm_crtc
*crtc
;
686 struct drm_connector
*connector
;
687 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
688 unsigned int surface_width
= 0, surface_height
= 0;
691 int ret
, i
, conn_count
= 0;
692 struct fb_info
*info
;
693 struct drm_framebuffer
*fb
;
694 struct drm_mode_set
*modeset
= NULL
;
695 struct drm_fb_helper
*fb_helper
;
696 uint32_t surface_depth
= 24, surface_bpp
= 32;
698 /* first up get a count of crtcs now in use and new min/maxes width/heights */
699 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
700 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
702 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
707 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
709 if (cmdline_mode
->bpp_specified
) {
710 switch (cmdline_mode
->bpp
) {
712 surface_depth
= surface_bpp
= 8;
719 surface_depth
= surface_bpp
= 16;
722 surface_depth
= surface_bpp
= 24;
733 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
734 if (drm_helper_crtc_in_use(crtc
)) {
735 if (crtc
->desired_mode
) {
736 if (crtc
->desired_mode
->hdisplay
< fb_width
)
737 fb_width
= crtc
->desired_mode
->hdisplay
;
739 if (crtc
->desired_mode
->vdisplay
< fb_height
)
740 fb_height
= crtc
->desired_mode
->vdisplay
;
742 if (crtc
->desired_mode
->hdisplay
> surface_width
)
743 surface_width
= crtc
->desired_mode
->hdisplay
;
745 if (crtc
->desired_mode
->vdisplay
> surface_height
)
746 surface_height
= crtc
->desired_mode
->vdisplay
;
752 if (crtc_count
== 0 || fb_width
== -1 || fb_height
== -1) {
753 /* hmm everyone went away - assume VGA cable just fell out
754 and will come back later. */
758 /* do we have an fb already? */
759 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
760 ret
= (*fb_create
)(dev
, fb_width
, fb_height
, surface_width
,
761 surface_height
, surface_depth
, surface_bpp
,
767 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
768 struct drm_framebuffer
, filp_head
);
770 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
771 As really we can't resize an fbdev that is in the wild currently due to fbdev
772 not really being designed for the lower layers moving stuff around under it.
773 - so in the grand style of things - punt. */
774 if ((fb
->width
< surface_width
) ||
775 (fb
->height
< surface_height
)) {
776 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
782 fb_helper
= info
->par
;
785 /* okay we need to setup new connector sets in the crtcs */
786 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
787 modeset
= &fb_helper
->crtc_info
[crtc_count
].mode_set
;
790 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
791 if (connector
->encoder
)
792 if (connector
->encoder
->crtc
== modeset
->crtc
) {
793 modeset
->connectors
[conn_count
] = connector
;
795 if (conn_count
> fb_helper
->conn_limit
)
800 for (i
= conn_count
; i
< fb_helper
->conn_limit
; i
++)
801 modeset
->connectors
[i
] = NULL
;
803 modeset
->crtc
= crtc
;
806 modeset
->num_connectors
= conn_count
;
807 if (modeset
->crtc
->desired_mode
) {
809 drm_mode_destroy(dev
, modeset
->mode
);
810 modeset
->mode
= drm_mode_duplicate(dev
,
811 modeset
->crtc
->desired_mode
);
814 fb_helper
->crtc_count
= crtc_count
;
818 info
->var
.pixclock
= -1;
819 if (register_framebuffer(info
) < 0)
822 drm_fb_helper_set_par(info
);
824 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
827 /* Switch back to kernel console on panic */
828 /* multi card linked list maybe */
829 if (list_empty(&kernel_fb_helper_list
)) {
830 printk(KERN_INFO
"registered panic notifier\n");
831 atomic_notifier_chain_register(&panic_notifier_list
,
833 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
835 list_add(&fb_helper
->kernel_fb_list
, &kernel_fb_helper_list
);
838 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe
);
840 void drm_fb_helper_free(struct drm_fb_helper
*helper
)
842 list_del(&helper
->kernel_fb_list
);
843 if (list_empty(&kernel_fb_helper_list
)) {
844 printk(KERN_INFO
"unregistered panic notifier\n");
845 atomic_notifier_chain_unregister(&panic_notifier_list
,
847 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
849 drm_fb_helper_crtc_free(helper
);
851 EXPORT_SYMBOL(drm_fb_helper_free
);
853 void drm_fb_helper_fill_fix(struct fb_info
*info
, uint32_t pitch
)
855 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
856 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
857 info
->fix
.type_aux
= 0;
858 info
->fix
.xpanstep
= 1; /* doing it in hw */
859 info
->fix
.ypanstep
= 1; /* doing it in hw */
860 info
->fix
.ywrapstep
= 0;
861 info
->fix
.accel
= FB_ACCEL_NONE
;
862 info
->fix
.type_aux
= 0;
864 info
->fix
.line_length
= pitch
;
867 EXPORT_SYMBOL(drm_fb_helper_fill_fix
);
869 void drm_fb_helper_fill_var(struct fb_info
*info
, struct drm_framebuffer
*fb
,
870 uint32_t fb_width
, uint32_t fb_height
)
872 info
->pseudo_palette
= fb
->pseudo_palette
;
873 info
->var
.xres_virtual
= fb
->width
;
874 info
->var
.yres_virtual
= fb
->height
;
875 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
876 info
->var
.xoffset
= 0;
877 info
->var
.yoffset
= 0;
878 info
->var
.activate
= FB_ACTIVATE_NOW
;
879 info
->var
.height
= -1;
880 info
->var
.width
= -1;
884 info
->var
.red
.offset
= 0;
885 info
->var
.green
.offset
= 0;
886 info
->var
.blue
.offset
= 0;
887 info
->var
.red
.length
= 8; /* 8bit DAC */
888 info
->var
.green
.length
= 8;
889 info
->var
.blue
.length
= 8;
890 info
->var
.transp
.offset
= 0;
891 info
->var
.transp
.length
= 0;
894 info
->var
.red
.offset
= 10;
895 info
->var
.green
.offset
= 5;
896 info
->var
.blue
.offset
= 0;
897 info
->var
.red
.length
= 5;
898 info
->var
.green
.length
= 5;
899 info
->var
.blue
.length
= 5;
900 info
->var
.transp
.offset
= 15;
901 info
->var
.transp
.length
= 1;
904 info
->var
.red
.offset
= 11;
905 info
->var
.green
.offset
= 5;
906 info
->var
.blue
.offset
= 0;
907 info
->var
.red
.length
= 5;
908 info
->var
.green
.length
= 6;
909 info
->var
.blue
.length
= 5;
910 info
->var
.transp
.offset
= 0;
913 info
->var
.red
.offset
= 16;
914 info
->var
.green
.offset
= 8;
915 info
->var
.blue
.offset
= 0;
916 info
->var
.red
.length
= 8;
917 info
->var
.green
.length
= 8;
918 info
->var
.blue
.length
= 8;
919 info
->var
.transp
.offset
= 0;
920 info
->var
.transp
.length
= 0;
923 info
->var
.red
.offset
= 16;
924 info
->var
.green
.offset
= 8;
925 info
->var
.blue
.offset
= 0;
926 info
->var
.red
.length
= 8;
927 info
->var
.green
.length
= 8;
928 info
->var
.blue
.length
= 8;
929 info
->var
.transp
.offset
= 24;
930 info
->var
.transp
.length
= 8;
936 info
->var
.xres
= fb_width
;
937 info
->var
.yres
= fb_height
;
939 EXPORT_SYMBOL(drm_fb_helper_fill_var
);