intel_fb.c revision 1ae8c0a56eeb3ed358b78ccadd024d6b721f26bc
1/* 2 * Copyright © 2007 David Airlie 3 * 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: 10 * 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 13 * Software. 14 * 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. 22 * 23 * Authors: 24 * David Airlie 25 */ 26 27#include <linux/module.h> 28#include <linux/kernel.h> 29#include <linux/errno.h> 30#include <linux/string.h> 31#include <linux/mm.h> 32#include <linux/tty.h> 33#include <linux/slab.h> 34#include <linux/sysrq.h> 35#include <linux/delay.h> 36#include <linux/fb.h> 37#include <linux/init.h> 38 39#include "drmP.h" 40#include "drm.h" 41#include "drm_crtc.h" 42#include "intel_drv.h" 43#include "i915_drm.h" 44#include "i915_drv.h" 45 46struct intelfb_par { 47 struct drm_device *dev; 48 struct drm_display_mode *our_mode; 49 struct intel_framebuffer *intel_fb; 50 int crtc_count; 51 /* crtc currently bound to this */ 52 uint32_t crtc_ids[2]; 53}; 54 55static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, 56 unsigned blue, unsigned transp, 57 struct fb_info *info) 58{ 59 struct intelfb_par *par = info->par; 60 struct drm_device *dev = par->dev; 61 struct drm_crtc *crtc; 62 int i; 63 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; 68 69 for (i = 0; i < par->crtc_count; i++) 70 if (crtc->base.id == par->crtc_ids[i]) 71 break; 72 73 if (i == par->crtc_count) 74 continue; 75 76 77 if (regno > 255) 78 return 1; 79 80 if (fb->depth == 8) { 81 intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); 82 return 0; 83 } 84 85 if (regno < 16) { 86 switch (fb->depth) { 87 case 15: 88 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | 89 ((green & 0xf800) >> 6) | 90 ((blue & 0xf800) >> 11); 91 break; 92 case 16: 93 fb->pseudo_palette[regno] = (red & 0xf800) | 94 ((green & 0xfc00) >> 5) | 95 ((blue & 0xf800) >> 11); 96 break; 97 case 24: 98 case 32: 99 fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | 100 (green & 0xff00) | 101 ((blue & 0xff00) >> 8); 102 break; 103 } 104 } 105 } 106 return 0; 107} 108 109static int intelfb_check_var(struct fb_var_screeninfo *var, 110 struct fb_info *info) 111{ 112 struct intelfb_par *par = info->par; 113 struct intel_framebuffer *intel_fb = par->intel_fb; 114 struct drm_framebuffer *fb = &intel_fb->base; 115 int depth; 116 117 if (var->pixclock == -1 || !var->pixclock) 118 return -EINVAL; 119 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"); 124 return -EINVAL; 125 } 126 127 switch (var->bits_per_pixel) { 128 case 16: 129 depth = (var->green.length == 6) ? 16 : 15; 130 break; 131 case 32: 132 depth = (var->transp.length > 0) ? 32 : 24; 133 break; 134 default: 135 depth = var->bits_per_pixel; 136 break; 137 } 138 139 switch (depth) { 140 case 8: 141 var->red.offset = 0; 142 var->green.offset = 0; 143 var->blue.offset = 0; 144 var->red.length = 8; 145 var->green.length = 8; 146 var->blue.length = 8; 147 var->transp.length = 0; 148 var->transp.offset = 0; 149 break; 150 case 15: 151 var->red.offset = 10; 152 var->green.offset = 5; 153 var->blue.offset = 0; 154 var->red.length = 5; 155 var->green.length = 5; 156 var->blue.length = 5; 157 var->transp.length = 1; 158 var->transp.offset = 15; 159 break; 160 case 16: 161 var->red.offset = 11; 162 var->green.offset = 5; 163 var->blue.offset = 0; 164 var->red.length = 5; 165 var->green.length = 6; 166 var->blue.length = 5; 167 var->transp.length = 0; 168 var->transp.offset = 0; 169 break; 170 case 24: 171 var->red.offset = 16; 172 var->green.offset = 8; 173 var->blue.offset = 0; 174 var->red.length = 8; 175 var->green.length = 8; 176 var->blue.length = 8; 177 var->transp.length = 0; 178 var->transp.offset = 0; 179 break; 180 case 32: 181 var->red.offset = 16; 182 var->green.offset = 8; 183 var->blue.offset = 0; 184 var->red.length = 8; 185 var->green.length = 8; 186 var->blue.length = 8; 187 var->transp.length = 8; 188 var->transp.offset = 24; 189 break; 190 default: 191 return -EINVAL; 192 } 193 194 return 0; 195} 196 197/* this will let fbcon do the mode init */ 198/* FIXME: take mode config lock? */ 199static int intelfb_set_par(struct fb_info *info) 200{ 201 struct intelfb_par *par = info->par; 202 struct drm_device *dev = par->dev; 203 struct fb_var_screeninfo *var = &info->var; 204 int i; 205 206 DRM_DEBUG("%d %d\n", var->xres, var->pixclock); 207 208 if (var->pixclock != -1) { 209 210 DRM_ERROR("PIXEL CLOCK SET\n"); 211 return -EINVAL; 212 } else { 213 struct drm_crtc *crtc; 214 int ret; 215 216 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 217 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 218 219 for (i = 0; i < par->crtc_count; i++) 220 if (crtc->base.id == par->crtc_ids[i]) 221 break; 222 223 if (i == par->crtc_count) 224 continue; 225 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); 230 if (ret) 231 return ret; 232 } 233 } 234 return 0; 235 } 236} 237 238static int intelfb_pan_display(struct fb_var_screeninfo *var, 239 struct fb_info *info) 240{ 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; 246 int ret = 0; 247 int i; 248 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]) 252 break; 253 254 if (i == par->crtc_count) 255 continue; 256 257 intel_crtc = to_intel_crtc(crtc); 258 modeset = &intel_crtc->mode_set; 259 260 modeset->x = var->xoffset; 261 modeset->y = var->yoffset; 262 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); 267 if (!ret) { 268 info->var.xoffset = var->xoffset; 269 info->var.yoffset = var->yoffset; 270 } 271 } 272 } 273 274 return ret; 275} 276 277static void intelfb_on(struct fb_info *info) 278{ 279 struct intelfb_par *par = info->par; 280 struct drm_device *dev = par->dev; 281 struct drm_crtc *crtc; 282 struct drm_encoder *encoder; 283 int i; 284 285 /* 286 * For each CRTC in this fb, find all associated encoders 287 * and turn them off, then turn off the CRTC. 288 */ 289 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 290 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 291 292 for (i = 0; i < par->crtc_count; i++) 293 if (crtc->base.id == par->crtc_ids[i]) 294 break; 295 296 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); 297 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); 304 } 305 } 306 } 307} 308 309static void intelfb_off(struct fb_info *info, int dpms_mode) 310{ 311 struct intelfb_par *par = info->par; 312 struct drm_device *dev = par->dev; 313 struct drm_crtc *crtc; 314 struct drm_encoder *encoder; 315 int i; 316 317 /* 318 * For each CRTC in this fb, find all associated encoders 319 * and turn them off, then turn off the CRTC. 320 */ 321 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 322 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 323 324 for (i = 0; i < par->crtc_count; i++) 325 if (crtc->base.id == par->crtc_ids[i]) 326 break; 327 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); 334 } 335 } 336 if (dpms_mode == DRM_MODE_DPMS_OFF) 337 crtc_funcs->dpms(crtc, dpms_mode); 338 } 339} 340 341static int intelfb_blank(int blank, struct fb_info *info) 342{ 343 switch (blank) { 344 case FB_BLANK_UNBLANK: 345 intelfb_on(info); 346 break; 347 case FB_BLANK_NORMAL: 348 intelfb_off(info, DRM_MODE_DPMS_STANDBY); 349 break; 350 case FB_BLANK_HSYNC_SUSPEND: 351 intelfb_off(info, DRM_MODE_DPMS_STANDBY); 352 break; 353 case FB_BLANK_VSYNC_SUSPEND: 354 intelfb_off(info, DRM_MODE_DPMS_SUSPEND); 355 break; 356 case FB_BLANK_POWERDOWN: 357 intelfb_off(info, DRM_MODE_DPMS_OFF); 358 break; 359 } 360 return 0; 361} 362 363static 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, 373}; 374 375/** 376 * Curretly it is assumed that the old framebuffer is reused. 377 * 378 * LOCKING 379 * caller should hold the mode config lock. 380 * 381 */ 382int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) 383{ 384 struct fb_info *info; 385 struct drm_framebuffer *fb; 386 struct drm_display_mode *mode = crtc->desired_mode; 387 388 fb = crtc->fb; 389 if (!fb) 390 return 1; 391 392 info = fb->fbdev; 393 if (!info) 394 return 1; 395 396 if (!mode) 397 return 1; 398 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; 408 /* avoid overflow */ 409 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; 410 411 return 0; 412} 413EXPORT_SYMBOL(intelfb_resize); 414 415static struct drm_mode_set kernelfb_mode; 416 417static int intelfb_panic(struct notifier_block *n, unsigned long ununsed, 418 void *panic_str) 419{ 420 DRM_ERROR("panic occurred, switching back to text console\n"); 421 422 intelfb_restore(); 423 return 0; 424} 425 426static struct notifier_block paniced = { 427 .notifier_call = intelfb_panic, 428}; 429 430static int intelfb_create(struct drm_device *dev, uint32_t fb_width, 431 uint32_t fb_height, uint32_t surface_width, 432 uint32_t surface_height, 433 struct intel_framebuffer **intel_fb_p) 434{ 435 struct fb_info *info; 436 struct intelfb_par *par; 437 struct drm_framebuffer *fb; 438 struct intel_framebuffer *intel_fb; 439 struct drm_mode_fb_cmd mode_cmd; 440 struct drm_gem_object *fbo = NULL; 441 struct drm_i915_gem_object *obj_priv; 442 struct device *device = &dev->pdev->dev; 443 int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; 444 445 mode_cmd.width = surface_width; 446 mode_cmd.height = surface_height; 447 448 mode_cmd.bpp = 32; 449 mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); 450 mode_cmd.depth = 24; 451 452 size = mode_cmd.pitch * mode_cmd.height; 453 size = ALIGN(size, PAGE_SIZE); 454 fbo = drm_gem_object_alloc(dev, size); 455 if (!fbo) { 456 DRM_ERROR("failed to allocate framebuffer\n"); 457 ret = -ENOMEM; 458 goto out; 459 } 460 obj_priv = fbo->driver_private; 461 462 mutex_lock(&dev->struct_mutex); 463 464 ret = i915_gem_object_pin(fbo, PAGE_SIZE); 465 if (ret) { 466 DRM_ERROR("failed to pin fb: %d\n", ret); 467 goto out_unref; 468 } 469 470 /* Flush everything out, we'll be doing GTT only from now on */ 471 i915_gem_object_set_to_gtt_domain(fbo, 1); 472 473 ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); 474 if (ret) { 475 DRM_ERROR("failed to allocate fb.\n"); 476 goto out_unpin; 477 } 478 479 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); 480 481 intel_fb = to_intel_framebuffer(fb); 482 *intel_fb_p = intel_fb; 483 484 info = framebuffer_alloc(sizeof(struct intelfb_par), device); 485 if (!info) { 486 ret = -ENOMEM; 487 goto out_unpin; 488 } 489 490 par = info->par; 491 492 strcpy(info->fix.id, "inteldrmfb"); 493 info->fix.type = FB_TYPE_PACKED_PIXELS; 494 info->fix.visual = FB_VISUAL_TRUECOLOR; 495 info->fix.type_aux = 0; 496 info->fix.xpanstep = 1; /* doing it in hw */ 497 info->fix.ypanstep = 1; /* doing it in hw */ 498 info->fix.ywrapstep = 0; 499 info->fix.accel = FB_ACCEL_I830; 500 info->fix.type_aux = 0; 501 502 info->flags = FBINFO_DEFAULT; 503 504 info->fbops = &intelfb_ops; 505 506 info->fix.line_length = fb->pitch; 507 508 /* setup aperture base/size for vesafb takeover */ 509 info->aperture_base = dev->mode_config.fb_base; 510 if (IS_I9XX(dev)) 511 info->aperture_size = pci_resource_len(dev->pdev, 2); 512 else 513 info->aperture_size = pci_resource_len(dev->pdev, 0); 514 515 info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; 516 info->fix.smem_len = size; 517 518 info->flags = FBINFO_DEFAULT; 519 520 info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset, 521 size); 522 if (!info->screen_base) { 523 ret = -ENOSPC; 524 goto out_unpin; 525 } 526 info->screen_size = size; 527 528// memset(info->screen_base, 0, size); 529 530 info->pseudo_palette = fb->pseudo_palette; 531 info->var.xres_virtual = fb->width; 532 info->var.yres_virtual = fb->height; 533 info->var.bits_per_pixel = fb->bits_per_pixel; 534 info->var.xoffset = 0; 535 info->var.yoffset = 0; 536 info->var.activate = FB_ACTIVATE_NOW; 537 info->var.height = -1; 538 info->var.width = -1; 539 540 info->var.xres = fb_width; 541 info->var.yres = fb_height; 542 543 /* FIXME: we really shouldn't expose mmio space at all */ 544 info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); 545 info->fix.mmio_len = pci_resource_len(dev->pdev, mmio_bar); 546 547 info->pixmap.size = 64*1024; 548 info->pixmap.buf_align = 8; 549 info->pixmap.access_align = 32; 550 info->pixmap.flags = FB_PIXMAP_SYSTEM; 551 info->pixmap.scan_align = 1; 552 553 switch(fb->depth) { 554 case 8: 555 info->var.red.offset = 0; 556 info->var.green.offset = 0; 557 info->var.blue.offset = 0; 558 info->var.red.length = 8; /* 8bit DAC */ 559 info->var.green.length = 8; 560 info->var.blue.length = 8; 561 info->var.transp.offset = 0; 562 info->var.transp.length = 0; 563 break; 564 case 15: 565 info->var.red.offset = 10; 566 info->var.green.offset = 5; 567 info->var.blue.offset = 0; 568 info->var.red.length = 5; 569 info->var.green.length = 5; 570 info->var.blue.length = 5; 571 info->var.transp.offset = 15; 572 info->var.transp.length = 1; 573 break; 574 case 16: 575 info->var.red.offset = 11; 576 info->var.green.offset = 5; 577 info->var.blue.offset = 0; 578 info->var.red.length = 5; 579 info->var.green.length = 6; 580 info->var.blue.length = 5; 581 info->var.transp.offset = 0; 582 break; 583 case 24: 584 info->var.red.offset = 16; 585 info->var.green.offset = 8; 586 info->var.blue.offset = 0; 587 info->var.red.length = 8; 588 info->var.green.length = 8; 589 info->var.blue.length = 8; 590 info->var.transp.offset = 0; 591 info->var.transp.length = 0; 592 break; 593 case 32: 594 info->var.red.offset = 16; 595 info->var.green.offset = 8; 596 info->var.blue.offset = 0; 597 info->var.red.length = 8; 598 info->var.green.length = 8; 599 info->var.blue.length = 8; 600 info->var.transp.offset = 24; 601 info->var.transp.length = 8; 602 break; 603 default: 604 break; 605 } 606 607 fb->fbdev = info; 608 609 par->intel_fb = intel_fb; 610 par->dev = dev; 611 612 /* To allow resizeing without swapping buffers */ 613 DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, 614 intel_fb->base.height, obj_priv->gtt_offset, fbo); 615 616 mutex_unlock(&dev->struct_mutex); 617 return 0; 618 619out_unpin: 620 i915_gem_object_unpin(fbo); 621out_unref: 622 drm_gem_object_unreference(fbo); 623 mutex_unlock(&dev->struct_mutex); 624out: 625 return ret; 626} 627 628static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) 629{ 630 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 631 struct intel_framebuffer *intel_fb; 632 struct drm_framebuffer *fb; 633 struct drm_connector *connector; 634 struct fb_info *info; 635 struct intelfb_par *par; 636 struct drm_mode_set *modeset; 637 unsigned int width, height; 638 int new_fb = 0; 639 int ret, i, conn_count; 640 641 if (!drm_helper_crtc_in_use(crtc)) 642 return 0; 643 644 if (!crtc->desired_mode) 645 return 0; 646 647 width = crtc->desired_mode->hdisplay; 648 height = crtc->desired_mode->vdisplay; 649 650 /* is there an fb bound to this crtc already */ 651 if (!intel_crtc->mode_set.fb) { 652 ret = intelfb_create(dev, width, height, width, height, &intel_fb); 653 if (ret) 654 return -EINVAL; 655 new_fb = 1; 656 } else { 657 fb = intel_crtc->mode_set.fb; 658 intel_fb = to_intel_framebuffer(fb); 659 if ((intel_fb->base.width < width) || (intel_fb->base.height < height)) 660 return -EINVAL; 661 } 662 663 info = intel_fb->base.fbdev; 664 par = info->par; 665 666 modeset = &intel_crtc->mode_set; 667 modeset->fb = &intel_fb->base; 668 conn_count = 0; 669 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 670 if (connector->encoder) 671 if (connector->encoder->crtc == modeset->crtc) { 672 modeset->connectors[conn_count] = connector; 673 conn_count++; 674 if (conn_count > INTELFB_CONN_LIMIT) 675 BUG(); 676 } 677 } 678 679 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) 680 modeset->connectors[i] = NULL; 681 682 par->crtc_ids[0] = crtc->base.id; 683 684 modeset->num_connectors = conn_count; 685 if (modeset->crtc->desired_mode) { 686 if (modeset->mode) 687 drm_mode_destroy(dev, modeset->mode); 688 modeset->mode = drm_mode_duplicate(dev, 689 modeset->crtc->desired_mode); 690 } 691 692 par->crtc_count = 1; 693 694 if (new_fb) { 695 info->var.pixclock = -1; 696 if (register_framebuffer(info) < 0) 697 return -EINVAL; 698 } else 699 intelfb_set_par(info); 700 701 DRM_INFO("fb%d: %s frame buffer device\n", info->node, 702 info->fix.id); 703 704 /* Switch back to kernel console on panic */ 705 kernelfb_mode = *modeset; 706 atomic_notifier_chain_register(&panic_notifier_list, &paniced); 707 DRM_DEBUG("registered panic notifier\n"); 708 709 return 0; 710} 711 712static int intelfb_multi_fb_probe(struct drm_device *dev) 713{ 714 715 struct drm_crtc *crtc; 716 int ret = 0; 717 718 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 719 ret = intelfb_multi_fb_probe_crtc(dev, crtc); 720 if (ret) 721 return ret; 722 } 723 return ret; 724} 725 726static int intelfb_single_fb_probe(struct drm_device *dev) 727{ 728 struct drm_crtc *crtc; 729 struct drm_connector *connector; 730 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; 731 unsigned int surface_width = 0, surface_height = 0; 732 int new_fb = 0; 733 int crtc_count = 0; 734 int ret, i, conn_count = 0; 735 struct intel_framebuffer *intel_fb; 736 struct fb_info *info; 737 struct intelfb_par *par; 738 struct drm_mode_set *modeset = NULL; 739 740 DRM_DEBUG("\n"); 741 742 /* Get a count of crtcs now in use and new min/maxes width/heights */ 743 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 744 if (!drm_helper_crtc_in_use(crtc)) 745 continue; 746 747 crtc_count++; 748 if (!crtc->desired_mode) 749 continue; 750 751 /* Smallest mode determines console size... */ 752 if (crtc->desired_mode->hdisplay < fb_width) 753 fb_width = crtc->desired_mode->hdisplay; 754 755 if (crtc->desired_mode->vdisplay < fb_height) 756 fb_height = crtc->desired_mode->vdisplay; 757 758 /* ... but largest for memory allocation dimensions */ 759 if (crtc->desired_mode->hdisplay > surface_width) 760 surface_width = crtc->desired_mode->hdisplay; 761 762 if (crtc->desired_mode->vdisplay > surface_height) 763 surface_height = crtc->desired_mode->vdisplay; 764 } 765 766 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { 767 /* hmm everyone went away - assume VGA cable just fell out 768 and will come back later. */ 769 DRM_DEBUG("no CRTCs available?\n"); 770 return 0; 771 } 772 773//fail 774 /* Find the fb for our new config */ 775 if (list_empty(&dev->mode_config.fb_kernel_list)) { 776 DRM_DEBUG("creating new fb (console size %dx%d, " 777 "buffer size %dx%d)\n", fb_width, fb_height, 778 surface_width, surface_height); 779 ret = intelfb_create(dev, fb_width, fb_height, surface_width, 780 surface_height, &intel_fb); 781 if (ret) 782 return -EINVAL; 783 new_fb = 1; 784 } else { 785 struct drm_framebuffer *fb; 786 787 fb = list_first_entry(&dev->mode_config.fb_kernel_list, 788 struct drm_framebuffer, filp_head); 789 intel_fb = to_intel_framebuffer(fb); 790 791 /* if someone hotplugs something bigger than we have already 792 * allocated, we are pwned. As really we can't resize an 793 * fbdev that is in the wild currently due to fbdev not really 794 * being designed for the lower layers moving stuff around 795 * under it. 796 * - so in the grand style of things - punt. 797 */ 798 if ((fb->width < surface_width) || 799 (fb->height < surface_height)) { 800 DRM_ERROR("fb not large enough for console\n"); 801 return -EINVAL; 802 } 803 } 804// fail 805 806 info = intel_fb->base.fbdev; 807 par = info->par; 808 809 crtc_count = 0; 810 /* 811 * For each CRTC, set up the connector list for the CRTC's mode 812 * set configuration. 813 */ 814 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 815 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 816 817 modeset = &intel_crtc->mode_set; 818 modeset->fb = &intel_fb->base; 819 conn_count = 0; 820 list_for_each_entry(connector, &dev->mode_config.connector_list, 821 head) { 822 if (!connector->encoder) 823 continue; 824 825 if(connector->encoder->crtc == modeset->crtc) { 826 modeset->connectors[conn_count++] = connector; 827 if (conn_count > INTELFB_CONN_LIMIT) 828 BUG(); 829 } 830 } 831 832 /* Zero out remaining connector pointers */ 833 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) 834 modeset->connectors[i] = NULL; 835 836 par->crtc_ids[crtc_count++] = crtc->base.id; 837 838 modeset->num_connectors = conn_count; 839 if (modeset->crtc->desired_mode) { 840 if (modeset->mode) 841 drm_mode_destroy(dev, modeset->mode); 842 modeset->mode = drm_mode_duplicate(dev, 843 modeset->crtc->desired_mode); 844 } 845 } 846 par->crtc_count = crtc_count; 847 848 if (new_fb) { 849 info->var.pixclock = -1; 850 if (register_framebuffer(info) < 0) 851 return -EINVAL; 852 } else 853 intelfb_set_par(info); 854 855 DRM_INFO("fb%d: %s frame buffer device\n", info->node, 856 info->fix.id); 857 858 /* Switch back to kernel console on panic */ 859 kernelfb_mode = *modeset; 860 atomic_notifier_chain_register(&panic_notifier_list, &paniced); 861 DRM_DEBUG("registered panic notifier\n"); 862 863 return 0; 864} 865 866/** 867 * intelfb_restore - restore the framebuffer console (kernel) config 868 * 869 * Restore's the kernel's fbcon mode, used for lastclose & panic paths. 870 */ 871void intelfb_restore(void) 872{ 873 int ret; 874 if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) { 875 DRM_ERROR("Failed to restore crtc configuration: %d\n", 876 ret); 877 } 878} 879 880static void intelfb_restore_work_fn(struct work_struct *ignored) 881{ 882 intelfb_restore(); 883} 884static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn); 885 886static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3) 887{ 888 schedule_work(&intelfb_restore_work); 889} 890 891static struct sysrq_key_op sysrq_intelfb_restore_op = { 892 .handler = intelfb_sysrq, 893 .help_msg = "force-fb(V)", 894 .action_msg = "Restore framebuffer console", 895}; 896 897int intelfb_probe(struct drm_device *dev) 898{ 899 int ret; 900 901 DRM_DEBUG("\n"); 902 903 /* something has changed in the lower levels of hell - deal with it 904 here */ 905 906 /* two modes : a) 1 fb to rule all crtcs. 907 b) one fb per crtc. 908 two actions 1) new connected device 909 2) device removed. 910 case a/1 : if the fb surface isn't big enough - resize the surface fb. 911 if the fb size isn't big enough - resize fb into surface. 912 if everything big enough configure the new crtc/etc. 913 case a/2 : undo the configuration 914 possibly resize down the fb to fit the new configuration. 915 case b/1 : see if it is on a new crtc - setup a new fb and add it. 916 case b/2 : teardown the new fb. 917 */ 918 919 /* mode a first */ 920 /* search for an fb */ 921 if (i915_fbpercrtc == 1) { 922 ret = intelfb_multi_fb_probe(dev); 923 } else { 924 ret = intelfb_single_fb_probe(dev); 925 } 926 927 register_sysrq_key('v', &sysrq_intelfb_restore_op); 928 929 return ret; 930} 931EXPORT_SYMBOL(intelfb_probe); 932 933int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) 934{ 935 struct fb_info *info; 936 937 if (!fb) 938 return -EINVAL; 939 940 info = fb->fbdev; 941 942 if (info) { 943 unregister_framebuffer(info); 944 iounmap(info->screen_base); 945 framebuffer_release(info); 946 } 947 948 atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); 949 memset(&kernelfb_mode, 0, sizeof(struct drm_mode_set)); 950 return 0; 951} 952EXPORT_SYMBOL(intelfb_remove); 953MODULE_LICENSE("GPL and additional rights"); 954