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 ret = i915_gem_object_pin(fbo, PAGE_SIZE);
721 DRM_ERROR("failed to pin fb: %d\n", ret);
725 fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd);
727 DRM_ERROR("failed to allocate fb.\n");
732 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
734 intel_fb = to_intel_framebuffer(fb);
735 *intel_fb_p = intel_fb;
739 info = framebuffer_alloc(sizeof(struct intelfb_par), device);
747 strcpy(info->fix.id, "inteldrmfb");
748 info->fix.type = FB_TYPE_PACKED_PIXELS;
749 info->fix.visual = FB_VISUAL_TRUECOLOR;
750 info->fix.type_aux = 0;
751 info->fix.xpanstep = 1; /* doing it in hw */
752 info->fix.ypanstep = 1; /* doing it in hw */
753 info->fix.ywrapstep = 0;
754 info->fix.accel = FB_ACCEL_I830;
755 info->fix.type_aux = 0;
757 info->flags = FBINFO_DEFAULT;
759 info->fbops = &intelfb_ops;
761 info->fix.line_length = fb->pitch;
762 info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
763 info->fix.smem_len = size;
765 info->flags = FBINFO_DEFAULT;
767 info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset,
769 if (!info->screen_base) {
773 info->screen_size = size;
775 memset(info->screen_base, 0, size);
777 info->pseudo_palette = fb->pseudo_palette;
778 info->var.xres_virtual = fb->width;
779 info->var.yres_virtual = fb->height;
780 info->var.bits_per_pixel = fb->bits_per_pixel;
781 info->var.xoffset = 0;
782 info->var.yoffset = 0;
783 info->var.activate = FB_ACTIVATE_NOW;
784 info->var.height = -1;
785 info->var.width = -1;
787 info->var.xres = fb_width;
788 info->var.yres = fb_height;
791 info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
792 info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
794 info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
795 info->fix.mmio_len = pci_resource_len(dev->pdev, 1);
798 info->pixmap.size = 64*1024;
799 info->pixmap.buf_align = 8;
800 info->pixmap.access_align = 32;
801 info->pixmap.flags = FB_PIXMAP_SYSTEM;
802 info->pixmap.scan_align = 1;
804 DRM_DEBUG("fb depth is %d\n", fb->depth);
805 DRM_DEBUG(" pitch is %d\n", fb->pitch);
808 info->var.red.offset = 0;
809 info->var.green.offset = 0;
810 info->var.blue.offset = 0;
811 info->var.red.length = 8; /* 8bit DAC */
812 info->var.green.length = 8;
813 info->var.blue.length = 8;
814 info->var.transp.offset = 0;
815 info->var.transp.length = 0;
818 info->var.red.offset = 10;
819 info->var.green.offset = 5;
820 info->var.blue.offset = 0;
821 info->var.red.length = 5;
822 info->var.green.length = 5;
823 info->var.blue.length = 5;
824 info->var.transp.offset = 15;
825 info->var.transp.length = 1;
828 info->var.red.offset = 11;
829 info->var.green.offset = 5;
830 info->var.blue.offset = 0;
831 info->var.red.length = 5;
832 info->var.green.length = 6;
833 info->var.blue.length = 5;
834 info->var.transp.offset = 0;
837 info->var.red.offset = 16;
838 info->var.green.offset = 8;
839 info->var.blue.offset = 0;
840 info->var.red.length = 8;
841 info->var.green.length = 8;
842 info->var.blue.length = 8;
843 info->var.transp.offset = 0;
844 info->var.transp.length = 0;
847 info->var.red.offset = 16;
848 info->var.green.offset = 8;
849 info->var.blue.offset = 0;
850 info->var.red.length = 8;
851 info->var.green.length = 8;
852 info->var.blue.length = 8;
853 info->var.transp.offset = 24;
854 info->var.transp.length = 8;
862 par->intel_fb = intel_fb;
865 /* To allow resizeing without swapping buffers */
866 printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
867 intel_fb->base.height, obj_priv->gtt_offset, fbo);
869 mutex_unlock(&dev->struct_mutex);
873 drm_gem_object_unreference(fbo);
874 mutex_unlock(&dev->struct_mutex);
879 static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc)
881 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
882 struct intel_framebuffer *intel_fb;
883 struct drm_framebuffer *fb;
884 struct drm_connector *connector;
885 struct fb_info *info;
886 struct intelfb_par *par;
887 struct drm_mode_set *modeset;
888 unsigned int width, height;
890 int ret, i, conn_count;
892 if (!drm_helper_crtc_in_use(crtc))
895 if (!crtc->desired_mode)
898 width = crtc->desired_mode->hdisplay;
899 height = crtc->desired_mode->vdisplay;
901 /* is there an fb bound to this crtc already */
902 if (!intel_crtc->mode_set.fb) {
903 ret = intelfb_create(dev, width, height, width, height, &intel_fb);
908 fb = intel_crtc->mode_set.fb;
909 intel_fb = to_intel_framebuffer(fb);
910 if ((intel_fb->base.width < width) || (intel_fb->base.height < height))
914 info = intel_fb->base.fbdev;
917 modeset = &intel_crtc->mode_set;
918 modeset->fb = &intel_fb->base;
920 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
921 if (connector->encoder)
922 if (connector->encoder->crtc == modeset->crtc) {
923 modeset->connectors[conn_count] = connector;
925 if (conn_count > INTELFB_CONN_LIMIT)
930 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
931 modeset->connectors[i] = NULL;
933 par->crtc_ids[0] = crtc->base.id;
935 modeset->num_connectors = conn_count;
936 if (modeset->mode != modeset->crtc->desired_mode)
937 modeset->mode = modeset->crtc->desired_mode;
942 info->var.pixclock = -1;
943 if (register_framebuffer(info) < 0)
946 intelfb_set_par(info);
948 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
951 /* Switch back to kernel console on panic */
952 panic_mode = *modeset;
953 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
954 printk(KERN_INFO "registered panic notifier\n");
959 static int intelfb_multi_fb_probe(struct drm_device *dev)
962 struct drm_crtc *crtc;
965 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
966 ret = intelfb_multi_fb_probe_crtc(dev, crtc);
973 static int intelfb_single_fb_probe(struct drm_device *dev)
975 struct drm_crtc *crtc;
976 struct drm_connector *connector;
977 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
978 unsigned int surface_width = 0, surface_height = 0;
981 int ret, i, conn_count = 0;
982 struct intel_framebuffer *intel_fb;
983 struct fb_info *info;
984 struct intelfb_par *par;
985 struct drm_mode_set *modeset = NULL;
988 /* first up get a count of crtcs now in use and new min/maxes width/heights */
989 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
990 if (drm_helper_crtc_in_use(crtc)) {
991 if (crtc->desired_mode) {
992 if (crtc->desired_mode->hdisplay < fb_width)
993 fb_width = crtc->desired_mode->hdisplay;
995 if (crtc->desired_mode->vdisplay < fb_height)
996 fb_height = crtc->desired_mode->vdisplay;
998 if (crtc->desired_mode->hdisplay > surface_width)
999 surface_width = crtc->desired_mode->hdisplay;
1001 if (crtc->desired_mode->vdisplay > surface_height)
1002 surface_height = crtc->desired_mode->vdisplay;
1009 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
1010 /* hmm everyone went away - assume VGA cable just fell out
1011 and will come back later. */
1015 /* do we have an fb already? */
1016 if (list_empty(&dev->mode_config.fb_kernel_list)) {
1017 /* create an fb if we don't have one */
1018 ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb);
1023 struct drm_framebuffer *fb;
1024 fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
1025 intel_fb = to_intel_framebuffer(fb);
1027 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
1028 As really we can't resize an fbdev that is in the wild currently due to fbdev
1029 not really being designed for the lower layers moving stuff around under it.
1030 - so in the grand style of things - punt. */
1031 if ((fb->width < surface_width) || (fb->height < surface_height)) {
1032 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
1037 info = intel_fb->base.fbdev;
1041 /* okay we need to setup new connector sets in the crtcs */
1042 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1043 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1044 modeset = &intel_crtc->mode_set;
1045 modeset->fb = &intel_fb->base;
1047 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1048 if (connector->encoder)
1049 if(connector->encoder->crtc == modeset->crtc) {
1050 modeset->connectors[conn_count] = connector;
1052 if (conn_count > INTELFB_CONN_LIMIT)
1057 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
1058 modeset->connectors[i] = NULL;
1060 par->crtc_ids[crtc_count++] = crtc->base.id;
1062 modeset->num_connectors = conn_count;
1063 if (modeset->mode != modeset->crtc->desired_mode)
1064 modeset->mode = modeset->crtc->desired_mode;
1066 par->crtc_count = crtc_count;
1069 info->var.pixclock = -1;
1070 if (register_framebuffer(info) < 0)
1073 intelfb_set_par(info);
1075 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
1078 /* Switch back to kernel console on panic */
1079 panic_mode = *modeset;
1080 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
1081 printk(KERN_INFO "registered panic notifier\n");
1086 int intelfb_probe(struct drm_device *dev)
1092 /* something has changed in the lower levels of hell - deal with it
1095 /* two modes : a) 1 fb to rule all crtcs.
1097 two actions 1) new connected device
1099 case a/1 : if the fb surface isn't big enough - resize the surface fb.
1100 if the fb size isn't big enough - resize fb into surface.
1101 if everything big enough configure the new crtc/etc.
1102 case a/2 : undo the configuration
1103 possibly resize down the fb to fit the new configuration.
1104 case b/1 : see if it is on a new crtc - setup a new fb and add it.
1105 case b/2 : teardown the new fb.
1109 /* search for an fb */
1110 if (i915_fbpercrtc == 1) {
1111 ret = intelfb_multi_fb_probe(dev);
1113 ret = intelfb_single_fb_probe(dev);
1118 EXPORT_SYMBOL(intelfb_probe);
1120 int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
1122 struct fb_info *info;
1123 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
1131 unregister_framebuffer(info);
1132 iounmap(info->screen_base);
1133 mutex_lock(&dev->struct_mutex);
1134 drm_gem_object_unreference(intel_fb->obj);
1135 mutex_unlock(&dev->struct_mutex);
1136 framebuffer_release(info);
1139 atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
1140 memset(&panic_mode, 0, sizeof(struct drm_mode_set));
1143 EXPORT_SYMBOL(intelfb_remove);
1144 MODULE_LICENSE("GPL");