All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jesse Barnes <jbarnes@virtuousgeek.org>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH 6/6] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v10
Date: Fri,  7 Feb 2014 12:10:40 -0800	[thread overview]
Message-ID: <1391803840-2629-6-git-send-email-jbarnes@virtuousgeek.org> (raw)
In-Reply-To: <1391803840-2629-1-git-send-email-jbarnes@virtuousgeek.org>

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)

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_drv.h   |    1 +
 drivers/gpu/drm/i915/intel_fbdev.c |  155 +++++++++++++++++++++++++++++++++---
 2 files changed, 145 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8f5e798..80e6ad2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -113,6 +113,7 @@ struct intel_fbdev {
 	struct intel_framebuffer *fb;
 	struct list_head fbdev_list;
 	struct drm_display_mode *our_mode;
+	int preferred_bpp;
 };
 
 struct intel_encoder {
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 8ce3405..71a57ed 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -132,6 +132,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 	struct drm_framebuffer *fb;
 	struct drm_i915_gem_object *obj;
 	int size, ret;
+	bool prealloc = false;
 
 	mutex_lock(&dev->struct_mutex);
 
@@ -143,6 +144,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 		intel_fb = ifbdev->fb;
 	} else {
 		DRM_DEBUG_KMS("re-using BIOS fb\n");
+		prealloc = true;
 		sizes->fb_width = intel_fb->base.width;
 		sizes->fb_height = intel_fb->base.height;
 	}
@@ -204,7 +206,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 	 * If the object is stolen however, it will be full of whatever
 	 * garbage was left in there.
 	 */
-	if (ifbdev->fb->obj->stolen)
+	if (ifbdev->fb->obj->stolen && !prealloc)
 		memset_io(info->screen_base, 0, info->screen_size);
 
 	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
@@ -319,7 +321,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 		}
 
 		if (!to_intel_crtc(encoder->crtc)->active) {
-			DRM_DEBUG_KMS("connector %s on inactive crtc %d, borting\n",
+			DRM_DEBUG_KMS("connector %s on inactive crtc %d, aborting\n",
 				      drm_get_connector_name(connector),
 				      encoder->crtc->base.id);
 			return false;
@@ -364,27 +366,156 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 	kfree(ifbdev->fb);
 }
 
+/*
+ * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
+ * The core display code will have read out the current plane configuration,
+ * so we use that to figure out if there's an object for us to use as the
+ * fb, and if so, we re-use it for the fbdev configuration.
+ *
+ * Note we only support a single fb shared across pipes for boot (mostly for
+ * fbcon), so we just find the biggest and use that.
+ */
+static bool intel_fbdev_init_bios(struct drm_device *dev,
+				 struct intel_fbdev *ifbdev)
+{
+	struct intel_framebuffer *fb = NULL;
+	struct drm_crtc *crtc;
+	struct intel_crtc *intel_crtc;
+	struct intel_plane_config *plane_config = NULL;
+	unsigned int last_size = 0, max_size = 0;
+
+	if (!i915.fastboot)
+		return false;
+
+	/* Find how big the fb would need to be for the largest pipe */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		unsigned int tmp, stride;
+
+		intel_crtc = to_intel_crtc(crtc);
+
+		if (!intel_crtc->active || !intel_crtc->plane_config.fb) {
+			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
+				      pipe_name(intel_crtc->pipe));
+			continue;
+		}
+
+		if (intel_crtc->plane_config.fb) {
+			stride = intel_crtc->plane_config.fb->base.pitches[0];
+		} else {
+			stride = intel_crtc->config.adjusted_mode.crtc_hdisplay;
+			stride *= 8; /* presumed worst case */
+		}
+		tmp = intel_crtc->config.adjusted_mode.crtc_vdisplay * stride;
+		max_size = max(max_size, tmp);
+	}
+
+	/* Find one that fits in the largest pipe, then free the others */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		intel_crtc = to_intel_crtc(crtc);
+
+		if (!intel_crtc->active || !intel_crtc->plane_config.fb) {
+			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
+				      pipe_name(intel_crtc->pipe));
+			continue;
+		}
+
+		if (intel_crtc->plane_config.size > last_size &&
+		    intel_crtc->plane_config.size >= max_size) {
+			plane_config = &intel_crtc->plane_config;
+			last_size = plane_config->size;
+			fb = plane_config->fb;
+		}
+	}
+
+	/* Free unused fbs */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_framebuffer *cur_fb;
+
+		intel_crtc = to_intel_crtc(crtc);
+		cur_fb = intel_crtc->plane_config.fb;
+
+		if (cur_fb && cur_fb != fb)
+			intel_framebuffer_fini(cur_fb);
+	}
+
+	if (!fb) {
+		DRM_DEBUG_KMS("no active pipes found, not using BIOS config\n");
+		goto out;
+	}
+
+	ifbdev->preferred_bpp = plane_config->fb->base.bits_per_pixel;
+	ifbdev->helper.funcs = &intel_fb_helper_funcs;
+	ifbdev->helper.funcs->initial_config = intel_fb_initial_config;
+	ifbdev->fb = fb;
+
+	/* Assuming a single fb across all pipes here */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		intel_crtc = to_intel_crtc(crtc);
+
+		if (!intel_crtc->active)
+			continue;
+
+		/*
+		 * This should only fail on the first one so we don't need
+		 * to cleanup any secondary crtc->fbs
+		 */
+		if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL))
+			goto out_unref_obj;
+
+		crtc->fb = &fb->base;
+		drm_gem_object_reference(&fb->obj->base);
+		drm_framebuffer_reference(&fb->base);
+	}
+
+	/* Final pass to check if any active pipes don't have fbs */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		intel_crtc = to_intel_crtc(crtc);
+
+		if (!intel_crtc->active)
+			continue;
+
+		WARN(!crtc->fb,
+		     "re-used BIOS config but lost an fb on crtc %d\n",
+		     crtc->base.id);
+	}
+
+
+	DRM_DEBUG_KMS("using BIOS fb for initial console\n");
+	return true;
+
+out_unref_obj:
+	intel_framebuffer_fini(fb);
+out:
+
+	return false;
+}
+
 int intel_fbdev_init(struct drm_device *dev)
 {
 	struct intel_fbdev *ifbdev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
-	ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL);
-	if (!ifbdev)
+	if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
+		return -ENODEV;
+
+	ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
+	if (ifbdev == NULL)
 		return -ENOMEM;
 
