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>
35 #include "drm_fb_helper.h"
36 #include "drm_crtc_helper.h"
38 MODULE_AUTHOR("David Airlie, Jesse Barnes");
39 MODULE_DESCRIPTION("DRM KMS helper");
40 MODULE_LICENSE("GPL and additional rights");
42 static LIST_HEAD(kernel_fb_helper_list
);
44 int drm_fb_helper_add_connector(struct drm_connector
*connector
)
46 connector
->fb_helper_private
= kzalloc(sizeof(struct drm_fb_helper_connector
), GFP_KERNEL
);
47 if (!connector
->fb_helper_private
)
52 EXPORT_SYMBOL(drm_fb_helper_add_connector
);
55 * drm_fb_helper_connector_parse_command_line - parse command line for connector
56 * @connector - connector to parse line for
57 * @mode_option - per connector mode option
59 * This parses the connector specific then generic command lines for
60 * modes and options to configure the connector.
62 * This uses the same parameters as the fb modedb.c, except for extra
63 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
65 * enable/enable Digital/disable bit at the end
67 static bool drm_fb_helper_connector_parse_command_line(struct drm_connector
*connector
,
68 const char *mode_option
)
72 int res_specified
= 0, bpp_specified
= 0, refresh_specified
= 0;
73 unsigned int xres
= 0, yres
= 0, bpp
= 32, refresh
= 0;
74 int yres_specified
= 0, cvt
= 0, rb
= 0, interlace
= 0, margins
= 0;
76 enum drm_connector_force force
= DRM_FORCE_UNSPECIFIED
;
77 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
78 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
83 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
85 mode_option
= fb_mode_option
;
88 cmdline_mode
->specified
= false;
93 namelen
= strlen(name
);
94 for (i
= namelen
-1; i
>= 0; i
--) {
98 if (!refresh_specified
&& !bpp_specified
&&
100 refresh
= simple_strtol(&name
[i
+1], NULL
, 10);
101 refresh_specified
= 1;
109 if (!bpp_specified
&& !yres_specified
) {
110 bpp
= simple_strtol(&name
[i
+1], NULL
, 10);
118 if (!yres_specified
) {
119 yres
= simple_strtol(&name
[i
+1], NULL
, 10);
142 force
= DRM_FORCE_ON
;
145 if ((connector
->connector_type
!= DRM_MODE_CONNECTOR_DVII
) &&
146 (connector
->connector_type
!= DRM_MODE_CONNECTOR_HDMIB
))
147 force
= DRM_FORCE_ON
;
149 force
= DRM_FORCE_ON_DIGITAL
;
152 force
= DRM_FORCE_OFF
;
158 if (i
< 0 && yres_specified
) {
159 xres
= simple_strtol(name
, NULL
, 10);
164 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
165 drm_get_connector_name(connector
), xres
, yres
,
166 (refresh
) ? refresh
: 60, (rb
) ? " reduced blanking" :
167 "", (margins
) ? " with margins" : "", (interlace
) ?
173 case DRM_FORCE_OFF
: s
= "OFF"; break;
174 case DRM_FORCE_ON_DIGITAL
: s
= "ON - dig"; break;
176 case DRM_FORCE_ON
: s
= "ON"; break;
179 DRM_INFO("forcing %s connector %s\n",
180 drm_get_connector_name(connector
), s
);
181 connector
->force
= force
;
185 cmdline_mode
->specified
= true;
186 cmdline_mode
->xres
= xres
;
187 cmdline_mode
->yres
= yres
;
190 if (refresh_specified
) {
191 cmdline_mode
->refresh_specified
= true;
192 cmdline_mode
->refresh
= refresh
;
196 cmdline_mode
->bpp_specified
= true;
197 cmdline_mode
->bpp
= bpp
;
199 cmdline_mode
->rb
= rb
? true : false;
200 cmdline_mode
->cvt
= cvt
? true : false;
201 cmdline_mode
->interlace
= interlace
? true : false;
206 int drm_fb_helper_parse_command_line(struct drm_device
*dev
)
208 struct drm_connector
*connector
;
210 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
213 /* do something on return - turn off connector maybe */
214 if (fb_get_options(drm_get_connector_name(connector
), &option
))
217 drm_fb_helper_connector_parse_command_line(connector
, option
);
222 bool drm_fb_helper_force_kernel_mode(void)
225 bool ret
, error
= false;
226 struct drm_fb_helper
*helper
;
228 if (list_empty(&kernel_fb_helper_list
))
231 list_for_each_entry(helper
, &kernel_fb_helper_list
, kernel_fb_list
) {
232 for (i
= 0; i
< helper
->crtc_count
; i
++) {
233 struct drm_mode_set
*mode_set
= &helper
->crtc_info
[i
].mode_set
;
234 ret
= drm_crtc_helper_set_config(mode_set
);
242 int drm_fb_helper_panic(struct notifier_block
*n
, unsigned long ununsed
,
245 DRM_ERROR("panic occurred, switching back to text console\n");
246 return drm_fb_helper_force_kernel_mode();
249 EXPORT_SYMBOL(drm_fb_helper_panic
);
251 static struct notifier_block paniced
= {
252 .notifier_call
= drm_fb_helper_panic
,
256 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
258 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
260 void drm_fb_helper_restore(void)
263 ret
= drm_fb_helper_force_kernel_mode();
265 DRM_ERROR("Failed to restore crtc configuration\n");
267 EXPORT_SYMBOL(drm_fb_helper_restore
);
269 #ifdef CONFIG_MAGIC_SYSRQ
270 static void drm_fb_helper_restore_work_fn(struct work_struct
*ignored
)
272 drm_fb_helper_restore();
274 static DECLARE_WORK(drm_fb_helper_restore_work
, drm_fb_helper_restore_work_fn
);
276 static void drm_fb_helper_sysrq(int dummy1
, struct tty_struct
*dummy3
)
278 schedule_work(&drm_fb_helper_restore_work
);
281 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op
= {
282 .handler
= drm_fb_helper_sysrq
,
283 .help_msg
= "force-fb(V)",
284 .action_msg
= "Restore framebuffer console",
288 static void drm_fb_helper_on(struct fb_info
*info
)
290 struct drm_fb_helper
*fb_helper
= info
->par
;
291 struct drm_device
*dev
= fb_helper
->dev
;
292 struct drm_crtc
*crtc
;
293 struct drm_encoder
*encoder
;
297 * For each CRTC in this fb, turn the crtc on then,
298 * find all associated encoders and turn them on.
300 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
301 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
302 struct drm_crtc_helper_funcs
*crtc_funcs
=
303 crtc
->helper_private
;
305 /* Only mess with CRTCs in this fb */
306 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
310 mutex_lock(&dev
->mode_config
.mutex
);
311 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_ON
);
312 mutex_unlock(&dev
->mode_config
.mutex
);
314 /* Found a CRTC on this fb, now find encoders */
315 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
316 if (encoder
->crtc
== crtc
) {
317 struct drm_encoder_helper_funcs
*encoder_funcs
;
319 encoder_funcs
= encoder
->helper_private
;
320 mutex_lock(&dev
->mode_config
.mutex
);
321 encoder_funcs
->dpms(encoder
, DRM_MODE_DPMS_ON
);
322 mutex_unlock(&dev
->mode_config
.mutex
);
329 static void drm_fb_helper_off(struct fb_info
*info
, int dpms_mode
)
331 struct drm_fb_helper
*fb_helper
= info
->par
;
332 struct drm_device
*dev
= fb_helper
->dev
;
333 struct drm_crtc
*crtc
;
334 struct drm_encoder
*encoder
;
338 * For each CRTC in this fb, find all associated encoders
339 * and turn them off, then turn off the CRTC.
341 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
342 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
343 struct drm_crtc_helper_funcs
*crtc_funcs
=
344 crtc
->helper_private
;
346 /* Only mess with CRTCs in this fb */
347 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
351 /* Found a CRTC on this fb, now find encoders */
352 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
353 if (encoder
->crtc
== crtc
) {
354 struct drm_encoder_helper_funcs
*encoder_funcs
;
356 encoder_funcs
= encoder
->helper_private
;
357 mutex_lock(&dev
->mode_config
.mutex
);
358 encoder_funcs
->dpms(encoder
, dpms_mode
);
359 mutex_unlock(&dev
->mode_config
.mutex
);
362 mutex_lock(&dev
->mode_config
.mutex
);
363 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_OFF
);
364 mutex_unlock(&dev
->mode_config
.mutex
);
369 int drm_fb_helper_blank(int blank
, struct fb_info
*info
)
372 /* Display: On; HSync: On, VSync: On */
373 case FB_BLANK_UNBLANK
:
374 drm_fb_helper_on(info
);
376 /* Display: Off; HSync: On, VSync: On */
377 case FB_BLANK_NORMAL
:
378 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
380 /* Display: Off; HSync: Off, VSync: On */
381 case FB_BLANK_HSYNC_SUSPEND
:
382 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
384 /* Display: Off; HSync: On, VSync: Off */
385 case FB_BLANK_VSYNC_SUSPEND
:
386 drm_fb_helper_off(info
, DRM_MODE_DPMS_SUSPEND
);
388 /* Display: Off; HSync: Off, VSync: Off */
389 case FB_BLANK_POWERDOWN
:
390 drm_fb_helper_off(info
, DRM_MODE_DPMS_OFF
);
395 EXPORT_SYMBOL(drm_fb_helper_blank
);
397 static void drm_fb_helper_crtc_free(struct drm_fb_helper
*helper
)
401 for (i
= 0; i
< helper
->crtc_count
; i
++)
402 kfree(helper
->crtc_info
[i
].mode_set
.connectors
);
403 kfree(helper
->crtc_info
);
406 int drm_fb_helper_init_crtc_count(struct drm_fb_helper
*helper
, int crtc_count
, int max_conn_count
)
408 struct drm_device
*dev
= helper
->dev
;
409 struct drm_crtc
*crtc
;
413 helper
->crtc_info
= kcalloc(crtc_count
, sizeof(struct drm_fb_helper_crtc
), GFP_KERNEL
);
414 if (!helper
->crtc_info
)
417 helper
->crtc_count
= crtc_count
;
419 for (i
= 0; i
< crtc_count
; i
++) {
420 helper
->crtc_info
[i
].mode_set
.connectors
=
421 kcalloc(max_conn_count
,
422 sizeof(struct drm_connector
*),
425 if (!helper
->crtc_info
[i
].mode_set
.connectors
) {
429 helper
->crtc_info
[i
].mode_set
.num_connectors
= 0;
433 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
434 helper
->crtc_info
[i
].crtc_id
= crtc
->base
.id
;
435 helper
->crtc_info
[i
].mode_set
.crtc
= crtc
;
438 helper
->conn_limit
= max_conn_count
;
441 drm_fb_helper_crtc_free(helper
);
444 EXPORT_SYMBOL(drm_fb_helper_init_crtc_count
);
446 static int setcolreg(struct drm_crtc
*crtc
, u16 red
, u16 green
,
447 u16 blue
, u16 regno
, struct fb_info
*info
)
449 struct drm_fb_helper
*fb_helper
= info
->par
;
450 struct drm_framebuffer
*fb
= fb_helper
->fb
;
453 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
456 /* place color in psuedopalette */
459 palette
= (u32
*)info
->pseudo_palette
;
460 red
>>= (16 - info
->var
.red
.length
);
461 green
>>= (16 - info
->var
.green
.length
);
462 blue
>>= (16 - info
->var
.blue
.length
);
463 value
= (red
<< info
->var
.red
.offset
) |
464 (green
<< info
->var
.green
.offset
) |
465 (blue
<< info
->var
.blue
.offset
);
466 palette
[regno
] = value
;
472 if (fb
->bits_per_pixel
== 16) {
475 if (fb
->depth
== 16 && regno
> 63)
477 if (fb
->depth
== 15 && regno
> 31)
480 if (fb
->depth
== 16) {
484 for (i
= 0; i
< 8; i
++)
485 fb_helper
->funcs
->gamma_set(crtc
, red
,
486 green
, blue
, pindex
+ i
);
489 fb_helper
->funcs
->gamma_get(crtc
, &r
,
493 for (i
= 0; i
< 4; i
++)
494 fb_helper
->funcs
->gamma_set(crtc
, r
,
501 fb_helper
->funcs
->gamma_set(crtc
, red
, green
, blue
, pindex
);
505 int drm_fb_helper_setcmap(struct fb_cmap
*cmap
, struct fb_info
*info
)
507 struct drm_fb_helper
*fb_helper
= info
->par
;
508 struct drm_device
*dev
= fb_helper
->dev
;
509 u16
*red
, *green
, *blue
, *transp
;
510 struct drm_crtc
*crtc
;
514 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
515 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
516 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
517 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
520 if (i
== fb_helper
->crtc_count
)
526 transp
= cmap
->transp
;
529 for (i
= 0; i
< cmap
->len
; i
++) {
530 u16 hred
, hgreen
, hblue
, htransp
= 0xffff;
539 rc
= setcolreg(crtc
, hred
, hgreen
, hblue
, start
++, info
);
543 crtc_funcs
->load_lut(crtc
);
547 EXPORT_SYMBOL(drm_fb_helper_setcmap
);
549 int drm_fb_helper_setcolreg(unsigned regno
,
554 struct fb_info
*info
)
556 struct drm_fb_helper
*fb_helper
= info
->par
;
557 struct drm_device
*dev
= fb_helper
->dev
;
558 struct drm_crtc
*crtc
;
565 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
566 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
567 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
568 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
571 if (i
== fb_helper
->crtc_count
)
574 ret
= setcolreg(crtc
, red
, green
, blue
, regno
, info
);
578 crtc_funcs
->load_lut(crtc
);
582 EXPORT_SYMBOL(drm_fb_helper_setcolreg
);
584 int drm_fb_helper_check_var(struct fb_var_screeninfo
*var
,
585 struct fb_info
*info
)
587 struct drm_fb_helper
*fb_helper
= info
->par
;
588 struct drm_framebuffer
*fb
= fb_helper
->fb
;
591 if (var
->pixclock
!= 0)
594 /* Need to resize the fb object !!! */
595 if (var
->bits_per_pixel
> fb
->bits_per_pixel
|| var
->xres
> fb
->width
|| var
->yres
> fb
->height
) {
596 DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
597 "object %dx%d-%d > %dx%d-%d\n", var
->xres
, var
->yres
, var
->bits_per_pixel
,
598 fb
->width
, fb
->height
, fb
->bits_per_pixel
);
602 switch (var
->bits_per_pixel
) {
604 depth
= (var
->green
.length
== 6) ? 16 : 15;
607 depth
= (var
->transp
.length
> 0) ? 32 : 24;
610 depth
= var
->bits_per_pixel
;
617 var
->green
.offset
= 0;
618 var
->blue
.offset
= 0;
620 var
->green
.length
= 8;
621 var
->blue
.length
= 8;
622 var
->transp
.length
= 0;
623 var
->transp
.offset
= 0;
626 var
->red
.offset
= 10;
627 var
->green
.offset
= 5;
628 var
->blue
.offset
= 0;
630 var
->green
.length
= 5;
631 var
->blue
.length
= 5;
632 var
->transp
.length
= 1;
633 var
->transp
.offset
= 15;
636 var
->red
.offset
= 11;
637 var
->green
.offset
= 5;
638 var
->blue
.offset
= 0;
640 var
->green
.length
= 6;
641 var
->blue
.length
= 5;
642 var
->transp
.length
= 0;
643 var
->transp
.offset
= 0;
646 var
->red
.offset
= 16;
647 var
->green
.offset
= 8;
648 var
->blue
.offset
= 0;
650 var
->green
.length
= 8;
651 var
->blue
.length
= 8;
652 var
->transp
.length
= 0;
653 var
->transp
.offset
= 0;
656 var
->red
.offset
= 16;
657 var
->green
.offset
= 8;
658 var
->blue
.offset
= 0;
660 var
->green
.length
= 8;
661 var
->blue
.length
= 8;
662 var
->transp
.length
= 8;
663 var
->transp
.offset
= 24;
670 EXPORT_SYMBOL(drm_fb_helper_check_var
);
672 /* this will let fbcon do the mode init */
673 int drm_fb_helper_set_par(struct fb_info
*info
)
675 struct drm_fb_helper
*fb_helper
= info
->par
;
676 struct drm_device
*dev
= fb_helper
->dev
;
677 struct fb_var_screeninfo
*var
= &info
->var
;
678 struct drm_crtc
*crtc
;
682 if (var
->pixclock
!= 0) {
683 DRM_ERROR("PIXEL CLOCK SET\n");
687 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
689 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
690 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
693 if (i
== fb_helper
->crtc_count
)
696 if (crtc
->fb
== fb_helper
->crtc_info
[i
].mode_set
.fb
) {
697 mutex_lock(&dev
->mode_config
.mutex
);
698 ret
= crtc
->funcs
->set_config(&fb_helper
->crtc_info
[i
].mode_set
);
699 mutex_unlock(&dev
->mode_config
.mutex
);
706 EXPORT_SYMBOL(drm_fb_helper_set_par
);
708 int drm_fb_helper_pan_display(struct fb_var_screeninfo
*var
,
709 struct fb_info
*info
)
711 struct drm_fb_helper
*fb_helper
= info
->par
;
712 struct drm_device
*dev
= fb_helper
->dev
;
713 struct drm_mode_set
*modeset
;
714 struct drm_crtc
*crtc
;
718 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
719 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
720 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
724 if (i
== fb_helper
->crtc_count
)
727 modeset
= &fb_helper
->crtc_info
[i
].mode_set
;
729 modeset
->x
= var
->xoffset
;
730 modeset
->y
= var
->yoffset
;
732 if (modeset
->num_connectors
) {
733 mutex_lock(&dev
->mode_config
.mutex
);
734 ret
= crtc
->funcs
->set_config(modeset
);
735 mutex_unlock(&dev
->mode_config
.mutex
);
737 info
->var
.xoffset
= var
->xoffset
;
738 info
->var
.yoffset
= var
->yoffset
;
744 EXPORT_SYMBOL(drm_fb_helper_pan_display
);
746 int drm_fb_helper_single_fb_probe(struct drm_device
*dev
,
748 int (*fb_create
)(struct drm_device
*dev
,
751 uint32_t surface_width
,
752 uint32_t surface_height
,
753 uint32_t surface_depth
,
754 uint32_t surface_bpp
,
755 struct drm_framebuffer
**fb_ptr
))
757 struct drm_crtc
*crtc
;
758 struct drm_connector
*connector
;
759 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
760 unsigned int surface_width
= 0, surface_height
= 0;
763 int ret
, i
, conn_count
= 0;
764 struct fb_info
*info
;
765 struct drm_framebuffer
*fb
;
766 struct drm_mode_set
*modeset
= NULL
;
767 struct drm_fb_helper
*fb_helper
;
768 uint32_t surface_depth
= 24, surface_bpp
= 32;
770 /* if driver picks 8 or 16 by default use that
771 for both depth/bpp */
772 if (preferred_bpp
!= surface_bpp
) {
773 surface_depth
= surface_bpp
= preferred_bpp
;
775 /* first up get a count of crtcs now in use and new min/maxes width/heights */
776 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
777 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
779 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
784 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
786 if (cmdline_mode
->bpp_specified
) {
787 switch (cmdline_mode
->bpp
) {
789 surface_depth
= surface_bpp
= 8;
796 surface_depth
= surface_bpp
= 16;
799 surface_depth
= surface_bpp
= 24;
810 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
811 if (drm_helper_crtc_in_use(crtc
)) {
812 if (crtc
->desired_mode
) {
813 if (crtc
->desired_mode
->hdisplay
< fb_width
)
814 fb_width
= crtc
->desired_mode
->hdisplay
;
816 if (crtc
->desired_mode
->vdisplay
< fb_height
)
817 fb_height
= crtc
->desired_mode
->vdisplay
;
819 if (crtc
->desired_mode
->hdisplay
> surface_width
)
820 surface_width
= crtc
->desired_mode
->hdisplay
;
822 if (crtc
->desired_mode
->vdisplay
> surface_height
)
823 surface_height
= crtc
->desired_mode
->vdisplay
;
829 if (crtc_count
== 0 || fb_width
== -1 || fb_height
== -1) {
830 /* hmm everyone went away - assume VGA cable just fell out
831 and will come back later. */
835 /* do we have an fb already? */
836 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
837 ret
= (*fb_create
)(dev
, fb_width
, fb_height
, surface_width
,
838 surface_height
, surface_depth
, surface_bpp
,
844 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
845 struct drm_framebuffer
, filp_head
);
847 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
848 As really we can't resize an fbdev that is in the wild currently due to fbdev
849 not really being designed for the lower layers moving stuff around under it.
850 - so in the grand style of things - punt. */
851 if ((fb
->width
< surface_width
) ||
852 (fb
->height
< surface_height
)) {
853 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
859 fb_helper
= info
->par
;
862 /* okay we need to setup new connector sets in the crtcs */
863 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
864 modeset
= &fb_helper
->crtc_info
[crtc_count
].mode_set
;
867 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
868 if (connector
->encoder
)
869 if (connector
->encoder
->crtc
== modeset
->crtc
) {
870 modeset
->connectors
[conn_count
] = connector
;
872 if (conn_count
> fb_helper
->conn_limit
)
877 for (i
= conn_count
; i
< fb_helper
->conn_limit
; i
++)
878 modeset
->connectors
[i
] = NULL
;
880 modeset
->crtc
= crtc
;
883 modeset
->num_connectors
= conn_count
;
884 if (modeset
->crtc
->desired_mode
) {
886 drm_mode_destroy(dev
, modeset
->mode
);
887 modeset
->mode
= drm_mode_duplicate(dev
,
888 modeset
->crtc
->desired_mode
);
891 fb_helper
->crtc_count
= crtc_count
;
895 info
->var
.pixclock
= 0;
896 ret
= fb_alloc_cmap(&info
->cmap
, modeset
->crtc
->gamma_size
, 0);
899 if (register_framebuffer(info
) < 0) {
900 fb_dealloc_cmap(&info
->cmap
);
904 drm_fb_helper_set_par(info
);
906 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
909 /* Switch back to kernel console on panic */
910 /* multi card linked list maybe */
911 if (list_empty(&kernel_fb_helper_list
)) {
912 printk(KERN_INFO
"registered panic notifier\n");
913 atomic_notifier_chain_register(&panic_notifier_list
,
915 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
917 list_add(&fb_helper
->kernel_fb_list
, &kernel_fb_helper_list
);
920 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe
);
922 void drm_fb_helper_free(struct drm_fb_helper
*helper
)
924 list_del(&helper
->kernel_fb_list
);
925 if (list_empty(&kernel_fb_helper_list
)) {
926 printk(KERN_INFO
"unregistered panic notifier\n");
927 atomic_notifier_chain_unregister(&panic_notifier_list
,
929 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
931 drm_fb_helper_crtc_free(helper
);
932 fb_dealloc_cmap(&helper
->fb
->fbdev
->cmap
);
934 EXPORT_SYMBOL(drm_fb_helper_free
);
936 void drm_fb_helper_fill_fix(struct fb_info
*info
, uint32_t pitch
,
939 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
940 info
->fix
.visual
= depth
== 8 ? FB_VISUAL_PSEUDOCOLOR
:
942 info
->fix
.type_aux
= 0;
943 info
->fix
.xpanstep
= 1; /* doing it in hw */
944 info
->fix
.ypanstep
= 1; /* doing it in hw */
945 info
->fix
.ywrapstep
= 0;
946 info
->fix
.accel
= FB_ACCEL_NONE
;
947 info
->fix
.type_aux
= 0;
949 info
->fix
.line_length
= pitch
;
952 EXPORT_SYMBOL(drm_fb_helper_fill_fix
);
954 void drm_fb_helper_fill_var(struct fb_info
*info
, struct drm_framebuffer
*fb
,
955 uint32_t fb_width
, uint32_t fb_height
)
957 info
->pseudo_palette
= fb
->pseudo_palette
;
958 info
->var
.xres_virtual
= fb
->width
;
959 info
->var
.yres_virtual
= fb
->height
;
960 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
961 info
->var
.xoffset
= 0;
962 info
->var
.yoffset
= 0;
963 info
->var
.activate
= FB_ACTIVATE_NOW
;
964 info
->var
.height
= -1;
965 info
->var
.width
= -1;
969 info
->var
.red
.offset
= 0;
970 info
->var
.green
.offset
= 0;
971 info
->var
.blue
.offset
= 0;
972 info
->var
.red
.length
= 8; /* 8bit DAC */
973 info
->var
.green
.length
= 8;
974 info
->var
.blue
.length
= 8;
975 info
->var
.transp
.offset
= 0;
976 info
->var
.transp
.length
= 0;
979 info
->var
.red
.offset
= 10;
980 info
->var
.green
.offset
= 5;
981 info
->var
.blue
.offset
= 0;
982 info
->var
.red
.length
= 5;
983 info
->var
.green
.length
= 5;
984 info
->var
.blue
.length
= 5;
985 info
->var
.transp
.offset
= 15;
986 info
->var
.transp
.length
= 1;
989 info
->var
.red
.offset
= 11;
990 info
->var
.green
.offset
= 5;
991 info
->var
.blue
.offset
= 0;
992 info
->var
.red
.length
= 5;
993 info
->var
.green
.length
= 6;
994 info
->var
.blue
.length
= 5;
995 info
->var
.transp
.offset
= 0;
998 info
->var
.red
.offset
= 16;
999 info
->var
.green
.offset
= 8;
1000 info
->var
.blue
.offset
= 0;
1001 info
->var
.red
.length
= 8;
1002 info
->var
.green
.length
= 8;
1003 info
->var
.blue
.length
= 8;
1004 info
->var
.transp
.offset
= 0;
1005 info
->var
.transp
.length
= 0;
1008 info
->var
.red
.offset
= 16;
1009 info
->var
.green
.offset
= 8;
1010 info
->var
.blue
.offset
= 0;
1011 info
->var
.red
.length
= 8;
1012 info
->var
.green
.length
= 8;
1013 info
->var
.blue
.length
= 8;
1014 info
->var
.transp
.offset
= 24;
1015 info
->var
.transp
.length
= 8;
1021 info
->var
.xres
= fb_width
;
1022 info
->var
.yres
= fb_height
;
1024 EXPORT_SYMBOL(drm_fb_helper_fill_var
);