aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2014-03-07 11:57:51 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-03-08 05:31:52 -0500
commitd978ef14456a38034f6c0e94a794129501f89200 (patch)
tree06624ee3b2e6659b47f6bcd4f2cbe0f551fabfcd
parent4c6baa595f4e8516bb9cf0081765f90856aa2fe3 (diff)
drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v12
Retrieve current framebuffer config info from the regs and create an fb object for the buffer the BIOS or boot loader left us. This should allow for smooth transitions to userspace apps once we finish the initial configuration construction. v2: check for non-native modes and adjust (Jesse) fixup aperture and cmap frees (Imre) use unlocked unref if init_bios fails (Jesse) fix curly brace around DSPADDR check (Imre) comment failure path for pin_and_fence (Imre) v3: fixup fixup of aperture frees (Chris) v4: update to current bits (locking & pin_and_fence hack) (Jesse) v5: move fb config fetch to display code (Jesse) re-order hw state readout on initial load to suit fb inherit (Jesse) re-add pin_and_fence in fbdev code to make sure we refcount properly (Je v6: rename to plane_config (Daniel) check for valid object when initializing BIOS fb (Jesse) split from plane_config readout and other display changes (Jesse) drop use_bios_fb option (Chris) update comments (Jesse) rework fbdev_init_bios for clarity (Jesse) drop fb obj ref under lock (Chris) v7: use fb object from plane_config instead (Ville) take ref on fb object (Jesse) v8: put under i915_fastboot option (Jesse) fix fb ptr checking (Jesse) inform drm_fb_helper if we fail to enable a connector (Jesse) drop unnecessary enabled[] modifications in failure cases (Chris) split from BIOS connector config readout (Daniel) don't memset the fb buffer if preallocated (Chris) alloc ifbdev up front and pass to init_bios (Chris) check for bad ifbdev in restore_mode too (Chris) v9: fix up !fastboot bpp setting (Jesse) fix up !fastboot helper alloc (Jesse) make sure BIOS fb is sufficient for biggest active pipe (Jesse) v10:fix up size calculation for proposed fbs (Chris) go back to two pass pipe fb assignment (Chris) add warning for active pipes w/o fbs (Chris) clean up num_pipes checks in fbdev_init and fbdev_restore_mode (Chris) move i915.fastboot into fbdev_init (Chris) v11:make BIOS connector config usage unconditional (Daniel) v12:fix up fb vs pipe size checking (Chris) Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c174
3 files changed, 166 insertions, 10 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9fc18770d207..d3c29116711f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2108,7 +2108,6 @@ static void intel_alloc_plane_obj(struct intel_crtc *crtc,
2108out_unref_obj: 2108out_unref_obj:
2109 drm_gem_object_unreference(&obj->base); 2109 drm_gem_object_unreference(&obj->base);
2110 mutex_unlock(&dev->struct_mutex); 2110 mutex_unlock(&dev->struct_mutex);
2111
2112} 2111}
2113 2112
2114static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, 2113static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 48af57bbc73d..75baa64a357d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -113,6 +113,7 @@ struct intel_fbdev {
113 struct intel_framebuffer *fb; 113 struct intel_framebuffer *fb;
114 struct list_head fbdev_list; 114 struct list_head fbdev_list;
115 struct drm_display_mode *our_mode; 115 struct drm_display_mode *our_mode;
116 int preferred_bpp;
116}; 117};
117 118
118struct intel_encoder { 119struct intel_encoder {
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 6b5beed28d70..32a05edc517c 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,179 @@ 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 || !intel_crtc->plane_config.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 = plane_config->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 /* Free unused fbs */
547 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
548 struct intel_framebuffer *cur_fb;
549
550 intel_crtc = to_intel_crtc(crtc);
551 cur_fb = intel_crtc->plane_config.fb;
552
553 if (cur_fb && cur_fb != fb)
554 drm_framebuffer_unreference(&cur_fb->base);
555 }
556
557 if (!fb) {
558 DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n");
559 goto out;
560 }
561
562 ifbdev->preferred_bpp = plane_config->fb->base.bits_per_pixel;
563 ifbdev->fb = fb;
564
565 /* Assuming a single fb across all pipes here */
566 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
567 intel_crtc = to_intel_crtc(crtc);
568
569 if (!intel_crtc->active)
570 continue;
571
572 /*
573 * This should only fail on the first one so we don't need
574 * to cleanup any secondary crtc->fbs
575 */
576 if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL))
577 goto out_unref_obj;
578
579 crtc->fb = &fb->base;
580 drm_gem_object_reference(&fb->obj->base);
581 drm_framebuffer_reference(&fb->base);
582 }
583
584 /* Final pass to check if any active pipes don't have fbs */
585 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
586 intel_crtc = to_intel_crtc(crtc);
587
588 if (!intel_crtc->active)
589 continue;
590
591 WARN(!crtc->fb,
592 "re-used BIOS config but lost an fb on crtc %d\n",
593 crtc->base.id);
594 }
595
596
597 DRM_DEBUG_KMS("using BIOS fb for initial console\n");
598 return true;
599
600out_unref_obj:
601 drm_framebuffer_unreference(&fb->base);
602out:
603
604 return false;
605}
606
457int intel_fbdev_init(struct drm_device *dev) 607int intel_fbdev_init(struct drm_device *dev)
458{ 608{
459 struct intel_fbdev *ifbdev; 609 struct intel_fbdev *ifbdev;
460 struct drm_i915_private *dev_priv = dev->dev_private; 610 struct drm_i915_private *dev_priv = dev->dev_private;
461 int ret; 611 int ret;
462 612
463 ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL); 613 if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
464 if (!ifbdev) 614 return -ENODEV;
615
616 ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
617 if (ifbdev == NULL)
465 return -ENOMEM; 618 return -ENOMEM;
466 619
467 dev_priv->fbdev = ifbdev;
468 ifbdev->helper.funcs = &intel_fb_helper_funcs; 620 ifbdev->helper.funcs = &intel_fb_helper_funcs;
621 if (!intel_fbdev_init_bios(dev, ifbdev))
622 ifbdev->preferred_bpp = 32;
469 623
470 ret = drm_fb_helper_init(dev, &ifbdev->helper, 624 ret = drm_fb_helper_init(dev, &ifbdev->helper,
471 INTEL_INFO(dev)->num_pipes, 625 INTEL_INFO(dev)->num_pipes, 4);
472 4);
473 if (ret) { 626 if (ret) {
474 kfree(ifbdev); 627 kfree(ifbdev);
475 return ret; 628 return ret;
476 } 629 }
477 630
631 dev_priv->fbdev = ifbdev;
478 drm_fb_helper_single_add_all_connectors(&ifbdev->helper); 632 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
479 633
480 return 0; 634 return 0;
@@ -483,9 +637,10 @@ int intel_fbdev_init(struct drm_device *dev)
483void intel_fbdev_initial_config(struct drm_device *dev) 637void intel_fbdev_initial_config(struct drm_device *dev)
484{ 638{
485 struct drm_i915_private *dev_priv = dev->dev_private; 639 struct drm_i915_private *dev_priv = dev->dev_private;
640 struct intel_fbdev *ifbdev = dev_priv->fbdev;
486 641
487 /* Due to peculiar init order wrt to hpd handling this is separate. */ 642 /* Due to peculiar init order wrt to hpd handling this is separate. */
488 drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); 643 drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
489} 644}
490 645
491void intel_fbdev_fini(struct drm_device *dev) 646void intel_fbdev_fini(struct drm_device *dev)
@@ -523,7 +678,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
523void intel_fbdev_output_poll_changed(struct drm_device *dev) 678void intel_fbdev_output_poll_changed(struct drm_device *dev)
524{ 679{
525 struct drm_i915_private *dev_priv = dev->dev_private; 680 struct drm_i915_private *dev_priv = dev->dev_private;
526 drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); 681 if (dev_priv->fbdev)
682 drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
527} 683}
528 684
529void intel_fbdev_restore_mode(struct drm_device *dev) 685void intel_fbdev_restore_mode(struct drm_device *dev)
@@ -531,7 +687,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
531 int ret; 687 int ret;
532 struct drm_i915_private *dev_priv = dev->dev_private; 688 struct drm_i915_private *dev_priv = dev->dev_private;
533 689
534 if (INTEL_INFO(dev)->num_pipes == 0) 690 if (!dev_priv->fbdev)
535 return; 691 return;
536 692
537 drm_modeset_lock_all(dev); 693 drm_modeset_lock_all(dev);