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 ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
267 drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_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 void intelfb_on(struct fb_info *info)
530 struct intelfb_par *par = info->par;
531 struct drm_device *dev = par->dev;
532 struct drm_crtc *crtc;
533 struct drm_encoder *encoder;
537 * For each CRTC in this fb, find all associated encoders
538 * and turn them off, then turn off the CRTC.
540 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
541 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
543 for (i = 0; i < par->crtc_count; i++)
544 if (crtc->base.id == par->crtc_ids[i])
547 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
549 /* Found a CRTC on this fb, now find encoders */
550 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
551 if (encoder->crtc == crtc) {
552 struct drm_encoder_helper_funcs *encoder_funcs;
553 encoder_funcs = encoder->helper_private;
554 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
560 static void intelfb_off(struct fb_info *info, int dpms_mode)
562 struct intelfb_par *par = info->par;
563 struct drm_device *dev = par->dev;
564 struct drm_crtc *crtc;
565 struct drm_encoder *encoder;
569 * For each CRTC in this fb, find all associated encoders
570 * and turn them off, then turn off the CRTC.
572 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
573 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
575 for (i = 0; i < par->crtc_count; i++)
576 if (crtc->base.id == par->crtc_ids[i])
579 /* Found a CRTC on this fb, now find encoders */
580 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
581 if (encoder->crtc == crtc) {
582 struct drm_encoder_helper_funcs *encoder_funcs;
583 encoder_funcs = encoder->helper_private;
584 encoder_funcs->dpms(encoder, dpms_mode);
587 if (dpms_mode == DRM_MODE_DPMS_OFF)
588 crtc_funcs->dpms(crtc, dpms_mode);
592 int intelfb_blank(int blank, struct fb_info *info)
595 case FB_BLANK_UNBLANK:
598 case FB_BLANK_NORMAL:
599 intelfb_off(info, DRM_MODE_DPMS_STANDBY);
601 case FB_BLANK_HSYNC_SUSPEND:
602 intelfb_off(info, DRM_MODE_DPMS_STANDBY);
604 case FB_BLANK_VSYNC_SUSPEND:
605 intelfb_off(info, DRM_MODE_DPMS_SUSPEND);
607 case FB_BLANK_POWERDOWN:
608 intelfb_off(info, DRM_MODE_DPMS_OFF);
614 static struct fb_ops intelfb_ops = {
615 .owner = THIS_MODULE,
616 //.fb_open = intelfb_open,
617 //.fb_read = intelfb_read,
618 //.fb_write = intelfb_write,
619 //.fb_release = intelfb_release,
620 //.fb_ioctl = intelfb_ioctl,
621 .fb_check_var = intelfb_check_var,
622 .fb_set_par = intelfb_set_par,
623 .fb_setcolreg = intelfb_setcolreg,
624 .fb_fillrect = cfb_fillrect,
625 .fb_copyarea = cfb_copyarea, //intelfb_copyarea,
626 .fb_imageblit = cfb_imageblit, //intelfb_imageblit,
627 .fb_pan_display = intelfb_pan_display,
628 .fb_blank = intelfb_blank,
632 * Curretly it is assumed that the old framebuffer is reused.
635 * caller should hold the mode config lock.
638 int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
640 struct fb_info *info;
641 struct drm_framebuffer *fb;
642 struct drm_display_mode *mode = crtc->desired_mode;
655 info->var.xres = mode->hdisplay;
656 info->var.right_margin = mode->hsync_start - mode->hdisplay;
657 info->var.hsync_len = mode->hsync_end - mode->hsync_start;
658 info->var.left_margin = mode->htotal - mode->hsync_end;
659 info->var.yres = mode->vdisplay;
660 info->var.lower_margin = mode->vsync_start - mode->vdisplay;
661 info->var.vsync_len = mode->vsync_end - mode->vsync_start;
662 info->var.upper_margin = mode->vtotal - mode->vsync_end;
663 info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
665 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
669 EXPORT_SYMBOL(intelfb_resize);
671 static struct drm_mode_set panic_mode;
673 int intelfb_panic(struct notifier_block *n, unsigned long ununsed,
676 DRM_ERROR("panic occurred, switching back to text console\n");
677 drm_crtc_helper_set_config(&panic_mode);
681 EXPORT_SYMBOL(intelfb_panic);
683 static struct notifier_block paniced = {
684 .notifier_call = intelfb_panic,
687 int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height,
688 uint32_t surface_width, uint32_t surface_height,
689 struct intel_framebuffer **intel_fb_p)
691 struct fb_info *info;
692 struct intelfb_par *par;
693 struct drm_framebuffer *fb;
694 struct intel_framebuffer *intel_fb;
695 struct drm_mode_fb_cmd mode_cmd;
696 struct drm_gem_object *fbo = NULL;
697 struct drm_i915_gem_object *obj_priv;
698 struct device *device = &dev->pdev->dev;
699 int size, aligned_size, ret;
701 mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */
702 mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */
705 mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8);
708 size = mode_cmd.pitch * mode_cmd.height;
709 aligned_size = ALIGN(size, PAGE_SIZE);
710 fbo = drm_gem_object_alloc(dev, aligned_size);
712 printk(KERN_ERR "failed to allocate framebuffer\n");
716 obj_priv = fbo->driver_private;
718 mutex_lock(&dev->struct_mutex);
719 /* Flush everything out, we'll be doing GTT only from now on */
720 i915_gem_object_set_domain(fbo, I915_GEM_DOMAIN_GTT,
721 I915_GEM_DOMAIN_GTT);
723 ret = i915_gem_object_pin(fbo, PAGE_SIZE);
725 DRM_ERROR("failed to pin fb: %d\n", ret);
729 i915_gem_clflush_object(fbo);
731 fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd);
733 DRM_ERROR("failed to allocate fb.\n");
738 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
740 intel_fb = to_intel_framebuffer(fb);
741 *intel_fb_p = intel_fb;
745 info = framebuffer_alloc(sizeof(struct intelfb_par), device);
753 strcpy(info->fix.id, "inteldrmfb");
754 info->fix.type = FB_TYPE_PACKED_PIXELS;
755 info->fix.visual = FB_VISUAL_TRUECOLOR;
756 info->fix.type_aux = 0;
757 info->fix.xpanstep = 1; /* doing it in hw */
758 info->fix.ypanstep = 1; /* doing it in hw */
759 info->fix.ywrapstep = 0;
760 info->fix.accel = FB_ACCEL_I830;
761 info->fix.type_aux = 0;
763 info->flags = FBINFO_DEFAULT;
765 info->fbops = &intelfb_ops;
767 info->fix.line_length = fb->pitch;
768 info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
769 info->fix.smem_len = size;
771 info->flags = FBINFO_DEFAULT;
773 info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset,
775 if (!info->screen_base) {
779 info->screen_size = size;
781 memset(info->screen_base, 0, size);
783 info->pseudo_palette = fb->pseudo_palette;
784 info->var.xres_virtual = fb->width;
785 info->var.yres_virtual = fb->height;
786 info->var.bits_per_pixel = fb->bits_per_pixel;
787 info->var.xoffset = 0;
788 info->var.yoffset = 0;
789 info->var.activate = FB_ACTIVATE_NOW;
790 info->var.height = -1;
791 info->var.width = -1;
793 info->var.xres = fb_width;
794 info->var.yres = fb_height;
797 info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
798 info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
800 info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
801 info->fix.mmio_len = pci_resource_len(dev->pdev, 1);
804 info->pixmap.size = 64*1024;
805 info->pixmap.buf_align = 8;
806 info->pixmap.access_align = 32;
807 info->pixmap.flags = FB_PIXMAP_SYSTEM;
808 info->pixmap.scan_align = 1;
810 DRM_DEBUG("fb depth is %d\n", fb->depth);
811 DRM_DEBUG(" pitch is %d\n", fb->pitch);
814 info->var.red.offset = 0;
815 info->var.green.offset = 0;
816 info->var.blue.offset = 0;
817 info->var.red.length = 8; /* 8bit DAC */
818 info->var.green.length = 8;
819 info->var.blue.length = 8;
820 info->var.transp.offset = 0;
821 info->var.transp.length = 0;
824 info->var.red.offset = 10;
825 info->var.green.offset = 5;
826 info->var.blue.offset = 0;
827 info->var.red.length = 5;
828 info->var.green.length = 5;
829 info->var.blue.length = 5;
830 info->var.transp.offset = 15;
831 info->var.transp.length = 1;
834 info->var.red.offset = 11;
835 info->var.green.offset = 5;
836 info->var.blue.offset = 0;
837 info->var.red.length = 5;
838 info->var.green.length = 6;
839 info->var.blue.length = 5;
840 info->var.transp.offset = 0;
843 info->var.red.offset = 16;
844 info->var.green.offset = 8;
845 info->var.blue.offset = 0;
846 info->var.red.length = 8;
847 info->var.green.length = 8;
848 info->var.blue.length = 8;
849 info->var.transp.offset = 0;
850 info->var.transp.length = 0;
853 info->var.red.offset = 16;
854 info->var.green.offset = 8;
855 info->var.blue.offset = 0;
856 info->var.red.length = 8;
857 info->var.green.length = 8;
858 info->var.blue.length = 8;
859 info->var.transp.offset = 24;
860 info->var.transp.length = 8;
868 par->intel_fb = intel_fb;
871 /* To allow resizeing without swapping buffers */
872 printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
873 intel_fb->base.height, obj_priv->gtt_offset, fbo);
875 mutex_unlock(&dev->struct_mutex);
879 drm_gem_object_unreference(fbo);
880 mutex_unlock(&dev->struct_mutex);
885 static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc)
887 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
888 struct intel_framebuffer *intel_fb;
889 struct drm_framebuffer *fb;
890 struct drm_connector *connector;
891 struct fb_info *info;
892 struct intelfb_par *par;
893 struct drm_mode_set *modeset;
894 unsigned int width, height;
896 int ret, i, conn_count;
898 if (!drm_helper_crtc_in_use(crtc))
901 if (!crtc->desired_mode)
904 width = crtc->desired_mode->hdisplay;
905 height = crtc->desired_mode->vdisplay;
907 /* is there an fb bound to this crtc already */
908 if (!intel_crtc->mode_set.fb) {
909 ret = intelfb_create(dev, width, height, width, height, &intel_fb);
914 fb = intel_crtc->mode_set.fb;
915 intel_fb = to_intel_framebuffer(fb);
916 if ((intel_fb->base.width < width) || (intel_fb->base.height < height))
920 info = intel_fb->base.fbdev;
923 modeset = &intel_crtc->mode_set;
924 modeset->fb = &intel_fb->base;
926 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
927 if (connector->encoder)
928 if (connector->encoder->crtc == modeset->crtc) {
929 modeset->connectors[conn_count] = connector;
931 if (conn_count > INTELFB_CONN_LIMIT)
936 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
937 modeset->connectors[i] = NULL;
939 par->crtc_ids[0] = crtc->base.id;
941 modeset->num_connectors = conn_count;
942 if (modeset->mode != modeset->crtc->desired_mode)
943 modeset->mode = modeset->crtc->desired_mode;
948 info->var.pixclock = -1;
949 if (register_framebuffer(info) < 0)
952 intelfb_set_par(info);
954 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
957 /* Switch back to kernel console on panic */
958 panic_mode = *modeset;
959 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
960 printk(KERN_INFO "registered panic notifier\n");
965 static int intelfb_multi_fb_probe(struct drm_device *dev)
968 struct drm_crtc *crtc;
971 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
972 ret = intelfb_multi_fb_probe_crtc(dev, crtc);
979 static int intelfb_single_fb_probe(struct drm_device *dev)
981 struct drm_crtc *crtc;
982 struct drm_connector *connector;
983 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
984 unsigned int surface_width = 0, surface_height = 0;
987 int ret, i, conn_count = 0;
988 struct intel_framebuffer *intel_fb;
989 struct fb_info *info;
990 struct intelfb_par *par;
991 struct drm_mode_set *modeset = NULL;
994 /* first up get a count of crtcs now in use and new min/maxes width/heights */
995 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
996 if (drm_helper_crtc_in_use(crtc)) {
997 if (crtc->desired_mode) {
998 if (crtc->desired_mode->hdisplay < fb_width)
999 fb_width = crtc->desired_mode->hdisplay;
1001 if (crtc->desired_mode->vdisplay < fb_height)
1002 fb_height = crtc->desired_mode->vdisplay;
1004 if (crtc->desired_mode->hdisplay > surface_width)
1005 surface_width = crtc->desired_mode->hdisplay;
1007 if (crtc->desired_mode->vdisplay > surface_height)
1008 surface_height = crtc->desired_mode->vdisplay;
1015 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
1016 /* hmm everyone went away - assume VGA cable just fell out
1017 and will come back later. */
1021 /* do we have an fb already? */
1022 if (list_empty(&dev->mode_config.fb_kernel_list)) {
1023 /* create an fb if we don't have one */
1024 ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb);
1029 struct drm_framebuffer *fb;
1030 fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
1031 intel_fb = to_intel_framebuffer(fb);
1033 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
1034 As really we can't resize an fbdev that is in the wild currently due to fbdev
1035 not really being designed for the lower layers moving stuff around under it.
1036 - so in the grand style of things - punt. */
1037 if ((fb->width < surface_width) || (fb->height < surface_height)) {
1038 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
1043 info = intel_fb->base.fbdev;
1047 /* okay we need to setup new connector sets in the crtcs */
1048 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1049 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1050 modeset = &intel_crtc->mode_set;
1051 modeset->fb = &intel_fb->base;
1053 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1054 if (connector->encoder)
1055 if(connector->encoder->crtc == modeset->crtc) {
1056 modeset->connectors[conn_count] = connector;
1058 if (conn_count > INTELFB_CONN_LIMIT)
1063 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
1064 modeset->connectors[i] = NULL;
1066 par->crtc_ids[crtc_count++] = crtc->base.id;
1068 modeset->num_connectors = conn_count;
1069 if (modeset->mode != modeset->crtc->desired_mode)
1070 modeset->mode = modeset->crtc->desired_mode;
1072 par->crtc_count = crtc_count;
1075 info->var.pixclock = -1;
1076 if (register_framebuffer(info) < 0)
1079 intelfb_set_par(info);
1081 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
1084 /* Switch back to kernel console on panic */
1085 panic_mode = *modeset;
1086 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
1087 printk(KERN_INFO "registered panic notifier\n");
1092 int intelfb_probe(struct drm_device *dev)
1098 /* something has changed in the lower levels of hell - deal with it
1101 /* two modes : a) 1 fb to rule all crtcs.
1103 two actions 1) new connected device
1105 case a/1 : if the fb surface isn't big enough - resize the surface fb.
1106 if the fb size isn't big enough - resize fb into surface.
1107 if everything big enough configure the new crtc/etc.
1108 case a/2 : undo the configuration
1109 possibly resize down the fb to fit the new configuration.
1110 case b/1 : see if it is on a new crtc - setup a new fb and add it.
1111 case b/2 : teardown the new fb.
1115 /* search for an fb */
1116 if (i915_fbpercrtc == 1) {
1117 ret = intelfb_multi_fb_probe(dev);
1119 ret = intelfb_single_fb_probe(dev);
1124 EXPORT_SYMBOL(intelfb_probe);
1126 int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
1128 struct fb_info *info;
1129 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
1137 unregister_framebuffer(info);
1138 iounmap(info->screen_base);
1139 mutex_lock(&dev->struct_mutex);
1140 drm_gem_object_unreference(intel_fb->obj);
1141 mutex_unlock(&dev->struct_mutex);
1142 framebuffer_release(info);
1145 atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
1146 memset(&panic_mode, 0, sizeof(struct drm_mode_set));
1149 EXPORT_SYMBOL(intelfb_remove);
1150 MODULE_LICENSE("GPL");