[Intel-gfx] [PATCH 36/43] drm/i915: try to handle multi-head BIOS configurations too

Chris Wilson chris at chris-wilson.co.uk
Fri May 25 14:33:15 CEST 2012


From: Jesse Barnes <jbarnes at virtuousgeek.org>

If the BIOS hands us a multi-pipe configuration, try to allocate an fb
large enough for the largest screen and preserve the mode.

Still need to fix the other initial_config function in case one or more
of the pipes was rejected due to an incompatibility with the others.

Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_fb.c |  190 ++++++++++++++++++++++++++-------------
 1 file changed, 129 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 74bd22e..e69567d 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -288,23 +288,49 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 	}
 }
 
+/*
+ * Try to read the BIOS display configuration and use it for the initial
+ * fb configuration.
+ *
+ * The BIOS or boot loader will generally create an initial display
+ * configuration for us that includes some set of active pipes and displays.
+ * This routine tries to figure out which pipes are active, what resolutions
+ * are being displayed, and then allocates a framebuffer and initial fb
+ * config based on that data.
+ *
+ * If the BIOS or boot loader leaves the display in VGA mode, there's not
+ * much we can do; switching out of that mode involves allocating a new,
+ * high res buffer, and also recalculating bandwidth requirements for the
+ * new bpp configuration.
+ *
+ * However, if we're loaded into an existing, high res mode, we should
+ * be able to allocate a buffer big enough to handle the largest active
+ * mode, create a mode_set for it, and pass it to the fb helper to create
+ * the configuration.
+ */
 void intel_fbdev_init_bios(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_fbdev *ifbdev;
-	int pipe, ret;
-
-	for_each_pipe(pipe) {
-		struct intel_crtc *crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-		struct drm_mode_fb_cmd2 mode_cmd;
-		struct drm_i915_gem_object *obj;
-		struct fb_info *info;
-		u32 val, bpp, depth;
-		u32 size, offset;
-
-		val = I915_READ(DSPCNTR(crtc->plane));
-		if ((val & DISPLAY_PLANE_ENABLE) == 0)
+	struct drm_crtc *crtc;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_i915_gem_object *obj;
+	struct fb_info *info;
+	u32 obj_size = 0, obj_offset = 0, last_bpp = 0, last_depth = 0;
+	int ret;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		int pipe = intel_crtc->pipe, plane = intel_crtc->plane;
+		u32 val, bpp, depth, offset;
+		int pitch, width, height, size;
+
+		if (!intel_crtc->active) {
+			DRM_DEBUG_KMS("pipe %d not active, skipping\n", pipe);
 			continue;
+		}
+
+		val = I915_READ(DSPCNTR(plane));
 
 		if (INTEL_INFO(dev)->gen >= 4) {
 			if (val & DISPPLANE_TILED) {
@@ -329,77 +355,119 @@ void intel_fbdev_init_bios(struct drm_device *dev)
 			break;
 		}
 
+		if (!last_bpp)
+			last_bpp = bpp;
+		if (!last_depth)
+			last_depth = depth;
+
+		if (bpp != last_bpp || depth != last_depth) {
+			DRM_DEBUG_KMS("pipe %d has depth/bpp mismatch: "
+				      "(%d/%d vs %d/%d), skipping\n",
+				      pipe, bpp, depth, last_bpp, last_depth);
+			continue;
+		}
+
+		last_bpp = bpp;
+		last_depth = depth;
+
 		if (INTEL_INFO(dev)->gen >= 4)
-			offset = I915_READ(DSPSURF(crtc->plane));
+			offset = I915_READ(DSPSURF(plane));
 		else
-			offset = I915_READ(DSPADDR(crtc->plane));
-		mode_cmd.pitches[0] = I915_READ(DSPSTRIDE(crtc->plane));
+			offset = I915_READ(DSPADDR(plane));
 
-		val = I915_READ(PIPESRC(crtc->pipe));
-		mode_cmd.width = ((val >> 16) & 0xfff) + 1;
-		mode_cmd.height = ((val >> 0) & 0xfff) + 1;
-		mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth);
+		pitch = I915_READ(DSPSTRIDE(plane));
+
+		val = I915_READ(PIPESRC(pipe));
+		width = ((val >> 16) & 0xfff) + 1;
+		height = ((val >> 0) & 0xfff) + 1;
 
 		DRM_DEBUG_KMS("Found active pipe [%d/%d]: size=%dx%d@%d, offset=%x\n",
-			      crtc->pipe, crtc->plane,
-			      mode_cmd.width, mode_cmd.height, depth, offset);
+			      pipe, plane, width, height, depth, offset);
 
-		size = mode_cmd.pitches[0] * mode_cmd.height;
+		size = pitch * height;
 		size = ALIGN(size, PAGE_SIZE);
 
-		ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
-		if (!ifbdev)
-			continue;
+		/* In case we're handed multiple fbs, inherit the largest one */
+		if (!obj_size || size > obj_size) {
+			obj_size = size;
+			obj_offset = offset;
 
-		ifbdev->helper.funcs = &intel_fb_helper_funcs;
-		ret = drm_fb_helper_init(dev, &ifbdev->helper,
-					 dev_priv->num_pipe,
-					 INTELFB_CONN_LIMIT);
-		if (ret) {
-			kfree(ifbdev);
-			continue;
+			mode_cmd.pitches[0] = pitch;
+			mode_cmd.width = width;
+			mode_cmd.height = height;
+			mode_cmd.pixel_format =
+				drm_mode_legacy_fb_format(bpp, depth);
 		}
+	}
 
-		/* assume a 1:1 linear mapping between stolen and GTT */
-		obj = i915_gem_object_create_stolen_for_preallocated
-			(dev, offset, offset, size);
-		if (obj == NULL) {
-			DRM_DEBUG_KMS("failed to create stolen fb\n");
-			kfree(ifbdev);
-			continue;
-		}
+	if (!obj_size) {
+		DRM_DEBUG_KMS("no active pipes found, not using BIOS config\n");
+		goto out_fail;
+	}
 
-		ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
-		if (ret) {
-			drm_gem_object_unreference(&obj->base);
-			kfree(ifbdev);
-			continue;
-		}
+	ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
+	if (!ifbdev) {
+		DRM_DEBUG_KMS("failed to alloc intel fbdev\n");
+		goto out_fail;
+	}
+
+	ifbdev->helper.funcs = &intel_fb_helper_funcs;
+	ret = drm_fb_helper_init(dev, &ifbdev->helper,
+				 dev_priv->num_pipe,
+				 INTELFB_CONN_LIMIT);
+	if (ret) {
+		DRM_DEBUG_KMS("drm fb init failed\n");
+		goto out_free_ifbdev;
+	}
+
+	/* assume a 1:1 linear mapping between stolen and GTT */
+	obj = i915_gem_object_create_stolen_for_preallocated(dev, obj_offset,
+							     obj_offset,
+							     obj_size);
+	if (obj == NULL) {
+		DRM_DEBUG_KMS("failed to create stolen fb\n");
+		goto out_free_ifbdev;
+	}
 
-		info = intelfb_create_info(ifbdev);
-		if (info == NULL) {
-			drm_gem_object_unreference(&obj->base);
-			kfree(ifbdev);
+	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
+	if (ret) {
+		DRM_DEBUG_KMS("intel fb init failed\n");
+		goto out_unref_obj;
+	}
+
+	info = intelfb_create_info(ifbdev);
+	if (info == NULL) {
+		DRM_DEBUG_KMS("intelfb fb creation failed\n");
+		goto out_unref_obj;
+	}
+
+	/* FIXME: omit any crtcs left out in the above loop */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		if (!intel_crtc->active)
 			continue;
-		}
 
-		crtc->base.fb = &ifbdev->ifb.base;
+		crtc->fb = &ifbdev->ifb.base;
 		obj->pin_count++;
-		ifbdev->bios_fb = true;
+	}
+	ifbdev->bios_fb = true;
 
-		drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
-		drm_fb_helper_initial_config(&ifbdev->helper, bpp);
+	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
+	drm_fb_helper_initial_config(&ifbdev->helper, last_bpp);
 
-		vga_switcheroo_client_fb_set(dev->pdev, info);
-		dev_priv->fbdev = ifbdev;
+	vga_switcheroo_client_fb_set(dev->pdev, info);
+	dev_priv->fbdev = ifbdev;
 
-		DRM_DEBUG_KMS("using BIOS config for initial console\n");
+	DRM_DEBUG_KMS("using BIOS config for initial console\n");
 
-		return;
-	}
+	return;
 
+out_unref_obj:
+	drm_gem_object_unreference(&obj->base);
+out_free_ifbdev:
+	kfree(ifbdev);
+out_fail:
 	/* otherwise disable all the possible crtcs before KMS */
-	DRM_DEBUG_KMS("No active planes found\n");
 	drm_helper_disable_unused_functions(dev);
 }
 
-- 
1.7.10




More information about the Intel-gfx mailing list