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 CLOCK 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 DRM_ERROR("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
;
508 /* setup aperture base/size for vesafb takeover */
509 info
->aperture_base
= dev
->mode_config
.fb_base
;
511 info
->aperture_size
= pci_resource_len(dev
->pdev
, 2);
513 info
->aperture_size
= pci_resource_len(dev
->pdev
, 0);
515 info
->fix
.smem_start
= dev
->mode_config
.fb_base
+ obj_priv
->gtt_offset
;
516 info
->fix
.smem_len
= size
;
518 info
->flags
= FBINFO_DEFAULT
;
520 info
->screen_base
= ioremap_wc(dev
->agp
->base
+ obj_priv
->gtt_offset
,
522 if (!info
->screen_base
) {
526 info
->screen_size
= size
;
528 // memset(info->screen_base, 0, size);
530 info
->pseudo_palette
= fb
->pseudo_palette
;
531 info
->var
.xres_virtual
= fb
->width
;
532 info
->var
.yres_virtual
= fb
->height
;
533 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
534 info
->var
.xoffset
= 0;
535 info
->var
.yoffset
= 0;
536 info
->var
.activate
= FB_ACTIVATE_NOW
;
537 info
->var
.height
= -1;
538 info
->var
.width
= -1;
540 info
->var
.xres
= fb_width
;
541 info
->var
.yres
= fb_height
;
543 /* FIXME: we really shouldn't expose mmio space at all */
544 info
->fix
.mmio_start
= pci_resource_start(dev
->pdev
, mmio_bar
);
545 info
->fix
.mmio_len
= pci_resource_len(dev
->pdev
, mmio_bar
);
547 info
->pixmap
.size
= 64*1024;
548 info
->pixmap
.buf_align
= 8;
549 info
->pixmap
.access_align
= 32;
550 info
->pixmap
.flags
= FB_PIXMAP_SYSTEM
;
551 info
->pixmap
.scan_align
= 1;
555 info
->var
.red
.offset
= 0;
556 info
->var
.green
.offset
= 0;
557 info
->var
.blue
.offset
= 0;
558 info
->var
.red
.length
= 8; /* 8bit DAC */
559 info
->var
.green
.length
= 8;
560 info
->var
.blue
.length
= 8;
561 info
->var
.transp
.offset
= 0;
562 info
->var
.transp
.length
= 0;
565 info
->var
.red
.offset
= 10;
566 info
->var
.green
.offset
= 5;
567 info
->var
.blue
.offset
= 0;
568 info
->var
.red
.length
= 5;
569 info
->var
.green
.length
= 5;
570 info
->var
.blue
.length
= 5;
571 info
->var
.transp
.offset
= 15;
572 info
->var
.transp
.length
= 1;
575 info
->var
.red
.offset
= 11;
576 info
->var
.green
.offset
= 5;
577 info
->var
.blue
.offset
= 0;
578 info
->var
.red
.length
= 5;
579 info
->var
.green
.length
= 6;
580 info
->var
.blue
.length
= 5;
581 info
->var
.transp
.offset
= 0;
584 info
->var
.red
.offset
= 16;
585 info
->var
.green
.offset
= 8;
586 info
->var
.blue
.offset
= 0;
587 info
->var
.red
.length
= 8;
588 info
->var
.green
.length
= 8;
589 info
->var
.blue
.length
= 8;
590 info
->var
.transp
.offset
= 0;
591 info
->var
.transp
.length
= 0;
594 info
->var
.red
.offset
= 16;
595 info
->var
.green
.offset
= 8;
596 info
->var
.blue
.offset
= 0;
597 info
->var
.red
.length
= 8;
598 info
->var
.green
.length
= 8;
599 info
->var
.blue
.length
= 8;
600 info
->var
.transp
.offset
= 24;
601 info
->var
.transp
.length
= 8;
609 par
->intel_fb
= intel_fb
;
612 /* To allow resizeing without swapping buffers */
613 DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb
->base
.width
,
614 intel_fb
->base
.height
, obj_priv
->gtt_offset
, fbo
);
616 mutex_unlock(&dev
->struct_mutex
);
620 i915_gem_object_unpin(fbo
);
622 drm_gem_object_unreference(fbo
);
623 mutex_unlock(&dev
->struct_mutex
);
628 static int intelfb_multi_fb_probe_crtc(struct drm_device
*dev
, struct drm_crtc
*crtc
)
630 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
631 struct intel_framebuffer
*intel_fb
;
632 struct drm_framebuffer
*fb
;
633 struct drm_connector
*connector
;
634 struct fb_info
*info
;
635 struct intelfb_par
*par
;
636 struct drm_mode_set
*modeset
;
637 unsigned int width
, height
;
639 int ret
, i
, conn_count
;
641 if (!drm_helper_crtc_in_use(crtc
))
644 if (!crtc
->desired_mode
)
647 width
= crtc
->desired_mode
->hdisplay
;
648 height
= crtc
->desired_mode
->vdisplay
;
650 /* is there an fb bound to this crtc already */
651 if (!intel_crtc
->mode_set
.fb
) {
652 ret
= intelfb_create(dev
, width
, height
, width
, height
, &intel_fb
);
657 fb
= intel_crtc
->mode_set
.fb
;
658 intel_fb
= to_intel_framebuffer(fb
);
659 if ((intel_fb
->base
.width
< width
) || (intel_fb
->base
.height
< height
))
663 info
= intel_fb
->base
.fbdev
;
666 modeset
= &intel_crtc
->mode_set
;
667 modeset
->fb
= &intel_fb
->base
;
669 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
670 if (connector
->encoder
)
671 if (connector
->encoder
->crtc
== modeset
->crtc
) {
672 modeset
->connectors
[conn_count
] = connector
;
674 if (conn_count
> INTELFB_CONN_LIMIT
)
679 for (i
= conn_count
; i
< INTELFB_CONN_LIMIT
; i
++)
680 modeset
->connectors
[i
] = NULL
;
682 par
->crtc_ids
[0] = crtc
->base
.id
;
684 modeset
->num_connectors
= conn_count
;
685 if (modeset
->crtc
->desired_mode
) {
687 drm_mode_destroy(dev
, modeset
->mode
);
688 modeset
->mode
= drm_mode_duplicate(dev
,
689 modeset
->crtc
->desired_mode
);
695 info
->var
.pixclock
= -1;
696 if (register_framebuffer(info
) < 0)
699 intelfb_set_par(info
);
701 DRM_INFO("fb%d: %s frame buffer device\n", info
->node
,
704 /* Switch back to kernel console on panic */
705 kernelfb_mode
= *modeset
;
706 atomic_notifier_chain_register(&panic_notifier_list
, &paniced
);
707 DRM_DEBUG("registered panic notifier\n");
712 static int intelfb_multi_fb_probe(struct drm_device
*dev
)
715 struct drm_crtc
*crtc
;
718 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
719 ret
= intelfb_multi_fb_probe_crtc(dev
, crtc
);
726 static int intelfb_single_fb_probe(struct drm_device
*dev
)
728 struct drm_crtc
*crtc
;
729 struct drm_connector
*connector
;
730 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
731 unsigned int surface_width
= 0, surface_height
= 0;
734 int ret
, i
, conn_count
= 0;
735 struct intel_framebuffer
*intel_fb
;
736 struct fb_info
*info
;
737 struct intelfb_par
*par
;
738 struct drm_mode_set
*modeset
= NULL
;
742 /* Get a count of crtcs now in use and new min/maxes width/heights */
743 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
744 if (!drm_helper_crtc_in_use(crtc
))
748 if (!crtc
->desired_mode
)
751 /* Smallest mode determines console size... */
752 if (crtc
->desired_mode
->hdisplay
< fb_width
)
753 fb_width
= crtc
->desired_mode
->hdisplay
;
755 if (crtc
->desired_mode
->vdisplay
< fb_height
)
756 fb_height
= crtc
->desired_mode
->vdisplay
;
758 /* ... but largest for memory allocation dimensions */
759 if (crtc
->desired_mode
->hdisplay
> surface_width
)
760 surface_width
= crtc
->desired_mode
->hdisplay
;
762 if (crtc
->desired_mode
->vdisplay
> surface_height
)
763 surface_height
= crtc
->desired_mode
->vdisplay
;
766 if (crtc_count
== 0 || fb_width
== -1 || fb_height
== -1) {
767 /* hmm everyone went away - assume VGA cable just fell out
768 and will come back later. */
769 DRM_DEBUG("no CRTCs available?\n");
774 /* Find the fb for our new config */
775 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
776 DRM_DEBUG("creating new fb (console size %dx%d, "
777 "buffer size %dx%d)\n", fb_width
, fb_height
,
778 surface_width
, surface_height
);
779 ret
= intelfb_create(dev
, fb_width
, fb_height
, surface_width
,
780 surface_height
, &intel_fb
);
785 struct drm_framebuffer
*fb
;
787 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
788 struct drm_framebuffer
, filp_head
);
789 intel_fb
= to_intel_framebuffer(fb
);
791 /* if someone hotplugs something bigger than we have already
792 * allocated, we are pwned. As really we can't resize an
793 * fbdev that is in the wild currently due to fbdev not really
794 * being designed for the lower layers moving stuff around
796 * - so in the grand style of things - punt.
798 if ((fb
->width
< surface_width
) ||
799 (fb
->height
< surface_height
)) {
800 DRM_ERROR("fb not large enough for console\n");
806 info
= intel_fb
->base
.fbdev
;
811 * For each CRTC, set up the connector list for the CRTC's mode
814 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
815 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
817 modeset
= &intel_crtc
->mode_set
;
818 modeset
->fb
= &intel_fb
->base
;
820 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
,
822 if (!connector
->encoder
)
825 if(connector
->encoder
->crtc
== modeset
->crtc
) {
826 modeset
->connectors
[conn_count
++] = connector
;
827 if (conn_count
> INTELFB_CONN_LIMIT
)
832 /* Zero out remaining connector pointers */
833 for (i
= conn_count
; i
< INTELFB_CONN_LIMIT
; i
++)
834 modeset
->connectors
[i
] = NULL
;
836 par
->crtc_ids
[crtc_count
++] = crtc
->base
.id
;
838 modeset
->num_connectors
= conn_count
;
839 if (modeset
->crtc
->desired_mode
) {
841 drm_mode_destroy(dev
, modeset
->mode
);
842 modeset
->mode
= drm_mode_duplicate(dev
,
843 modeset
->crtc
->desired_mode
);
846 par
->crtc_count
= crtc_count
;
849 info
->var
.pixclock
= -1;
850 if (register_framebuffer(info
) < 0)
853 intelfb_set_par(info
);
855 DRM_INFO("fb%d: %s frame buffer device\n", info
->node
,
858 /* Switch back to kernel console on panic */
859 kernelfb_mode
= *modeset
;
860 atomic_notifier_chain_register(&panic_notifier_list
, &paniced
);
861 DRM_DEBUG("registered panic notifier\n");
867 * intelfb_restore - restore the framebuffer console (kernel) config
869 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
871 void intelfb_restore(void)
874 if ((ret
= drm_crtc_helper_set_config(&kernelfb_mode
)) != 0) {
875 DRM_ERROR("Failed to restore crtc configuration: %d\n",
880 static void intelfb_restore_work_fn(struct work_struct
*ignored
)
884 static DECLARE_WORK(intelfb_restore_work
, intelfb_restore_work_fn
);
886 static void intelfb_sysrq(int dummy1
, struct tty_struct
*dummy3
)
888 schedule_work(&intelfb_restore_work
);
891 static struct sysrq_key_op sysrq_intelfb_restore_op
= {
892 .handler
= intelfb_sysrq
,
893 .help_msg
= "force-fb(V)",
894 .action_msg
= "Restore framebuffer console",
897 int intelfb_probe(struct drm_device
*dev
)
903 /* something has changed in the lower levels of hell - deal with it
906 /* two modes : a) 1 fb to rule all crtcs.
908 two actions 1) new connected device
910 case a/1 : if the fb surface isn't big enough - resize the surface fb.
911 if the fb size isn't big enough - resize fb into surface.
912 if everything big enough configure the new crtc/etc.
913 case a/2 : undo the configuration
914 possibly resize down the fb to fit the new configuration.
915 case b/1 : see if it is on a new crtc - setup a new fb and add it.
916 case b/2 : teardown the new fb.
920 /* search for an fb */
921 if (i915_fbpercrtc
== 1) {
922 ret
= intelfb_multi_fb_probe(dev
);
924 ret
= intelfb_single_fb_probe(dev
);
927 register_sysrq_key('v', &sysrq_intelfb_restore_op
);
931 EXPORT_SYMBOL(intelfb_probe
);
933 int intelfb_remove(struct drm_device
*dev
, struct drm_framebuffer
*fb
)
935 struct fb_info
*info
;
943 unregister_framebuffer(info
);
944 iounmap(info
->screen_base
);
945 framebuffer_release(info
);
948 atomic_notifier_chain_unregister(&panic_notifier_list
, &paniced
);
949 memset(&kernelfb_mode
, 0, sizeof(struct drm_mode_set
));
952 EXPORT_SYMBOL(intelfb_remove
);
953 MODULE_LICENSE("GPL and additional rights");