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/kernel.h>
31 #include <linux/sysrq.h>
32 #include <linux/slab.h>
36 #include "drm_fb_helper.h"
37 #include "drm_crtc_helper.h"
39 MODULE_AUTHOR("David Airlie, Jesse Barnes");
40 MODULE_DESCRIPTION("DRM KMS helper");
41 MODULE_LICENSE("GPL and additional rights");
43 static LIST_HEAD(kernel_fb_helper_list
);
45 int drm_fb_helper_add_connector(struct drm_connector
*connector
)
47 connector
->fb_helper_private
= kzalloc(sizeof(struct drm_fb_helper_connector
), GFP_KERNEL
);
48 if (!connector
->fb_helper_private
)
53 EXPORT_SYMBOL(drm_fb_helper_add_connector
);
56 * drm_fb_helper_connector_parse_command_line - parse command line for connector
57 * @connector - connector to parse line for
58 * @mode_option - per connector mode option
60 * This parses the connector specific then generic command lines for
61 * modes and options to configure the connector.
63 * This uses the same parameters as the fb modedb.c, except for extra
64 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
66 * enable/enable Digital/disable bit at the end
68 static bool drm_fb_helper_connector_parse_command_line(struct drm_connector
*connector
,
69 const char *mode_option
)
73 int res_specified
= 0, bpp_specified
= 0, refresh_specified
= 0;
74 unsigned int xres
= 0, yres
= 0, bpp
= 32, refresh
= 0;
75 int yres_specified
= 0, cvt
= 0, rb
= 0, interlace
= 0, margins
= 0;
77 enum drm_connector_force force
= DRM_FORCE_UNSPECIFIED
;
78 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
79 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
84 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
86 mode_option
= fb_mode_option
;
89 cmdline_mode
->specified
= false;
94 namelen
= strlen(name
);
95 for (i
= namelen
-1; i
>= 0; i
--) {
99 if (!refresh_specified
&& !bpp_specified
&&
101 refresh
= simple_strtol(&name
[i
+1], NULL
, 10);
102 refresh_specified
= 1;
110 if (!bpp_specified
&& !yres_specified
) {
111 bpp
= simple_strtol(&name
[i
+1], NULL
, 10);
119 if (!yres_specified
) {
120 yres
= simple_strtol(&name
[i
+1], NULL
, 10);
143 force
= DRM_FORCE_ON
;
146 if ((connector
->connector_type
!= DRM_MODE_CONNECTOR_DVII
) &&
147 (connector
->connector_type
!= DRM_MODE_CONNECTOR_HDMIB
))
148 force
= DRM_FORCE_ON
;
150 force
= DRM_FORCE_ON_DIGITAL
;
153 force
= DRM_FORCE_OFF
;
159 if (i
< 0 && yres_specified
) {
160 xres
= simple_strtol(name
, NULL
, 10);
165 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
166 drm_get_connector_name(connector
), xres
, yres
,
167 (refresh
) ? refresh
: 60, (rb
) ? " reduced blanking" :
168 "", (margins
) ? " with margins" : "", (interlace
) ?
174 case DRM_FORCE_OFF
: s
= "OFF"; break;
175 case DRM_FORCE_ON_DIGITAL
: s
= "ON - dig"; break;
177 case DRM_FORCE_ON
: s
= "ON"; break;
180 DRM_INFO("forcing %s connector %s\n",
181 drm_get_connector_name(connector
), s
);
182 connector
->force
= force
;
186 cmdline_mode
->specified
= true;
187 cmdline_mode
->xres
= xres
;
188 cmdline_mode
->yres
= yres
;
191 if (refresh_specified
) {
192 cmdline_mode
->refresh_specified
= true;
193 cmdline_mode
->refresh
= refresh
;
197 cmdline_mode
->bpp_specified
= true;
198 cmdline_mode
->bpp
= bpp
;
200 cmdline_mode
->rb
= rb
? true : false;
201 cmdline_mode
->cvt
= cvt
? true : false;
202 cmdline_mode
->interlace
= interlace
? true : false;
207 int drm_fb_helper_parse_command_line(struct drm_device
*dev
)
209 struct drm_connector
*connector
;
211 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
214 /* do something on return - turn off connector maybe */
215 if (fb_get_options(drm_get_connector_name(connector
), &option
))
218 drm_fb_helper_connector_parse_command_line(connector
, option
);
223 bool drm_fb_helper_force_kernel_mode(void)
226 bool ret
, error
= false;
227 struct drm_fb_helper
*helper
;
229 if (list_empty(&kernel_fb_helper_list
))
232 list_for_each_entry(helper
, &kernel_fb_helper_list
, kernel_fb_list
) {
233 for (i
= 0; i
< helper
->crtc_count
; i
++) {
234 struct drm_mode_set
*mode_set
= &helper
->crtc_info
[i
].mode_set
;
235 ret
= drm_crtc_helper_set_config(mode_set
);
243 int drm_fb_helper_panic(struct notifier_block
*n
, unsigned long ununsed
,
246 DRM_ERROR("panic occurred, switching back to text console\n");
247 return drm_fb_helper_force_kernel_mode();
250 EXPORT_SYMBOL(drm_fb_helper_panic
);
252 static struct notifier_block paniced
= {
253 .notifier_call
= drm_fb_helper_panic
,
257 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
259 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
261 void drm_fb_helper_restore(void)
264 ret
= drm_fb_helper_force_kernel_mode();
266 DRM_ERROR("Failed to restore crtc configuration\n");
268 EXPORT_SYMBOL(drm_fb_helper_restore
);
270 #ifdef CONFIG_MAGIC_SYSRQ
271 static void drm_fb_helper_restore_work_fn(struct work_struct
*ignored
)
273 drm_fb_helper_restore();
275 static DECLARE_WORK(drm_fb_helper_restore_work
, drm_fb_helper_restore_work_fn
);
277 static void drm_fb_helper_sysrq(int dummy1
, struct tty_struct
*dummy3
)
279 schedule_work(&drm_fb_helper_restore_work
);
282 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op
= {
283 .handler
= drm_fb_helper_sysrq
,
284 .help_msg
= "force-fb(V)",
285 .action_msg
= "Restore framebuffer console",
289 static void drm_fb_helper_on(struct fb_info
*info
)
291 struct drm_fb_helper
*fb_helper
= info
->par
;
292 struct drm_device
*dev
= fb_helper
->dev
;
293 struct drm_crtc
*crtc
;
294 struct drm_encoder
*encoder
;
298 * For each CRTC in this fb, turn the crtc on then,
299 * find all associated encoders and turn them on.
301 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
302 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
303 struct drm_crtc_helper_funcs
*crtc_funcs
=
304 crtc
->helper_private
;
306 /* Only mess with CRTCs in this fb */
307 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
311 mutex_lock(&dev
->mode_config
.mutex
);
312 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_ON
);
313 mutex_unlock(&dev
->mode_config
.mutex
);
315 /* Found a CRTC on this fb, now find encoders */
316 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
317 if (encoder
->crtc
== crtc
) {
318 struct drm_encoder_helper_funcs
*encoder_funcs
;
320 encoder_funcs
= encoder
->helper_private
;
321 mutex_lock(&dev
->mode_config
.mutex
);
322 encoder_funcs
->dpms(encoder
, DRM_MODE_DPMS_ON
);
323 mutex_unlock(&dev
->mode_config
.mutex
);
330 static void drm_fb_helper_off(struct fb_info
*info
, int dpms_mode
)
332 struct drm_fb_helper
*fb_helper
= info
->par
;
333 struct drm_device
*dev
= fb_helper
->dev
;
334 struct drm_crtc
*crtc
;
335 struct drm_encoder
*encoder
;
339 * For each CRTC in this fb, find all associated encoders
340 * and turn them off, then turn off the CRTC.
342 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
343 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
344 struct drm_crtc_helper_funcs
*crtc_funcs
=
345 crtc
->helper_private
;
347 /* Only mess with CRTCs in this fb */
348 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
352 /* Found a CRTC on this fb, now find encoders */
353 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
354 if (encoder
->crtc
== crtc
) {
355 struct drm_encoder_helper_funcs
*encoder_funcs
;
357 encoder_funcs
= encoder
->helper_private
;
358 mutex_lock(&dev
->mode_config
.mutex
);
359 encoder_funcs
->dpms(encoder
, dpms_mode
);
360 mutex_unlock(&dev
->mode_config
.mutex
);
363 mutex_lock(&dev
->mode_config
.mutex
);
364 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_OFF
);
365 mutex_unlock(&dev
->mode_config
.mutex
);
370 int drm_fb_helper_blank(int blank
, struct fb_info
*info
)
373 /* Display: On; HSync: On, VSync: On */
374 case FB_BLANK_UNBLANK
:
375 drm_fb_helper_on(info
);
377 /* Display: Off; HSync: On, VSync: On */
378 case FB_BLANK_NORMAL
:
379 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
381 /* Display: Off; HSync: Off, VSync: On */
382 case FB_BLANK_HSYNC_SUSPEND
:
383 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
385 /* Display: Off; HSync: On, VSync: Off */
386 case FB_BLANK_VSYNC_SUSPEND
:
387 drm_fb_helper_off(info
, DRM_MODE_DPMS_SUSPEND
);
389 /* Display: Off; HSync: Off, VSync: Off */
390 case FB_BLANK_POWERDOWN
:
391 drm_fb_helper_off(info
, DRM_MODE_DPMS_OFF
);
396 EXPORT_SYMBOL(drm_fb_helper_blank
);
398 static void drm_fb_helper_crtc_free(struct drm_fb_helper
*helper
)
402 for (i
= 0; i
< helper
->crtc_count
; i
++)
403 kfree(helper
->crtc_info
[i
].mode_set
.connectors
);
404 kfree(helper
->crtc_info
);
407 int drm_fb_helper_init_crtc_count(struct drm_fb_helper
*helper
, int crtc_count
, int max_conn_count
)
409 struct drm_device
*dev
= helper
->dev
;
410 struct drm_crtc
*crtc
;
414 helper
->crtc_info
= kcalloc(crtc_count
, sizeof(struct drm_fb_helper_crtc
), GFP_KERNEL
);
415 if (!helper
->crtc_info
)
418 helper
->crtc_count
= crtc_count
;
420 for (i
= 0; i
< crtc_count
; i
++) {
421 helper
->crtc_info
[i
].mode_set
.connectors
=
422 kcalloc(max_conn_count
,
423 sizeof(struct drm_connector
*),
426 if (!helper
->crtc_info
[i
].mode_set
.connectors
) {
430 helper
->crtc_info
[i
].mode_set
.num_connectors
= 0;
434 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
435 helper
->crtc_info
[i
].crtc_id
= crtc
->base
.id
;
436 helper
->crtc_info
[i
].mode_set
.crtc
= crtc
;
439 helper
->conn_limit
= max_conn_count
;
442 drm_fb_helper_crtc_free(helper
);
445 EXPORT_SYMBOL(drm_fb_helper_init_crtc_count
);
447 static int setcolreg(struct drm_crtc
*crtc
, u16 red
, u16 green
,
448 u16 blue
, u16 regno
, struct fb_info
*info
)
450 struct drm_fb_helper
*fb_helper
= info
->par
;
451 struct drm_framebuffer
*fb
= fb_helper
->fb
;
454 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
457 /* place color in psuedopalette */
460 palette
= (u32
*)info
->pseudo_palette
;
461 red
>>= (16 - info
->var
.red
.length
);
462 green
>>= (16 - info
->var
.green
.length
);
463 blue
>>= (16 - info
->var
.blue
.length
);
464 value
= (red
<< info
->var
.red
.offset
) |
465 (green
<< info
->var
.green
.offset
) |
466 (blue
<< info
->var
.blue
.offset
);
467 palette
[regno
] = value
;
473 if (fb
->bits_per_pixel
== 16) {
476 if (fb
->depth
== 16 && regno
> 63)
478 if (fb
->depth
== 15 && regno
> 31)
481 if (fb
->depth
== 16) {
485 for (i
= 0; i
< 8; i
++)
486 fb_helper
->funcs
->gamma_set(crtc
, red
,
487 green
, blue
, pindex
+ i
);
490 fb_helper
->funcs
->gamma_get(crtc
, &r
,
494 for (i
= 0; i
< 4; i
++)
495 fb_helper
->funcs
->gamma_set(crtc
, r
,
502 fb_helper
->funcs
->gamma_set(crtc
, red
, green
, blue
, pindex
);
506 int drm_fb_helper_setcmap(struct fb_cmap
*cmap
, struct fb_info
*info
)
508 struct drm_fb_helper
*fb_helper
= info
->par
;
509 struct drm_device
*dev
= fb_helper
->dev
;
510 u16
*red
, *green
, *blue
, *transp
;
511 struct drm_crtc
*crtc
;
515 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
516 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
517 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
518 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
521 if (i
== fb_helper
->crtc_count
)
527 transp
= cmap
->transp
;
530 for (i
= 0; i
< cmap
->len
; i
++) {
531 u16 hred
, hgreen
, hblue
, htransp
= 0xffff;
540 rc
= setcolreg(crtc
, hred
, hgreen
, hblue
, start
++, info
);
544 crtc_funcs
->load_lut(crtc
);
548 EXPORT_SYMBOL(drm_fb_helper_setcmap
);
550 int drm_fb_helper_setcolreg(unsigned regno
,
555 struct fb_info
*info
)
557 struct drm_fb_helper
*fb_helper
= info
->par
;
558 struct drm_device
*dev
= fb_helper
->dev
;
559 struct drm_crtc
*crtc
;
566 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
567 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
568 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
569 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
572 if (i
== fb_helper
->crtc_count
)
575 ret
= setcolreg(crtc
, red
, green
, blue
, regno
, info
);
579 crtc_funcs
->load_lut(crtc
);
583 EXPORT_SYMBOL(drm_fb_helper_setcolreg
);
585 int drm_fb_helper_check_var(struct fb_var_screeninfo
*var
,
586 struct fb_info
*info
)
588 struct drm_fb_helper
*fb_helper
= info
->par
;
589 struct drm_framebuffer
*fb
= fb_helper
->fb
;
592 if (var
->pixclock
!= 0)
595 /* Need to resize the fb object !!! */
596 if (var
->bits_per_pixel
> fb
->bits_per_pixel
|| var
->xres
> fb
->width
|| var
->yres
> fb
->height
) {
597 DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
598 "object %dx%d-%d > %dx%d-%d\n", var
->xres
, var
->yres
, var
->bits_per_pixel
,
599 fb
->width
, fb
->height
, fb
->bits_per_pixel
);
603 switch (var
->bits_per_pixel
) {
605 depth
= (var
->green
.length
== 6) ? 16 : 15;
608 depth
= (var
->transp
.length
> 0) ? 32 : 24;
611 depth
= var
->bits_per_pixel
;
618 var
->green
.offset
= 0;
619 var
->blue
.offset
= 0;
621 var
->green
.length
= 8;
622 var
->blue
.length
= 8;
623 var
->transp
.length
= 0;
624 var
->transp
.offset
= 0;
627 var
->red
.offset
= 10;
628 var
->green
.offset
= 5;
629 var
->blue
.offset
= 0;
631 var
->green
.length
= 5;
632 var
->blue
.length
= 5;
633 var
->transp
.length
= 1;
634 var
->transp
.offset
= 15;
637 var
->red
.offset
= 11;
638 var
->green
.offset
= 5;
639 var
->blue
.offset
= 0;
641 var
->green
.length
= 6;
642 var
->blue
.length
= 5;
643 var
->transp
.length
= 0;
644 var
->transp
.offset
= 0;
647 var
->red
.offset
= 16;
648 var
->green
.offset
= 8;
649 var
->blue
.offset
= 0;
651 var
->green
.length
= 8;
652 var
->blue
.length
= 8;
653 var
->transp
.length
= 0;
654 var
->transp
.offset
= 0;
657 var
->red
.offset
= 16;
658 var
->green
.offset
= 8;
659 var
->blue
.offset
= 0;
661 var
->green
.length
= 8;
662 var
->blue
.length
= 8;
663 var
->transp
.length
= 8;
664 var
->transp
.offset
= 24;
671 EXPORT_SYMBOL(drm_fb_helper_check_var
);
673 /* this will let fbcon do the mode init */
674 int drm_fb_helper_set_par(struct fb_info
*info
)
676 struct drm_fb_helper
*fb_helper
= info
->par
;
677 struct drm_device
*dev
= fb_helper
->dev
;
678 struct fb_var_screeninfo
*var
= &info
->var
;
679 struct drm_crtc
*crtc
;
683 if (var
->pixclock
!= 0) {
684 DRM_ERROR("PIXEL CLOCK SET\n");
688 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
690 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
691 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
694 if (i
== fb_helper
->crtc_count
)
697 if (crtc
->fb
== fb_helper
->crtc_info
[i
].mode_set
.fb
) {
698 mutex_lock(&dev
->mode_config
.mutex
);
699 ret
= crtc
->funcs
->set_config(&fb_helper
->crtc_info
[i
].mode_set
);
700 mutex_unlock(&dev
->mode_config
.mutex
);
707 EXPORT_SYMBOL(drm_fb_helper_set_par
);
709 int drm_fb_helper_pan_display(struct fb_var_screeninfo
*var
,
710 struct fb_info
*info
)
712 struct drm_fb_helper
*fb_helper
= info
->par
;
713 struct drm_device
*dev
= fb_helper
->dev
;
714 struct drm_mode_set
*modeset
;
715 struct drm_crtc
*crtc
;
719 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
720 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
721 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
725 if (i
== fb_helper
->crtc_count
)
728 modeset
= &fb_helper
->crtc_info
[i
].mode_set
;
730 modeset
->x
= var
->xoffset
;
731 modeset
->y
= var
->yoffset
;
733 if (modeset
->num_connectors
) {
734 mutex_lock(&dev
->mode_config
.mutex
);
735 ret
= crtc
->funcs
->set_config(modeset
);
736 mutex_unlock(&dev
->mode_config
.mutex
);
738 info
->var
.xoffset
= var
->xoffset
;
739 info
->var
.yoffset
= var
->yoffset
;
745 EXPORT_SYMBOL(drm_fb_helper_pan_display
);
747 int drm_fb_helper_single_fb_probe(struct drm_device
*dev
,
749 int (*fb_create
)(struct drm_device
*dev
,
752 uint32_t surface_width
,
753 uint32_t surface_height
,
754 uint32_t surface_depth
,
755 uint32_t surface_bpp
,
756 struct drm_framebuffer
**fb_ptr
))
758 struct drm_crtc
*crtc
;
759 struct drm_connector
*connector
;
760 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
761 unsigned int surface_width
= 0, surface_height
= 0;
764 int ret
, i
, conn_count
= 0;
765 struct fb_info
*info
;
766 struct drm_framebuffer
*fb
;
767 struct drm_mode_set
*modeset
= NULL
;
768 struct drm_fb_helper
*fb_helper
;
769 uint32_t surface_depth
= 24, surface_bpp
= 32;
771 /* if driver picks 8 or 16 by default use that
772 for both depth/bpp */
773 if (preferred_bpp
!= surface_bpp
) {
774 surface_depth
= surface_bpp
= preferred_bpp
;
776 /* first up get a count of crtcs now in use and new min/maxes width/heights */
777 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
778 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
780 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
785 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
787 if (cmdline_mode
->bpp_specified
) {
788 switch (cmdline_mode
->bpp
) {
790 surface_depth
= surface_bpp
= 8;
797 surface_depth
= surface_bpp
= 16;
800 surface_depth
= surface_bpp
= 24;
811 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
812 if (drm_helper_crtc_in_use(crtc
)) {
813 if (crtc
->desired_mode
) {
814 if (crtc
->desired_mode
->hdisplay
< fb_width
)
815 fb_width
= crtc
->desired_mode
->hdisplay
;
817 if (crtc
->desired_mode
->vdisplay
< fb_height
)
818 fb_height
= crtc
->desired_mode
->vdisplay
;
820 if (crtc
->desired_mode
->hdisplay
> surface_width
)
821 surface_width
= crtc
->desired_mode
->hdisplay
;
823 if (crtc
->desired_mode
->vdisplay
> surface_height
)
824 surface_height
= crtc
->desired_mode
->vdisplay
;
830 if (crtc_count
== 0 || fb_width
== -1 || fb_height
== -1) {
831 /* hmm everyone went away - assume VGA cable just fell out
832 and will come back later. */
836 /* do we have an fb already? */
837 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
838 ret
= (*fb_create
)(dev
, fb_width
, fb_height
, surface_width
,
839 surface_height
, surface_depth
, surface_bpp
,
845 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
846 struct drm_framebuffer
, filp_head
);
848 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
849 As really we can't resize an fbdev that is in the wild currently due to fbdev
850 not really being designed for the lower layers moving stuff around under it.
851 - so in the grand style of things - punt. */
852 if ((fb
->width
< surface_width
) ||
853 (fb
->height
< surface_height
)) {
854 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
860 fb_helper
= info
->par
;
863 /* okay we need to setup new connector sets in the crtcs */
864 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
865 modeset
= &fb_helper
->crtc_info
[crtc_count
].mode_set
;
868 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
869 if (connector
->encoder
)
870 if (connector
->encoder
->crtc
== modeset
->crtc
) {
871 modeset
->connectors
[conn_count
] = connector
;
873 if (conn_count
> fb_helper
->conn_limit
)
878 for (i
= conn_count
; i
< fb_helper
->conn_limit
; i
++)
879 modeset
->connectors
[i
] = NULL
;
881 modeset
->crtc
= crtc
;
884 modeset
->num_connectors
= conn_count
;
885 if (modeset
->crtc
->desired_mode
) {
887 drm_mode_destroy(dev
, modeset
->mode
);
888 modeset
->mode
= drm_mode_duplicate(dev
,
889 modeset
->crtc
->desired_mode
);
892 fb_helper
->crtc_count
= crtc_count
;
896 info
->var
.pixclock
= 0;
897 ret
= fb_alloc_cmap(&info
->cmap
, modeset
->crtc
->gamma_size
, 0);
900 if (register_framebuffer(info
) < 0) {
901 fb_dealloc_cmap(&info
->cmap
);
905 drm_fb_helper_set_par(info
);
907 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
910 /* Switch back to kernel console on panic */
911 /* multi card linked list maybe */
912 if (list_empty(&kernel_fb_helper_list
)) {
913 printk(KERN_INFO
"registered panic notifier\n");
914 atomic_notifier_chain_register(&panic_notifier_list
,
916 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
918 list_add(&fb_helper
->kernel_fb_list
, &kernel_fb_helper_list
);
921 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe
);
923 void drm_fb_helper_free(struct drm_fb_helper
*helper
)
925 list_del(&helper
->kernel_fb_list
);
926 if (list_empty(&kernel_fb_helper_list
)) {
927 printk(KERN_INFO
"unregistered panic notifier\n");
928 atomic_notifier_chain_unregister(&panic_notifier_list
,
930 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
932 drm_fb_helper_crtc_free(helper
);
933 fb_dealloc_cmap(&helper
->fb
->fbdev
->cmap
);
935 EXPORT_SYMBOL(drm_fb_helper_free
);
937 void drm_fb_helper_fill_fix(struct fb_info
*info
, uint32_t pitch
,
940 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
941 info
->fix
.visual
= depth
== 8 ? FB_VISUAL_PSEUDOCOLOR
:
943 info
->fix
.type_aux
= 0;
944 info
->fix
.xpanstep
= 1; /* doing it in hw */
945 info
->fix
.ypanstep
= 1; /* doing it in hw */
946 info
->fix
.ywrapstep
= 0;
947 info
->fix
.accel
= FB_ACCEL_NONE
;
948 info
->fix
.type_aux
= 0;
950 info
->fix
.line_length
= pitch
;
953 EXPORT_SYMBOL(drm_fb_helper_fill_fix
);
955 void drm_fb_helper_fill_var(struct fb_info
*info
, struct drm_framebuffer
*fb
,
956 uint32_t fb_width
, uint32_t fb_height
)
958 info
->pseudo_palette
= fb
->pseudo_palette
;
959 info
->var
.xres_virtual
= fb
->width
;
960 info
->var
.yres_virtual
= fb
->height
;
961 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
962 info
->var
.xoffset
= 0;
963 info
->var
.yoffset
= 0;
964 info
->var
.activate
= FB_ACTIVATE_NOW
;
965 info
->var
.height
= -1;
966 info
->var
.width
= -1;
970 info
->var
.red
.offset
= 0;
971 info
->var
.green
.offset
= 0;
972 info
->var
.blue
.offset
= 0;
973 info
->var
.red
.length
= 8; /* 8bit DAC */
974 info
->var
.green
.length
= 8;
975 info
->var
.blue
.length
= 8;
976 info
->var
.transp
.offset
= 0;
977 info
->var
.transp
.length
= 0;
980 info
->var
.red
.offset
= 10;
981 info
->var
.green
.offset
= 5;
982 info
->var
.blue
.offset
= 0;
983 info
->var
.red
.length
= 5;
984 info
->var
.green
.length
= 5;
985 info
->var
.blue
.length
= 5;
986 info
->var
.transp
.offset
= 15;
987 info
->var
.transp
.length
= 1;
990 info
->var
.red
.offset
= 11;
991 info
->var
.green
.offset
= 5;
992 info
->var
.blue
.offset
= 0;
993 info
->var
.red
.length
= 5;
994 info
->var
.green
.length
= 6;
995 info
->var
.blue
.length
= 5;
996 info
->var
.transp
.offset
= 0;
999 info
->var
.red
.offset
= 16;
1000 info
->var
.green
.offset
= 8;
1001 info
->var
.blue
.offset
= 0;
1002 info
->var
.red
.length
= 8;
1003 info
->var
.green
.length
= 8;
1004 info
->var
.blue
.length
= 8;
1005 info
->var
.transp
.offset
= 0;
1006 info
->var
.transp
.length
= 0;
1009 info
->var
.red
.offset
= 16;
1010 info
->var
.green
.offset
= 8;
1011 info
->var
.blue
.offset
= 0;
1012 info
->var
.red
.length
= 8;
1013 info
->var
.green
.length
= 8;
1014 info
->var
.blue
.length
= 8;
1015 info
->var
.transp
.offset
= 24;
1016 info
->var
.transp
.length
= 8;
1022 info
->var
.xres
= fb_width
;
1023 info
->var
.yres
= fb_height
;
1025 EXPORT_SYMBOL(drm_fb_helper_fill_var
);