[v2,20/22,EXPERIMENTAL] drm: Use vga_switcheroo active client as proxy when reading DDC/AUX
diff mbox

Message ID e92963887342af48adb1dc962b793daf4ec823cb.1439288957.git.lukas@wunner.de
State New
Headers show

Commit Message

Lukas Wunner May 6, 2015, 12:06 p.m. UTC
The retina MacBook Pro uses an eDP panel and a gmux controller to switch
the panel between its two GPUs. Unfortunately it seems that it cannot
switch the AUX channel separately from the main link.

But we can emulate switching of DDC/AUX in software by using the active
client as a proxy to talk to the panel.

When reading the DPCD or EDID, store the struct drm_dp_aux and struct
i2c_adapter (for DDC) in vga_switcheroo. Retrieve the active client's
structures and use them in lieu of the client's own structures.

To avoid using proxying with external DP-connected displays, this is
constrained to eDP connectors and further constrained by vga_switcheroo
to its clients.

Based (loosely) on patches by Matthew Garrett <mjg59@srcf.ucam.org>
who used stashing instead of proxying and changed each driver rather
than the generic helper functions:
http://www.codon.org.uk/~mjg59/tmp/retina_patches/0025-i915-Use-vga_switcheroo-to-obtain-and-stash-EDID-DPC.patch
http://www.codon.org.uk/~mjg59/tmp/retina_patches/0026-nouveau-Use-vga_switcheroo-to-obtain-and-stash-EDID-.patch

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
    [MBP  6,2 2010  intel ILK + nvidia GT216  pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
    [MBP  8,2 2011  intel SNB + amd turks     pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
    [MBP  9,1 2012  intel IVB + nvidia GK107  pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
    [MBP 11,3 2013  intel HSW + nvidia GK107  retina -- work in progress]

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/gpu/drm/drm_dp_helper.c | 14 ++++++++++++++
 drivers/gpu/drm/drm_edid.c      | 12 ++++++++++++
 2 files changed, 26 insertions(+)

Patch
diff mbox

diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 80a02a4..f34622f 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -27,6 +27,7 @@ 
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/i2c.h>
+#include <linux/vga_switcheroo.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drmP.h>
 
@@ -239,6 +240,19 @@  static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
 			 void *buffer, size_t size)
 {
+	struct pci_dev *pdev = to_pci_dev(aux->dev);
+	struct drm_dp_aux *proxy_aux;
+
+	if (aux->connector &&
+	    aux->connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		vga_switcheroo_set_aux(pdev, aux);
+		proxy_aux = vga_switcheroo_get_aux(pdev);
+		if (proxy_aux && proxy_aux != aux) {
+			DRM_DEBUG_KMS("Using vga_switcheroo active client as proxy\n");
+			aux = proxy_aux;
+		}
+	}
+
 	return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer,
 				  size);
 }
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index cdb2fa1..b4b0e01 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1379,6 +1379,18 @@  struct edid *drm_get_edid(struct drm_connector *connector,
 {
 	struct edid *edid;
 	struct pci_dev *pdev = connector->dev->pdev;
+	struct i2c_adapter *proxy_ddc;
+
+	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+	    connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		vga_switcheroo_set_ddc(pdev, adapter);
+		proxy_ddc = vga_switcheroo_get_ddc(pdev);
+		if (proxy_ddc && proxy_ddc != adapter) {
+			DRM_DEBUG_KMS("Using vga_switcheroo active client as proxy\n");
+			adapter = proxy_ddc;
+			pdev = to_pci_dev(proxy_ddc->dev.parent);
+		}
+	}
 
 	vga_switcheroo_lock_ddc(pdev);