aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_fbdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_fbdev.c')
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c144
1 files changed, 135 insertions, 9 deletions
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 6b5beed28d70..2b1d42dbfe13 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -128,6 +128,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
128 struct drm_framebuffer *fb; 128 struct drm_framebuffer *fb;
129 struct drm_i915_gem_object *obj; 129 struct drm_i915_gem_object *obj;
130 int size, ret; 130 int size, ret;
131 bool prealloc = false;
131 132
132 mutex_lock(&dev->struct_mutex); 133 mutex_lock(&dev->struct_mutex);
133 134
@@ -139,6 +140,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
139 intel_fb = ifbdev->fb; 140 intel_fb = ifbdev->fb;
140 } else { 141 } else {
141 DRM_DEBUG_KMS("re-using BIOS fb\n"); 142 DRM_DEBUG_KMS("re-using BIOS fb\n");
143 prealloc = true;
142 sizes->fb_width = intel_fb->base.width; 144 sizes->fb_width = intel_fb->base.width;
143 sizes->fb_height = intel_fb->base.height; 145 sizes->fb_height = intel_fb->base.height;
144 } 146 }
@@ -200,7 +202,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
200 * If the object is stolen however, it will be full of whatever 202 * If the object is stolen however, it will be full of whatever
201 * garbage was left in there. 203 * garbage was left in there.
202 */ 204 */
203 if (ifbdev->fb->obj->stolen) 205 if (ifbdev->fb->obj->stolen && !prealloc)
204 memset_io(info->screen_base, 0, info->screen_size); 206 memset_io(info->screen_base, 0, info->screen_size);
205 207
206 /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ 208 /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
@@ -454,27 +456,149 @@ static void intel_fbdev_destroy(struct drm_device *dev,
454 drm_framebuffer_remove(&ifbdev->fb->base); 456 drm_framebuffer_remove(&ifbdev->fb->base);
455} 457}
456 458
459/*
460 * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
461 * The core display code will have read out the current plane configuration,
462 * so we use that to figure out if there's an object for us to use as the
463 * fb, and if so, we re-use it for the fbdev configuration.
464 *
465 * Note we only support a single fb shared across pipes for boot (mostly for
466 * fbcon), so we just find the biggest and use that.
467 */
468static bool intel_fbdev_init_bios(struct drm_device *dev,
469 struct intel_fbdev *ifbdev)
470{
471 struct intel_framebuffer *fb = NULL;
472 struct drm_crtc *crtc;
473 struct intel_crtc *intel_crtc;
474 struct intel_plane_config *plane_config = NULL;
475 unsigned int max_size = 0;
476
477 if (!i915.fastboot)
478 return false;
479
480 /* Find the largest fb */
481 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
482 intel_crtc = to_intel_crtc(crtc);
483
484 if (!intel_crtc->active || !crtc->primary->fb) {
485 DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
486 pipe_name(intel_crtc->pipe));
487 continue;
488 }
489
490 if (intel_crtc->plane_config.size > max_size) {
491 DRM_DEBUG_KMS("found possible fb from plane %c\n",
492 pipe_name(intel_crtc->pipe));
493 plane_config = &intel_crtc->plane_config;
494 fb = to_intel_framebuffer(crtc->primary->fb);
495 max_size = plane_config->size;
496 }
497 }
498
499 if (!fb) {
500 DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n");
501 goto out;
502 }
503
504 /* Now make sure all the pipes will fit into it */
505 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
506 unsigned int cur_size;
507
508 intel_crtc = to_intel_crtc(crtc);
509
510 if (!intel_crtc->active) {
511 DRM_DEBUG_KMS("pipe %c not active, skipping\n",
512 pipe_name(intel_crtc->pipe));
513 continue;
514 }
515
516 DRM_DEBUG_KMS("checking plane %c for BIOS fb\n",
517 pipe_name(intel_crtc->pipe));
518
519 /*
520 * See if the plane fb we found above will fit on this
521 * pipe. Note we need to use the selected fb's bpp rather
522 * than the current pipe's, since they could be different.
523 */
524 cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay *
525 intel_crtc->config.adjusted_mode.crtc_vdisplay;
526 DRM_DEBUG_KMS("pipe %c area: %d\n", pipe_name(intel_crtc->pipe),
527 cur_size);
528 cur_size *= fb->base.bits_per_pixel / 8;
529 DRM_DEBUG_KMS("total size %d (bpp %d)\n", cur_size,
530 fb->base.bits_per_pixel / 8);
531
532 if (cur_size > max_size) {
533 DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n",
534 pipe_name(intel_crtc->pipe),
535 cur_size, max_size);
536 plane_config = NULL;
537 fb = NULL;
538 break;
539 }
540
541 DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n",
542 pipe_name(intel_crtc->pipe),
543 max_size, cur_size);
544 }
545
546 if (!fb) {
547 DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n");
548 goto out;
549 }
550
551 ifbdev->preferred_bpp = fb->base.bits_per_pixel;
552 ifbdev->fb = fb;
553
554 drm_framebuffer_reference(&ifbdev->fb->base);
555
556 /* Final pass to check if any active pipes don't have fbs */
557 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
558 intel_crtc = to_intel_crtc(crtc);
559
560 if (!intel_crtc->active)
561 continue;
562
563 WARN(!crtc->primary->fb,
564 "re-used BIOS config but lost an fb on crtc %d\n",
565 crtc->base.id);
566 }
567
568
569 DRM_DEBUG_KMS("using BIOS fb for initial console\n");
570 return true;
571
572out:
573
574 return false;
575}
576
457int intel_fbdev_init(struct drm_device *dev) 577int intel_fbdev_init(struct drm_device *dev)
458{ 578{
459 struct intel_fbdev *ifbdev; 579 struct intel_fbdev *ifbdev;
460 struct drm_i915_private *dev_priv = dev->dev_private; 580 struct drm_i915_private *dev_priv = dev->dev_private;
461 int ret; 581 int ret;
462 582
463 ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); 583 if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
464 if (!ifbdev) 584 return -ENODEV;
585
586 ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
587 if (ifbdev == NULL)
465 return -ENOMEM; 588 return -ENOMEM;
466 589
467 dev_priv->fbdev = ifbdev;
468 ifbdev->helper.funcs = &intel_fb_helper_funcs; 590 ifbdev->helper.funcs = &intel_fb_helper_funcs;
591 if (!intel_fbdev_init_bios(dev, ifbdev))
592 ifbdev->preferred_bpp = 32;
469 593
470 ret = drm_fb_helper_init(dev, &ifbdev->helper, 594 ret = drm_fb_helper_init(dev, &ifbdev->helper,
471 INTEL_INFO(dev)->num_pipes, 595 INTEL_INFO(dev)->num_pipes, 4);
472 4);
473 if (ret) { 596 if (ret) {
474 kfree(ifbdev); 597 kfree(ifbdev);
475 return ret; 598 return ret;
476 } 599 }
477 600
601 dev_priv->fbdev = ifbdev;
478 drm_fb_helper_single_add_all_connectors(&ifbdev->helper); 602 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
479 603
480 return 0; 604 return 0;
@@ -483,9 +607,10 @@ int intel_fbdev_init(struct drm_device *dev)
483void intel_fbdev_initial_config(struct drm_device *dev) 607void intel_fbdev_initial_config(struct drm_device *dev)
484{ 608{
485 struct drm_i915_private *dev_priv = dev->dev_private; 609 struct drm_i915_private *dev_priv = dev->dev_private;
610 struct intel_fbdev *ifbdev = dev_priv->fbdev;
486 611
487 /* Due to peculiar init order wrt to hpd handling this is separate. */ 612 /* Due to peculiar init order wrt to hpd handling this is separate. */
488 drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); 613 drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
489} 614}
490 615
491void intel_fbdev_fini(struct drm_device *dev) 616void intel_fbdev_fini(struct drm_device *dev)
@@ -523,7 +648,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
523void intel_fbdev_output_poll_changed(struct drm_device *dev) 648void intel_fbdev_output_poll_changed(struct drm_device *dev)
524{ 649{
525 struct drm_i915_private *dev_priv = dev->dev_private; 650 struct drm_i915_private *dev_priv = dev->dev_private;
526 drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); 651 if (dev_priv->fbdev)
652 drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
527} 653}
528 654
529void intel_fbdev_restore_mode(struct drm_device *dev) 655void intel_fbdev_restore_mode(struct drm_device *dev)
@@ -531,7 +657,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
531 int ret; 657 int ret;
532 struct drm_i915_private *dev_priv = dev->dev_private; 658 struct drm_i915_private *dev_priv = dev->dev_private;
533 659
534 if (INTEL_INFO(dev)->num_pipes == 0) 660 if (!dev_priv->fbdev)
535 return; 661 return;
536 662
537 drm_modeset_lock_all(dev); 663 drm_modeset_lock_all(dev);