2 * Copyright © 2007 David Airlie
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
27 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/errno.h>
30 #include <linux/string.h>
32 #include <linux/tty.h>
33 #include <linux/slab.h>
34 #include <linux/sysrq.h>
35 #include <linux/delay.h>
37 #include <linux/init.h>
42 #include "intel_drv.h"
47 struct drm_device
*dev
;
48 struct drm_display_mode
*our_mode
;
49 struct intel_framebuffer
*intel_fb
;
51 /* crtc currently bound to this */
55 static int intelfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
56 unsigned blue
, unsigned transp
,
59 struct intelfb_par
*par
= info
->par
;
60 struct drm_device
*dev
= par
->dev
;
61 struct drm_crtc
*crtc
;
64 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
65 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
66 struct drm_mode_set
*modeset
= &intel_crtc
->mode_set
;
67 struct drm_framebuffer
*fb
= modeset
->fb
;
69 for (i
= 0; i
< par
->crtc_count
; i
++)
70 if (crtc
->base
.id
== par
->crtc_ids
[i
])
73 if (i
== par
->crtc_count
)
81 intel_crtc_fb_gamma_set(crtc
, red
, green
, blue
, regno
);
88 fb
->pseudo_palette
[regno
] = ((red
& 0xf800) >> 1) |
89 ((green
& 0xf800) >> 6) |
90 ((blue
& 0xf800) >> 11);
93 fb
->pseudo_palette
[regno
] = (red
& 0xf800) |
94 ((green
& 0xfc00) >> 5) |
95 ((blue
& 0xf800) >> 11);
99 fb
->pseudo_palette
[regno
] = ((red
& 0xff00) << 8) |
101 ((blue
& 0xff00) >> 8);
109 static int intelfb_check_var(struct fb_var_screeninfo
*var
,
110 struct fb_info
*info
)
112 struct intelfb_par
*par
= info
->par
;
113 struct intel_framebuffer
*intel_fb
= par
->intel_fb
;
114 struct drm_framebuffer
*fb
= &intel_fb
->base
;
117 if (var
->pixclock
== -1 || !var
->pixclock
)
120 /* Need to resize the fb object !!! */
121 if (var
->xres
> fb
->width
|| var
->yres
> fb
->height
) {
122 DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var
->xres
,var
->yres
,fb
->width
,fb
->height
);
123 DRM_ERROR("Need resizing code.\n");
127 switch (var
->bits_per_pixel
) {
129 depth
= (var
->green
.length
== 6) ? 16 : 15;
132 depth
= (var
->transp
.length
> 0) ? 32 : 24;
135 depth
= var
->bits_per_pixel
;
142 var
->green
.offset
= 0;
143 var
->blue
.offset
= 0;
145 var
->green
.length
= 8;
146 var
->blue
.length
= 8;
147 var
->transp
.length
= 0;
148 var
->transp
.offset
= 0;
151 var
->red
.offset
= 10;
152 var
->green
.offset
= 5;
153 var
->blue
.offset
= 0;
155 var
->green
.length
= 5;
156 var
->blue
.length
= 5;
157 var
->transp
.length
= 1;
158 var
->transp
.offset
= 15;
161 var
->red
.offset
= 11;
162 var
->green
.offset
= 5;
163 var
->blue
.offset
= 0;
165 var
->green
.length
= 6;
166 var
->blue
.length
= 5;
167 var
->transp
.length
= 0;
168 var
->transp
.offset
= 0;
171 var
->red
.offset
= 16;
172 var
->green
.offset
= 8;
173 var
->blue
.offset
= 0;
175 var
->green
.length
= 8;
176 var
->blue
.length
= 8;
177 var
->transp
.length
= 0;
178 var
->transp
.offset
= 0;
181 var
->red
.offset
= 16;
182 var
->green
.offset
= 8;
183 var
->blue
.offset
= 0;
185 var
->green
.length
= 8;
186 var
->blue
.length
= 8;
187 var
->transp
.length
= 8;
188 var
->transp
.offset
= 24;
197 /* this will let fbcon do the mode init */
198 /* FIXME: take mode config lock? */
199 static int intelfb_set_par(struct fb_info
*info
)
201 struct intelfb_par
*par
= info
->par
;
202 struct drm_device
*dev
= par
->dev
;
203 struct fb_var_screeninfo
*var
= &info
->var
;
206 DRM_DEBUG("%d %d\n", var
->xres
, var
->pixclock
);
208 if (var
->pixclock
!= -1) {
210 DRM_ERROR("PIXEL CLCOK SET\n");
213 struct drm_crtc
*crtc
;
216 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
217 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
219 for (i
= 0; i
< par
->crtc_count
; i
++)
220 if (crtc
->base
.id
== par
->crtc_ids
[i
])
223 if (i
== par
->crtc_count
)
226 if (crtc
->fb
== intel_crtc
->mode_set
.fb
) {
227 mutex_lock(&dev
->mode_config
.mutex
);
228 ret
= crtc
->funcs
->set_config(&intel_crtc
->mode_set
);
229 mutex_unlock(&dev
->mode_config
.mutex
);
238 static int intelfb_pan_display(struct fb_var_screeninfo
*var
,
239 struct fb_info
*info
)
241 struct intelfb_par
*par
= info
->par
;
242 struct drm_device
*dev
= par
->dev
;
243 struct drm_mode_set
*modeset
;
244 struct drm_crtc
*crtc
;
245 struct intel_crtc
*intel_crtc
;
249 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
250 for (i
= 0; i
< par
->crtc_count
; i
++)
251 if (crtc
->base
.id
== par
->crtc_ids
[i
])
254 if (i
== par
->crtc_count
)
257 intel_crtc
= to_intel_crtc(crtc
);
258 modeset
= &intel_crtc
->mode_set
;
260 modeset
->x
= var
->xoffset
;
261 modeset
->y
= var
->yoffset
;
263 if (modeset
->num_connectors
) {
264 mutex_lock(&dev
->mode_config
.mutex
);
265 ret
= crtc
->funcs
->set_config(modeset
);
266 mutex_unlock(&dev
->mode_config
.mutex
);
268 info
->var
.xoffset
= var
->xoffset
;
269 info
->var
.yoffset
= var
->yoffset
;
277 static void intelfb_on(struct fb_info
*info
)
279 struct intelfb_par
*par
= info
->par
;
280 struct drm_device
*dev
= par
->dev
;
281 struct drm_crtc
*crtc
;
282 struct drm_encoder
*encoder
;
286 * For each CRTC in this fb, find all associated encoders
287 * and turn them off, then turn off the CRTC.
289 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
290 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
292 for (i
= 0; i
< par
->crtc_count
; i
++)
293 if (crtc
->base
.id
== par
->crtc_ids
[i
])
296 crtc_funcs
->dpms(crtc
, DRM_MODE_DPMS_ON
);
298 /* Found a CRTC on this fb, now find encoders */
299 list_for_each_entry(encoder
, &dev
->mode_config
.encoder_list
, head
) {
300 if (encoder
->crtc
== crtc
) {
301 struct drm_encoder_helper_funcs
*encoder_funcs
;
302 encoder_funcs
= encoder
->helper_private
;
303 encoder_funcs
->dpms(encoder
, DRM_MODE_DPMS_ON
);
309 static void intelfb_off(struct fb_info
*info
, int dpms_mode
)
311 struct intelfb_par
*par
= info
->par
;
312 struct drm_device
*dev
= par
->dev
;
313 struct drm_crtc
*crtc
;
314 struct drm_encoder
*encoder
;
318 * For each CRTC in this fb, find all associated encoders
319 * and turn them off, then turn off the CRTC.
321 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
322 struct drm_crtc_helper_funcs
*crtc_funcs
= crtc
->helper_private
;
324 for (i
= 0; i
< par
->crtc_count
; i
++)
325 if (crtc
->base
.id
== par
->crtc_ids
[i
])
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
;
332 encoder_funcs
= encoder
->helper_private
;
333 encoder_funcs
->dpms(encoder
, dpms_mode
);
336 if (dpms_mode
== DRM_MODE_DPMS_OFF
)
337 crtc_funcs
->dpms(crtc
, dpms_mode
);
341 static int intelfb_blank(int blank
, struct fb_info
*info
)
344 case FB_BLANK_UNBLANK
:
347 case FB_BLANK_NORMAL
:
348 intelfb_off(info
, DRM_MODE_DPMS_STANDBY
);
350 case FB_BLANK_HSYNC_SUSPEND
:
351 intelfb_off(info
, DRM_MODE_DPMS_STANDBY
);
353 case FB_BLANK_VSYNC_SUSPEND
:
354 intelfb_off(info
, DRM_MODE_DPMS_SUSPEND
);
356 case FB_BLANK_POWERDOWN
:
357 intelfb_off(info
, DRM_MODE_DPMS_OFF
);
363 static struct fb_ops intelfb_ops
= {
364 .owner
= THIS_MODULE
,
365 .fb_check_var
= intelfb_check_var
,
366 .fb_set_par
= intelfb_set_par
,
367 .fb_setcolreg
= intelfb_setcolreg
,
368 .fb_fillrect
= cfb_fillrect
,
369 .fb_copyarea
= cfb_copyarea
,
370 .fb_imageblit
= cfb_imageblit
,
371 .fb_pan_display
= intelfb_pan_display
,
372 .fb_blank
= intelfb_blank
,
376 * Curretly it is assumed that the old framebuffer is reused.
379 * caller should hold the mode config lock.
382 int intelfb_resize(struct drm_device
*dev
, struct drm_crtc
*crtc
)
384 struct fb_info
*info
;
385 struct drm_framebuffer
*fb
;
386 struct drm_display_mode
*mode
= crtc
->desired_mode
;
399 info
->var
.xres
= mode
->hdisplay
;
400 info
->var
.right_margin
= mode
->hsync_start
- mode
->hdisplay
;
401 info
->var
.hsync_len
= mode
->hsync_end
- mode
->hsync_start
;
402 info
->var
.left_margin
= mode
->htotal
- mode
->hsync_end
;
403 info
->var
.yres
= mode
->vdisplay
;
404 info
->var
.lower_margin
= mode
->vsync_start
- mode
->vdisplay
;
405 info
->var
.vsync_len
= mode
->vsync_end
- mode
->vsync_start
;
406 info
->var
.upper_margin
= mode
->vtotal
- mode
->vsync_end
;
407 info
->var
.pixclock
= 10000000 / mode
->htotal
* 1000 / mode
->vtotal
* 100;
409 info
->var
.pixclock
= info
->var
.pixclock
* 1000 / mode
->vrefresh
;
413 EXPORT_SYMBOL(intelfb_resize
);
415 static struct drm_mode_set kernelfb_mode
;
417 static int intelfb_panic(struct notifier_block
*n
, unsigned long ununsed
,
420 DRM_ERROR("panic occurred, switching back to text console\n");
426 static struct notifier_block paniced
= {
427 .notifier_call
= intelfb_panic
,
430 static int intelfb_create(struct drm_device
*dev
, uint32_t fb_width
,
431 uint32_t fb_height
, uint32_t surface_width
,
432 uint32_t surface_height
,
433 struct intel_framebuffer
**intel_fb_p
)
435 struct fb_info
*info
;
436 struct intelfb_par
*par
;
437 struct drm_framebuffer
*fb
;
438 struct intel_framebuffer
*intel_fb
;
439 struct drm_mode_fb_cmd mode_cmd
;
440 struct drm_gem_object
*fbo
= NULL
;
441 struct drm_i915_gem_object
*obj_priv
;
442 struct device
*device
= &dev
->pdev
->dev
;
443 int size
, ret
, mmio_bar
= IS_I9XX(dev
) ? 0 : 1;
445 mode_cmd
.width
= surface_width
;
446 mode_cmd
.height
= surface_height
;
449 mode_cmd
.pitch
= ALIGN(mode_cmd
.width
* ((mode_cmd
.bpp
+ 1) / 8), 64);
452 size
= mode_cmd
.pitch
* mode_cmd
.height
;
453 size
= ALIGN(size
, PAGE_SIZE
);
454 fbo
= drm_gem_object_alloc(dev
, size
);
456 printk(KERN_ERR
"failed to allocate framebuffer\n");
460 obj_priv
= fbo
->driver_private
;
462 mutex_lock(&dev
->struct_mutex
);
464 ret
= i915_gem_object_pin(fbo
, PAGE_SIZE
);
466 DRM_ERROR("failed to pin fb: %d\n", ret
);
470 /* Flush everything out, we'll be doing GTT only from now on */
471 i915_gem_object_set_to_gtt_domain(fbo
, 1);
473 ret
= intel_framebuffer_create(dev
, &mode_cmd
, &fb
, fbo
);
475 DRM_ERROR("failed to allocate fb.\n");
479 list_add(&fb
->filp_head
, &dev
->mode_config
.fb_kernel_list
);
481 intel_fb
= to_intel_framebuffer(fb
);
482 *intel_fb_p
= intel_fb
;
484 info
= framebuffer_alloc(sizeof(struct intelfb_par
), device
);
492 strcpy(info
->fix
.id
, "inteldrmfb");
493 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
494 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
495 info
->fix
.type_aux
= 0;
496 info
->fix
.xpanstep
= 1; /* doing it in hw */
497 info
->fix
.ypanstep
= 1; /* doing it in hw */
498 info
->fix
.ywrapstep
= 0;
499 info
->fix
.accel
= FB_ACCEL_I830
;
500 info
->fix
.type_aux
= 0;
502 info
->flags
= FBINFO_DEFAULT
;
504 info
->fbops
= &intelfb_ops
;
506 info
->fix
.line_length
= fb
->pitch
;
507 info
->fix
.smem_start
= dev
->mode_config
.fb_base
+ obj_priv
->gtt_offset
;
508 info
->fix
.smem_len
= size
;
510 info
->flags
= FBINFO_DEFAULT
;
512 info
->screen_base
= ioremap_wc(dev
->agp
->base
+ obj_priv
->gtt_offset
,
514 if (!info
->screen_base
) {
518 info
->screen_size
= size
;
520 // memset(info->screen_base, 0, size);
522 info
->pseudo_palette
= fb
->pseudo_palette
;
523 info
->var
.xres_virtual
= fb
->width
;
524 info
->var
.yres_virtual
= fb
->height
;
525 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
526 info
->var
.xoffset
= 0;
527 info
->var
.yoffset
= 0;
528 info
->var
.activate
= FB_ACTIVATE_NOW
;
529 info
->var
.height
= -1;
530 info
->var
.width
= -1;
532 info
->var
.xres
= fb_width
;
533 info
->var
.yres
= fb_height
;
535 /* FIXME: we really shouldn't expose mmio space at all */
536 info
->fix
.mmio_start
= pci_resource_start(dev
->pdev
, mmio_bar
);
537 info
->fix
.mmio_len
= pci_resource_len(dev
->pdev
, mmio_bar
);
539 info
->pixmap
.size
= 64*1024;
540 info
->pixmap
.buf_align
= 8;
541 info
->pixmap
.access_align
= 32;
542 info
->pixmap
.flags
= FB_PIXMAP_SYSTEM
;
543 info
->pixmap
.scan_align
= 1;
547 info
->var
.red
.offset
= 0;
548 info
->var
.green
.offset
= 0;
549 info
->var
.blue
.offset
= 0;
550 info
->var
.red
.length
= 8; /* 8bit DAC */
551 info
->var
.green
.length
= 8;
552 info
->var
.blue
.length
= 8;
553 info
->var
.transp
.offset
= 0;
554 info
->var
.transp
.length
= 0;
557 info
->var
.red
.offset
= 10;
558 info
->var
.green
.offset
= 5;
559 info
->var
.blue
.offset
= 0;
560 info
->var
.red
.length
= 5;
561 info
->var
.green
.length
= 5;
562 info
->var
.blue
.length
= 5;
563 info
->var
.transp
.offset
= 15;
564 info
->var
.transp
.length
= 1;
567 info
->var
.red
.offset
= 11;
568 info
->var
.green
.offset
= 5;
569 info
->var
.blue
.offset
= 0;
570 info
->var
.red
.length
= 5;
571 info
->var
.green
.length
= 6;
572 info
->var
.blue
.length
= 5;
573 info
->var
.transp
.offset
= 0;
576 info
->var
.red
.offset
= 16;
577 info
->var
.green
.offset
= 8;
578 info
->var
.blue
.offset
= 0;
579 info
->var
.red
.length
= 8;
580 info
->var
.green
.length
= 8;
581 info
->var
.blue
.length
= 8;
582 info
->var
.transp
.offset
= 0;
583 info
->var
.transp
.length
= 0;
586 info
->var
.red
.offset
= 16;
587 info
->var
.green
.offset
= 8;
588 info
->var
.blue
.offset
= 0;
589 info
->var
.red
.length
= 8;
590 info
->var
.green
.length
= 8;
591 info
->var
.blue
.length
= 8;
592 info
->var
.transp
.offset
= 24;
593 info
->var
.transp
.length
= 8;
601 par
->intel_fb
= intel_fb
;
604 /* To allow resizeing without swapping buffers */
605 printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb
->base
.width
,
606 intel_fb
->base
.height
, obj_priv
->gtt_offset
, fbo
);
608 mutex_unlock(&dev
->struct_mutex
);
612 drm_gem_object_unreference(fbo
);
613 mutex_unlock(&dev
->struct_mutex
);
618 static int intelfb_multi_fb_probe_crtc(struct drm_device
*dev
, struct drm_crtc
*crtc
)
620 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
621 struct intel_framebuffer
*intel_fb
;
622 struct drm_framebuffer
*fb
;
623 struct drm_connector
*connector
;
624 struct fb_info
*info
;
625 struct intelfb_par
*par
;
626 struct drm_mode_set
*modeset
;
627 unsigned int width
, height
;
629 int ret
, i
, conn_count
;
631 if (!drm_helper_crtc_in_use(crtc
))
634 if (!crtc
->desired_mode
)
637 width
= crtc
->desired_mode
->hdisplay
;
638 height
= crtc
->desired_mode
->vdisplay
;
640 /* is there an fb bound to this crtc already */
641 if (!intel_crtc
->mode_set
.fb
) {
642 ret
= intelfb_create(dev
, width
, height
, width
, height
, &intel_fb
);
647 fb
= intel_crtc
->mode_set
.fb
;
648 intel_fb
= to_intel_framebuffer(fb
);
649 if ((intel_fb
->base
.width
< width
) || (intel_fb
->base
.height
< height
))
653 info
= intel_fb
->base
.fbdev
;
656 modeset
= &intel_crtc
->mode_set
;
657 modeset
->fb
= &intel_fb
->base
;
659 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
660 if (connector
->encoder
)
661 if (connector
->encoder
->crtc
== modeset
->crtc
) {
662 modeset
->connectors
[conn_count
] = connector
;
664 if (conn_count
> INTELFB_CONN_LIMIT
)
669 for (i
= conn_count
; i
< INTELFB_CONN_LIMIT
; i
++)
670 modeset
->connectors
[i
] = NULL
;
672 par
->crtc_ids
[0] = crtc
->base
.id
;
674 modeset
->num_connectors
= conn_count
;
675 if (modeset
->mode
!= modeset
->crtc
->desired_mode
)
676 modeset
->mode
= modeset
->crtc
->desired_mode
;
681 info
->var
.pixclock
= -1;
682 if (register_framebuffer(info
) < 0)
685 intelfb_set_par(info
);
687 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
690 /* Switch back to kernel console on panic */
691 kernelfb_mode
= *modeset
;
692 atomic_notifier_chain_register(&panic_notifier_list
, &paniced
);
693 printk(KERN_INFO
"registered panic notifier\n");
698 static int intelfb_multi_fb_probe(struct drm_device
*dev
)
701 struct drm_crtc
*crtc
;
704 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
705 ret
= intelfb_multi_fb_probe_crtc(dev
, crtc
);
712 static int intelfb_single_fb_probe(struct drm_device
*dev
)
714 struct drm_crtc
*crtc
;
715 struct drm_connector
*connector
;
716 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
717 unsigned int surface_width
= 0, surface_height
= 0;
720 int ret
, i
, conn_count
= 0;
721 struct intel_framebuffer
*intel_fb
;
722 struct fb_info
*info
;
723 struct intelfb_par
*par
;
724 struct drm_mode_set
*modeset
= NULL
;
728 /* Get a count of crtcs now in use and new min/maxes width/heights */
729 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
730 if (!drm_helper_crtc_in_use(crtc
))
734 if (!crtc
->desired_mode
)
737 /* Smallest mode determines console size... */
738 if (crtc
->desired_mode
->hdisplay
< fb_width
)
739 fb_width
= crtc
->desired_mode
->hdisplay
;
741 if (crtc
->desired_mode
->vdisplay
< fb_height
)
742 fb_height
= crtc
->desired_mode
->vdisplay
;
744 /* ... but largest for memory allocation dimensions */
745 if (crtc
->desired_mode
->hdisplay
> surface_width
)
746 surface_width
= crtc
->desired_mode
->hdisplay
;
748 if (crtc
->desired_mode
->vdisplay
> surface_height
)
749 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. */
755 DRM_DEBUG("no CRTCs available?\n");
760 /* Find the fb for our new config */
761 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
762 DRM_DEBUG("creating new fb (console size %dx%d, "
763 "buffer size %dx%d)\n", fb_width
, fb_height
,
764 surface_width
, surface_height
);
765 ret
= intelfb_create(dev
, fb_width
, fb_height
, surface_width
,
766 surface_height
, &intel_fb
);
771 struct drm_framebuffer
*fb
;
773 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
774 struct drm_framebuffer
, filp_head
);
775 intel_fb
= to_intel_framebuffer(fb
);
777 /* if someone hotplugs something bigger than we have already
778 * allocated, we are pwned. As really we can't resize an
779 * fbdev that is in the wild currently due to fbdev not really
780 * being designed for the lower layers moving stuff around
782 * - so in the grand style of things - punt.
784 if ((fb
->width
< surface_width
) ||
785 (fb
->height
< surface_height
)) {
786 DRM_ERROR("fb not large enough for console\n");
792 info
= intel_fb
->base
.fbdev
;
797 * For each CRTC, set up the connector list for the CRTC's mode
800 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
801 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
803 modeset
= &intel_crtc
->mode_set
;
804 modeset
->fb
= &intel_fb
->base
;
806 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
,
808 if (!connector
->encoder
)
811 if(connector
->encoder
->crtc
== modeset
->crtc
) {
812 modeset
->connectors
[conn_count
++] = connector
;
813 if (conn_count
> INTELFB_CONN_LIMIT
)
818 /* Zero out remaining connector pointers */
819 for (i
= conn_count
; i
< INTELFB_CONN_LIMIT
; i
++)
820 modeset
->connectors
[i
] = NULL
;
822 par
->crtc_ids
[crtc_count
++] = crtc
->base
.id
;
824 modeset
->num_connectors
= conn_count
;
825 if (modeset
->mode
!= modeset
->crtc
->desired_mode
)
826 modeset
->mode
= modeset
->crtc
->desired_mode
;
828 par
->crtc_count
= crtc_count
;
831 info
->var
.pixclock
= -1;
832 if (register_framebuffer(info
) < 0)
835 intelfb_set_par(info
);
837 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
840 /* Switch back to kernel console on panic */
841 kernelfb_mode
= *modeset
;
842 atomic_notifier_chain_register(&panic_notifier_list
, &paniced
);
843 printk(KERN_INFO
"registered panic notifier\n");
849 * intelfb_restore - restore the framebuffer console (kernel) config
851 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
853 void intelfb_restore(void)
855 drm_crtc_helper_set_config(&kernelfb_mode
);
858 static void intelfb_sysrq(int dummy1
, struct tty_struct
*dummy3
)
863 static struct sysrq_key_op sysrq_intelfb_restore_op
= {
864 .handler
= intelfb_sysrq
,
865 .help_msg
= "force fb",
866 .action_msg
= "force restore of fb console",
869 int intelfb_probe(struct drm_device
*dev
)
875 /* something has changed in the lower levels of hell - deal with it
878 /* two modes : a) 1 fb to rule all crtcs.
880 two actions 1) new connected device
882 case a/1 : if the fb surface isn't big enough - resize the surface fb.
883 if the fb size isn't big enough - resize fb into surface.
884 if everything big enough configure the new crtc/etc.
885 case a/2 : undo the configuration
886 possibly resize down the fb to fit the new configuration.
887 case b/1 : see if it is on a new crtc - setup a new fb and add it.
888 case b/2 : teardown the new fb.
892 /* search for an fb */
893 if (i915_fbpercrtc
== 1) {
894 ret
= intelfb_multi_fb_probe(dev
);
896 ret
= intelfb_single_fb_probe(dev
);
899 register_sysrq_key('g', &sysrq_intelfb_restore_op
);
903 EXPORT_SYMBOL(intelfb_probe
);
905 int intelfb_remove(struct drm_device
*dev
, struct drm_framebuffer
*fb
)
907 struct fb_info
*info
;
915 unregister_framebuffer(info
);
916 iounmap(info
->screen_base
);
917 framebuffer_release(info
);
920 atomic_notifier_chain_unregister(&panic_notifier_list
, &paniced
);
921 memset(&kernelfb_mode
, 0, sizeof(struct drm_mode_set
));
924 EXPORT_SYMBOL(intelfb_remove
);
925 MODULE_LICENSE("GPL and additional rights");