aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_fbdev.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-04-02 17:51:54 -0400
committerDave Airlie <airlied@redhat.com>2014-04-02 17:51:54 -0400
commit66e514c14a1cb9c2540c685c40d94dc6ef6b6bb5 (patch)
treeb21a13e80e7a27e8829fa1f1693c46bf2cab4507 /drivers/gpu/drm/i915/intel_fbdev.c
parent2844ea3f252331cc0ecf3ae74f6226db2f580f8a (diff)
parent698b3135acb94e838a33a69f1a7a684fe0d90734 (diff)
Merge tag 'drm-intel-next-2014-03-21' of git://anongit.freedesktop.org/drm-intel into drm-next
- Inherit/reuse firmwar framebuffers (for real this time) from Jesse, less flicker for fastbooting. - More flexible cloning for hdmi (Ville). - Some PPGTT fixes from Ben. - Ring init fixes from Naresh Kumar. - set_cache_level regression fixes for the vma conversion from Ville&Chris. - Conversion to the new dp aux helpers (Jani). - Unification of runtime pm with pc8 support from Paulo, prep work for runtime pm on other platforms than HSW. - Larger cursor sizes (Sagar Kamble). - Piles of improvements and fixes all over, as usual. * tag 'drm-intel-next-2014-03-21' of git://anongit.freedesktop.org/drm-intel: (75 commits) drm/i915: Include a note about the dangers of I915_READ64/I915_WRITE64 drm/i915/sdvo: fix questionable return value check drm/i915: Fix unsafe loop iteration over vma whilst unbinding them drm/i915: Enabling 128x128 and 256x256 ARGB Cursor Support drm/i915: Print how many objects are shared in per-process stats drm/i915: Per-process stats work better when evaluated per-process drm/i915: remove rps local variables drm/i915: Remove extraneous MMIO for RPS drm/i915: Rename and comment all the RPS *stuff* drm/i915: Store the HW min frequency as min_freq drm/i915: Fix coding style for RPS drm/i915: Reorganize the overclock code drm/i915: init pm.suspended earlier drm/i915: update the PC8 and runtime PM documentation drm/i915: rename __hsw_do_{en, dis}able_pc8 drm/i915: kill struct i915_package_c8 drm/i915: move pc8.irqs_disabled to pm.irqs_disabled drm/i915: remove dev_priv->pc8.enabled drm/i915: don't get/put PC8 when getting/putting power wells drm/i915: make intel_aux_display_runtime_get get runtime PM, not PC8 ... Conflicts: drivers/gpu/drm/i915/intel_display.c drivers/gpu/drm/i915/intel_dp.c
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);