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 #ifdef CONFIG_MAGIC_SYSRQ
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",
302 static void drm_fb_helper_on(struct fb_info
*info
)
304 struct drm_fb_helper
*fb_helper
= info
->par
;
305 struct drm_device
*dev
= fb_helper
->dev
;
306 struct drm_crtc
*crtc
;
307 struct drm_encoder
*encoder
;
311 * For each CRTC in this fb, turn the crtc on then,
312 * find all associated encoders and turn them on.
314 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
315 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
316 struct drm_crtc_helper_funcs
*crtc_funcs
=
317 crtc
->helper_private
;
319 /* Only mess with CRTCs in this fb */
320 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
324 mutex_lock(&dev
->mode_config
.mutex
);
325 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_ON
);
326 mutex_unlock(&dev
->mode_config
.mutex
);
328 /* Found a CRTC on this fb, now find encoders */
329 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
330 if (encoder
->crtc
== crtc
) {
331 struct drm_encoder_helper_funcs
*encoder_funcs
;
333 encoder_funcs
= encoder
->helper_private
;
334 mutex_lock(&dev
->mode_config
.mutex
);
335 encoder_funcs
->dpms(encoder
, DRM_MODE_DPMS_ON
);
336 mutex_unlock(&dev
->mode_config
.mutex
);
343 static void drm_fb_helper_off(struct fb_info
*info
, int dpms_mode
)
345 struct drm_fb_helper
*fb_helper
= info
->par
;
346 struct drm_device
*dev
= fb_helper
->dev
;
347 struct drm_crtc
*crtc
;
348 struct drm_encoder
*encoder
;
352 * For each CRTC in this fb, find all associated encoders
353 * and turn them off, then turn off the CRTC.
355 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
356 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
357 struct drm_crtc_helper_funcs
*crtc_funcs
=
358 crtc
->helper_private
;
360 /* Only mess with CRTCs in this fb */
361 if (crtc
->base
.id
!= fb_helper
->crtc_info
[i
].crtc_id
||
365 /* Found a CRTC on this fb, now find encoders */
366 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
367 if (encoder
->crtc
== crtc
) {
368 struct drm_encoder_helper_funcs
*encoder_funcs
;
370 encoder_funcs
= encoder
->helper_private
;
371 mutex_lock(&dev
->mode_config
.mutex
);
372 encoder_funcs
->dpms(encoder
, dpms_mode
);
373 mutex_unlock(&dev
->mode_config
.mutex
);
376 mutex_lock(&dev
->mode_config
.mutex
);
377 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_OFF
);
378 mutex_unlock(&dev
->mode_config
.mutex
);
383 int drm_fb_helper_blank(int blank
, struct fb_info
*info
)
386 /* Display: On; HSync: On, VSync: On */
387 case FB_BLANK_UNBLANK
:
388 drm_fb_helper_on(info
);
390 /* Display: Off; HSync: On, VSync: On */
391 case FB_BLANK_NORMAL
:
392 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
394 /* Display: Off; HSync: Off, VSync: On */
395 case FB_BLANK_HSYNC_SUSPEND
:
396 drm_fb_helper_off(info
, DRM_MODE_DPMS_STANDBY
);
398 /* Display: Off; HSync: On, VSync: Off */
399 case FB_BLANK_VSYNC_SUSPEND
:
400 drm_fb_helper_off(info
, DRM_MODE_DPMS_SUSPEND
);
402 /* Display: Off; HSync: Off, VSync: Off */
403 case FB_BLANK_POWERDOWN
:
404 drm_fb_helper_off(info
, DRM_MODE_DPMS_OFF
);
409 EXPORT_SYMBOL(drm_fb_helper_blank
);
411 static void drm_fb_helper_crtc_free(struct drm_fb_helper
*helper
)
415 for (i
= 0; i
< helper
->crtc_count
; i
++)
416 kfree(helper
->crtc_info
[i
].mode_set
.connectors
);
417 kfree(helper
->crtc_info
);
420 int drm_fb_helper_init_crtc_count(struct drm_fb_helper
*helper
, int crtc_count
, int max_conn_count
)
422 struct drm_device
*dev
= helper
->dev
;
423 struct drm_crtc
*crtc
;
427 helper
->crtc_info
= kcalloc(crtc_count
, sizeof(struct drm_fb_helper_crtc
), GFP_KERNEL
);
428 if (!helper
->crtc_info
)
431 helper
->crtc_count
= crtc_count
;
433 for (i
= 0; i
< crtc_count
; i
++) {
434 helper
->crtc_info
[i
].mode_set
.connectors
=
435 kcalloc(max_conn_count
,
436 sizeof(struct drm_connector
*),
439 if (!helper
->crtc_info
[i
].mode_set
.connectors
) {
443 helper
->crtc_info
[i
].mode_set
.num_connectors
= 0;
447 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
448 helper
->crtc_info
[i
].crtc_id
= crtc
->base
.id
;
449 helper
->crtc_info
[i
].mode_set
.crtc
= crtc
;
452 helper
->conn_limit
= max_conn_count
;
455 drm_fb_helper_crtc_free(helper
);
458 EXPORT_SYMBOL(drm_fb_helper_init_crtc_count
);
460 static int setcolreg(struct drm_crtc
*crtc
, u16 red
, u16 green
,
461 u16 blue
, u16 regno
, struct fb_info
*info
)
463 struct drm_fb_helper
*fb_helper
= info
->par
;
464 struct drm_framebuffer
*fb
= fb_helper
->fb
;
467 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
470 /* place color in psuedopalette */
473 palette
= (u32
*)info
->pseudo_palette
;
474 red
>>= (16 - info
->var
.red
.length
);
475 green
>>= (16 - info
->var
.green
.length
);
476 blue
>>= (16 - info
->var
.blue
.length
);
477 value
= (red
<< info
->var
.red
.offset
) |
478 (green
<< info
->var
.green
.offset
) |
479 (blue
<< info
->var
.blue
.offset
);
480 palette
[regno
] = value
;
486 if (fb
->bits_per_pixel
== 16) {
489 if (fb
->depth
== 16 && regno
> 63)
491 if (fb
->depth
== 15 && regno
> 31)
494 if (fb
->depth
== 16) {
498 for (i
= 0; i
< 8; i
++)
499 fb_helper
->funcs
->gamma_set(crtc
, red
,
500 green
, blue
, pindex
+ i
);
503 fb_helper
->funcs
->gamma_get(crtc
, &r
,
507 for (i
= 0; i
< 4; i
++)
508 fb_helper
->funcs
->gamma_set(crtc
, r
,
515 fb_helper
->funcs
->gamma_set(crtc
, red
, green
, blue
, pindex
);
519 int drm_fb_helper_setcmap(struct fb_cmap
*cmap
, struct fb_info
*info
)
521 struct drm_fb_helper
*fb_helper
= info
->par
;
522 struct drm_device
*dev
= fb_helper
->dev
;
523 u16
*red
, *green
, *blue
, *transp
;
524 struct drm_crtc
*crtc
;
528 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
529 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
530 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
531 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
534 if (i
== fb_helper
->crtc_count
)
540 transp
= cmap
->transp
;
543 for (i
= 0; i
< cmap
->len
; i
++) {
544 u16 hred
, hgreen
, hblue
, htransp
= 0xffff;
553 rc
= setcolreg(crtc
, hred
, hgreen
, hblue
, start
++, info
);
557 crtc_funcs
->load_lut(crtc
);
561 EXPORT_SYMBOL(drm_fb_helper_setcmap
);
563 int drm_fb_helper_setcolreg(unsigned regno
,
568 struct fb_info
*info
)
570 struct drm_fb_helper
*fb_helper
= info
->par
;
571 struct drm_device
*dev
= fb_helper
->dev
;
572 struct drm_crtc
*crtc
;
579 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
580 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
581 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
582 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
585 if (i
== fb_helper
->crtc_count
)
588 ret
= setcolreg(crtc
, red
, green
, blue
, regno
, info
);
592 crtc_funcs
->load_lut(crtc
);
596 EXPORT_SYMBOL(drm_fb_helper_setcolreg
);
598 int drm_fb_helper_check_var(struct fb_var_screeninfo
*var
,
599 struct fb_info
*info
)
601 struct drm_fb_helper
*fb_helper
= info
->par
;
602 struct drm_framebuffer
*fb
= fb_helper
->fb
;
605 if (var
->pixclock
!= 0)
608 /* Need to resize the fb object !!! */
609 if (var
->bits_per_pixel
> fb
->bits_per_pixel
|| var
->xres
> fb
->width
|| var
->yres
> fb
->height
) {
610 DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
611 "object %dx%d-%d > %dx%d-%d\n", var
->xres
, var
->yres
, var
->bits_per_pixel
,
612 fb
->width
, fb
->height
, fb
->bits_per_pixel
);
616 switch (var
->bits_per_pixel
) {
618 depth
= (var
->green
.length
== 6) ? 16 : 15;
621 depth
= (var
->transp
.length
> 0) ? 32 : 24;
624 depth
= var
->bits_per_pixel
;
631 var
->green
.offset
= 0;
632 var
->blue
.offset
= 0;
634 var
->green
.length
= 8;
635 var
->blue
.length
= 8;
636 var
->transp
.length
= 0;
637 var
->transp
.offset
= 0;
640 var
->red
.offset
= 10;
641 var
->green
.offset
= 5;
642 var
->blue
.offset
= 0;
644 var
->green
.length
= 5;
645 var
->blue
.length
= 5;
646 var
->transp
.length
= 1;
647 var
->transp
.offset
= 15;
650 var
->red
.offset
= 11;
651 var
->green
.offset
= 5;
652 var
->blue
.offset
= 0;
654 var
->green
.length
= 6;
655 var
->blue
.length
= 5;
656 var
->transp
.length
= 0;
657 var
->transp
.offset
= 0;
660 var
->red
.offset
= 16;
661 var
->green
.offset
= 8;
662 var
->blue
.offset
= 0;
664 var
->green
.length
= 8;
665 var
->blue
.length
= 8;
666 var
->transp
.length
= 0;
667 var
->transp
.offset
= 0;
670 var
->red
.offset
= 16;
671 var
->green
.offset
= 8;
672 var
->blue
.offset
= 0;
674 var
->green
.length
= 8;
675 var
->blue
.length
= 8;
676 var
->transp
.length
= 8;
677 var
->transp
.offset
= 24;
684 EXPORT_SYMBOL(drm_fb_helper_check_var
);
686 /* this will let fbcon do the mode init */
687 int drm_fb_helper_set_par(struct fb_info
*info
)
689 struct drm_fb_helper
*fb_helper
= info
->par
;
690 struct drm_device
*dev
= fb_helper
->dev
;
691 struct fb_var_screeninfo
*var
= &info
->var
;
692 struct drm_crtc
*crtc
;
696 if (var
->pixclock
!= 0) {
697 DRM_ERROR("PIXEL CLCOK SET\n");
701 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
703 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
704 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
707 if (i
== fb_helper
->crtc_count
)
710 if (crtc
->fb
== fb_helper
->crtc_info
[i
].mode_set
.fb
) {
711 mutex_lock(&dev
->mode_config
.mutex
);
712 ret
= crtc
->funcs
->set_config(&fb_helper
->crtc_info
[i
].mode_set
);
713 mutex_unlock(&dev
->mode_config
.mutex
);
720 EXPORT_SYMBOL(drm_fb_helper_set_par
);
722 int drm_fb_helper_pan_display(struct fb_var_screeninfo
*var
,
723 struct fb_info
*info
)
725 struct drm_fb_helper
*fb_helper
= info
->par
;
726 struct drm_device
*dev
= fb_helper
->dev
;
727 struct drm_mode_set
*modeset
;
728 struct drm_crtc
*crtc
;
732 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
733 for (i
= 0; i
< fb_helper
->crtc_count
; i
++) {
734 if (crtc
->base
.id
== fb_helper
->crtc_info
[i
].crtc_id
)
738 if (i
== fb_helper
->crtc_count
)
741 modeset
= &fb_helper
->crtc_info
[i
].mode_set
;
743 modeset
->x
= var
->xoffset
;
744 modeset
->y
= var
->yoffset
;
746 if (modeset
->num_connectors
) {
747 mutex_lock(&dev
->mode_config
.mutex
);
748 ret
= crtc
->funcs
->set_config(modeset
);
749 mutex_unlock(&dev
->mode_config
.mutex
);
751 info
->var
.xoffset
= var
->xoffset
;
752 info
->var
.yoffset
= var
->yoffset
;
758 EXPORT_SYMBOL(drm_fb_helper_pan_display
);
760 int drm_fb_helper_single_fb_probe(struct drm_device
*dev
,
762 int (*fb_create
)(struct drm_device
*dev
,
765 uint32_t surface_width
,
766 uint32_t surface_height
,
767 uint32_t surface_depth
,
768 uint32_t surface_bpp
,
769 struct drm_framebuffer
**fb_ptr
))
771 struct drm_crtc
*crtc
;
772 struct drm_connector
*connector
;
773 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
774 unsigned int surface_width
= 0, surface_height
= 0;
777 int ret
, i
, conn_count
= 0;
778 struct fb_info
*info
;
779 struct drm_framebuffer
*fb
;
780 struct drm_mode_set
*modeset
= NULL
;
781 struct drm_fb_helper
*fb_helper
;
782 uint32_t surface_depth
= 24, surface_bpp
= 32;
784 /* if driver picks 8 or 16 by default use that
785 for both depth/bpp */
786 if (preferred_bpp
!= surface_bpp
) {
787 surface_depth
= surface_bpp
= preferred_bpp
;
789 /* first up get a count of crtcs now in use and new min/maxes width/heights */
790 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
791 struct drm_fb_helper_connector
*fb_help_conn
= connector
->fb_helper_private
;
793 struct drm_fb_helper_cmdline_mode
*cmdline_mode
;
798 cmdline_mode
= &fb_help_conn
->cmdline_mode
;
800 if (cmdline_mode
->bpp_specified
) {
801 switch (cmdline_mode
->bpp
) {
803 surface_depth
= surface_bpp
= 8;
810 surface_depth
= surface_bpp
= 16;
813 surface_depth
= surface_bpp
= 24;
824 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
825 if (drm_helper_crtc_in_use(crtc
)) {
826 if (crtc
->desired_mode
) {
827 if (crtc
->desired_mode
->hdisplay
< fb_width
)
828 fb_width
= crtc
->desired_mode
->hdisplay
;
830 if (crtc
->desired_mode
->vdisplay
< fb_height
)
831 fb_height
= crtc
->desired_mode
->vdisplay
;
833 if (crtc
->desired_mode
->hdisplay
> surface_width
)
834 surface_width
= crtc
->desired_mode
->hdisplay
;
836 if (crtc
->desired_mode
->vdisplay
> surface_height
)
837 surface_height
= crtc
->desired_mode
->vdisplay
;
843 if (crtc_count
== 0 || fb_width
== -1 || fb_height
== -1) {
844 /* hmm everyone went away - assume VGA cable just fell out
845 and will come back later. */
849 /* do we have an fb already? */
850 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
851 ret
= (*fb_create
)(dev
, fb_width
, fb_height
, surface_width
,
852 surface_height
, surface_depth
, surface_bpp
,
858 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
859 struct drm_framebuffer
, filp_head
);
861 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
862 As really we can't resize an fbdev that is in the wild currently due to fbdev
863 not really being designed for the lower layers moving stuff around under it.
864 - so in the grand style of things - punt. */
865 if ((fb
->width
< surface_width
) ||
866 (fb
->height
< surface_height
)) {
867 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
873 fb_helper
= info
->par
;
876 /* okay we need to setup new connector sets in the crtcs */
877 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
878 modeset
= &fb_helper
->crtc_info
[crtc_count
].mode_set
;
881 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
882 if (connector
->encoder
)
883 if (connector
->encoder
->crtc
== modeset
->crtc
) {
884 modeset
->connectors
[conn_count
] = connector
;
886 if (conn_count
> fb_helper
->conn_limit
)
891 for (i
= conn_count
; i
< fb_helper
->conn_limit
; i
++)
892 modeset
->connectors
[i
] = NULL
;
894 modeset
->crtc
= crtc
;
897 modeset
->num_connectors
= conn_count
;
898 if (modeset
->crtc
->desired_mode
) {
900 drm_mode_destroy(dev
, modeset
->mode
);
901 modeset
->mode
= drm_mode_duplicate(dev
,
902 modeset
->crtc
->desired_mode
);
905 fb_helper
->crtc_count
= crtc_count
;
909 info
->var
.pixclock
= 0;
910 ret
= fb_alloc_cmap(&info
->cmap
, modeset
->crtc
->gamma_size
, 0);
913 if (register_framebuffer(info
) < 0) {
914 fb_dealloc_cmap(&info
->cmap
);
918 drm_fb_helper_set_par(info
);
920 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
923 /* Switch back to kernel console on panic */
924 /* multi card linked list maybe */
925 if (list_empty(&kernel_fb_helper_list
)) {
926 printk(KERN_INFO
"registered panic notifier\n");
927 atomic_notifier_chain_register(&panic_notifier_list
,
929 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
931 list_add(&fb_helper
->kernel_fb_list
, &kernel_fb_helper_list
);
934 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe
);
936 void drm_fb_helper_free(struct drm_fb_helper
*helper
)
938 list_del(&helper
->kernel_fb_list
);
939 if (list_empty(&kernel_fb_helper_list
)) {
940 printk(KERN_INFO
"unregistered panic notifier\n");
941 atomic_notifier_chain_unregister(&panic_notifier_list
,
943 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op
);
945 drm_fb_helper_crtc_free(helper
);
946 fb_dealloc_cmap(&helper
->fb
->fbdev
->cmap
);
948 EXPORT_SYMBOL(drm_fb_helper_free
);
950 void drm_fb_helper_fill_fix(struct fb_info
*info
, uint32_t pitch
,
953 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
954 info
->fix
.visual
= depth
== 8 ? FB_VISUAL_PSEUDOCOLOR
:
956 info
->fix
.type_aux
= 0;
957 info
->fix
.xpanstep
= 1; /* doing it in hw */
958 info
->fix
.ypanstep
= 1; /* doing it in hw */
959 info
->fix
.ywrapstep
= 0;
960 info
->fix
.accel
= FB_ACCEL_NONE
;
961 info
->fix
.type_aux
= 0;
963 info
->fix
.line_length
= pitch
;
966 EXPORT_SYMBOL(drm_fb_helper_fill_fix
);
968 void drm_fb_helper_fill_var(struct fb_info
*info
, struct drm_framebuffer
*fb
,
969 uint32_t fb_width
, uint32_t fb_height
)
971 info
->pseudo_palette
= fb
->pseudo_palette
;
972 info
->var
.xres_virtual
= fb
->width
;
973 info
->var
.yres_virtual
= fb
->height
;
974 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
975 info
->var
.xoffset
= 0;
976 info
->var
.yoffset
= 0;
977 info
->var
.activate
= FB_ACTIVATE_NOW
;
978 info
->var
.height
= -1;
979 info
->var
.width
= -1;
983 info
->var
.red
.offset
= 0;
984 info
->var
.green
.offset
= 0;
985 info
->var
.blue
.offset
= 0;
986 info
->var
.red
.length
= 8; /* 8bit DAC */
987 info
->var
.green
.length
= 8;
988 info
->var
.blue
.length
= 8;
989 info
->var
.transp
.offset
= 0;
990 info
->var
.transp
.length
= 0;
993 info
->var
.red
.offset
= 10;
994 info
->var
.green
.offset
= 5;
995 info
->var
.blue
.offset
= 0;
996 info
->var
.red
.length
= 5;
997 info
->var
.green
.length
= 5;
998 info
->var
.blue
.length
= 5;
999 info
->var
.transp
.offset
= 15;
1000 info
->var
.transp
.length
= 1;
1003 info
->var
.red
.offset
= 11;
1004 info
->var
.green
.offset
= 5;
1005 info
->var
.blue
.offset
= 0;
1006 info
->var
.red
.length
= 5;
1007 info
->var
.green
.length
= 6;
1008 info
->var
.blue
.length
= 5;
1009 info
->var
.transp
.offset
= 0;
1012 info
->var
.red
.offset
= 16;
1013 info
->var
.green
.offset
= 8;
1014 info
->var
.blue
.offset
= 0;
1015 info
->var
.red
.length
= 8;
1016 info
->var
.green
.length
= 8;
1017 info
->var
.blue
.length
= 8;
1018 info
->var
.transp
.offset
= 0;
1019 info
->var
.transp
.length
= 0;
1022 info
->var
.red
.offset
= 16;
1023 info
->var
.green
.offset
= 8;
1024 info
->var
.blue
.offset
= 0;
1025 info
->var
.red
.length
= 8;
1026 info
->var
.green
.length
= 8;
1027 info
->var
.blue
.length
= 8;
1028 info
->var
.transp
.offset
= 24;
1029 info
->var
.transp
.length
= 8;
1035 info
->var
.xres
= fb_width
;
1036 info
->var
.yres
= fb_height
;
1038 EXPORT_SYMBOL(drm_fb_helper_fill_var
);