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 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 int intelfb_panic(struct notifier_block
*n
, unsigned long ununsed
,
420 DRM_ERROR("panic occurred, switching back to text console\n");
425 EXPORT_SYMBOL(intelfb_panic
);
427 static struct notifier_block paniced
= {
428 .notifier_call
= intelfb_panic
,
431 int intelfb_create(struct drm_device
*dev
, uint32_t fb_width
,
432 uint32_t fb_height
, uint32_t surface_width
,
433 uint32_t surface_height
,
434 struct intel_framebuffer
**intel_fb_p
)
436 struct fb_info
*info
;
437 struct intelfb_par
*par
;
438 struct drm_framebuffer
*fb
;
439 struct intel_framebuffer
*intel_fb
;
440 struct drm_mode_fb_cmd mode_cmd
;
441 struct drm_gem_object
*fbo
= NULL
;
442 struct drm_i915_gem_object
*obj_priv
;
443 struct device
*device
= &dev
->pdev
->dev
;
444 int size
, ret
, mmio_bar
= IS_I9XX(dev
) ? 0 : 1;
446 mode_cmd
.width
= surface_width
;
447 mode_cmd
.height
= surface_height
;
450 mode_cmd
.pitch
= mode_cmd
.width
* ((mode_cmd
.bpp
+ 1) / 8);
453 size
= mode_cmd
.pitch
* mode_cmd
.height
;
454 size
= ALIGN(size
, PAGE_SIZE
);
455 fbo
= drm_gem_object_alloc(dev
, size
);
457 printk(KERN_ERR
"failed to allocate framebuffer\n");
461 obj_priv
= fbo
->driver_private
;
463 mutex_lock(&dev
->struct_mutex
);
465 ret
= i915_gem_object_pin(fbo
, PAGE_SIZE
);
467 DRM_ERROR("failed to pin fb: %d\n", ret
);
471 /* Flush everything out, we'll be doing GTT only from now on */
472 i915_gem_object_set_to_gtt_domain(fbo
, 1);
474 ret
= intel_framebuffer_create(dev
, &mode_cmd
, &fb
, fbo
);
476 DRM_ERROR("failed to allocate fb.\n");
480 list_add(&fb
->filp_head
, &dev
->mode_config
.fb_kernel_list
);
482 intel_fb
= to_intel_framebuffer(fb
);
483 *intel_fb_p
= intel_fb
;
485 info
= framebuffer_alloc(sizeof(struct intelfb_par
), device
);
493 strcpy(info
->fix
.id
, "inteldrmfb");
494 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
495 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
496 info
->fix
.type_aux
= 0;
497 info
->fix
.xpanstep
= 1; /* doing it in hw */
498 info
->fix
.ypanstep
= 1; /* doing it in hw */
499 info
->fix
.ywrapstep
= 0;
500 info
->fix
.accel
= FB_ACCEL_I830
;
501 info
->fix
.type_aux
= 0;
503 info
->flags
= FBINFO_DEFAULT
;
505 info
->fbops
= &intelfb_ops
;
507 info
->fix
.line_length
= fb
->pitch
;
508 info
->fix
.smem_start
= dev
->mode_config
.fb_base
+ obj_priv
->gtt_offset
;
509 info
->fix
.smem_len
= size
;
511 info
->flags
= FBINFO_DEFAULT
;
513 info
->screen_base
= ioremap_wc(dev
->agp
->base
+ obj_priv
->gtt_offset
,
515 if (!info
->screen_base
) {
519 info
->screen_size
= size
;
521 // memset(info->screen_base, 0, size);
523 info
->pseudo_palette
= fb
->pseudo_palette
;
524 info
->var
.xres_virtual
= fb
->width
;
525 info
->var
.yres_virtual
= fb
->height
;
526 info
->var
.bits_per_pixel
= fb
->bits_per_pixel
;
527 info
->var
.xoffset
= 0;
528 info
->var
.yoffset
= 0;
529 info
->var
.activate
= FB_ACTIVATE_NOW
;
530 info
->var
.height
= -1;
531 info
->var
.width
= -1;
533 info
->var
.xres
= fb_width
;
534 info
->var
.yres
= fb_height
;
536 /* FIXME: we really shouldn't expose mmio space at all */
537 info
->fix
.mmio_start
= pci_resource_start(dev
->pdev
, mmio_bar
);
538 info
->fix
.mmio_len
= pci_resource_len(dev
->pdev
, mmio_bar
);
540 info
->pixmap
.size
= 64*1024;
541 info
->pixmap
.buf_align
= 8;
542 info
->pixmap
.access_align
= 32;
543 info
->pixmap
.flags
= FB_PIXMAP_SYSTEM
;
544 info
->pixmap
.scan_align
= 1;
548 info
->var
.red
.offset
= 0;
549 info
->var
.green
.offset
= 0;
550 info
->var
.blue
.offset
= 0;
551 info
->var
.red
.length
= 8; /* 8bit DAC */
552 info
->var
.green
.length
= 8;
553 info
->var
.blue
.length
= 8;
554 info
->var
.transp
.offset
= 0;
555 info
->var
.transp
.length
= 0;
558 info
->var
.red
.offset
= 10;
559 info
->var
.green
.offset
= 5;
560 info
->var
.blue
.offset
= 0;
561 info
->var
.red
.length
= 5;
562 info
->var
.green
.length
= 5;
563 info
->var
.blue
.length
= 5;
564 info
->var
.transp
.offset
= 15;
565 info
->var
.transp
.length
= 1;
568 info
->var
.red
.offset
= 11;
569 info
->var
.green
.offset
= 5;
570 info
->var
.blue
.offset
= 0;
571 info
->var
.red
.length
= 5;
572 info
->var
.green
.length
= 6;
573 info
->var
.blue
.length
= 5;
574 info
->var
.transp
.offset
= 0;
577 info
->var
.red
.offset
= 16;
578 info
->var
.green
.offset
= 8;
579 info
->var
.blue
.offset
= 0;
580 info
->var
.red
.length
= 8;
581 info
->var
.green
.length
= 8;
582 info
->var
.blue
.length
= 8;
583 info
->var
.transp
.offset
= 0;
584 info
->var
.transp
.length
= 0;
587 info
->var
.red
.offset
= 16;
588 info
->var
.green
.offset
= 8;
589 info
->var
.blue
.offset
= 0;
590 info
->var
.red
.length
= 8;
591 info
->var
.green
.length
= 8;
592 info
->var
.blue
.length
= 8;
593 info
->var
.transp
.offset
= 24;
594 info
->var
.transp
.length
= 8;
602 par
->intel_fb
= intel_fb
;
605 /* To allow resizeing without swapping buffers */
606 printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb
->base
.width
,
607 intel_fb
->base
.height
, obj_priv
->gtt_offset
, fbo
);
609 mutex_unlock(&dev
->struct_mutex
);
613 drm_gem_object_unreference(fbo
);
614 mutex_unlock(&dev
->struct_mutex
);
619 static int intelfb_multi_fb_probe_crtc(struct drm_device
*dev
, struct drm_crtc
*crtc
)
621 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
622 struct intel_framebuffer
*intel_fb
;
623 struct drm_framebuffer
*fb
;
624 struct drm_connector
*connector
;
625 struct fb_info
*info
;
626 struct intelfb_par
*par
;
627 struct drm_mode_set
*modeset
;
628 unsigned int width
, height
;
630 int ret
, i
, conn_count
;
632 if (!drm_helper_crtc_in_use(crtc
))
635 if (!crtc
->desired_mode
)
638 width
= crtc
->desired_mode
->hdisplay
;
639 height
= crtc
->desired_mode
->vdisplay
;
641 /* is there an fb bound to this crtc already */
642 if (!intel_crtc
->mode_set
.fb
) {
643 ret
= intelfb_create(dev
, width
, height
, width
, height
, &intel_fb
);
648 fb
= intel_crtc
->mode_set
.fb
;
649 intel_fb
= to_intel_framebuffer(fb
);
650 if ((intel_fb
->base
.width
< width
) || (intel_fb
->base
.height
< height
))
654 info
= intel_fb
->base
.fbdev
;
657 modeset
= &intel_crtc
->mode_set
;
658 modeset
->fb
= &intel_fb
->base
;
660 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
661 if (connector
->encoder
)
662 if (connector
->encoder
->crtc
== modeset
->crtc
) {
663 modeset
->connectors
[conn_count
] = connector
;
665 if (conn_count
> INTELFB_CONN_LIMIT
)
670 for (i
= conn_count
; i
< INTELFB_CONN_LIMIT
; i
++)
671 modeset
->connectors
[i
] = NULL
;
673 par
->crtc_ids
[0] = crtc
->base
.id
;
675 modeset
->num_connectors
= conn_count
;
676 if (modeset
->mode
!= modeset
->crtc
->desired_mode
)
677 modeset
->mode
= modeset
->crtc
->desired_mode
;
682 info
->var
.pixclock
= -1;
683 if (register_framebuffer(info
) < 0)
686 intelfb_set_par(info
);
688 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
691 /* Switch back to kernel console on panic */
692 kernelfb_mode
= *modeset
;
693 atomic_notifier_chain_register(&panic_notifier_list
, &paniced
);
694 printk(KERN_INFO
"registered panic notifier\n");
699 static int intelfb_multi_fb_probe(struct drm_device
*dev
)
702 struct drm_crtc
*crtc
;
705 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
706 ret
= intelfb_multi_fb_probe_crtc(dev
, crtc
);
713 static int intelfb_single_fb_probe(struct drm_device
*dev
)
715 struct drm_crtc
*crtc
;
716 struct drm_connector
*connector
;
717 unsigned int fb_width
= (unsigned)-1, fb_height
= (unsigned)-1;
718 unsigned int surface_width
= 0, surface_height
= 0;
721 int ret
, i
, conn_count
= 0;
722 struct intel_framebuffer
*intel_fb
;
723 struct fb_info
*info
;
724 struct intelfb_par
*par
;
725 struct drm_mode_set
*modeset
= NULL
;
729 /* Get a count of crtcs now in use and new min/maxes width/heights */
730 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
731 if (!drm_helper_crtc_in_use(crtc
))
735 if (!crtc
->desired_mode
)
738 /* Smallest mode determines console size... */
739 if (crtc
->desired_mode
->hdisplay
< fb_width
)
740 fb_width
= crtc
->desired_mode
->hdisplay
;
742 if (crtc
->desired_mode
->vdisplay
< fb_height
)
743 fb_height
= crtc
->desired_mode
->vdisplay
;
745 /* ... but largest for memory allocation dimensions */
746 if (crtc
->desired_mode
->hdisplay
> surface_width
)
747 surface_width
= crtc
->desired_mode
->hdisplay
;
749 if (crtc
->desired_mode
->vdisplay
> surface_height
)
750 surface_height
= crtc
->desired_mode
->vdisplay
;
753 if (crtc_count
== 0 || fb_width
== -1 || fb_height
== -1) {
754 /* hmm everyone went away - assume VGA cable just fell out
755 and will come back later. */
756 DRM_DEBUG("no CRTCs available?\n");
761 /* Find the fb for our new config */
762 if (list_empty(&dev
->mode_config
.fb_kernel_list
)) {
763 DRM_DEBUG("creating new fb (console size %dx%d, "
764 "buffer size %dx%d)\n", fb_width
, fb_height
,
765 surface_width
, surface_height
);
766 ret
= intelfb_create(dev
, fb_width
, fb_height
, surface_width
,
767 surface_height
, &intel_fb
);
772 struct drm_framebuffer
*fb
;
774 fb
= list_first_entry(&dev
->mode_config
.fb_kernel_list
,
775 struct drm_framebuffer
, filp_head
);
776 intel_fb
= to_intel_framebuffer(fb
);
778 /* if someone hotplugs something bigger than we have already
779 * allocated, we are pwned. As really we can't resize an
780 * fbdev that is in the wild currently due to fbdev not really
781 * being designed for the lower layers moving stuff around
783 * - so in the grand style of things - punt.
785 if ((fb
->width
< surface_width
) ||
786 (fb
->height
< surface_height
)) {
787 DRM_ERROR("fb not large enough for console\n");
793 info
= intel_fb
->base
.fbdev
;
798 * For each CRTC, set up the connector list for the CRTC's mode
801 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
802 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
804 modeset
= &intel_crtc
->mode_set
;
805 modeset
->fb
= &intel_fb
->base
;
807 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
,
809 if (!connector
->encoder
)
812 if(connector
->encoder
->crtc
== modeset
->crtc
) {
813 modeset
->connectors
[conn_count
++] = connector
;
814 if (conn_count
> INTELFB_CONN_LIMIT
)
819 /* Zero out remaining connector pointers */
820 for (i
= conn_count
; i
< INTELFB_CONN_LIMIT
; i
++)
821 modeset
->connectors
[i
] = NULL
;
823 par
->crtc_ids
[crtc_count
++] = crtc
->base
.id
;
825 modeset
->num_connectors
= conn_count
;
826 if (modeset
->mode
!= modeset
->crtc
->desired_mode
)
827 modeset
->mode
= modeset
->crtc
->desired_mode
;
829 par
->crtc_count
= crtc_count
;
832 info
->var
.pixclock
= -1;
833 if (register_framebuffer(info
) < 0)
836 intelfb_set_par(info
);
838 printk(KERN_INFO
"fb%d: %s frame buffer device\n", info
->node
,
841 /* Switch back to kernel console on panic */
842 kernelfb_mode
= *modeset
;
843 atomic_notifier_chain_register(&panic_notifier_list
, &paniced
);
844 printk(KERN_INFO
"registered panic notifier\n");
850 * intelfb_restore - restore the framebuffer console (kernel) config
852 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
854 void intelfb_restore(void)
856 drm_crtc_helper_set_config(&kernelfb_mode
);
859 static void intelfb_sysrq(int dummy1
, struct tty_struct
*dummy3
)
864 static struct sysrq_key_op sysrq_intelfb_restore_op
= {
865 .handler
= intelfb_sysrq
,
866 .help_msg
= "force fb",
867 .action_msg
= "force restore of fb console",
870 int intelfb_probe(struct drm_device
*dev
)
876 /* something has changed in the lower levels of hell - deal with it
879 /* two modes : a) 1 fb to rule all crtcs.
881 two actions 1) new connected device
883 case a/1 : if the fb surface isn't big enough - resize the surface fb.
884 if the fb size isn't big enough - resize fb into surface.
885 if everything big enough configure the new crtc/etc.
886 case a/2 : undo the configuration
887 possibly resize down the fb to fit the new configuration.
888 case b/1 : see if it is on a new crtc - setup a new fb and add it.
889 case b/2 : teardown the new fb.
893 /* search for an fb */
894 if (i915_fbpercrtc
== 1) {
895 ret
= intelfb_multi_fb_probe(dev
);
897 ret
= intelfb_single_fb_probe(dev
);
900 register_sysrq_key('g', &sysrq_intelfb_restore_op
);
904 EXPORT_SYMBOL(intelfb_probe
);
906 int intelfb_remove(struct drm_device
*dev
, struct drm_framebuffer
*fb
)
908 struct fb_info
*info
;
916 unregister_framebuffer(info
);
917 iounmap(info
->screen_base
);
918 framebuffer_release(info
);
921 atomic_notifier_chain_unregister(&panic_notifier_list
, &paniced
);
922 memset(&kernelfb_mode
, 0, sizeof(struct drm_mode_set
));
925 EXPORT_SYMBOL(intelfb_remove
);
926 MODULE_LICENSE("GPL and additional rights");