-	dev_priv->fbdev = ifbdev;
-	ifbdev->helper.funcs = &intel_fb_helper_funcs;
+	if (!intel_fbdev_init_bios(dev, ifbdev)) {
+		ifbdev->helper.funcs = &intel_fb_helper_funcs;
+		ifbdev->preferred_bpp = 32;
+	}
 
 	ret = drm_fb_helper_init(dev, &ifbdev->helper,
-				 INTEL_INFO(dev)->num_pipes,
-				 4);
+				 INTEL_INFO(dev)->num_pipes, 4);
 	if (ret) {
 		kfree(ifbdev);
 		return ret;
 	}
 
+	dev_priv->fbdev = ifbdev;
 	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
 
 	return 0;
@@ -393,9 +524,10 @@ int intel_fbdev_init(struct drm_device *dev)
 void intel_fbdev_initial_config(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_fbdev *ifbdev = dev_priv->fbdev;
 
 	/* Due to peculiar init order wrt to hpd handling this is separate. */
-	drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
+	drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
 }
 
 void intel_fbdev_fini(struct drm_device *dev)
@@ -433,7 +565,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
 void intel_fbdev_output_poll_changed(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
+	if (dev_priv->fbdev)
+		drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
 }
 
 void intel_fbdev_restore_mode(struct drm_device *dev)
@@ -441,7 +574,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
 	int ret;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (INTEL_INFO(dev)->num_pipes == 0)
+	if (!dev_priv->fbdev)
 		return;
 
 	drm_modeset_lock_all(dev);
-- 
1.7.9.5

      parent reply	other threads:[~2014-02-07 20:10 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-07 20:10 [PATCH 1/6] drm/i915: split aligned height calculation out v2 Jesse Barnes
2014-02-07 20:10 ` [PATCH 2/6] drm/i915: get_plane_config for i9xx v10 Jesse Barnes
2014-02-10 23:35   ` Daniel Vetter
2014-02-07 20:10 ` [PATCH 3/6] drm/i915: get_plane_config support for ILK+ Jesse Barnes
2014-02-07 20:10 ` [PATCH 4/6] drm/i915: alloc intel_fb in the intel_fbdev struct Jesse Barnes
2014-02-10  9:38   ` Daniel Vetter
2014-02-10 10:01   ` [PATCH 1/2] drm/i915: Use normal fb deref for the fbcon framebuffer Daniel Vetter
2014-02-10 10:01     ` [PATCH 2/2] drm/i915: Fix error path leak in fbdev fb allocation Daniel Vetter
2014-02-10 17:00   ` [PATCH 1/2] drm/i915: Use normal fb deref for the fbcon framebuffer Daniel Vetter
2014-02-10 17:00     ` [PATCH 2/2] drm/i915: Fix error path leak in fbdev fb allocation Daniel Vetter
2014-02-10 17:47       ` Jesse Barnes
2014-02-10 23:19         ` Daniel Vetter
2014-02-10 17:38     ` [PATCH 1/2] drm/i915: Use normal fb deref for the fbcon framebuffer Jesse Barnes
2014-02-07 20:10 ` [PATCH 5/6] drm/i915: allow re-use BIOS connector config for initial fbdev config Jesse Barnes
2014-02-10 10:22   ` Daniel Vetter
2014-02-07 20:10 ` Jesse Barnes [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1391803840-2629-6-git-send-email-jbarnes@virtuousgeek.org \
    --to=jbarnes@virtuousgeek.org \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.