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.
30 #include <linux/module.h>
31 #include <linux/kernel.h>
32 #include <linux/errno.h>
33 #include <linux/string.h>
35 #include <linux/tty.h>
36 #include <linux/slab.h>
37 #include <linux/delay.h>
39 #include <linux/init.h>
44 #include "intel_drv.h"
49 struct drm_device *dev;
50 struct drm_display_mode *our_mode;
51 struct intel_framebuffer *intel_fb;
53 /* crtc currently bound to this */
58 var_to_refresh(const struct fb_var_screeninfo *var)
60 int xtot = var->xres + var->left_margin + var->right_margin +
62 int ytot = var->yres + var->upper_margin + var->lower_margin +
65 return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
68 static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
69 unsigned blue, unsigned transp,
72 struct intelfb_par *par = info->par;
73 struct drm_device *dev = par->dev;
74 struct drm_crtc *crtc;
77 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
78 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
79 struct drm_mode_set *modeset = &intel_crtc->mode_set;
80 struct drm_framebuffer *fb = modeset->fb;
82 for (i = 0; i < par->crtc_count; i++)
83 if (crtc->base.id == par->crtc_ids[i])
86 if (i == par->crtc_count)
94 intel_crtc_fb_gamma_set(crtc, red, green, blue, regno);
101 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
102 ((green & 0xf800) >> 6) |
103 ((blue & 0xf800) >> 11);
106 fb->pseudo_palette[regno] = (red & 0xf800) |
107 ((green & 0xfc00) >> 5) |
108 ((blue & 0xf800) >> 11);
112 fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
114 ((blue & 0xff00) >> 8);
122 static int intelfb_check_var(struct fb_var_screeninfo *var,
123 struct fb_info *info)
125 struct intelfb_par *par = info->par;
126 struct intel_framebuffer *intel_fb = par->intel_fb;
127 struct drm_framebuffer *fb = &intel_fb->base;
130 if (var->pixclock == -1 || !var->pixclock)
133 /* Need to resize the fb object !!! */
134 if (var->xres > fb->width || var->yres > fb->height) {
135 DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
136 DRM_ERROR("Need resizing code.\n");
140 switch (var->bits_per_pixel) {
142 depth = (var->green.length == 6) ? 16 : 15;
145 depth = (var->transp.length > 0) ? 32 : 24;
148 depth = var->bits_per_pixel;
155 var->green.offset = 0;
156 var->blue.offset = 0;
158 var->green.length = 8;
159 var->blue.length = 8;
160 var->transp.length = 0;
161 var->transp.offset = 0;
164 var->red.offset = 10;
165 var->green.offset = 5;
166 var->blue.offset = 0;
168 var->green.length = 5;
169 var->blue.length = 5;
170 var->transp.length = 1;
171 var->transp.offset = 15;
174 var->red.offset = 11;
175 var->green.offset = 5;
176 var->blue.offset = 0;
178 var->green.length = 6;
179 var->blue.length = 5;
180 var->transp.length = 0;
181 var->transp.offset = 0;
184 var->red.offset = 16;
185 var->green.offset = 8;
186 var->blue.offset = 0;
188 var->green.length = 8;
189 var->blue.length = 8;
190 var->transp.length = 0;
191 var->transp.offset = 0;
194 var->red.offset = 16;
195 var->green.offset = 8;
196 var->blue.offset = 0;
198 var->green.length = 8;
199 var->blue.length = 8;
200 var->transp.length = 8;
201 var->transp.offset = 24;
210 /* this will let fbcon do the mode init */
211 /* FIXME: take mode config lock? */
212 static int intelfb_set_par(struct fb_info *info)
214 struct intelfb_par *par = info->par;
215 struct drm_device *dev = par->dev;
216 struct fb_var_screeninfo *var = &info->var;
219 DRM_DEBUG("%d %d\n", var->xres, var->pixclock);
221 if (var->pixclock != -1) {
223 DRM_ERROR("PIXEL CLCOK SET\n");
225 struct intel_framebuffer *intel_fb = par->intel_fb;
226 struct drm_framebuffer *fb = &intel_fb->base;
227 struct drm_display_mode *drm_mode, *search_mode;
228 struct drm_connector *connector = NULL;
229 struct drm_device *dev = par->dev;
233 switch (var->bits_per_pixel) {
235 fb->depth = (var->green.length == 6) ? 16 : 15;
238 fb->depth = (var->transp.length > 0) ? 32 : 24;
241 fb->depth = var->bits_per_pixel;
245 fb->bits_per_pixel = var->bits_per_pixel;
247 info->fix.line_length = fb->pitch;
248 info->fix.smem_len = info->fix.line_length * fb->height;
249 info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
251 info->screen_size = info->fix.smem_len; /* ??? */
252 /* reuse desired mode if possible */
253 /* create a drm mode */
254 drm_mode = drm_mode_create(dev);
255 drm_mode->hdisplay = var->xres;
256 drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
257 drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
258 drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
259 drm_mode->vdisplay = var->yres;
260 drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
261 drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
262 drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
263 drm_mode->clock = PICOS2KHZ(var->pixclock);
264 drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
266 drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
267 drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
269 drm_mode_set_name(drm_mode);
270 drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
273 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
274 if (connector->encoder &&
275 connector->encoder->crtc == par->set.crtc){
281 /* no connector bound, bail */
286 drm_mode_debug_printmodeline(drm_mode);
287 list_for_each_entry(search_mode, &connector->modes, head) {
288 drm_mode_debug_printmodeline(search_mode);
289 if (drm_mode_equal(drm_mode, search_mode)) {
290 drm_mode_destroy(dev, drm_mode);
291 drm_mode = search_mode;
297 /* If we didn't find a matching mode that exists on our connector,
298 * create a new attachment for the incoming user specified mode
302 /* this also destroys the mode */
303 drm_mode_detachmode_crtc(dev, par->our_mode);
306 par->set.mode = drm_mode;
307 par->our_mode = drm_mode;
308 drm_mode_debug_printmodeline(drm_mode);
310 drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode);
312 par->set.mode = drm_mode;
314 drm_mode_detachmode_crtc(dev, par->our_mode);
315 par->our_mode = NULL;
317 return par->set.crtc->funcs->set_config(&par->set);
321 struct drm_crtc *crtc;
324 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
325 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
327 for (i = 0; i < par->crtc_count; i++)
328 if (crtc->base.id == par->crtc_ids[i])
331 if (i == par->crtc_count)
334 if (crtc->fb == intel_crtc->mode_set.fb) {
335 ret = crtc->funcs->set_config(&intel_crtc->mode_set);
345 static void intelfb_copyarea(struct fb_info *info,
346 const struct fb_copyarea *region)
348 struct intelfb_par *par = info->par;
349 struct drm_device *dev = par->dev;
350 struct drm_i915_private *dev_priv = dev->dev_private;
351 u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset;
352 u32 cmd, rop_depth_pitch, src_pitch;
355 cmd = XY_SRC_COPY_BLT_CMD;
360 dst_x2 = region->dx + region->width;
361 dst_y2 = region->dy + region->height;
362 offset = par->fb->offset;
363 rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch;
364 src_pitch = par->fb->pitch;
366 switch (par->fb->bits_per_pixel) {
368 rop_depth_pitch |= BLT_DEPTH_16_565;
371 rop_depth_pitch |= BLT_DEPTH_32;
372 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
378 OUT_RING(rop_depth_pitch);
379 OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
380 OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
382 OUT_RING((src_y1 << 16) | (src_x1 & 0xffff));
388 #define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y))
389 #define ROUND_DOWN_TO(x, y) ((x) / (y) * (y))
391 void intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
393 struct intelfb_par *par = info->par;
394 struct drm_device *dev = par->dev;
395 struct drm_i915_private *dev_priv = dev->dev_private;
396 u32 cmd, rop_pitch_depth, tmp;
397 int nbytes, ndwords, pad;
398 u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg;
403 /* size in bytes of a padded scanline */
404 nbytes = ROUND_UP_TO(image->width, 16) / 8;
406 /* Total bytes of padded scanline data to write out. */
407 nbytes *= image->height;
410 * Check if the glyph data exceeds the immediate mode limit.
411 * It would take a large font (1K pixels) to hit this limit.
413 if (nbytes > 128 || image->depth != 1)
414 return cfb_imageblit(info, image);
416 /* Src data is packaged a dword (32-bit) at a time. */
417 ndwords = ROUND_UP_TO(nbytes, 4) / 4;
420 * Ring has to be padded to a quad word. But because the command starts
421 with 7 bytes, pad only if there is an even number of ndwords
423 pad = !(ndwords % 2);
425 DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width,
426 image->height, image->depth, image->dx, image->dy);
427 DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad);
429 tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords;
430 cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp;
431 offset = par->fb->offset;
434 dst_x2 = image->dx + image->width;
435 dst_y2 = image->dy + image->height;
436 rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch;
438 switch (par->fb->bits_per_pixel) {
440 rop_pitch_depth |= BLT_DEPTH_8;
441 fg = image->fg_color;
442 bg = image->bg_color;
445 rop_pitch_depth |= BLT_DEPTH_16_565;
446 fg = par->fb->pseudo_palette[image->fg_color];
447 bg = par->fb->pseudo_palette[image->bg_color];
450 rop_pitch_depth |= BLT_DEPTH_32;
451 cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
452 fg = par->fb->pseudo_palette[image->fg_color];
453 bg = par->fb->pseudo_palette[image->bg_color];
456 DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel);
460 BEGIN_LP_RING(8 + ndwords);
462 OUT_RING(rop_pitch_depth);
463 OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
464 OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
469 iw = ROUND_UP_TO(image->width, 8) / 8;
472 for (j = 0; j < 2; ++j) {
473 for (i = 0; i < 2; ++i) {
474 if (ix != iw || i == 0)
475 dat |= image->data[iy*iw + ix++] << (i+j*2)*8;
477 if (ix == iw && iy != (image->height - 1)) {
489 static int intelfb_pan_display(struct fb_var_screeninfo *var,
490 struct fb_info *info)
492 struct intelfb_par *par = info->par;
493 struct drm_device *dev = par->dev;
494 struct drm_mode_set *modeset;
495 struct drm_crtc *crtc;
496 struct intel_crtc *intel_crtc;
500 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
502 for (i = 0; i < par->crtc_count; i++)
503 if (crtc->base.id == par->crtc_ids[i])
506 if (i == par->crtc_count)
509 intel_crtc = to_intel_crtc(crtc);
510 modeset = &intel_crtc->mode_set;
512 modeset->x = var->xoffset;
513 modeset->y = var->yoffset;
515 if (modeset->num_connectors) {
516 ret = crtc->funcs->set_config(modeset);
519 info->var.xoffset = var->xoffset;
520 info->var.yoffset = var->yoffset;
528 static struct fb_ops intelfb_ops = {
529 .owner = THIS_MODULE,
530 //.fb_open = intelfb_open,
531 //.fb_read = intelfb_read,
532 //.fb_write = intelfb_write,
533 //.fb_release = intelfb_release,
534 //.fb_ioctl = intelfb_ioctl,
535 .fb_check_var = intelfb_check_var,
536 .fb_set_par = intelfb_set_par,
537 .fb_setcolreg = intelfb_setcolreg,
538 .fb_fillrect = cfb_fillrect,
539 .fb_copyarea = cfb_copyarea, //intelfb_copyarea,
540 .fb_imageblit = cfb_imageblit, //intelfb_imageblit,
541 .fb_pan_display = intelfb_pan_display,
545 * Curretly it is assumed that the old framebuffer is reused.
548 * caller should hold the mode config lock.
551 int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
553 struct fb_info *info;
554 struct drm_framebuffer *fb;
555 struct drm_display_mode *mode = crtc->desired_mode;
568 info->var.xres = mode->hdisplay;
569 info->var.right_margin = mode->hsync_start - mode->hdisplay;
570 info->var.hsync_len = mode->hsync_end - mode->hsync_start;
571 info->var.left_margin = mode->htotal - mode->hsync_end;
572 info->var.yres = mode->vdisplay;
573 info->var.lower_margin = mode->vsync_start - mode->vdisplay;
574 info->var.vsync_len = mode->vsync_end - mode->vsync_start;
575 info->var.upper_margin = mode->vtotal - mode->vsync_end;
576 info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
578 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
582 EXPORT_SYMBOL(intelfb_resize);
584 static struct drm_mode_set panic_mode;
586 int intelfb_panic(struct notifier_block *n, unsigned long ununsed,
589 DRM_ERROR("panic occurred, switching back to text console\n");
590 drm_crtc_helper_set_config(&panic_mode);
594 EXPORT_SYMBOL(intelfb_panic);
596 static struct notifier_block paniced = {
597 .notifier_call = intelfb_panic,
600 int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height,
601 uint32_t surface_width, uint32_t surface_height,
602 struct intel_framebuffer **intel_fb_p)
604 struct fb_info *info;
605 struct intelfb_par *par;
606 struct drm_framebuffer *fb;
607 struct intel_framebuffer *intel_fb;
608 struct drm_mode_fb_cmd mode_cmd;
609 struct drm_buffer_object *fbo = NULL;
610 struct device *device = &dev->pdev->dev;
613 mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */
614 mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */
617 mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8);
620 ret = drm_buffer_object_create(dev, mode_cmd.pitch * mode_cmd.height,
625 DRM_BO_FLAG_MEM_VRAM |
626 DRM_BO_FLAG_NO_EVICT,
627 DRM_BO_HINT_DONT_FENCE, 0, 0,
630 printk(KERN_ERR "failed to allocate framebuffer\n");
635 fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd);
637 drm_bo_usage_deref_unlocked(&fbo);
638 DRM_ERROR("failed to allocate fb.\n");
642 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
644 intel_fb = to_intel_framebuffer(fb);
645 *intel_fb_p = intel_fb;
649 info = framebuffer_alloc(sizeof(struct intelfb_par), device);
655 strcpy(info->fix.id, "inteldrmfb");
656 info->fix.type = FB_TYPE_PACKED_PIXELS;
657 info->fix.visual = FB_VISUAL_TRUECOLOR;
658 info->fix.type_aux = 0;
659 info->fix.xpanstep = 1; /* doing it in hw */
660 info->fix.ypanstep = 1; /* doing it in hw */
661 info->fix.ywrapstep = 0;
662 info->fix.accel = FB_ACCEL_I830;
663 info->fix.type_aux = 0;
665 info->flags = FBINFO_DEFAULT;
667 info->fbops = &intelfb_ops;
669 info->fix.line_length = fb->pitch;
670 info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base;
671 info->fix.smem_len = info->fix.line_length * fb->height;
673 info->flags = FBINFO_DEFAULT;
675 ret = drm_bo_kmap(intel_fb->bo, 0, intel_fb->bo->num_pages, &intel_fb->kmap);
677 DRM_ERROR("error mapping fb: %d\n", ret);
679 info->screen_base = intel_fb->kmap.virtual;
680 info->screen_size = info->fix.smem_len; /* FIXME */
682 memset(intel_fb->kmap.virtual, 0, info->screen_size);
684 info->pseudo_palette = fb->pseudo_palette;
685 info->var.xres_virtual = fb->width;
686 info->var.yres_virtual = fb->height;
687 info->var.bits_per_pixel = fb->bits_per_pixel;
688 info->var.xoffset = 0;
689 info->var.yoffset = 0;
690 info->var.activate = FB_ACTIVATE_NOW;
691 info->var.height = -1;
692 info->var.width = -1;
694 info->var.xres = fb_width;
695 info->var.yres = fb_height;
698 info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
699 info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
701 info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
702 info->fix.mmio_len = pci_resource_len(dev->pdev, 1);
705 info->pixmap.size = 64*1024;
706 info->pixmap.buf_align = 8;
707 info->pixmap.access_align = 32;
708 info->pixmap.flags = FB_PIXMAP_SYSTEM;
709 info->pixmap.scan_align = 1;
711 DRM_DEBUG("fb depth is %d\n", fb->depth);
712 DRM_DEBUG(" pitch is %d\n", fb->pitch);
715 info->var.red.offset = 0;
716 info->var.green.offset = 0;
717 info->var.blue.offset = 0;
718 info->var.red.length = 8; /* 8bit DAC */
719 info->var.green.length = 8;
720 info->var.blue.length = 8;
721 info->var.transp.offset = 0;
722 info->var.transp.length = 0;
725 info->var.red.offset = 10;
726 info->var.green.offset = 5;
727 info->var.blue.offset = 0;
728 info->var.red.length = 5;
729 info->var.green.length = 5;
730 info->var.blue.length = 5;
731 info->var.transp.offset = 15;
732 info->var.transp.length = 1;
735 info->var.red.offset = 11;
736 info->var.green.offset = 5;
737 info->var.blue.offset = 0;
738 info->var.red.length = 5;
739 info->var.green.length = 6;
740 info->var.blue.length = 5;
741 info->var.transp.offset = 0;
744 info->var.red.offset = 16;
745 info->var.green.offset = 8;
746 info->var.blue.offset = 0;
747 info->var.red.length = 8;
748 info->var.green.length = 8;
749 info->var.blue.length = 8;
750 info->var.transp.offset = 0;
751 info->var.transp.length = 0;
754 info->var.red.offset = 16;
755 info->var.green.offset = 8;
756 info->var.blue.offset = 0;
757 info->var.red.length = 8;
758 info->var.green.length = 8;
759 info->var.blue.length = 8;
760 info->var.transp.offset = 24;
761 info->var.transp.length = 8;
769 par->intel_fb = intel_fb;
772 /* To allow resizeing without swapping buffers */
773 printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width,
774 intel_fb->base.height, intel_fb->bo->offset, fbo);
779 static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc)
781 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
782 struct intel_framebuffer *intel_fb;
783 struct drm_framebuffer *fb;
784 struct drm_connector *connector;
785 struct fb_info *info;
786 struct intelfb_par *par;
787 struct drm_mode_set *modeset;
788 unsigned int width, height;
790 int ret, i, conn_count;
792 if (!drm_helper_crtc_in_use(crtc))
795 if (!crtc->desired_mode)
798 width = crtc->desired_mode->hdisplay;
799 height = crtc->desired_mode->vdisplay;
801 /* is there an fb bound to this crtc already */
802 if (!intel_crtc->mode_set.fb) {
803 ret = intelfb_create(dev, width, height, width, height, &intel_fb);
808 fb = intel_crtc->mode_set.fb;
809 intel_fb = to_intel_framebuffer(fb);
810 if ((intel_fb->base.width < width) || (intel_fb->base.height < height))
814 info = intel_fb->base.fbdev;
817 modeset = &intel_crtc->mode_set;
818 modeset->fb = &intel_fb->base;
820 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
821 if (connector->encoder)
822 if (connector->encoder->crtc == modeset->crtc) {
823 modeset->connectors[conn_count] = connector;
825 if (conn_count > INTELFB_CONN_LIMIT)
830 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
831 modeset->connectors[i] = NULL;
833 par->crtc_ids[0] = crtc->base.id;
835 modeset->num_connectors = conn_count;
836 if (modeset->mode != modeset->crtc->desired_mode)
837 modeset->mode = modeset->crtc->desired_mode;
842 info->var.pixclock = -1;
843 if (register_framebuffer(info) < 0)
846 intelfb_set_par(info);
848 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
851 /* Switch back to kernel console on panic */
852 panic_mode = *modeset;
853 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
854 printk(KERN_INFO "registered panic notifier\n");
859 static int intelfb_multi_fb_probe(struct drm_device *dev)
862 struct drm_crtc *crtc;
865 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
866 ret = intelfb_multi_fb_probe_crtc(dev, crtc);
873 static int intelfb_single_fb_probe(struct drm_device *dev)
875 struct drm_crtc *crtc;
876 struct drm_connector *connector;
877 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
878 unsigned int surface_width = 0, surface_height = 0;
881 int ret, i, conn_count = 0;
882 struct intel_framebuffer *intel_fb;
883 struct fb_info *info;
884 struct intelfb_par *par;
885 struct drm_mode_set *modeset = NULL;
888 /* first up get a count of crtcs now in use and new min/maxes width/heights */
889 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
890 if (drm_helper_crtc_in_use(crtc)) {
891 if (crtc->desired_mode) {
892 if (crtc->desired_mode->hdisplay < fb_width)
893 fb_width = crtc->desired_mode->hdisplay;
895 if (crtc->desired_mode->vdisplay < fb_height)
896 fb_height = crtc->desired_mode->vdisplay;
898 if (crtc->desired_mode->hdisplay > surface_width)
899 surface_width = crtc->desired_mode->hdisplay;
901 if (crtc->desired_mode->vdisplay > surface_height)
902 surface_height = crtc->desired_mode->vdisplay;
909 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
910 /* hmm everyone went away - assume VGA cable just fell out
911 and will come back later. */
915 /* do we have an fb already? */
916 if (list_empty(&dev->mode_config.fb_kernel_list)) {
917 /* create an fb if we don't have one */
918 ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb);
923 struct drm_framebuffer *fb;
924 fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
925 intel_fb = to_intel_framebuffer(fb);
927 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
928 As really we can't resize an fbdev that is in the wild currently due to fbdev
929 not really being designed for the lower layers moving stuff around under it.
930 - so in the grand style of things - punt. */
931 if ((fb->width < surface_width) || (fb->height < surface_height)) {
932 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
937 info = intel_fb->base.fbdev;
941 /* okay we need to setup new connector sets in the crtcs */
942 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
943 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
944 modeset = &intel_crtc->mode_set;
945 modeset->fb = &intel_fb->base;
947 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
948 if (connector->encoder)
949 if(connector->encoder->crtc == modeset->crtc) {
950 modeset->connectors[conn_count] = connector;
952 if (conn_count > INTELFB_CONN_LIMIT)
957 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
958 modeset->connectors[i] = NULL;
960 par->crtc_ids[crtc_count++] = crtc->base.id;
962 modeset->num_connectors = conn_count;
963 if (modeset->mode != modeset->crtc->desired_mode)
964 modeset->mode = modeset->crtc->desired_mode;
966 par->crtc_count = crtc_count;
969 info->var.pixclock = -1;
970 if (register_framebuffer(info) < 0)
973 intelfb_set_par(info);
975 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
978 /* Switch back to kernel console on panic */
979 panic_mode = *modeset;
980 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
981 printk(KERN_INFO "registered panic notifier\n");
986 int intelfb_probe(struct drm_device *dev)
992 /* something has changed in the lower levels of hell - deal with it
995 /* two modes : a) 1 fb to rule all crtcs.
997 two actions 1) new connected device
999 case a/1 : if the fb surface isn't big enough - resize the surface fb.
1000 if the fb size isn't big enough - resize fb into surface.
1001 if everything big enough configure the new crtc/etc.
1002 case a/2 : undo the configuration
1003 possibly resize down the fb to fit the new configuration.
1004 case b/1 : see if it is on a new crtc - setup a new fb and add it.
1005 case b/2 : teardown the new fb.
1009 /* search for an fb */
1010 if (i915_fbpercrtc == 1) {
1011 ret = intelfb_multi_fb_probe(dev);
1013 ret = intelfb_single_fb_probe(dev);
1018 EXPORT_SYMBOL(intelfb_probe);
1020 int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
1022 struct fb_info *info;
1023 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
1031 unregister_framebuffer(info);
1032 drm_bo_kunmap(&intel_fb->kmap);
1033 drm_bo_usage_deref_unlocked(&intel_fb->bo);
1034 framebuffer_release(info);
1037 atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
1038 memset(&panic_mode, 0, sizeof(struct drm_mode_set));
1041 EXPORT_SYMBOL(intelfb_remove);
1042 MODULE_LICENSE("GPL");