[PATCH 25/43] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_dma.c      |    4 ++
 drivers/gpu/drm/i915/intel_display.c |    3 -
 drivers/gpu/drm/i915/intel_drv.h     |    1 +
 drivers/gpu/drm/i915/intel_fb.c      |  118 ++++++++++++++++++++++++++++++++--
 4 files changed, 119 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index f947926..51c8200 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1312,6 +1312,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
 	intel_modeset_init(dev);
 
+	/* Wrap existing BIOS mode configuration prior to GEM takeover */
+	intel_fbdev_init_bios(dev);
+
 	ret = i915_gem_init(dev);
 	if (ret)
 		goto cleanup_gem_stolen;
@@ -1326,6 +1329,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
 	/* FIXME: do pre/post-mode set stuff in core KMS code */
 	dev->vblank_disable_allowed = 1;
 
+	/* Install a default KMS/GEM fbcon if we failed to wrap the BIOS fb */
 	ret = intel_fbdev_init(dev);
 	if (ret)
 		goto cleanup_irq;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1a0ded5..97f294e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6506,9 +6506,6 @@ static void intel_setup_outputs(struct drm_device *dev)
 			intel_encoder_clones(dev, encoder->clone_mask);
 	}
 
-	/* disable all the possible outputs/crtcs before entering KMS mode */
-	drm_helper_disable_unused_functions(dev);
-
 	if (HAS_PCH_SPLIT(dev))
 		ironlake_init_pch_refclk(dev);
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 094f31e..762d580 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -436,6 +436,7 @@ extern int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
 				  struct drm_mode_fb_cmd2 *mode_cmd,
 				  struct drm_i915_gem_object *obj);
+extern void intel_fbdev_init_bios(struct drm_device *dev);
 extern int intel_fbdev_init(struct drm_device *dev);
 extern void intel_fbdev_fini(struct drm_device *dev);
 extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 7835297..9be61b5 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -233,19 +233,127 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 	}
 }
 
-int intel_fbdev_init(struct drm_device *dev)
+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)
+			continue;
+
+		if (INTEL_INFO(dev)->gen >= 4) {
+			if (val & DISPPLANE_TILED)
+				continue; /* unexpected! */
+		}
+
+		switch (val & DISPPLANE_PIXFORMAT_MASK) {
+		default:
+		case DISPPLANE_8BPP:
+			continue; /* ignore palettes */
+		case DISPPLANE_15_16BPP:
+			depth = 15; bpp = 16;
+			break;
+		case DISPPLANE_16BPP:
+			depth = bpp = 16;
+			break;
+		case DISPPLANE_32BPP_NO_ALPHA:
+			depth = 24; bpp = 32;
+			break;
+		}
+
+		if (INTEL_INFO(dev)->gen >= 4)
+			offset = I915_READ(DSPSURF(crtc->plane));
+		else
+			offset = I915_READ(DSPADDR(crtc->plane));
+		mode_cmd.pitches[0] = I915_READ(DSPSTRIDE(crtc->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);
+
+		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);
+
+		size = mode_cmd.pitches[0] * mode_cmd.height;
+		size = ALIGN(size, PAGE_SIZE);
+
+		ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
+		if (!ifbdev)
+			continue;
+
+		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;
+		}
+
+		/* 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) {
+			kfree(ifbdev);
+			continue;
+		}
+
+		ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
+		if (ret) {
+			drm_gem_object_unreference(&obj->base);
+			kfree(ifbdev);
+			continue;
+		}
+
+		info = intelfb_create_info(ifbdev);
+		if (info == NULL) {
+			drm_gem_object_unreference(&obj->base);
+			kfree(ifbdev);
+			continue;
+		}
+
+		crtc->base.fb = &ifbdev->ifb.base;
+		obj->pin_count++;
+
+		drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
+		drm_fb_helper_hotplug_event(&ifbdev->helper);
+
+		vga_switcheroo_client_fb_set(dev->pdev, info);
+		dev_priv->fbdev = ifbdev;
+		return;
+	}
+
+	/* otherwise disable all the possible crtcs before KMS */
+	DRM_DEBUG_KMS("No active planes found\n");
+	drm_helper_disable_unused_functions(dev);
+}
+
+int intel_fbdev_init(struct drm_device *dev)
+{
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_fbdev *ifbdev;
 	int ret;
 
+	if (dev_priv->fbdev)
+		return 0;
+
 	ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
-	if (!ifbdev)
+	if (ifbdev == NULL)
 		return -ENOMEM;
 
-	dev_priv->fbdev = ifbdev;
 	ifbdev->helper.funcs = &intel_fb_helper_funcs;
-
 	ret = drm_fb_helper_init(dev, &ifbdev->helper,
 				 dev_priv->num_pipe,
 				 INTELFB_CONN_LIMIT);
@@ -254,6 +362,8 @@ int intel_fbdev_init(struct drm_device *dev)
 		return ret;
 	}
 
+	dev_priv->fbdev = ifbdev;
+
 	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
 	drm_fb_helper_initial_config(&ifbdev->helper, 32);
 	return 0;
-- 
1.7.10



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux