diff mbox

[10/11] drm/i915: Reprobe connectors if vga_switcheroo handler registers late

Message ID 13e2b3aaed80274f37a07c1254c92fc30a33a523.1429610300.git.lukas@wunner.de (mailing list archive)
State New, archived
Headers show

Commit Message

Lukas Wunner April 19, 2015, 3:01 p.m. UTC
MacBook Pro hybrid graphics use a gmux chip to switch DDC lines between
gpus. It may register after the i915 driver, necessitating a reprobe of
the connectors and reinitialization of the fbdev.

Inspired by Matthew Garrett, who duplicated intel_setup_outputs() and
reduced it to just the eDP probing portion (which is not sufficient
since pre-retina MBPs used LVDS):
http://www.codon.org.uk/~mjg59/tmp/retina_patches/0024-i915-Add-support-for-reprobing-for-a-panel.patch

Commit 92122789b2d699a1e82dca502940e0dd37bf6f3b (drm/i915: preserve SSC
if previously set v3) sets lvds_use_ssc to 0, it must be reset to 1 so
that the SSC gets used on the panel.

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/gpu/drm/i915/i915_dma.c      | 40 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_drv.h      |  1 +
 drivers/gpu/drm/i915/intel_display.c |  2 +-
 3 files changed, 42 insertions(+), 1 deletion(-)

Comments

Chris Wilson April 21, 2015, 11:50 a.m. UTC | #1
On Sun, Apr 19, 2015 at 05:01:17PM +0200, Lukas Wunner wrote:
> +cleanup_gem:
> +	DRM_ERROR("failed to reinitialize fbdev\n");
> +	mutex_lock(&dev->struct_mutex);
> +	i915_gem_cleanup_ringbuffer(dev);
> +	i915_gem_context_fini(dev);
> +	mutex_unlock(&dev->struct_mutex);

This is a bit random since you don't initialize GEM here and presumably
the GPU is still available even if it has no outputs.
-Chris
Lukas Wunner April 21, 2015, 12:16 p.m. UTC | #2
Hi Chris,

On Tue, Apr 21, 2015 at 12:50:10PM +0100, Chris Wilson wrote:
> On Sun, Apr 19, 2015 at 05:01:17PM +0200, Lukas Wunner wrote:
> > +cleanup_gem:
> > +	DRM_ERROR("failed to reinitialize fbdev\n");
> > +	mutex_lock(&dev->struct_mutex);
> > +	i915_gem_cleanup_ringbuffer(dev);
> > +	i915_gem_context_fini(dev);
> > +	mutex_unlock(&dev->struct_mutex);
> 
> This is a bit random since you don't initialize GEM here and presumably
> the GPU is still available even if it has no outputs.

Hm, I copied this verbatim from i915_dma.c:i915_load_modeset_init(),
I was under the impression that this is required if fbdev initialization
failed. Am I missing something?

Thanks,

Lukas
Chris Wilson April 21, 2015, 12:37 p.m. UTC | #3
On Tue, Apr 21, 2015 at 02:16:56PM +0200, Lukas Wunner wrote:
> Hi Chris,
> 
> On Tue, Apr 21, 2015 at 12:50:10PM +0100, Chris Wilson wrote:
> > On Sun, Apr 19, 2015 at 05:01:17PM +0200, Lukas Wunner wrote:
> > > +cleanup_gem:
> > > +	DRM_ERROR("failed to reinitialize fbdev\n");
> > > +	mutex_lock(&dev->struct_mutex);
> > > +	i915_gem_cleanup_ringbuffer(dev);
> > > +	i915_gem_context_fini(dev);
> > > +	mutex_unlock(&dev->struct_mutex);
> > 
> > This is a bit random since you don't initialize GEM here and presumably
> > the GPU is still available even if it has no outputs.
> 
> Hm, I copied this verbatim from i915_dma.c:i915_load_modeset_init(),
> I was under the impression that this is required if fbdev initialization
> failed. Am I missing something?

Just that we haven't given much thought to its error path before. Here
it's even more different since we already have a working GEM, just no
connectors.
-Chris
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 68e0c85..86726b7 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -379,9 +379,49 @@  static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
 	return dev->open_count == 0;
 }
 
+static void i915_switcheroo_reprobe_connectors(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_encoder *encoder;
+
+	/*
+	 * Check whether we've already found a panel.
+	 * If so, we don't need to reprobe
+	 */
+	for_each_intel_encoder(dev, encoder)
+		if (encoder->type == INTEL_OUTPUT_LVDS ||
+		    encoder->type == INTEL_OUTPUT_EDP)
+			return;
+
+	/*
+	 * intel_modeset_gem_init() sets lvds_use_ssc to 0,
+	 * reset to 1 so that the SSC gets used on the panel
+	 */
+	dev_priv->vbt.lvds_use_ssc =
+		!(i915.panel_use_ssc == 0 ||
+		  dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
+	intel_setup_outputs(dev);
+
+	/* Destroy default 1024x768 fbdev and reinitialize */
+	intel_fbdev_fini(dev);
+	if (intel_fbdev_init(dev))
+		goto cleanup_gem;
+	async_schedule(intel_fbdev_initial_config, dev_priv);
+	return;
+
+cleanup_gem:
+	DRM_ERROR("failed to reinitialize fbdev\n");
+	mutex_lock(&dev->struct_mutex);
+	i915_gem_cleanup_ringbuffer(dev);
+	i915_gem_context_fini(dev);
+	mutex_unlock(&dev->struct_mutex);
+}
+
 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
 	.set_gpu_state = i915_switcheroo_set_state,
 	.reprobe = NULL,
+	.reprobe_connectors = i915_switcheroo_reprobe_connectors,
 	.can_switch = i915_switcheroo_can_switch,
 };
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e326ac9..7f58858 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3120,6 +3120,7 @@  extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
 extern void intel_detect_pch(struct drm_device *dev);
 extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
 extern int intel_enable_rc6(const struct drm_device *dev);
+extern void intel_setup_outputs(struct drm_device *dev);
 
 extern bool i915_semaphore_is_enabled(struct drm_device *dev);
 int i915_reg_read_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d547d9c8..9481206 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13027,7 +13027,7 @@  static bool intel_crt_present(struct drm_device *dev)
 	return true;
 }
 
-static void intel_setup_outputs(struct drm_device *dev)
+void intel_setup_outputs(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *encoder;